XP calculations are done in game.cpp and melee.cpp.

There are following formulas:

- 25% chance to get 1 xp/75% chance to get 0 xp for
`skill_melee`

per successful smash (via *void game::smash()*)

```
if (u.get_skill_level( skill_melee ) == 0) {
u.practice( skill_melee, rng(0, 1) * rng(0, 1));
}
```

- Practice melee
`skill_melee`

, `skill_bashing`

, `skill_cutting`

, `skill_stabbing`

and `skill_unarmed`

proportional to damage dealt (via *static void melee_train( player &p, int lo, int hi, const item &weap )*)

```
static void melee_train( player &p, int lo, int hi, const item &weap ) {
p.practice( skill_melee, ceil( rng( lo, hi ) / 2.0 ), hi );
// allocate XP proportional to damage stats
// Pure unarmed needs a special case because it has 0 weapon damage
int cut = weap.damage_melee( DT_CUT );
int stab = weap.damage_melee( DT_STAB );
int bash = weap.damage_melee( DT_BASH ) + ( weap.is_null() ? 1 : 0 );
float total = std::max( cut + stab + bash, 1 );
p.practice( skill_cutting, ceil( cut / total * rng( lo, hi ) ), hi );
p.practice( skill_stabbing, ceil( stab / total * rng( lo, hi ) ), hi );
// Unarmed skill scaled bashing damage and so scales with bashing damage
p.practice( weap.has_flag( "UNARMED_WEAPON" ) ? skill_unarmed : skill_bashing,
ceil( bash / total * rng( lo, hi ) ), hi );
}
```

- When CQB bionic is not active train
`skill_melee`

(via *void player::melee_attack(Creature &t, bool allow_special, const matec_id &force_technique, int hit_spread)*)

*When *`hit_spread`

is less than 0:

```
// Practice melee and relevant weapon skill (if any) except when using CQB bionic
if( !has_active_bionic( bio_cqb ) ) {
melee_train( *this, 2, 5, cur_weapon );
}
```

*When *`hit_spread`

is more than or equal to 0:

```
// Practice melee and relevant weapon skill (if any) except when using CQB bionic
if( !has_active_bionic( bio_cqb ) ) {
melee_train( *this, 5, 10, cur_weapon );
}
```

- Gain 0 to 10 xp with equal chance with
`skill_unarmed`

once per combo (via *void player::perform_special_attacks(Creature &t)*)

```
if( !practiced ) {
// Practice unarmed, at most once per combo
practiced = true;
practice( skill_unarmed, rng( 0, 10 ) );
}
```