REFFERENCE - CtH formula (as explained by Thomas)
The answer to the CTH formula is a little bit more tricky, since its compromised of multiple calculations as you would expect.
The core formula is
CTH = (skillBonus + level) * (weaponAccuracy + penaltiesAndBonuses) / 100.0f
Lets break it down!
Accuracy for a melee weapon is its json defined accuracy. For ranged weapons its using a "damage range" calculation to get a nice curve with a separate falloff on the other side of the effective range. Here is the code
drange = range - effectiveRange;
if (drange > 0)
{
accuracy = Mathf.RoundToInt(baseAccuracy - drange * drange / (float)muzzleVelocity);
}
else
{
accuracy = Mathf.RoundToInt(baseAccuracy - drange * drange / (float)mobility);
}
Last part of accuracy is a deduction for weapon condition if its worn down, as well as aiming bonus as defined in the json:
private static int GetAimingAccuracy(AimingMode mode)
{
return TXC.GameRulesSettings.Combat.AimingAccuracyBonus * (int) mode;
}
Aiming mode is
public enum AimingMode : int
{
Normal = 0,
Focused = 1,
Super = 2
}
The various bonus/malus are
penaltiesAndBonuses = -coverPenalty - stancePenalty - woundedPenalty - bodyPartPenalty - autoFirePenalty - energyPenalty + stanceBonus + meleeStanceBonus + sustainedFireBonus + perkBonus;
Each of those have their own formula, most of them super super simple. Takes a separate post to write them all, but most of these are defined in the GameRulesSettings.json file
Lastly the 2 perks SprayNPray and Finisher are hooked in to give their effect.
That all ends up giving a CtH %.
Then if you hit, there is a somewhat similar damage calculation done + a crit chance roll. The core damage for a ranged weapon is given by
float drange = range - effectiveRange;
int damage = 0; if (drange > 0)
{
damage = Mathf.RoundToInt(baseDamage - drange * drange / damageFalloff);
}
else
{
damage = baseDamage;
}