I've taken a look at the 357 reloading code. Apart from a few events that can be specified in animations, much of the timing appears to be hard-coded. Ideally you'd want the code to react to the end of an animation, but I don't know enough about the HL engine to say whether that's possible.
CPython::Reload
calls DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope );
, so the actual 'ammo transfer' happens after 2 seconds. Apparently that's when you can fire the weapon again, even if the reload animation hasn't finished yet.
DefaultReload
also contains the line m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3;
, which causes CPython::WeaponIdle
to pick a new idle animation after 3 seconds, regardless of whether the reload animation has finished. CPython::WeaponIdle
also contains hard-coded durations for each of the idle/fidget animations.