+ spectatee_status_prev = spectatee_status;
+
+ // amount of damage since last hit sound
+ float unaccounted_damage = damage_dealt_total - damage_dealt_total_prev;
+
+
+ if (autocvar_cl_hitsound == 1)
+ {
+ if ( time - hitsound_time_prev > autocvar_cl_hitsound_antispam_time )
+ if ( damage_dealt_total > 0 )
+ {
+ sound(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTEN_NONE);
+ hitsound_time_prev = time;
+ }
+ }
+ else if (unaccounted_damage > 0 && autocvar_cl_hitsound > 0 && time - hitsound_time_prev > autocvar_cl_hitsound_antispam_time)
+ {
+ // customizable gradient function that crosses (0,a), (c,1) and asymptotically approaches b
+ float a, b, c, x;
+ a = autocvar_cl_hitsound_max_pitch;
+ b = autocvar_cl_hitsound_min_pitch;
+ c = autocvar_cl_hitsound_nom_damage;
+ x = unaccounted_damage;
+ float pitch_shift = (b*x*(a-1) + a*c*(1-b)) / (x*(a-1) + c*(1-b));
+
+ // if sound variation is disabled, set pitch_shift to 1
+ if (autocvar_cl_hitsound == 1)
+ {
+ pitch_shift = 1;
+ }
+
+ // if pitch shift is reversed, mirror in (max-min)/2 + min
+ if (autocvar_cl_hitsound == 3)
+ {
+ float mirror_value = (a-b)/2 + b;
+ pitch_shift = mirror_value + (mirror_value - pitch_shift);
+ }
+
+ dprint("dmg total (dmg): ", ftos(damage_dealt_total), " (+", ftos(unaccounted_damage), "), pitch shift: ", ftos(pitch_shift), "\n");
+
+ // todo: avoid very long and very short sounds from wave stretching using different sound files? seems unnecessary
+ // todo: normalize sound pressure levels? seems unnecessary
+
+ // scale to fit function interface
+ float param_pitch_shift = pitch_shift * 100;
+
+ // play sound
+ sound7(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTN_NONE, param_pitch_shift, 0);
+
+ // track damage accounted for
+ damage_dealt_total_prev = damage_dealt_total;
+
+ // remember when this sound was played to prevent sound spam
+ hitsound_time_prev = time;
+ }
+ else if (autocvar_cl_hitsound == 0)
+ {
+ // forget the damage to prevent hitsound when enabling it
+ damage_dealt_total_prev = damage_dealt_total;
+ }
+