ID:1454500
 
(See the best response by D4RK3 54B3R.)
Problem description: I want to program a chance of hitting based on speed. I need it for my game. So if both the attacker and defender have equal speed then the attacker has as much chance of hitting the defender as the defender dodging the attack. If the attacker has greater speed then he has a higher chance of succeeding an attack, if the attacker has a lower speed than the defender then he has a lesser chance of hitting the defender.
Perhaps use ratios?

var/attackChance = 50 * (Attacker.Speed / Defender.Speed)
// If they're equal, attackChance will be set to 50
// Having a Speed 2x your target's speed will make 100% hit chance.
if(prob(attackChance)) // prob() returns 1 at a probability of attackChance
// Attack hits
else
// Attack misses
what about this:

mob/verb/test_spd()
var/spd1=10
var/spd2=5
var/firstroll=roll(1,spd1)
var/secondroll=roll(1,spd2)
if(firstroll>secondroll)
src << "spd1 hit!"
else if(firstroll==secondroll)
if(prob(50))
src << "spd1 hit!"
else src << "spd1 missed!"
else if(firstroll<secondroll)
src << "spd1 missed!"
?
I suppose it works.

spd1 has a 60% chance of being 5 or higher.
spd2 has a 20% chance of being 5
Yeah thanks. But how does your one work?
It's a little similar. It just considers the ratios of the speeds. Your base attack chance is 50%, that's why attackChance has 50 built in. The end part is the ratio of the speeds. If the attacker has a higher speed, then it multiplies 50 by a number greater than 1 (because X/Y > 1 where X > Y). Which ups the attack chance. So, for example.

Attacker_Speed = 10
Defender_Speed = 8
Attacker_Speed / Defender_Speed = 1.25
50 * 1.25 = 62.5 //<-- attackChance
if(prob(attackChance)) // if(prob(62.5))
// 62.5% chance to hit
else // 37.5% chance to miss

/* Let's swap the speeds */
Attacker_Speed = 8 ; Defender_Speed = 10
Attack_Speed / Defender_Speed = 0.8
50 * 0.8 = 40 // <-- attackChance
if(prob(attackChance)) // if(prob(40))
// 40% chance to hit
else // 60% chance to miss


Oh I didn't know that kind of math.
Best response
I would use a sigmoid sort of function.

These generally take one to three parameters. For our case, I think three is most appropriate.
I'm going to call them attackerSpeed, defenderSpeed, and scale.

The code for it looks like this.
proc/hitChanceSigmoid(attackerSpeed, defenderSpeed, scale = 10)
return 100 * 1/(1+10**((defenderSpeed-attackerSpeed)/(scale))

/*
if our parameters were
attackerSpeed = 10
defenderSpeed = 8

The returned chance to hit would be 61%

if our parameters were
attackerSpeed = 20
defenderSpeed = 8

The returned chance to hit would be 94%

if our parameters were
attackerSpeed = 8
defenderSpeed = 15

The returned chance to hit would be 17%
*/


When the difference between the attackerSpeed and defenderSpeed is equal to scale, then the chance to hit is roughly 91%. If the difference between the speeds is equal to 1/2 scale, then the chance to hit is roughly 75%. If the two speeds are equal, the chance to hit is 50%.

So you adjust the value of scale to match what is most appropriate for your game. For example: In an RPG, if you gain 1 speed per level and you want someone level 30 to hit someone level 20 about 90% of the time, then you can use a scale of 10. If you want someone level 50 to hit someone level 20 only 75% of the time, then maybe you should adjust scale to be 60.

This should make designing how the dodge mechanic scales relatively straightforward.

This sigmoid function has two horizontal asymptotes: One at 100%, and one at 0%. This means that you will never get a chance to hit that is below 0% or above 100%

The problem with Lugia's approach is that it can yield a chance to hit that is not confined to 0% to 100%.
For example, if attackerSpeed were 5, and defenderSpeed were 2, you would get a chance to hit of 125%
If you reverse them, with the attackerSpeed of 2 and defenderSpeed of 5, then you would get a chance to hit of 20%.

Using my sigmoid function for speeds of 2 and 5, you would get a chance to hit of 33% one way and 67% the other way.