Improved checkHit function

All development conversation and discussion takes place here

Moderator: Moderator

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

Improved checkHit function

#1 Post by Hachem_Muche »

Improved checkHit function

TOME currently uses two different functions to check for success in opposed roll situations, such as one skill countering another. These cases come up extensively in such things as melee attacks, spell saving throws, stealth and invisibility, detecting and disarming traps, etc. For most to-hit checks, the function checkHit compares offense (atk) verses defense (def) with the following formula:

HitChance = 50 + 2.5 * (atk - def)

This function is simple and linear, but needs hard limit checks to be robust, and is unforgiving of wide differences in offense versus defense. That is, the chance of success quickly vanishes or tops out once the difference between atk and def approaches +/-20 (subject to hard-coded limits). This is an important limitation because it allows certain combinations of npc (and player) talents to become nearly invincible. A random boss with several defense bonuses can become almost completely unhittable by a melee-based character, for example.

The second function, checkHitOld works in almost the same way, but uses an exponential function to compute success chance:

a = 1/(1 + exp(-(atk - def)/7))
b = atk/(atk + def)
HitChance = 50 * (a + b)

with limit checks to avoid singularities when atk = def. This function is smoother and more forgiving, but is computationally more expensive (not really an issue here) and starts to break down at low defense values -- it cannot tolerate atk and def <= 0. The function behaves differently in the early game than in the late game because the balance between atk and def is significantly affected by the magnitude of the values involved. Both functions require limit checks (default 5% and 95%) to keep success probabilities reasonable throughout the normal range of play.

As an alternative to these functions, I propose a new checkHit function (that I call checkHitSmooth) that combines the best features of both of the current formulas:

HitChance = 50 + 50 * (atk - def)/(abs(atk - def) + m)
m = constant > 0 (default 10)

This function is simple, both mathematically and computationally, is inherently bounded (it always gives a hit chance between 0% and 100% without limit checks needed, and scales well with all character levels. The tuning paramer, m, directly affects the slope of the line passing through (50%,0). Higher values flatten out the curve, while smaller ones steepen it near the middle. The following charts plot a comparison of the three functions (with the limit checks in place for checkHit and checkHitOld):
Charts1-4.jpg
Charts1-4.jpg (160.72 KiB) Viewed 5302 times
The stability of the new function is obvious. Since it depends only on the difference between atk and def, and not their absolute values, it maintains its integrity at any level, preserving game balance from character level 1 to level 50 (or beyond). It tolerates any conceivable range of values. (Since everyone really wants to know that -1,000,000 atk versus +10,000 def has a 0.000495% chance to succeed, when m = 10.) By tolerating negative numbers, it opens up the option of having negative offensive stats, particularly in the early game where debuffs are currently limited by small combat values.

Further, the new routine (below) is a completely compatible drop-in replacement for the current checkHit function, without any other changes required in the game:

Code: Select all

-- I5 updated to smooth out hit probabilities and to be more forgiving of level differences
function _M:checkHit(atk, def, min, max, factor)
	local min = min or 0
	local max = max or 100
	if game.player:hasQuest("tutorial-combat-stats") then
		min = 0
		max = 100
	end --ensures predictable combat for the tutorial
	local hit = 50+50*(atk-def)/(math.abs(atk-def)+10) -- tunable parameter in denominator 10> ~ 16.7% hit at -20 atk-def
	hit = util.bound(hit, min, max)  -- Limit checks aren't needed with the new formula.  Left in for compatibility
	print("checkHit(smooth)",atk,def,"=> chance to hit", hit)
	return rng.percent(hit), hit
end
The "factor" argument is a holdover from a previous version of checkHit that is still included (though not used) in some of the game's older routines. (It would be desirable to use this as a dynamic tuning parameter for the new function, but all of the legacy function calls would need to be updated.)

By changing the constant, m, checkHitSmooth can be tuned to more closely mimic either of the existing checkHit and checkHitOld functions. With m=20, it gives nearly identical results to checkHitOld, but without the deterioration at low values:
Chart5.jpg
Chart5.jpg (42.44 KiB) Viewed 5302 times
I have tested this function extensively in my Infinite500 addon, which requires that a large range of values be tolerated, sometimes as much as +/-100 deep in the I.D. Replacing both existing functions with this one, I have used m=10 as the tuning parameter as a compromise between the more forgiving checkHitOld and maintaining consistency in game play with the more widely used existing (linear) checkHit function. I think this has worked out especially well, since tactical uncertainty is increased: improbable events do occur requiring you to stay on your toes and you always have a reasonable chance to land an attack.
Author of the Infinite 500 and PlenumTooltip addons, and the joys of Scaling in ToME.

supermini
Uruivellas
Posts: 800
Joined: Tue May 15, 2012 11:44 pm

Re: Improved checkHit function

#2 Post by supermini »

Wow. Nice work. :)
<darkgod> all this fine balancing talk is boring
<darkgod> brb buffing boulder throwers

bricks
Sher'Tul
Posts: 1262
Joined: Mon Jun 13, 2011 4:10 pm

Re: Improved checkHit function

#3 Post by bricks »

+1000

Also, could this be applied to power vs. save checks?
Sorry about all the parentheses (sometimes I like to clarify things).

supermini
Uruivellas
Posts: 800
Joined: Tue May 15, 2012 11:44 pm

Re: Improved checkHit function

#4 Post by supermini »

bricks wrote:+1000

Also, could this be applied to power vs. save checks?
That would be good.
<darkgod> all this fine balancing talk is boring
<darkgod> brb buffing boulder throwers

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

Re: Improved checkHit function

#5 Post by Hachem_Muche »

supermini wrote:
bricks wrote:+1000

Also, could this be applied to power vs. save checks?
That would be good.
That's the default behavior.
Author of the Infinite 500 and PlenumTooltip addons, and the joys of Scaling in ToME.

Post Reply