• If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • Stop wasting time looking for files and revisions. Connect your Gmail, DriveDropbox, and Slack accounts and in less than 2 minutes, Dokkio will automatically organize all your file attachments. Learn more and claim your free account.


"How does it work" Part 4: Chance-to-Hit

Page history last edited by Little Alien 11 years, 7 months ago


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 \:D ). 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 \:\)

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? \:\)

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 \:\)


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 ;\)

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




To get the To-Hit bonus from a weapon or attachment, we'll need to have some values ready for us:

Item's To-Hit Bonus: Naturally, this is what we want to see added to our CTH at the end \:\) . We draw this straight from the XML.

Item's Best Laser Range: Most items that increase To-Hit bonus have a best laser range. This too is drawn from the XML data of the item.

Item's Bipod Bonus: Yup, this is where Bipods come in. We draw this data from XML too.

Is Shooter Prone?: This is either TRUE or FALSE. We'll want to know if the shooter is prone so we can decide whether to give him the Bipod Bonus. But this doesn't rely only on the shooter's stance - he must also be at least 5 tiles away from his target if he wants to get that bipod bonus!! If the effective range to the target is less than 5 tiles, then "Is_Shooter_Prone?" is FALSE, as far as this part of the program is concerned.

Let's get cracking. Here's the basic outline of the whole shebang:

Final_To-Hit_Bonus = 0

If Shooter is Prone, then
   Final_To-Hit_Bonus is increased by the Bipod_Bonus of the weapon's built-in bipod, if any.

Final_To-Hit_Bonus is increased by the Laser_Bonus of the weapon's built-in laser, if any (HARSH)
Final_To-Hit_Bonus is increased by the Ammo's To-Hit Bonus.

For each attachment, do:
   If Shooter is Prone, then
      Final_To-Hit_Bonus is increased by the Bipod_Bonus of the attachment
   Final_To-Hit_Bonus is increased by the Laser_Bonus of the attachment (HARSH)

It looks pretty simple, but then again we don't know how Laser_Bonus is calculated yet - it's not an XML value, we actually have to calculate it based on range, lighting, and a whole lot of other crap. We'll do that in a second. Please first pay attention - both laser bonuses are affected by the status of the gun or attachment giving those bonuses. It's a HARSH effect, meaning that if you go below 50% status, you start getting PENALTIES to your chance-to-hit, which is not good at all. Make sure you keep your lasers in good shape! Ammo and bipods do not rely on status.

Now, let's see how all that laser business is calculated. Remember we're going to calculate this for the weapon and all of its attachments, one by one. We'll later feed the results back into the formula, where it says "Laser_Bonus" above. This is going to be a bit rough, but certainly not as nasty as the aiming calculations from earlier.


If the item has no Best_Laser_Range, then
   Laser_Bonus = Item's_To-Hit_bonus (no changes!). Remember to check item status in the previous formula!

Great, some items and guns have a To-Hit bonus (or penalty) but no Best_Laser_Range. We treat those as flat modifiers, except we have to check it against the item's status when we return to the previous formula (remember? HARSH...)


If the Effective_Range is less than or equal to the item's Best_Laser_Range, then
   Laser_Bonus = Item's_To-Hit_bonus (no changes!). Remember to check item status in the previous formula!

If we're within laser range, our laser works perfectly. The bonus stays untouched, until we return to the previous formula and check it against the item's status. (HARSH, again...)

Now things get messy.


If Effective_Range is greater than the item's Best_Laser_Range, then
   Maximum_Laser_Range = Item's_Best_Laser_Range * ( (2 * Brightness_At_Target_Location) + 21 ) / 18

Ok, that's not even nearly as ugly as it looks in the code. Here's a rare occassion to look at something really scary. This is the same equation, but DIRECTLY out of the code:


   INT32 iMaxLaserRange = ( pItem->bestlaserrange*( 2*bLightLevel + 3*NORMAL_LIGHTLEVEL_NIGHT - 5*NORMAL_LIGHTLEVEL_DAY ) ) / ( 2 * ( NORMAL_LIGHTLEVEL_NIGHT - NORMAL_LIGHTLEVEL_DAY ) );

Ack. Well, in truth, the two are exactly the same. The reason mine's about half as long is that all those capital-letter names like NORMAL_LIGHTLEVEL_DAY are fixed values which the programmers can change if they ever need to. But in the end, assuming no changes are made to these values, my pseudo-code is correct.

Now let's pretend I never showed you that thing.

Right. So now we have the maximum range at which the laser pointer can be seen, based on the light level at the target tile. If the target is within that "maximum" laser range, we can still get a few to-hit bonus points from the laser, albeit less than the full amount. (we'll do that next)

Note that the light level is NOT what you see in-game when you press the F button. It's actually the opposite! In daylight, the light level of tiles is usually 3, and at night it is usually 12. So the higher, the darker! Weird, huh? It works like that throughout the whole game... EXCEPT when you press "F" to see the brightness level, in which case the program lies to you. Of course, the lie is intentional, because most of us would associate a LOWER level with LOWER light, and vice versa. We're just strange little humans. The program itself works the other way around - the higher the value, the darker it is! I guess they should've called it "DARKNESSLEVEL".

In any case, you can clearly see (now that I've explained this weirdness) that the darker the tile, the easier it is to see the red laser dot, and so the maximum range of the laser pointer will grow, for the purposes of shooting targets beyond the laser's original Best_Laser_Range. Of course, beyond the best_laser_range we're going to lose some of the laser's to-hit bonus, but as long as the target's withing the Max_range, we'll still get a few points.

Now, let's see how far outside the laser's best range we are, and how much Laser_Bonus we get, if any.


Laser_Bonus = ( Item's_To-Hit_Bonus * ( Maximum_Laser_Range - Effective_Range ) ) / ( Maximum_Laser_Range - Item's_Best_Laser_Range )

In effect, each tile of range beyond our Best_Laser_Range will decrease the bonus we were supposed to get from the laser. Dark conditions help, of course, because we're using Maximum_Laser_Range as well, which we've just calculated based on light levels. If the target is beyond the Maximum_Laser_Range, we'll get a result of 0 or less.

Finally, the program makes sure that we don't get a PENALTY:


If Laser_Bonus < 0, then
   Laser_Bonus = 0.

This is interesting to know - Laser_Bonus is a HARSH bonus, which means that if the laser's status is below 50%, it could give a penalty instead of a bonus. However, if the Laser_Bonus we've just calculated is 0 (meaning, we can't see the laser dot because the target is too far out of range), then we won't get a penalty either (negative 0 is still 0). So if the target is out of laser range, you don't get a penalty for using a broken laser. Realistic! \:D

Let's have a quick example here, just to make sure all this is understood:

Shooter is using a regular laser attachment, with 90 Best_Laser_Range, supposed to give a 20-point To-Hit Bonus. Target is 12 tiles away, in daylight (Brightness... errrr... darkness level 3).

If the item has no Best_Laser_Range, then

Laser_Bonus = Item's_To-Hit_bonus (no changes!). Remember to check item status in the previous formula!

No, the item has a best_laser_range, so we skip this. Next.

If the Effective_Range is less than or equal to the item's Best_Laser_Range, then

Laser_Bonus = Item's_To-Hit_bonus (no changes!). Remember to check item status in the previous formula!

No, the Effective_Range is 120 (12 tiles) and the laser range is 90, so we skip this.

If Effective_Range (120) is greater than the item's Best_Laser_Range (90), then

Maximum_Laser_Range = 90 * ( (2 * 3) + 21 ) / 18 = 135

The Great, so we're a bit out of range, the tile's not too dark, so we can still use the laser pointer effectively up to range 135. Let's move on:

Laser_Bonus = ( 20 * ( 135 - 120 ) ) / ( 135 - 90 ) = 6.666 (rounded down to 6).

So the final Laser_Bonus is 6. Much less than we should get from the laser, but of course we're a bit out of laser range.


All of the laser bonuses we've just calculated are added up to our Actual_Chance. Again, remember that the status of your laser will affect how much bonus you get from that laser, and you will get a penalty if the status is below 50%.


Next up are modifiers based on the bodypart we're trying to shoot.


If we're shooting at the head, then
   Bodypart_Penalty = 3 * Effective_Range / 10
   Actual_Chance is reduced by Bodypart_Penalty

When shooting at the head, we lose three CTH points per tile of effective distance. Remember that effective distance takes Camo and obstacles into account.


If we're shooting at the legs, then
   Bodypart_Penalty = Effective_Range / 10
   Actual_Chance is reduced by Bodypart_Penalty

When shooting at the legs, we lose 1 CTH point per tile of effective distance.


Now, the range to target really kicks in. We're going to rely on our weapon's Range value (which is drawn from XML). We'll compare it to the range to target. If the target is beyond range, we're going to start losing lots of CTH.


Range_Penalty = ( (Weapon's_Range - Range_to_Target) * 30 ) / 170
If Range_Penalty is a negative value, then
   Actual_Chance is reduced by Range_Penalty

What we do is to check the difference between the weapon's inherent range (the value we see in the description box, drawn out of the XML files) and the range to the target (unmodified, not the "Effective_Range"). If the weapon's range is larger or equal to the range_to_target, then there's no problem - the penalty is positive (or 0), and is then ignored. However, if the target is beyond the weapon's natural range, the penalty gets bigger.

Please note that this isn't the only range modifier. If the target is out of range, we're going to get a HUGE hit to our CTH soon.

But first thing's first, let's have two examples on this:

First, we'll use a sniper rifle. The rifle has a range of 75 tiles (750 meters), and the range to target is 60 tiles (600 meters)

Range_Penalty = ( (750 - 600) * 30 ) / 170 = 26.4

Range_Penalty is a positive value - that's a good thing, because it means we've got no problems with range. Our target is within the weapon's range, and the program skips this bit altogether. No penalty.

Second example, we'll shoot a pistol with a range of 11 tiles (110 meters) at a target standing at 13 tiles (13 meters)

Range_Penalty = ( (110 - 130) * 30 ) / 170 = -3.5

Ok, this time we've actually got a penalty of -3.5 points. Since it's a negative value, it's subtracted from the Chance-to-Hit. We've lost 3.5 points of CTH, and we're going to lose a lot more than that later.


Here's a bit that restricts shooting for tanks, at close range. Tanks have a problem firing at enemies who are very close, and this is where it gets calculated:


If Shooter is a tank, and Range_to_Target in Tiles is less than (2 * normal sight range in tiles), then
   Tank_Closerange_Penalty = 2 * ( (2 * Normal_Sight_Range in tiles) - Range_to_Target in Tiles )
   Actual_Chance is reduced by Tank_Closerange_Penalty

The normal sightrange is not a fixed number - you can set it in your JA2_Options.INI file. The default is 13. Therefore, if the target is less than 26 tiles

away, the tank gets a penalty to his shooting.



If Effective_Range = 0, then
   Actual_Chance is reduced by 80!!!

Heh, this is funny. The effective range only equals 0 if we don't have a clear line-of-sight to the target, or if we're using a seriously damaged scope. It means that we're trying to shoot blindly, and so our chance-to-hit drops considerably. I think it's just making sure we don't actually hit the target, no matter how good we are \:\)


Now we're going to do something interesting.


Universal_Range_Modifier = 3 * (NORMAL_RANGE - Effective_Range) / 10
Actual_Chance is increased/reduced by Universal_Range_Penalty

This universal modifier is a curious little bugger. It gives a 3 point bonus or penalty to CTH, based on the how much closer, or farther, the target is from the NORMAL_RANGE. But what is "Normal_Range"? Well, this is a fixed value set up by the JA2 programmers. In 1.13, the NORMAL_RANGE is 90 meters (9 tiles). That means that any target beyond 9 tiles is harder to hit, and any target closer than 9 tiles is easier to hit. Each tile of difference gives 3 points in bonus or penalty as required. Theoretically, chancing the Normal_Range would make the game behave differently. If you set it to 200 (20 tiles), then it will be much easier to hit stuff at long range, and MUCH easier to hit people who are very close to you! On the other hand, if you set it to 10 (1 tile) then shooting becomes much more difficult, even at people standing close to you. There is no current option to change the NORMAL_RANGE, other than editing the code.


We're going to check and see whether the shooter and his target are on different levels of the map, and apply penalties/bonuses as appropriate.


If Shooter is on a roof, and Target is on the ground, then
   Actual_Chance is increased by 15
If Shooter is on the ground, and Target is on the roof, then
   Actual_Chance is decreased by 25

Shooting up to the roof is tricky. Shooting down from a roof is easy. 'Nuff said.


We're going to have a look at our target now, to see what they are doing. The stance of the target, compared to the stance of the shooter, is going to affect our aim. Let's do this one by one, covering all three stances, STANDING, CROUCHING, and PRONE.


If Target is STANDING, then
   If Range_to_Target is 5 tiles or less, and Shooter is PRONE, then
      If we're not shooting at any particular bodypart, then
         Targetted_Bodypart = 2 (TORSO)
      Bodypart_Penalty = (5 - Targetted_Bodypart - Range_To_Target in Tiles) * 10
      Actual_Chance is reduced by Bodypart_Penalty

Ok, the penalty for shooting at a standing target only happens if the shooter is prone, and the range is 5 tiles or less.

Targetted_Bodypart is a numeric value, where 1 = Head, 2 = Torso, and 3 = Legs. Range_To_Target is always 5 or less, because we only get to this calculation if we're within 5 tiles range.


At range 2, shooting at the head (1):

Bodypart_Penalty = (5 - 1 - 2) * 10 = 20

At range 3, shooting at the Torso (2):

Bodypart_Penalty = (5 - 2 - 3) * 10 = 0

What's really weird is that you can actually get a bonus as well, especially if range is close to 5 tiles and shooting at the legs.

At range 4, shooting at the Legs (3):

Bodypart_Penalty = (5 - 3 - 4) * 10 = -20

It's negative, but because Actual_Chance is reduced by this, we get a bonus to CTH! So when prone, go for the legs!

Also note that in the code above, there's the bit that checks if we're not shooting at any particular bodypart. I think this happens when we're shooting at a prone target, but it also appears that it happens when shooting at a creature's glands (I.E., shooting them from behind?). In both cases, the game considers the shot to be aimed at the torso, for purposes of this calculation.




If Target is CROUCHED, then
   If Shooter is a Tank, and Range_to_Target is less than 120 meters (12 tiles) then
      Tank_Penalty = 13 * ( 120 - Range_to_Target ) / 10
      If Range_to_Target > 86 (???), then
         Actual_Chance is reduced by 20
      If Range_to_Target is between 16 and 86 (???), then
         Closerange_Penalty = 3 * ( (Range_to_Target - 16) / 10 )
         Actual_Chance is reduced by Closerange_Penalty

Ok, that's a bit complex.

First, tanks get a penalty for shooting at crouched targets that are closer than 12 tiles.

If the shooter isn't a tank, then it's a bit weird there. Note that I'm not sure about 86, it's quite possible that the value here should be 182, as I may have read the calculation wrong. In any case, if the target is crouched and beyond this range (in METERS, not tiles), then we lose 20 points from our CTH.

However, if the target is closer than this range, but more than 1 tile away (16 meters... ok, 1.6 tiles away, geez), then we lose 3 points from CTH for each tile of distance.




If Target is PRONE, then
   If Shooter is a Tank, and Range_to_Target is less than 120 meters (12 tiles) then
      Tank_Penalty = 25 * ( 120 - Range_to_Target ) / 10
      If Range_to_Target is greater than 16 meters (1.6 tiles), then
         Closerange_Penalty = 3 * ( (Range_to_Target - 16) / 10 )
         If Closerange_Penalty > 40, then
            Closerange_Penalty = 40
         Actual_Chance is reduced by Closerange_Penalty

It's almost the same as crouched, with a few differences.

Tanks suffer twice as much penalty for shooting at prone targets less than 12 tiles away. That's good to know - next time you charge at a tank, stay low and close!

As to other shooters, if you're prone and the target is prone and more than 1.6 tiles away, you will suffer a penalty of 3 points per tile. This penalty can't go over 40.


Next up, we take another drop of CTH based on how many tiles the target has moved during their turn:


Target_Movement_Penalty = Number of tiles moved * 1.5
If Target_Movement_Penalty > 30, then
   Target_Movement_Penalty = 30
Actual_Chance is reduced by Target_Movement_Penalty

So we get 1.5 points penalty for each tile the target has moved during its turn, but no more than 30. Note that the "Tiles_moved" value is reset at the start of the target's next turn, so it includes any tiles moved during interrupts. I think that if the target stops to do something other than move, the value is NOT reset, so it's the total tiles moved during the turn, regardless of other actions performed.


Next up, bullet-dodging!!! Yes, indeed, you can dodge bullets. An agile target causes a drop in the shooter's CTH. However, the shooter can compensate for this if his Dexterity is high. This is one of the reasons why dexterity is important for shooting.


If Target can see the Shooter, and Target is not a Tank, and Shooter is not the Bug Queen, then
   Dodging_Penalty = (Target's_Effective_Agility / 5) + (Target's_Effective_Experience_Level * 2)
   If Target is CROUCHED, then
      Dodging_Penalty is reduced by 1/3
   If Target is PRONE, then
      Dodging_Penalty is reduced by 2/3

   Dodging_Compensation = (Shooter's_Effective_Dexterity / 5) + (Shooter's_Effective_Experience_Level * 2)
   If Target is a Tank (?????), or Shooter is not the Bug Queen (?????), then
      Dodging_Compensation is cut in half!
   If Dodging_Penalty is greater than Dodging_Compensation, then
      Actual_Chance is reduced by (Dodging_Penalty - Dodging_Compensation)

There's an odd bit here but we'll get to it. If the target is aware of the shooter, they have a chance to try and dodge the bullet, by spotting the shooter preparing to fire, and trying to duck out of the way. Of course, tanks can't dodge out of the way, and the queen is apparently so good that her shots can't be dodged.

The dodging_penalty is based on the target's agility and experience level. To understand what the "EFFECTIVE" values are, please read the beginning of this topic, where this is explained.

Crouched targets are less likely to dodge, and prone targets will find it very hard to dodge.

The shooter's dexterity and level form the Dodging_Compensation. Again, these are EFFECTIVE levels, which are based on stuff like injury.

There's a strange bit here - the program tests to see whether the shooter is the Bug Queen, or the target is a Tank. However, the way the code is written, we won't even get to this point if either case is true! So this command (cut Dodging_Compensation in half) is never executed. Someone should take a look at this and fix it!!!

In any case, at the very end, the two values are compared. If the Dodging_Compensation is higher than the Penalty, that means the shooter is so good he can keep tracking the target even if it tries to dodge out of the way. If the penalty is higher, the target manages to reduce the shooter's CTH. The severity of the reduction depends on the difference between the Penalty and the Compensation, so the more skilled the target is, the more penalty it gives to the shooter!


There's a short bit here that gives range penalties to tanks that aren't firing directly at any target. Tanks sometimes do this if they know roughly where you are - they shoot close to you and hope to hit you in their area-of-effect.


If Target_Tile is empty, and Range_to_Target_tile is less than 120 meters (12 tiles), then
   Tank_Penalty = 25 * ( 120 - Range_to_Target_Tile ) / 10

This is similar to other tank penalties we've seen before. It's not a repeated penalty though, because earlier we were only talking about situations where the tank is firing at somebody, and this line is only executed if the tank isn't firing at anyone in particular.


We've already factored injury and fatigue into the calculation much earlier, but they're going to be calculated again, and may have a powerful impact on our CTH.


If Actual_Chance is still more than 0, and Shooter is Injured or Bandaged, then
   Bandage_Value = Amount of Shooter's health that is currently bandaged (pink)
   Injury_Penalty = Actual_Chance * 2 * ( Soldier's_Health_Below_Maximum + (Bandage_Value / 2) ) / (Soldier's_Maximum_Health * 3)
   Final_Injury_Penalty = Injury_Penalty * ( 100 - ( (Shooter's_Effective_Experience_Level - 1) * 10 ) ) / 100
   Actual_Chance is reduced by Final_Injury_Penalty

That's very confusing, of course. It's a lot of math, and I won't go too deeply into it. In practice, you get a drop to CTH based on your injury, meaning how much health you've got now compared to the maximum your merc can have. Bandaged damage is half as hurtful as unbandaged damage. Finally, your experience level helps compensate for the penalty, so experienced mercs will suffer less from injury.


Here's one of the most important penalties of them all. Ever notice how, when shooting at someone who is JUST outside your gun's range, your CTH is significantly lower? This is where it happens:


If Range_to_Target is greater than the Weapon's_Range, then
   Actual_Chance is cut by half!

Even one tile more than the gun's range, and you lose half your remaining CTH. The programmers say this is due to "bullet drop", but seriously, it's ridiculous. We've already had penalties for being out of range, and this one isn't even scaled - once you're just one tile out of range, you lose 50% of what little CTH you had left?! Hmpf.


Here's another CTH hit:


If the Target is beyond the Shooter's range of vision, then
   Actual_Chance is cut by half!

This happens when one soldier spots an enemy, and another soldier (who can't see the enemy) takes a shot. The calculation doesn't depend on whether the shooter can see the target right now, but whether he COULD see it if he turned in that direction and aimed his weapon. This bit of the code is the reason why Snipers need a good scope - otherwise their CTH will suck when firing at enemies they can't actually see.


Believe it or not, we've reached the very end of the formula. There's just one more thing left to do:


If Actual_Chance < 1, then
   Actual_Chance = 1.


OMG, this is the most annoying piece of code I have ever seen in my life. This is one of the reasons why I've been upset at JA2 for so long, especially once I started messing with XMLs to try and change the way that guns behave.

What this piece of code means is that CTH can NEVER EVER EVER EVER drop below 1%. You could be firing a pistol from the other end of the map, and it will have 1% chance of hitting the target. 1 in 100 shots is therefore guaranteed to hit the enemy, and with a good automatic weapon you can fire 100 shots within a couple of turns. Conversely, the enemy has a minimum of 1% too, and they tend to fire a whole lot of bullets, often without any realistic chance to hit you, but they still hit you anyway. Of course, if there are obstacles along the way they might stop the bullet, but on a clearer map with fewer obstacles you can actually hit from one side of the map to the other, 1 out of 100 times. This was made even worse by the fact that the program didn't use to really randomize numbers - it's complicated, but it was possible for the program to choose several numbers and only randomize between them, which meant that the minimum chance-to-hit was actually BETTER THAN 1/100 in some cases!!! Fortunately, SpaceViking has fixed the random number generator in the latest SVN builds.

I've actually managed to change the code and reduce the minimum CTH to 1/1000, and I can now change it to whatever I like, too. This isn't in the release version of 1.13, but I hope that some day this will be changed.


And that's it! The Actual_Chance value at this point is the Chance-to-Hit for the shot.

Please feel free to ask any questions about this.



As suggested by Moroes.

Things that help Chance-to-Hit


  • Marksmanship, Dexterity, Wisdom, Experience Level
    • Always helpful
  • Scope
    • Mostly helpful, especially if it's a high-power scope. Doesn't help if you're too close to the target (based on the scope's Minimum_Range_For_Aiming_Bonus).
  • Weapon, worn gear, and attachment condition
    • Always helpful to keep items repaired, at least above 85%. At 50% or less, you risk getting penalties instead of bonuses.
  • Morale
    • Always helpful to keep this at 50% or higher
  • Shooting a second time at the same target
    • This is, assuming that the target hasn't moved since the last time you shot at it.
  • PSYCHO trait
    • Always good for CTH (although not always good for the actual shooting process...)
  • Crouched or Prone stances
    • Always good, although the closer the enemy, the less benefit you get from these stances.

      Also, at very close range, Prone shooters should concentrate on the enemy's legs.

      Also, when using a high-powered scope, lie prone.

      When using a bipod, lie prone.

  • Weapon accuracy
    • It helps both CTH and the maximum bonus from aiming. More important if the weapon has a scope, less if it doesn't.
  • Range
    • Always good to keep the target at less than the weapon's effective range. If using a scope, try to keep the target at a range higher than the scope's Minimum_Range_For_Aiming_Bonus.

      Also, when crouched or prone, without a scope, try to keep the enemy about 4 or 5 tiles away, but no more than 5. You get a good bonus that way.

      Also, engagements at 9 tiles or less are always more accurate.

  • Ambidextrity trait
    • For shooting two handguns/SMGs at the same time.
  • Free second hand
    • When shooting a single handgun, gives a small bonus. This means don't put anything in the other hand.
  • Auto-Weapons trait
    • Great for bursts and auto-fire.
  • Heavy-Weapons trait
    • Good for rocket-launchers.
  • Sniper trait
    • Good for increasing the maximum aiming bonus possible.

      Also decreases the "effective" range to target.

  • Spend extra AP to aim
    • Helpful, up to a certain number of APs. Only very good marksmen will benefit from the last few APs spent, when using a high-powered scope.
  • Good quality laser, in the darkness
    • Darkness increases the laser's effective range.
  • EASY difficulty level
    • Enemies get lower CTH at easier difficulty, of course.
  • Higher weapon range
    • Always helpful
  • Close range to a tank
    • The closer you get to a tank (preferably under 12 tiles), the less chance it has to hit you.
  • Shooting from the roof to targets on the ground
    • A cool +25 for that.

Things that reduce chance-to-hit


  • Injury or bandages
    • Always bad for CTH. Bandages ("pink" health) have less effect than bleeding damage ("yellow" health).
  • Item condition below 85%, or below 50%.
    • Item condition below 85% will reduce the effectiveness of the item (weapon, or a bonus-giving attachment).

      With many weapons and attachments, condition below 50% may start giving penalties, so avoid it.

  • Drunkeness
    • Always bad for you. Hangovers have no effect though.
  • Low Morale
    • Anything below 50% morale is bad for you.
  • Fatigue
    • Anything below 85% fatigue is bad for you.
  • Standing or Crouching while using a high-powered scope
    • If the scope gives +15 aiming_bonus or more, you get a penalty when standing or crouching. Standing is obviously worse.
  • When firing and SMG, holding an item in the second hand
    • Gives a penalty. Try to keep both hands free for SMGs.
  • High burst penalty
    • When firing on burst/full-Auto modes. The more bullets are fired, the less likely they are to hit.
  • EXPERT or INSANE difficulty levels
    • Enemies get a bonus to CTH in these difficulty settings.
  • Being gassed
    • Always very bad for your CTH, unless you're wearing a mask.
  • Being bandaged by another merc
    • A somewhat serious impact on CTH.
  • Shock from being hit
    • Shock remains for a couple of turns after being hit. The worse you were hit, the lower your CTH will be.
  • Shooting at the head or legs
    • Much harder to hit than shooting at the torso, but of course there are benefits to this.
  • Target outside effective weapon range
    • Gives a huge penalty to CTH. You'll usually need a good scope to counteract this.
  • Obstacles, enemy camouflage, and smoke
    • They will all increase the "Effective range to target", making it harder to hit.
  • Shooting from the ground to the roof
    • A small but noticeable penalty.
  • Shooting at a target's head or torso, while the shooter is prone and at close range (up to 5 tiles).
    • Penalty for these.
  • CROUCHED or PRONE target
    • Will reduce your chance to hit considerably, especially at long-range
  • Moving target
    • The more your target has moved during its turn, the harder it is to hit
  • Agile/Experienced target
    • Decreases your CTH unless you're equally skilled.
  • Not being able to see the target
    • Huge penalty to CTH.

Things you can do to avoid getting hit


  • High agility and Experience Level
    • They help considerably to reduce the shooter's CTH.
  • Crouched/Prone stance
    • They help, especially at long range. Not very helpful at short range.
  • Stay outside enemy's effective range
    • Of course, you would need to know their weapon's range for that...
  • Camouflage, cover, and smoke
    • All will increase the enemy's Effective_Range value
  • Injure the enemy
    • Will increase their injury, fatigue, and shock penalties.
  • Gas the enemy
    • Assuming he isn't wearing a gas-mask.
  • If enemy is a tank, stay close and low
    • If you have to get close to a tank, try to get as close as possible, as fast as possible. Below 12 tiles of range, the tank begins to take serious penalties, especially if you're crouched or prone.
  • Get up on a roof
    • This decreases his chance to hit you, and increases your chance to hit him.
  • Move around!
    • The more you move during your turn, the less chance the enemy has to hit you.
  • High agility and experience level
    • Will help you dodge bullets... assuming the enemy isn't very skilled


Comments (0)

You don't have permission to comment on this page.