Various questions about the inner workings of skills

Andrei Nistor

First time out of the vault
Hello, I had a few questions regarding how some of the skills are working in FoT

Does anyone have any idea how the number of hit points healed works for First Aid and Doctor? Does it scale with the max hit points of the target, does it scale with the skill level of the healer. It certanly seems to be much higher than the levels in F1/2.

What does a skill roll look like, is the chance for critical failure similar to the f2 engine calculations? Any ideas on critical failure effects (like crippling limbs).

For first aid the experience reward from what I could gather is Max(15, [healed hit points])

For lockpick it seems like a mistery as it always fluctuates (could it possibly be related to the roll that you did, or a random roll based on the lock difficulty).

Is bandaged always applied after the third use of first aid on the same target or does it fluctuate based on the healer's skill level and also can it be wiped clean if enough time passes between applications of first aid.

Thank you!
 
Here's what I have from my old notes re: behavior of skills. (Note that these are old notes, and from before I started using Ghidra for analysis, so take the info with a grain of salt).

TL;DR:
* Healing amount scales with skill level of healer and heal rate of the target. Max HP doesn't matter, except for when Doctor skill gets a critical success.
* Bandaged state is a counter - each First Aid use increments by 1, and the status is displayed (and First Aid is prohibited) when the value reaches 3.
* Bandaged state can be reduced by applying Doctor skill (-1 to value), or by time passing (notes say -1 per day, not sure if this is exact)

Full details:

Important note: Skills which mention a "critical" success or failure have a serious bug, where an uninitialized variable is used to hold the bits indicating success/fail and critical. For the success/fail bit, the game will properly set/clear the bit value based on the result, but for the critical effect bit, the value from the uninitialized memory is kept. This means that, depending on the preceding code, the critical effects may occur slightly more often, completely randomly, or nearly always, even if they should not.

Sneak:
The game determines a "detection range" for each NPC vs a sneaking character. The range calculation is complex, but includes the following factors: light level (multiplier, formula appears to be (0.5 + [0.0-1.0 depending on brightness]) * 0.666), stance (multiplier, 0.8 for crouch and 0.6 for prone), moving vs not moving (multiplier, 1.5 if moving), NPC's Perception (base value for other multipliers: PE * 3 + 12), difference in skill between NPC and sneaking character (from notes, this is a multiplier: 80 / (SneakSkill - NPCSneakSkill/2 + 100) , with a 20% increase in character's sneak skill with Ghost perk if light level is below 0.6 ), and finally angle-off between sneaker's position and NPC's line of sight (multiplier, 1.0 if within 60 degrees of line of sight on either side, with linear reduction down to 0.0 when exactly behind the NPC). If the sneaking character is within this range when the NPC's think timer triggers, then they will be detected. Note that there is no randomness in the check, other than timing as to when the NPC's think timer triggers - so if a character remains hidden for more than a couple seconds, then they will stay hidden, as long as they and/or NPCs do not move or rotate.

Note the potential for a 0.0 multiplier if directly behind a target - if you can line your character up perfectly behind without being detected, then you can remain there indefinitely for as long or as close as you want.


Steal:
This is a contested skill roll check. Take the character's skill in Steal, and subtract difficulty, calculated as follows:

Target's PE * 0.1 * Target's Steal skill
+ (Total items weight * 2.0 , for weightless items use 0.1 weight per item)
+ 25 if stealing character within 90 degrees of line of sight
(previous two items skipped if stealer has Pickpocket perk)
- 100 if target is sleeping or unconscious
- 25 if stealer is sneaking
- 20 if target is prone
The difference between skill and difficulty is capped to a maximum of 95. This is then compared to a roll from 0-99. If the roll is below the difference, then stealing succeeds, otherwise it fails.

Note that because of the cap, there can never be a 100% chance of success for stealing.


First Aid, Doctor, Repair:
All of these appear to function similarly. First do a skill roll check on the relevant skill; e.g. determine a "success value" as:
skill (capped at 95%) - random roll from 1-100

If this is successful, do a critical check: (success value * 0.1 + critical chance) compared to a roll from 0-99. If roll is lower, then the heal is a "critical success".

Amount healed is:

First Aid: (Random value between [21/80 * FirstAidSkill, 35/80 * FirstAidSkill] + 4*HealerPerks) * (1 + 0.1 * TargetHealRate). Random range min/max is doubled if a critical heal. Applies +1 to Bandaged state; if Bandaged >= 3, then further First Aid will fail.

Doctor: If skill is at least 50%, heal unconscious status. On success, heal all injury states, reduce Bandaged by 1, and OverdosePoints by 15. Then, on non-critical heal, heal (random value between [35/100 * DoctorSkill, 58/100 * DoctorSkill] + 4*HealerPerks) * (1 + 0.1 * TargetHealRate), and on critical heal, fully heal the target.

Repair: On a (robot) actor, does the same as Doctor, just using Repair skill value (taking into account the Tight Nuts trait, reducing Repair skill by 50% if the target has it). On a vehicle, repair recovers a random value between [70/100 * RepairSkill, 122/100 * RepairSkill] vehicle HP, with no critical repair behavior.

If the heal skill check fails: there's a check for a "critical fail", only if the healer has Jinxed or Fear the Reaper traits. Chance for critical fail is 2x the character's critical chance, clamped between [5,25]. On critical fail, First Aid will injure a random body part, Doctor will do the same + deal between 1-9 damage. Repair fail on vehicle does nothing.

Lockpick, Science:
Both of these are straight "contested" skill checks: If skill >= (random roll [0-99] + difficulty), then succeed.

Traps:
In general, also straight "contested" skill checks, with following adjustments:
Setting a timer trap multiplies the effective Traps skill by 1.5
Disarming a trap reduces skill by both difficulty (Set in the entity definition) and "skill roll" (set either in level editor or when a player sets a mine). This is compared to the 1-100 roll as with a normal skill check.
Critical failure can happen on trap disarm if the check fails by at least 50 + 25 * DemolitionExpertPerks, or if the skill check critical condition occurs (same code as for the healing skills to critically fail). (Also affected by bug mentioned above - so trap disarm failures explode more than they are supposed to.)
 
God bless you @Melindil :D

I was so happy to find the first aid/doctor logic in the fallout 2-re git repo, implemented it on my end and when doing a sanity check with heals in fot I saw that the numbers weren't adding up. I can't wait to implement these ones now! I will have to move this implementation to a F1/2 flavor and get started on these new ones!

After I posted this I did do some tests in fot, inferred how the bandaged state was working and noticed that around 50% of the time the healing values were double for first aid (that would probably be the critical success, but seems a bit often, I will implement it on my end and report back).

For the values to fall within the ranges that I've recorded it would seem that at least the first aid kit does not actually add any skill effect on first aid (wondering if the field medic kit does) so that is strange as it is usally advertised in wikis that it adds 20% (even if no such effect is present in the entity editor for it).

If the heal skill check fails: there's a check for a "critical fail", only if the healer has Jinxed or Fear the Reaper traits.
During testing I've gotten quite a few critical fails injuring limbs without having any of the two traits on (Stitch)
Edit: I think I got it, you are saying that this critical fail check is on top of the normal critical fail check. If that is the case would it make more sense for the character getting healed to have the Fear the Reaper perk?

Chance for critical fail is 2x the character's critical chance, clamped between [5,25]
So the game punishes you for having a high crit chance :D

Any ideas on the formula used to grant xp on successful lockpick, science, trap disarm? And chance to find a trap?

Once again thank you so much for the info, and for the time you take to figure these things out.

I have tried a few times to poke thru the BOS.exe using Binary Ninja, even found the first aid skill use function, attached to the game, hit the breakpoint but then I was completely lost on how to interpret any of it, so I have no idea how you people actually do it, seems like black magic :D

If I even have any questions regarding the mechanics of FoT would you be open to get comissioned to look into them (get paid)? I'm not rich in any sense but it would be a small price to pay for having a true professional have my back when the mechanics get really murky.

Thanks again!
 
Last edited:
After I posted this I did do some tests in fot, inferred how the bandaged state was working and noticed that around 50% of the time the healing values were double for first aid (that would probably be the critical success, but seems a bit often, I will implement it on my end and report back).
This would be caused by the bug I mentioned. In a case where the uninitialized memory is pseudo-random, I'd expect around a 50/50 distribution of critical vs. non-critical outcomes.

During testing I've gotten quite a few critical fails injuring limbs without having any of the two traits on (Stitch)
Same here.

I'm likely going to add a fix in FTSE for the bug, but I'm not sure yet if I'll enable it by default. It's clear what the code is trying to do, and the intended effects make sense. But whatever (likely minimal) testing and balancing that was done for the game would have been done with the bug in place, so I don't know the degree to which fixing it will affect gameplay. At a minimum, likely effects would be: failed heals rarely have any impact other than wasting a use of the first aid kits, successful heals restore less HP, and trap disarm failures being much less deadly (though the extremely high difficulty traps would still critically fail often due to the secondary critical fail condition - e.g. the mines in the St. Louis base).

For the values to fall within the ranges that I've recorded it would seem that at least the first aid kit does not actually add any skill effect on first aid (wondering if the field medic kit does) so that is strange as it is usally advertised in wikis that it adds 20% (even if no such effect is present in the entity editor for it).
This is correct - I didn't see any specific increase from the regular first aid kit. The field medic kit does have a skill bonus of 20 for First Aid in the entity, so that would be applied at equip time. It's possible that whoever wrote the entry for the wiki was confused by the 1.2x multiplier coming from Heal Rate.

Any ideas on the formula used to grant xp on successful lockpick, science, trap disarm? And chance to find a trap?
For First Aid: XP is the amount healed, clamped between the values [15,150].

For Doctor: +15 XP if target was unconscious and woken up, +15 XP per recovered injury, and the same increase as First Aid for heal amount. On a critical heal, use +30 XP instead of the heal amount.

For Repair: Repair of robot is same as Doctor, repair of vehicle uses the amount of HP repaired clamped to [15,150], and repair of an item appears to use (RepairSkill - RepairDifficulty).

For Lockpick: Locking a door or container is always 15 XP. Unlocking gives XP based on the "Chance to Unlock" value in the editor, clamped between [15,150].

For Science: Gives XP equal to "Difficulty" in the entity/editor, clamped between [15,150].

For Traps: Disarming a trap gives XP equal to the sum of "Difficulty" and "Skill Roll" of the trap, clamped between [15,150].


Trap detection appears to work somewhat like sneak detection - the game calculates a range at which the character would be able to see the trap at its next think timer expiration. The distance where the mine can be seen is (Perception + MIN(0,(TrapsSkill - TotalDifficulty)/5)), where TotalDifficulty is the sum of the "Difficulty" and "Skill Roll" values. Note that the distance measurement is from edges of each bounding box, not the center point of the entities. Given the formula only applies the second value if difficulty is higher than skill, the maximum detection distance is the character's PE, and detection is impossible if the difficulty exceeds skill by 5*PE.

I have tried a few times to poke thru the BOS.exe using Binary Ninja, even found the first aid skill use function, attached to the game, hit the breakpoint but then I was completely lost on how to interpret any of it, so I have no idea how you people actually do it, seems like black magic :D
Actually, getting that far is pretty impressive - I was barely able to do more than that when I first started the Team Player hex fix that led to FTSE. It's more a matter of perseverance - walking through code with the debugger, finding what certain values in memory represent in the game, then going back to the static analysis (Binary Ninja or Ghidra) and plugging in the info you found. As you do this, the info the static analysis gives you is much more readable. So you can go from raw assembly code:

LAB_005ce341 XREF[1]: 005ce32d(j)
005ce341 8b 16 MOV EDX,dword ptr [ESI]
005ce343 8b ce MOV ECX,ESI
005ce345 ff 92 7c CALL dword ptr [EDX + 0x57c]
05 00 00
005ce34b 8b a8 f1 MOV EBP,dword ptr [EAX + 0xf1]
00 00 00
005ce351 8b 97 50 MOV EDX,dword ptr [EDI + 0x850]
08 00 00
005ce357 8b 8f 30 MOV ECX,dword ptr [EDI + 0x830]
08 00 00
005ce35d 05 c1 00 ADD EAX,0xc1
00 00
005ce362 2b ea SUB EBP,EDX
005ce364 2b e9 SUB EBP,ECX
005ce366 3b eb CMP EBP,EBX
005ce368 7e 02 JLE LAB_005ce36c
005ce36a 33 ed XOR EBP,EBP
LAB_005ce36c XREF[1]: 005ce368(j)
005ce36c 8b 06 MOV EAX,dword ptr [ESI]
005ce36e 8b ce MOV ECX,ESI
005ce370 ff 90 7c CALL dword ptr [EAX + 0x57c]
05 00 00
005ce376 8b c8 MOV ECX,EAX
005ce378 b8 67 66 MOV EAX,0x66666667
66 66
005ce37d f7 ed IMUL EBP

To something considerably more readable:

pAVar7 = (*pEVar13->entity_vtable->GetCurrentStats)(pEVar13);
skill_minus_difficulty = ((pAVar7->skills).traps - this->difficulty) - this->skillroll;
if (0 < skill_minus_difficulty) {
skill_minus_difficulty = 0;
}
pAVar7 = (*pEVar13->entity_vtable->GetCurrentStats)(pEVar13);
total_ability = (float)((pAVar7->stats).perception + skill_minus_difficulty / 5);
sighting_distance = (float)(int)total_ability;
if (sighting_distance < 0.0) {
sighting_distance = 0.0;
}
if ((float)dist_minus_bounding_box < sighting_distance * sighting_distance) {
dist_minus_bounding_box = &stack0xffffff44;
cVar4 = FUN_00553790();
if (cVar4 != '\0') {
this->hidden = false;

If you ever want to give it another try at some point, let me know - I can try to set you up with a copy of my Ghidra project, with the info I've collected so far. There's an archive of the Ghidra project in the FTSE GitHub under the Technical Docs section, but it's not up to date.

If I even have any questions regarding the mechanics of FoT would you be open to get comissioned to look into them (get paid)? I'm not rich in any sense but it would be a small price to pay for having a true professional have my back when the mechanics get really murky.
Nah, that's not necessary - I've always done this for fun as a hobby. Plus, my time is still pretty limited, so I'd hate to have someone dependent on my finding time to research/reverse. (That said, if the developer came to me and said "We lost the source code and want to do a remake, can you fully reverse engineer and make a reference implementation", and offered me a retirement-level sum of money .. Hey, one can dream, right? :) )
 
Last edited:
Back
Top