BP Logo
Home » MODDING HQ 1.13 » v1.13 Modding, Customising, Editing » v1.13 Time Capsule (How-to Library) » "How does it work?" Part 4: Chance-to-Hit
"How does it work?" Part 4: Chance-to-Hit[message #196106] Tue, 09 September 2008 11:45 Go to previous message

Registered:March 2006
Location: Jerusalem
I remember downloading a little tool, a long time ago, that allowed me to calculate the Chance-to-Hit of shots in Jagged Alliance 2. That was a long time ago, way before the 1.13 project started. The calculation was relatively simple, and you could even do it by hand. It was affected by about a dozen factors, but wasn't difficult to calculate them all together, although the tool really helped.

When I started playing 1.13, I was amazed by the CTH bar that appears over my shooting icon. It actually showed how likely my shots were to hit, which helped immensely. It's really hard to play the old JA2 now, without it, and I wonder how I've managed to play the vanilla JA2 at all! Then came the "F" hotkey, which even shows a numeric value of CTH. Life couldn't get much simpler than that.

But the simple calculation is gone now. No longer do we rely on a dozen factors, but several dozen. Nowadays, CTH is affected by everything but the kitched sink. The formula to calculate CTH in 1.13 is extremely complex, and since we only see the result, it can be very confusing. Why is one merc's CTH so much higher? Why is my CTH so low when it looks like I should have a better shot? What the hell is going on with the extra aiming?

Now, there are tons of questions, and it would take a long time to answer all of them one by one. So instead, in the best tradition of "How does it work?", I'm going to make a very ambitious and very foolish attempt to translate the entire CTH calculation into something resembling plain english and 5th grade maths.

The CTH formula is huge. It draws on a lot of factors, and frequently jumps aside, using other functions to make complex calculations. Translating it from C++ to the English Language was very tricky, and in some cases I wasn't even sure I understood what the hell was going on.

The explanation below is written partially in Pseudo-Code. That's the "English Translation" of the real game code, that is to say I've tried to use simple sentences instead of lines of code, to describe what's going on. In many cases, it remains cryptic as hell despite my best efforts. But at the very least, some things should be BLATANTLY clear.

I hope that this will, at least partially, help us understand what we are doing wrong, and help us reduce an enemy's CTH while increasing our own. I know my tactical understanding of the game has already benefitted from reading the formula, and I hope the same will happen to others who read this.

DISCLAIMER: Yes, this formula is EXTREMELY COMPLEX and you may not understand some/half/all of it. It's the best I could do though.

So, without further ado, the CHANCE TO HIT formula is unveiled!!


The formula is called in several cases, the most important of which is when we actually fire a weapon. But it is also called when we simply put our cursor on an enemy, and when we press the "F" key to see our CTH. In any case, the program will always put these values into the formula:

Shooter: The guy who's firing the gun!
TargetLocation: The point we were aiming at. Doesn't have to be an enemy, we'll see how that works later.
Targetted_Bodypart: The enemy's bodypart we are trying to hit, if there's an enemy at all. Also, when shooting at PRONE enemies or tanks, the targetted bodypart is "none".
AimTime: The number of extra APs we spent aiming at the target.

Armed with these, we can start calculating.


To begin, the program makes sure that the Shooter has some marksmanship:

If Shooter's_Marksmanship = 0 then
   Chance-To-Hit = a big fat 0. stop the calculation and go find something to eat.


Next, the program checks to see whether the weapon we're using has a high-power scope:

For each Attachment on the Weapon, do
   If Attachment gives more than +14 Aiming_Bonus, then
       High-Powered Scope!
       Not a high-powered scope.

Nice to know - scopes that give +15 or more Aiming Bonus are treated differently from others. The program needs to know that it needs to handle a high-powered scope - you'll see the effect this has in later parts of the program.


The program now calculates a modifier based on the gun's condition.

If Weapon_Status is greater than or equal to 85, then
   Status_Modifier = 100
   Status_Modifier = Weapon_Status * 100 / 85

If the condition of the weapon is 85-100%, the result (status_modifier) is 100. If the weapon's condition is 84%, the result will be 98. It drops steadily downwards after that. At 0% status, the weapon is broken and can't fire at all, so the result is 0.

We'll keep this value (called "Status_Modifier") for later.


Now we come to the most important part of the CTH formula - we're going to determine the base chance-to-hit. This is done primarily with our Marksmanship skill. It's done differently for RocketLaunchers, and I'll explain that in a moment. But here's the formula for bullet-shooting guns:

Effective_Marksmanship = Shooter's_Actual_Marksmanship
If Shooter is Drunk, then
   Effective_Marksmanship = Shooter's_Actual_Marksmanship * Drunkness_Value / 100
If Shooter is a Robot, then
   Effective_Marksmanship = Whichever is higher: the Robot's Marksmanship, or the Controller's Marksmanship

Drunkness takes effect here, and the drunkness_value depends on how severely drunk the shooter is.
If you're sober, the value is 100.
At drunkness level 1, the value is 75.
At drunkness level 2, it's 65.
At drunkness level 3, it's 50.
There's also a drunkness level 4 (hung over!) but it doesn't affect shooting (the value is 100, like when you're sober).

So in effect, if you're tipsy, you lose 25% of your effective_marksmanship. If you're drunk, you lose 50%.

Ok, let's get back to business, and see how Rocket Launchers are handled. This is a bit more complex, as it takes into account such things as dexterity and level. I'll do this bit by bit.

If Weapon is a Rocket Launcher, then
   Effective_Marksmanship = Average of:
      1) Shooter's_Actual_Marksmanship
      2) Shooter's_Actual_Dexterity
      3) Shooter's_Actual_Wisdom
      4) Shooter's_Actual_Level * 10

Each of these are then tempered by drunkness, in the same way explained above. Except level - if you're tipsy (first level of drunkness) there's no effect on level. At the next drunkness stage, you lose 1 level, and when completely drunk you lose 2 levels, for the purposes of this calculation. Again, being hung over doesn't matter here.

Also, level is further adjusted for Claustrophobic mercs. If you've read my previous articles, you'll know that when a Claustrophobic character is underground, their effective level is dropped by one point. Note that the effective level can't ever drop below 1.

Furthermore, the HEAVY_WEAPONS skill now takes effect:

If Weapon is a Rocket Launcher, then
   Effective Marksmanship is increased by 15 points per level of the HEAVY_WEAPONS skill.

Pretty straightforward there.


Right, so now we have our basic value, called "Effective_Marksmanship". From now, on, I'm just going to call it "Base_Chance". Later on, we're going to have another value called "Actual_Chance", but that's later.


First up, we're going to modify the Base_Chance a bit, and we'll start with Morale.

Morale works differently for Player Characters and AI characters. PCs have a morale value that goes from 0 to 100. 50, the middle value, is the "normal" state that our mercs are usually in (called "Stable" in the game). At 100, our morale is highest, and at very low values we get deserters. The AI however simply has four different morale "stages", going from "hopeless" to "worried" to "confident" to "fearless.

With PCs, this is the formula:
If Soldier's_Morale > 50, then
   Morale_Modifier = (Soldier's_Morale - 45) / 100
   Morale_Modifier = (Soldier's_Morale - 50) * 2 / 5

Effectively it means that at 55 morale, you get +1 Morale Modifier, and an extra +1 for each 10 points above 55. At 95-100 morale, we get the maximum bonus, which is +5.
When our morale is around 47, we get -1 penalty, and an extra -1 for each 2-3 points below 47. At 1 morale we get a whopping -20 modifier!

With NPCs, each "stage" of morale gives a different bonus:

"Hopeless" morale gives -15
"Worried" morale gives -7
"Confident" morale gives +2
"Fearless" morale gives +5

Right, regardless of whether it's a PC or NPC, we now add this up to the Base_Chance:

Base_Chance = Base_Chance + Morale Modifier

Next, we're going to calculate how stamina affects the shooter's aim. Here's another complicated formula for you:

Fatigue_Modifier = Base_Chance * Breath_Penalty  / 100 / 2

Breath_Penalty here depends on the character's current stamina, and it works in stages as we've seen some things do before:

At 85 or above, Breath_Penalty is 0
At 70-84, Breath_Penalty is 10
At 50-69, Breath_Penalty is 25
At 30-49, Breath_Penalty is 50
At 15-29, Breath_Penalty is 75
At 14 or less, Breath_Penatly is 90

When we figure this into the formula above, we see that the Fatigue_Modifier can't be more than 45% of our Base_Chance, and that's only if we're about to pass out. Normally, we'd only lose about 5% of our Base_Chance due to fatigue.

So once we have that penalty, let's just subtract it from our Base_Chance:

Base_Chance = Base_Chance - Fatigue_Modifier


This is where the Base_Chance value branches off. The program makes a "working copy" of this value, and saves the Base_Chance for later calculations. The copy will now be called "Actual_Chance", and we're going to be modifying it exclusively. It'll later be compared to Base_Chance, as you'll see soon, but the end result will be the Actual_Chance after it has gone through a TON of modifications.

Actual_Chance = Base_Chance

Straight away, however, the program does something very important - it'll check to see whether our gun is in good enough shape to compensate for the shooter's inaccuracy. We'll use the Status_Modifier we calculated a few steps ago.

If Status_Modifier < Base_Chance then
   Actual_Chance = average of:
       1) Base_Chance
       2) Status_Modifier

This can have a very serious impact on our chance-to-hit. It means that if the gun is in bad shape, it can drop our chance to hit by a good amount, before we've even had the chance to calculate other stuff! This is very strange though, because if you remember then we've already taken gun condition into account earlier in the calculations... I'm not sure I agree with this part of the code, but that's what we've got for now.


Right, so from now on we're going to be working with "Actual_Chance", and keep "Base_Chance" for later comparisons.

We're going to add a couple of straight bonuses now, and most of you probably know the first one well - a bonus for firing at the same target again:

If TargetLocation is the same as the TargetLocation of the previous shot, then
   Actual_Chance increased by 10

A flat +10 to CTH right there. Note of course that we haven't checked if the TargetLocation has an enemy in it yet - so you actually get a bonus for firing at empty squares repeatedly, too! Please note that it's always just +10, it's not an incremental bonus. You won't get +20 in the next shot at the same target.

After this, we'll add a wicked bonus to PSYCHO characters. Yes, indeed, all psychos get a bonus to their CTH, with any gun, at any mode of fire:

If Shooter is a PSYCHO, then
   Actual_Chance is increased by 15


Now we add another piece of data to the cauldron - "Range". The program computes this by itself, and the result we get is the range in METERS, not tiles. So from this point on, whenever range is discussed, I'm talking about meters (unless stated otherwise!). In the current game system, 10 METERS = 1 TILE.

Let's see how range figures into this, as we move on to our next section. This section calculates the modifier based on the shooter's stance. Different stances give different bonuses, of course.

We'll do them one by one, starting with the STANDING stance:

If Shooter is Standing, then
   If using a High_Power_Scope, and Range is greater than the Minimum_Range_For_Aim_Bonus of the scope, then
       Scope_Penalty = Scope_Aim_Bonus * (Range - Minimum_Range_For_Aim_Bonus) / 1000
       If Scope_Penalty > 20, then
          Scope_Penalty = 20

Hmmm, a tad complicated there. It's going to get even more complicated later on, but I'll do my best to explain.

Basically, in the Standing stance, we get no penalty to our accuracy, UNLESS we're firing a sniper rifle with a very powerful scope (remember? +15 aiming bonus or above is a high-power scope).

If such a scope is involved, things get complicated. The Minimum_Range_For_Aim_Bonus is drawn directly from the XML data of the scope we're using - it determines at which distance our character uses the scope. If the target is closer than this distance, the character doesn't use the scope at all. Beyond the distance, he can get aiming bonuses from the scope, but as you see here he'll also have some trouble using it while standing up.

See that complex line with the mathematical equation? We can write it a bit differently to have it make more sense:

Scope_Penalty = Scope_Aim_Bonus * The difference between the minimum range to use the scope and the actual range to target, in TILES / 100.

So for each tile beyond the minimum range to use the scope, we get a penalty equal to 1/100 of the scope's aiming bonus. This doesn't sound like much, of course, but let's show some examples of how this works:

A Scope 10x (a regular Sniper Scope) has a minimum range of 70 (that's 7 tiles), and an aiming bonus of 20. Let's see how this scope behaves when we shoot at someone who is standing 8 tiles from us:

Scope_Penalty = 20 * (8-7) / 100 = 0.2

Not a serious penalty, of course. 0.2 gets immediately translated to 0, anyway. Now, what happens if the target is standing further away, say 30 tiles away, just beyond viewing range?

Scope_Penalty = 20 * (30-7) / 100 = 4.6

That's a bit more impact there. I'm not happy with this bit, myself, because the penalty is really very small. But it's important that we understand how this works, because we're going to see this recurring later.

Also note in the code block above, that the program makes sure that the Stance_Penalty doesn't go above 20.

Next, let's look at the CROUCHING stance:

If Shooter is Crouched, then
   Stance_Bonus = Range IN TILES
   If Stance_Bonus > 10, then
      Stance_Bonus = 10

Wow, so actually, while we're crouched, we get a bonus equal to the distance to the target! The farther the enemy is from us, the more bonus we get! Of course, we don't get any bonus beyond the 10 tile range. This tells us something important though - at very short range, we only get a very small bonus when crouched, compared to standing up... That little bit of info could save us some APs in close-quarters-combat, eh?

Crouch stance also gives a penalty for using High-Powered Scopes, in fact it is exactly HALF the penalty we get while STANDING. Read about this above.

Prone stance is the best of all three, as far as shooting is concerned:

If Shooter is PRONE, then
   Stance_Bonus = Range IN TILES
   If Stance_Bonus > 20, then
      Stance_Bonus = 20

This is the same as crouched mode, except it works for up to 20 tiles of range (giving us a maximum bonus of 20). Again, the farther the target is, the more bonus you get.

But the best feature of Prone mode is, of course, that you do NOT get a penalty for using a high-powered scope! Snipers should lie down whenever they can for this very reason. Of course, as you saw above, the penalty isn't too big, so it doesn't REALLY matter much, but it does help. Also, of course, prone stance allows us to get bonuses from bipods, but that's later.

Let's add it all up:

Actual_Chance = Actual_Chance + Stance_Bonus - Scope_Penalty


Actual_Chance is increased by the weapon's Accuracy value

This should be obvious. The weapon's Accuracy is read directly from Weapons.XML, and never ever changes.


Next up, we take a look at handguns, and particularly, dual-firing (firing two weapons at the same time).

If Weapon is One-Handed, then
   If Other hand is free, then
      If Weapon is a Handgun, then
         Actual_Chance is increased by 5
   Else (if other hand is holding something)
      If Weapon is an SMG, then
         Actual_Chance is reduced by 5
      If character doesn't have the Ambidextrous skill, then
         If we meet the requirements to dual-fire, then
             Actual_chance is reduced by 20!

Let's break this up into components, and go step by step.

First we check to see if the weapon we're firing is one-handed, like a handgun or SMG. If it isn't, we move on, otherwise let's see what happens.

If the other hand is free, meaning we're not holding anything there (ANYTHING!!), and the gun we're firing is a handgun, then we can use both hands to hold it and we get +5 to our chance-to-hit.

If the other hand is occupied, and we're trying to fire an SMG, then our weapon is less stable. We lose 5 points of CTH for not holding the weapon with both hands.

Finally, if we're trying to shoot two weapons at the same time, and we don't have the ambidextrous trait, then we lose 20 points of CTH. That's why ambidextrous mercs are so much better at shooting two weapons at the same time!

Note that in the code above I used the words "meet the requirements to dual-fire". This is actually a pretty complex check. To be valid, the weapons you are holding have to answer these criteria:

1) Both weapons need to be guns. (not GLs, rockets, etc.)
2) Both weapons have to be one-handed.
3) Both weapons must not be set to burst fire.
4) Both weapons must have ammo.
5) Both weapons must be useable (condition better than 10)


From this point on, there's a pair of sub-calculation that need to be mentioned. These calculations are called "BonusReduce" and "BonusReduceMore". They are used to determine how much actual bonus is given by an item or attachment, based on their actual status.

When BonusReduce is used, items with 85 status or upwards give their full bonus. Under 85 status, the bonus begins to drop, until at 0 condition you get, well, 0 bonus. The formula is:

If Item's_Status is between 1 and 85 then
   Final_Bonus = ( ( (Item's_Status * 100) / 85 ) * Original_Bonus ) / 100
   Final_Bonus = Original_Bonus

In effect, if the item's status is 42%, then the bonus you receive from the item is roughly 50% of what it SHOULD give. If the item's status is 0, or over 85, the calculation is skipped and the result is simply the Original_Bonus.

The second formula, "BonusReduceMore", is much more severe. The bonus drops with item status, but at 50% status the item gives no bonus, and below 50% it gives a PENALTY instead:

If Item's_Status is between 1 and 99 then
   Final_Bonus = ( ( ( (Item's_Status * 100) / 100 ) - 50 ) * Original_Bonus ) / 50 
   Final_Bonus = Original_Bonus

Yeah it's kind of complex, but the end result is that as the item's condition falls towards 50%, it gives a smaller bonus. But if the item's condition gets below 50%, it starts giving a penalty, which at 1% condition is opposite in strength to the bonus that would've been given at 99%.

Many items use one kind of bonus formula, and many use the other kind of bonus formula. I'm not sure, but it's possible that one type of item might be checked differently in different parts of the game.

For simplicity's sake, I'll give them new names:

a "MILD" bonus check is the steady decrease of the bonus from 100% to 0%, based on condition.
a "HARSH" bonus check is for bonuses that decrease as the item falls towards 50% condition, then turn into penalties if the item is further damaged beyond 50%.


We'll need to use those bonus formula now, as we calculate burst and autofire penalties. Both of these penalties are calculated the same way, but the penalty value itself is different, because they're based on different values (Burst Penalty and Auto Penalty, respectively).

If the bullet we're shooting is part of a Burst, then
   Burst_Penalty = Weapon's_Total_Burst_Penalty * (number of bullets already fired in this burst - 1)
   If Shooter has the AUTO_WEAPONS trait, then
      Burst_Penalty is cut in half for each level of the trait

   Actual_Chance is reduced by Burst_Penalty

Pretty simple - the burst penalty only applies for each bullet after the first one, and gets more and more severe as we fire more bullets. The Auto_Weapons trait then cuts the penalty by half, and Expert_Auto_Weapons cuts it again by half (the resulting penalty would be only 25% as severe).

To calculate the Weapon's_Total_Burst_Penalty, the program does this:

Burst_Penalty = Weapon's_Inherent_Burst_Penalty

Burst_Bonus = Weapon's_Burst_To-Hit_Bonus (MILD)
Burst_Bonus is increased by Ammo's_Burst_To-Hit_Bonus
Burst_Bonus is increased by each attachment's Burst_To-Hit_Bonus (HARSH)

If Shooter is PRONE, then
   Burst_Bonus is increased by Weapon's_Bipod_Bonus
   Burst_Bonus is increased by each attachment's Bipod_Bonus

Burst_Penalty is reduced by Burst_Bonus

So we have two values here - Burst_Penalty, and Burst_Bonus. At the very end they are added up together.

The weapon's inherent burst penalty comes from the weapon itself, it's written in the Weapons.XML file.

The burst To-Hit Bonus works to offset that penalty. You can see that the weapon itself, as well as its ammo and attachments, can each increase the Burst To-Hit Bonus. Today, only Foregrips (or built-in foregrips) can do this. Note of course that attachments in bad condition can actually increase the penalty, as this is a HARSH bonus calculation type (see above, if you don't know what this means).
Finally, if the shooter is lying down, he gets the benefits of the weapon's built-in bipod (if any) and attached bipod (if any).

Burst_Penalty and Burst_Bonus are then added together. But the end result is always either 0 or negative, as the program makes sure it doesn't go above 0. You can't have a POSITIVE Burst_penalty, that's why it's called a penalty. Unless you've got a very stable weapon, with good bipod and all that stuff, each bullet in the burst will be less accurate than the previous bullet.

AUTOFIRE penalty works in almost exactly the same way. The first difference is that it looks at different values, namely "Auto_Penalty" and "Auto_To-Hit_bonus". Most guns and attachments have different values for burst and auto modifiers. Autofire is almost always less accurate, if not always.
Also, with autofire, it seems that the gun's condition is more important. The bonus you get from the gun's Autofire_To-Hit_Bonus" is HARSH, so a damaged weapon (below 50% status) with inherent bonus may actually give a penalty instead! It's quite bizarre, but that's what the code says.

Actual_Chance is reduced by Burst_Penalty, or
Actual_Chance is reduced by Auto_Penalty...
   Depending on the mode of fire, of course!


Now this is where things start getting really complex. At this point, we're actually going to split yet another value, this time it's Range.

We're going to remember the "pure" range-to-target, which is the exact calculation of the distance between the shooter and the target location.

We're also going to add a second value which will be called "Effective_Range". This value is differently calculated, because the program runs a VERY complex calculation to figure it out. Basically, a lot of stuff figures into effective range, but most importantly it's camo and cover. But other stuff figure in as well, or at least it seems so. The end result is the "effective" range to the target, which will be used more often than the actual range.
If "Effective_Range" is 0, that's when we get that "can't shoot" indicator, and our mercs complain a little if we still try to take the shot. Please note that ridiculously, you would still have a certain chance of hitting the target, but I'm not going to discuss that now.

Also from this point on, I'm going to assume that there is an enemy soldier in the target square. If not, the program behaves a bit differently.


If we can see the target, and have spent extra APs to aim, the program now begins a bit of calculating our aiming bonus. Please be patient with this one, it's a very important part of the process, but can be pretty difficult to understand. Once again, I'll do my best to explain it step by step, and there's a detailed example of it below. So don't worry, you'll get it. I hope.

In the original JA2, each AP we spent on aiming our weapon gave us a flat +10 to-hit bonus. In today's 1.13, things couldn't be more different. Not only is there a variable To-Hit bonus per AP that's based on many factors, but we also have a maximum bonus that can be achieved from extra aiming, which also depends on many factors.

So without further ado, here is the formula, which is comprised of two steps.

Step 1: Calculate the maximum possible bonus from extra aiming.

Maximum_Aiming_Bonus = 20 + ( (Base_Chance / 20) * Shooter's_Experience_Level ) + (Weapon's_Accuracy * 2) + 10 points for each level of the SNIPER trait

Here we're using the Base_Chance, a value we "saved for later" somewhere earlier in the formula. If you remember, it was based mainly on our Marksmanship, Fatigue, Morale, and the status of our weapon. Shooter's_Experience_Level is the level of the character, without any modifiers. Weapon's_Accuracy is the weapon's XML value. This is pretty simple to understand, I think. It's just basic arithmetics.

The Maximum_Aiming_Bonus is the highest possible bonus we can get from extra aiming. Even with a 10x Sniper Scope, if you've hit the maximum then any extra APs spent on aiming would simply be wasted. You'll soon see how the formula achieves this automatically.

Now we do some crazy math.

Step 2: Figure out aiming bonus per each extra AP spent.

For each extra AP spent on aiming, repeat the following:
   Aiming_Bonus = (Maximum_Aiming_Bonus * Aiming_Progression / 1000), but not more than 10.
   Maximum_Aiming_Bonus reduced by Aiming_Bonus
   Increase Actual_Chance by (Aiming_Bonus + 0.5), rounded down.

Let's do this line by line.

Line 1: "Aiming_Bonus = Blah blah blah"

First, we calculate the aiming bonus we get for this bullet. This is based on the maximum_aiming_bonus, but also on a value called "Aiming_Progression" which I haven't explained yet. Basically, Aiming_Progression is a value that gets bigger with each AP spent. With the first AP spent on extra aiming, the value Aiming_Progression equals 500. With the next AP spent, it still equals 500. With the third AP spent, it becomes 600. Then 600, 750, 750, 750, and with the eightth AP it is 1000. So you can see, we should get better results from spending the 8th AP than we get for spending the third AP. But while Aiming_Progression goes up, Maximum_Aiming_Bonus goes down (read next).

Line 2: "Maximum_Aiming_Bonus blah blah blah"

Next, we reduce Maximum_Aiming_Bonus. Since we go through the loop several times, each time we run Line 1, we get smaller results because Maximum_Aiming_Bonus has just been decreased. Characters with low marksmanship will feel this very strongly, because it makes each extra AP less useful than the last one, counteracting what we just did with the Aiming_Progression. Characters with high skills will not notice this so much - unless the weapon has a sniper scope and can add 8 extra APs, then each extra aiming will produce 10 points. If they do use a scope though, they'll find that their CTH increases rapidly at first, but the last few APs don't help as much. Then again, sniper rifles can be fired at very long ranges, so the first few APs might not even bring CTH above 0 at all! Then, the last few APs are very helpful...

Line 3: "Increase Actual_Chance blah blah blah"

This is where we add the aiming bonus we gained from this extra AP to our current chance-to-hit. Note that we get an extra 0.5 for some reason. Also, the value is rounded down, because Aiming_Bonus is a fractional value. It's always rounded down, even if it's negative (yeah, apparently you can get negative aiming bonus...), so -1.2 becomes -2.0 .

When we're done with all three lines, the loop runs again for the next AP spent. Eventually, all APs are calculated and the aiming bonuses are added to our current Chance-to-Hit one by one.

Good time for an example, as this has gotten quite complicated...

Let's take a merc with some imaginary values:

Base_Chance = 55 (This is the chance-to-hit after taking into account marksmanship, fatigue, etc, but before stance and to-hit bonuses etc. are applied)
Shooter's_Experience_Level = 3 (A somewhat experienced mercenary)
Weapon's Accuracy = 5 (A nice, accurate rifle)
We'll also give our merc one level of the SNIPER trait.

Here's the first part of the formula, concerning the maximum aiming bonus:

Maximum_Aiming_Bonus = 20 + ( ( 55 / 20 ) * 3 ) + (5 * 2) + 10 * 1 = 48.25

Now let's say out Actual_Chance (CTH after all the calculations so far, including stance, etc.) is 40. We'll aim the weapon with 8 extra APs. The second part of the formula will therefore run 8 times. Start with the first AP:

Aiming_Bonus = (48.25 * 500) / 1000 = 24.125, which is larger than 10, so the result is 10.
Maximum_Aiming_Bonus = 48.25 - 10 = 38.25
Actual_Chance = 40 + ( 10 + 0.5 rounded down ) = 50.

Great, we've increased by 10 points. Let's aim some more. AP number 2:

Aiming_Bonus = (38.25 * 500) / 1000 = 19.125, which is larger than 10, so the result is 10.
Maximum_Aiming_Bonus = 38.25 - 10 = 28.25
Actual_Chance = 50 + ( 10 + 0.5 rounded down ) = 60

Another 10 points for us! AP number 3 coming up:

Aiming_Bonus = (28.25 * 600) / 1000 = 16.95, which is larger than 10, so the result is 10.
Maximum_Aiming_Bonus = 28.25 - 10 = 18.25
Actual_Chance = 60 + ( 10 + 0.5 rounded down ) = 70

Another cool 10. You've probably noticed that the Aiming Progression has grown from 500 to 600, which is helping us to overcome the fast-dropping Maximum_Aiming_Bonus. It really helps that the maximum was so high to begin with (48.25), so we keep getting high results here. Maximum_Aiming_Bonus is going to vanish soon though. AP number 4:

Aiming_Bonus = (18.25 * 600) / 1000 = 10.95, which is larger than 10, so the result is 10.
Maximum_Aiming_Bonus = 18.25 - 10 = 8.25
Actual_Chance = 70 + ( 10 + 0.5 rounded down ) = 80

Yet another cool 10. But by now, the maximum aiming bonus is seriously low. Most rifles will not allow any more APs to be spent, so we've gained 40 points to our Chance-to-Hit, at the cost of 4 APs. This is mainly thanks to our sniper skill, an accurate rifle, and a relatively reasonable Base_Chance to begin with. But we've got a sniper rifle, so we can keep spending APs to aim some more. Let's see AP #5, then:

Aiming_Bonus = (8.25 * 750) / 1000 = 6.18, which is smaller than 10, so the result is 6.18
Maximum_Aiming_Bonus = 8.25 - 6.18 = 2.07
Actual_Chance = 80 + ( 6.18 + 0.5 rounded down ) = 86

Ah, this time around, we only got 6 point more. Our Experience Level and Sniper Skill are the major factors here - had they been higher, we would still be getting nice returns at this stage (more 10s!). Unfortunately, Maximum_Aiming_Bonus is close to disappearing, and even that increase from 600 to 750 Progression are not enough to give us good results at this stage. Going on to AP #6:

Aiming_Bonus = (2.07 * 750) / 1000 = 1.552, which is smaller than 10, so the result is 1.552
Maximum_Aiming_Bonus = 2.07 - 1.552 = 0.51
Actual_Chance = 86 + ( 1.552 + 0.5 rounded down ) = 88

Augh! Only 2 points extra CTH! This AP was almost entirely wasted! What happens with AP #7 then??

Aiming_Bonus = (0.51 * 750) / 1000 = 0.38, which is smaller (hell, much smaller) than 10, so the result is 0.38
Maximum_Aiming_Bonus = 0.51 - 0.38 = 0.13
Actual_Chance = 88 + ( 0.51 + 0.5 rounded down ) = 89

One stinking point. And that's only because we got lucky with that 0.51 there (and mainly because I'm avoiding very long fractional numbers, so the formula isn't 100% accurate Very Happy ). Can we even hope that the last AP, #8, with a progression of 1000, will give us that final boost we need? Let's see:

Aiming_Bonus = (0.13 * 1000) / 1000 = 0.13, which is smaller than 10. The result is 0.13
Maximum_Aiming_Bonus = 0.13-0.13 = 0
Actual_Chance = 89 + ( 0.13 + 0.5 rounded down ) = 89

Not a chance. Our last AP was utterly wasted, giving us no bonus to CTH. Even progression didn't help here, and again, if our Maximum_Aiming_Bonus had been higher to begin with, we might've actually still scored a few points here. Our merc still has a lot to learn, it seems.

Now how much CTH did we gain here, from all this extra aiming? We started out with an Actual_Chance value of 40, and ended up with 89. The difference is... Surprise, surprise! 49 points! Almost exactly the original value of our Maximum_Aiming_Bonus! So you could say we've maximized our potential here Smile

I just wonder why Dexterity played no part in this at all... odd.


Right. Now that we've got all of those bonuses out of the way, it's time to play nasty. Pretty much everything from now on will concern PENALTIES to CTH, which may cause it to drop like a rock. We're going to have a look at our target as well, see what he's doing and how it affects us.

We begin with something relatively simple:

If Shooter is an NPC (computer-controlled character), then
   If difficulty_level is EASY, then
      Actual_Chance is reduced by 5.

On the Easy difficulty level, all AI soldiers are given a 5 point penalty. That means enemies, militia, and civilians too. Just makes the game a bit easier, eh? Smile

On other difficulty levels though, it's the other way around:

If Shooter is an NPC, then
   If difficulty_level is EXPERT, then
      Actual_Chance is increased by 5.
   If difficulty_level is INSANE, then
      Actual_Chance is increased by 10.

Freaky. No wonder INSANE level is so difficult. Note that on "EXPERIENCED" difficulty, CTH is not modified.

Now we check for some basic penalties:

If Shooter is under the effect of gas, then
   Actual_Chance is reduced by 50!

Soldiers are only considered "gassed" if they're inside an active gas cloud and aren't wearing their mask. If the soldier's taken damage or stun damage from a gas attack at the beginning of the turn, they'll be "gassed" for the rest of the turn.

If Shooter is being bandaged, then
   Actual_Chance is reduced by 20!

Yeah, characters being treated for injuries have a lower chance-to-hit. Though if you're having them fire at the enemy, you usually have no other choice anyway, do you?

If Shooter is in shock, then
   Actual_Chance is reduced by 5 for each level of shock.

Shock is caused whenever a character is injured. It equals roughly 1/10th of the damage sustained, plus a little extra from any stamina damage from the attack. Therefore, if you're hit for 50 damage, your shock value is around 5. Each turn, shock is cut in half and rounded down.


We're going to calculate the gun's maximum range now. It's a relatively short calculation, but it's done separately, so I'm going to cover it now. Please make sure you've read a previous section that talks about BonusReduction.

Weapon_Max_Range = Weapon's_Range, from the XMLs
Weapon_Max_Range is increased by its own inherent Range_Bonus, if any (MILD)
Weapon_Max_Range is increased by the ammo's Range_Bonus, if any.
For each attachment, do:
   If the attachment is not a DUCKBILL, or if it is a DUCKBILL and we're firing BUCKSHOT ammo, then
      Weapon_Max_Range is inreased by the attachment's Range_Bonus (MILD)

Pretty simple. The gun's range, meaning the value taken from the gun's entry in Weapons.XML, is modified by its inherent range bonus (from built-in attachments), by the ammo (like Match ammo that increases range, or lockbuster ammo that decreases range), and by attachments. Duckbills give a range penalty, but only if you're firing non-buckshot ammo. You'll note that all of these bonuses are MILD, meaning that the status of the gun/attachment causes the bonus to drop steadily towards 0, but it can't go negative. Of course, if the bonus was originally negative, then a damaged item would not give as severe a penalty as a fixed item. This is kind of confusing, but attachments almost never (or never?) give range penalties anyway...

In any case, this is the gun's Maximum Range. We're going to use it later when determining whether the target is beyond our effective shooting range.

Note that the Max_Range can't ever fall below 1. That's important for the program, so it has failsafes to make sure it never happens.


We're going back to using the "Effective_Range" value which we've been working with before. Remember, this value represents not only the range to target, but also such effects as camouflage and obstacles (cover).

If the effective_Range is 0 (meaning, no clear line-of-sight to the target), it's pretty obvious that you're not going to make the shot. The code does continue to work with a value of 0 though, for some unexplained reason. Coupled with the fact that CTH can never go below 1%, that means that potentially any shot can hit anybody. Very annoying, and I've also made a few changes to that myself, but with the current release of 1.13, the minimum is still 1%. Of course, if Effective_Range is 0, that means some obstacle will probably stop the bullet anyway. But just so you'd know.


In any case, we're now going to do some stuff to our Actual_Chance - we're going to apply To-Hit bonuses from all our worn gear, weapon attachments (like lasers), and even the brightness of the enemy's tile.

Fair warning here - this stuff is going to get SERIOUSLY complex. It's as complex as the Aiming_Bonus we just calculated from scopes. Only worse. Prepare thyself!!!

First, we change our effective_range, based on the Aiming_Bonus (usually penalty!) we get from armor, face items, and any attachments on the armor and face items. Please note that we're going to have to know how many APs we spent on aiming our weapon.

Final_Aiming_Bonus = 0

If Range_to_Target is less than or equal to the Item's_Minimum_Range_For_Aiming_Bonus, then
   Return 0! No aiming bonus or penalty.
   If Armor's_Aiming_Bonus is a penalty (less than 0), then
      Extra_Aiming_APs = 1
   Range_to_Target = Effective_Range
   For each Extra_Aiming_AP, do:
      Range_Modifier = (Item's_Aiming_Bonus * Range_to_Target) / 100
      Range_to_Target is decreased by Range_Modifier
      Final_Aiming_Bonus is increased by Range_Modifier
      If Range_to_Target is now less than Item's_Minimum_Range_For_Aiming_Bonus, then
         Range_Modifier equals (Item's_Minimum_Range_For_Aiming_Bonus - Range_To_Target)
         Final_Aiming_Bonus is reduced by Range_Modifier
         Stop now and give a final result equal to Final_Aiming_Bonus.

Ok, yeah, it's a bitch. And we're actually going to do this for each and every piece of armor, face item, and their attachments, adding up all those "Final_Aiming_Bonuses" together.

I'm really not going to explain this. It's too complex, and I think an example would be much better here. So let's grab an item and start calculating:

The item we're going to use for this example is a Ghille Hood, which is worn over the head. Ghillie equipment gives an aiming PENALTY, but then again all worn items in 1.13 that modify Aiming will also give a penalty. I won't deal with bonuses, for that reason. A Ghillie hood gives -1 Aiming Bonus, and is worn on the head or attached to armor. Whether worn or attached doesn't matter to us - it would be treated the same way.

Let's also assume that the effective range to the target is 100 meters (10 tiles). The minimum_range_For_Aiming_Bonus is 0, as it is for all worn items. Let's rumble!

If 100 is less than or equal to 0, then
Return 0!

This, of course doesn't happen. 100 is greater than 0. Next.

If Armor's_Aiming_Bonus is a penalty, then Extra_Aiming_AP = 1

The aiming bonus of the ghillie hood is -1, so it's a penalty. That means the program considers us to be spending only one AP to aim, for the purposes of this formula. Next.

Range_to_Target = 100

For each Extra_Aiming_AP, do:
Range_Modifier = ( -1 * 100 ) / 100 = -1
Range_to_Target = 100 - (-1) = 101
Final_Aiming_Bonus is increased by (-1) (so its value is now -1).

Great, the penalty we get from the ghillie suit is now -1 points. The next line is:

If 101 is now less than 0, then

Whoa whoa, it's not. And since we only spent one AP to aim (as far as the program is telling itself), the loop ends here.

Not very interesting. The Ghillie Hood simply gave us the aiming penalty that is listed in the XML. Basically, this is the same for ALL worn items - they'll all give a penalty equal to their XML "Aiming_Bonus" value, which is always negative.

But let's have some fun with hypothesis. Let's create an item, a scope that can be worn on the face. Like a fixed binoculars hanging from the helmet. Makes some sense, right? Right. Let's assume that the item gives an aiming bonus of 20, like a Sniper Scope, and its minimum range for aiming bonus is 50. We'll spend 6 APs aiming our weapon. The range to target will stay the same (100 meters, equalling 10 tiles). Let's see the bonus we get for the first AP we spend:

Final_Aiming_Bonus = 0

If 100 is less than or equal to 50, then
Return 0! No aiming bonus or penalty.

Fortunately, the target is beyond the minimum range required to get the scope's bonus. Let's continue.

If 20 is a penalty (less than 0), then
Extra_Aiming_APs = 1

20 is not a penalty, so Extra_Aiming_Aps will equal the number of APs we spent aiming the weapon, 6.

Range_To_Target = 100

For each Extra_Aiming_AP (6 times), do:

Range_Modifier = (20 * 100) / 100 = 20
Range_To_Target = 100 - 20 = 80
Final_Aiming_Bonus = 0 + 20 = 20

Great, that's a 20 point bonus.

If 80 is now less than 50, then

Nono, it's not less than 50 yet. The target is still beyond the minimum range. Go on to AP #2:

Range_Modifier = (20 * 80) / 100 = 16
Range_To_Target = 80 - 16 = 64
Final_Aiming_Bonus = 20 + 16 = 36

Our bonus is now 36. We got less bonus for this AP than we did for the first one. Notice the range to target getting shorter, decreasing the bonus we get for each subsequent AP. On to AP #3:

Range_Modifier = (20 * 64) / 100 = 12.8 (rounded, this is 12)
Range_To_Target = 64 - 12 = 52
Final_Aiming_Bonus = 36 + 12 = 48

Right on to #4:

Range_Modifier = (20 * 52) / 100 = 10.4 (rounded, this is 10)
Range_To_Target = 52 - 10 = 42
Final_Aiming_Bonus = 48 + 10 = 58

Ok, so we keep getting less and less bonus for each AP we spend. But wait! Our Range_to_Target has just dropped below the minimum range for bonuses. Let's look at the last part of the loop:

If Range_to_Target (42) is now less than Item's_Minimum_Range_For_Aiming_Bonus (50), then
Range_Modifier = (50 - 42) = 8
Final_Aiming_Bonus = 58 - 8 = 50
Stop now and give a final result equal to Final_Aiming_Bonus, which is now 50.

Ah, ok. The last AP only gave us 2 points bonus to CTH, and the aiming bonus we got from this item is 50. Not too shabby, anyway Smile


We add up all the aiming bonuses/penalties we got from all worn armor, face items and attachments in the previous section.

Effective Range is reduced by the Total of all the Final_Aiming_Bonuses we got in the previous section.

Naturally, if the worn items, combined, gave a penalty, then the effective_range is INCREASED, which isn't a good thing. We want the target to be considered closer to us, and thus easier to hit. So we want Effective_Range to decrease as much as possible.


What we did with worn items before, we're now going to do with the weapon and its attachments as well. Again, Minimum_range will come into play in the same way, with all that Range_Modifier and Final_Aiming_Bonus mumbo-jumbo. If you want your head to explode, read that formula again. It's a big headache. There is one difference here though:

Effective Range is reduced by the Total of all the Final_Aiming_Bonuses we get from the weapon and its attachments. (HARSH)

Did you notice the word HARSH at the end? That's another one of those status-based modifiers. In this case, as the weapon or the attachment get damaged, their Final_Aiming_Bonus slowly decreases towards 0. It reaches 0 at 50% status, and if the item gets damaged beyond 50%, you start getting a PENALTY instead of a bonus!!! This is very different from armors, but then again armors always give penalties anyway in 1.13. I'm thinking people may want to change this, in the future...


The next step is to figure out how much Flat To-Hit bonuses we get from our worn items and weapons. Similar to what we just did with Aiming Bonuses, we're going to go through each item, including our armor, face items, weapon, and all attachments, to figure out the Final_To-Hit_Bonus of each and every one of them, and pool all those final bonuses together.

There's a big difference between Aiming Bonuses and To-Hit Bonuses. Aiming is affected mainly by how many times we right-click a target to increase our aim, at the cost of APs. To-Hit bonuses do not rely on aiming, but some of them do rely on an important factor - range to target, and "Best Laser Range". Yes, many of the items that give a To-Hit bonus are laser attachments, and they have a certain effective range. Now we're going to find out exactly how this range gets calculated. We're also going to see how brightness affects our aim!

For worn items (including armor, face items, and their attachments), the calculation is pretty simple. "Best Laser Range" doesn't play a factor here at all, so in effect we're getting a flat bonus (or penalty) to our CTH.

For each worn item, we do this:

Final_To-Hit_Bonus = 0

Final_To-Hit_Bonus increased by the item's_To-Hit_Bonus value, taken from the XML
For each attachment of the item, do:
   Final_To-Hit_Bonus increased by the attachment's_To-Hit_Bonus value, taken from the XML

Haha, finally something simple. We don't mess with ranges, we don't care about status, we just look at the XML values and add them all up. Unfortunately, most if not all worn items that modify our To-Hit are penalties. Bummer.

Now, with weapons it gets tricky. We'll need to look up Best Laser Ranges, and we'll also need to know our effective_range. But by now we're getting pretty good at this. There's just one thing we need to do first:

If character has the SNIPER trait, then:
   Effective_Range is decreased by 5% of the Real_Range_to_Target
   If character is an EXPERT SNIPER, then:
      Reduce effective_range by another 5% of the Real_Range_to_Target

Great, the SNIPER trait takes effect here too - it reduces the effective range to target, just before we measure whether the target is within laser range. This is really going to help us if we're using laser attachments. Note that we use the "REAL" range to target here, the actual distance in meters between you and the enemy, not taking into account camouflage and cover. It's not that important, but still important Wink

Ok, with this new Effective_Range value, we're ready to tackle weapon and attachment To-Hit bonuses.


... Continued in next post...

[Updated on: Mon, 27 April 2015 23:45] by Moderator

Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Read Message
Previous Topic: "How does it work?" Part 10: HAM Suppression
Next Topic: "How does it work?" Part 7b: Gaining Chances to Level Up
Goto Forum:

Current Time: Wed Jul 28 16:52:52 EEST 2021

Total time taken to generate the page: 0.02276 seconds