That's not super easy but if you want...
* your final chance to hit (toHit) is capped at <5, 95> range
* margin = toHit - Random(1, 100)
* if margin < 0 than it's miss
Critical failure can only happen if you miss your main hit roll and that miss is critical, here is raw formula:
isCritical = ((((-margin) / 10) + ((valid(realWeapon) && realWeapon.IsDeteriorable() && !_CritHasExtMode(cr, MODE_EXT_NO_DETERIORATION)) ? ((20 * realWeapon.Deterioration) / MAX_DETERIORATION) : 0)) >= Random(1, 100));
It says that miss is critical if "some value" >= Random(1, 100)
"some value" = ((-margin)/10) + "weapon deterioration mod"
"weapon deterioration mod" is calculated only if it's a valid weapon that is deteriorable and critter does not have special mode MODE_EXT_NO_DETERIORATION (for example guards has that), if not it's equal to 0
"weapon deterioration mod" = (20 * realWeapon.Deterioration) / MAX_DETERIORATION)
where:
MAX_DETERIORATION = 10000
real.Weapon.Deterioration = value from range 0 to 10000, where 0 is item in perfect condition
If isCritical is still false there is another check if you or your initial target got Jinxed, if yes than it's a 50% chance to make isCritical = true;
If isCritical is true than critical power roll is made:
int roll = Random(1, 100) - 5 * (cr.Stat[ST_LUCK] - 5);
if(roll <= 20)
roll = 0;
else if(roll <= 50)
roll = 1;
else if(roll <= 75)
roll = 2;
else if(roll <= 95)
roll = 3;
else
roll = 4;
It's used to read critical fail result from special critical fail table:
critfailFlags = CriticalFailureTable[5 * weapon.Weapon_CriticalFailture + roll];
This is CriticalFailureTable:
// fallout2.exe at file offset 0x1065A0 (517FA0 memory offset)
// row: weapon type (critfail list), column: critfail severity
const uint[] CriticalFailureTable = {
0x00000000, 0x00008000, 0x00008000, 0x00080002, 0x00200000,
0x00000000, 0x00008000, 0x00004000, 0x00100000, 0x00010000,
0x00000000, 0x00020000, 0x00004000, 0x00100000, 0x00002000,
0x00008000, 0x00028000, 0x0000C000, 0x00100000, 0x00009000,
0x00040000, 0x00004000, 0x00084000, 0x00100000, 0x00001000,
0x00008000, 0x00040000, 0x00002000, 0x00100000, 0x00009002,
0x00000000, 0x00008000, 0x00100000, 0x00002000, 0x00009400 };
Result is described as a flag that later on is processed to apply critical results to your character, those flags:
#define MF_KNOCKED_DOWN (0x00000002)
#define MF_ON_FIRE (0x00000400)
#define MF_WEAPON_EXPLODED (0x00001000)
#define MF_WEAPON_DESTROYED (0x00002000)
#define MF_WEAPON_DROPPED (0x00004000)
#define MF_LOST_NEXT_TURN (0x00008000)
#define MF_HIT_SELF (0x00010000)
#define MF_LOST_REST_OF_AMMO (0x00020000)
#define MF_FIRED_DUD_SHOT (0x00040000)
#define MF_HURT_SELF (0x00080000)
#define MF_HIT_RANDOMLY (0x00100000)
#define MF_CRIPPLED_RANDOM_LIMB (0x00200000)
#define MF_WAS_KILLED (0x10000000)
If result have few flags than it's equal to sum of those flags, example
MF_ON_FIRE (0x00000400) + MF_WEAPON_EXPLODED (0x00001000) = 0x000014000
As mentioned before we use this:
critfailFlags = CriticalFailureTable[5 * weapon.Weapon_CriticalFailture + roll];
to get position from CriticalFailureTable (index of element we want to read, with first index = 0)
5 * weapon.Weapon_CriticalFailture
Tells us which row we are looking at and roll specifies column.
weapon.Weapon_CriticalFailture is a value every weapon has set in it's proto, you can check that in FOnline Object Editor in /Tools/ObjectEditor in file /Server/proto/items/weapon.fopro
For example flamer got that value set to 6 and last column from last row got ON_FIRE flag
Have fun