Formula is something like:
weapon_dispersion + ammo_dispersion < skill_dispersion + type_offset + 15 * rng( 0, perception )
If this is true, skill is trained
Weapon and ammo are displayed on the item.
Skill dispersion is (10 - skill)*45 + (10 - marksmanship)*15
Type offset is a hardcoded variable: 135 for archery, 195 for throwing (sling but not slingshot), 0 for everything else. This makes bows and slings easier to gain skill in.
rng(x, y) is a random value from x to y (including both x and y).
The skill gain itself depends on how good the hit was: headshot exp is proportional to range, less accurate shots give less exp: [headshot exp]/2 for good shot, then headshot/3, then /4, then /5.
Any shot that trains the skill (even if it is a total miss) also gives some flat exp, dependent weakly on burst size.