On Critical Hits

I haven't talked about Witness To Unity in a long while, or posted on here. Maybe I should do that.

This is going to be a short one though, since I don't really remember the process behind developing this code. I just want to comment on it because I quite like this concept.

For a few things in Witness to Unity, I've been trying to reduce some of the randomness or chance, specifically in battle. For now there still exists chance for missing in battle, and there are specific recovery items that can fail to work. ... so it might actually be more like I've just shifted where the randomness lies. Erm.

Anyway, since this is titled critical hits, I want to comment on what I've done with that.

  def item_cri(user, item)
    rate = 0
    if item.damage.critical
      rate = rand > (1 + cev) ? 1 : user.cri
    return rate

This is Witness to Unity's critical hit rate. Later on in a larger block there exists @result.critical = (rand < item_cri(user, item)).

An additional note is the format of the above code is rate = condition ? success : failure.

What happens is dependant on a larger design change I made: by default, everyone - enemies and allies alike - have 0% critical hit chance (cri) and critical hit evasion (cev). The idea behind this design is that critical hits can now be controlled by the player's action. Under certain status conditions, the cri or cev of the afflicted will change from this base 0. The status condition Distress now makes the afflicted 50% likely to take a critical hit.

This probably sounds rather complicated, because the chance of a critical hit is basically made of four different values: two random numbers, and two thresholds. First a random number is rolled, which is checked against the first threshold cev. So that this design works, that threshold returns 1. If that threshold is not passed however, cri is returned, and is checked against a second randomised number.

Maybe this will make more sense with an example. Because cev is normally 0 we might get something like "is 0.47236 > (1 + 0)?" ... and the answer to that is no. Because it isn't, ignore that "1", and give user.cri to @result.critical to work out the critical hit rate. Because user.cri is normally zero, rand < item_cri will also fail.

Distress mentioned above decreases cev by 50%, this makes the above code "rand > 0.5", which makes it possible for it to return that "1". Since rand always returns under 1.0, it means @result.critical will absolutely give a critical hit. Once again, if the cev randomised value happened to fail (i.e. rand > 0.5), @result.critical's randomised variable has to compare with user.cri. If user.cri is 0, there's no critical hit. If the user has a critical hit boost of 50%, that instead works out as @result.critical = rand < 0.5.

Originally, RMVXAce does something like combining cri and cev together, which makes sense when it's not assumed that these values will be usually 0. This setup checks each one after another. While originally a critical hit rate and critical evasion rate of 50% would return 25% (or 0.5 and 0.25, but whatever), this system performs the 50% coinflip twice - if the first one is a success, the second is ignored.

Sunday, 6th July 02014

blog, games, programming, witness to unity.