]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/View.qc
Track hit time so that constant damage makes a noise
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / View.qc
index e4deda0341b161f4cc9114748544a074d203680c..3928ebd786e04427636bd2efd105ed3b45816441 100644 (file)
@@ -162,7 +162,7 @@ vector GetCurrentFov(float fov)
        else
                setsensitivityscale(1);
 
-       if(autocvar_cl_velocityzoom && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too
+       if(autocvar_cl_velocityzoom_enabled && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too
        {
                if(intermission) { curspeed = 0; }
                else
@@ -183,7 +183,7 @@ vector GetCurrentFov(float fov)
 
                velocityzoom = bound(0, drawframetime / max(0.000000001, autocvar_cl_velocityzoom_time), 1); // speed at which the zoom adapts to player velocity
                avgspeed = avgspeed * (1 - velocityzoom) + (curspeed / autocvar_cl_velocityzoom_speed) * velocityzoom;
-               velocityzoom = exp(float2range11(avgspeed * -autocvar_cl_velocityzoom / 1) * 1);
+               velocityzoom = exp(float2range11(avgspeed * -autocvar_cl_velocityzoom_factor / 1) * 1);
 
                //print(ftos(avgspeed), " avgspeed, ", ftos(curspeed), " curspeed, ", ftos(velocityzoom), " return\n"); // for debugging
        }
@@ -375,10 +375,6 @@ entity nightvision_noise, nightvision_noise2;
 
 #define MAX_TIME_DIFF 5
 float pickup_crosshair_time, pickup_crosshair_size;
-float hitsound_time_prev;
-float spectatee_status_prev; // for preventing hitsound when switching spectatee
-float damage_dealt_total, damage_dealt_total_prev;
-float typehit_time, typehit_time_prev;
 float hitindication_crosshair_size;
 float use_vortex_chargepool;
 
@@ -394,6 +390,30 @@ float contentavgalpha, liquidalpha_prev;
 vector liquidcolor_prev;
 
 float eventchase_current_distance;
+float eventchase_running;
+float WantEventchase()
+{
+       if(autocvar_cl_orthoview)
+               return FALSE;
+       if(intermission)
+               return TRUE;
+       if(spectatee_status >= 0)
+       {
+               if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_PORTO)))
+                       return TRUE;
+               if(autocvar_cl_eventchase_death && (getstati(STAT_HEALTH) <= 0))
+               {
+                       if(autocvar_cl_eventchase_death == 2)
+                       {
+                               // don't stop eventchase once it's started (even if velocity changes afterwards)
+                               if(self.velocity == '0 0 0' || eventchase_running)
+                                       return TRUE;
+                       }
+                       else return TRUE;
+               }
+       }
+       return FALSE;
+}
 
 vector damage_blurpostprocess, content_blurpostprocess;
 
@@ -495,9 +515,10 @@ void CSQC_UpdateView(float w, float h)
        // event chase camera
        if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped
        {
-               WepSet weapons_stat = WepSet_GetFromStat();
-               if(((spectatee_status >= 0 && (autocvar_cl_eventchase_death && is_dead)) || intermission) && !autocvar_cl_orthoview || (autocvar_cl_eventchase_nexball && spectatee_status >= 0 && gametype == MAPINFO_TYPE_NEXBALL && !(weapons_stat & WepSet_FromWeapon(WEP_PORTO))))
+               if(WantEventchase())
                {
+                       eventchase_running = TRUE;
+
                        // make special vector since we can't use view_origin (It is one frame old as of this code, it gets set later with the results this code makes.)
                        vector current_view_origin = (csqcplayer ? csqcplayer.origin : pmove_org);
 
@@ -538,6 +559,7 @@ void CSQC_UpdateView(float w, float h)
                }
                else if(autocvar_chase_active < 0) // time to disable chase_active if it was set by this code
                {
+                       eventchase_running = FALSE;
                        cvar_set("chase_active", "0");
                        eventchase_current_distance = 0; // start from 0 next time
                }
@@ -1151,83 +1173,62 @@ void CSQC_UpdateView(float w, float h)
        scoreboard_active = HUD_WouldDrawScoreboard();
 
        // varying sound pitch
-       damage_dealt_total = getstati(STAT_DAMAGE_DEALT_TOTAL);
-       
-       // detect overflow on server side
-       if (damage_dealt_total < damage_dealt_total_prev)
+
+       // accumulate damage with each stat update
+       static float unaccounted_damage = 0;
+       float unaccounted_damage_new = getstati(STAT_DAMAGE_DEALT_TOTAL);
+       static float damage_dealt_time_prev = 0;
+       float damage_dealt_time = getstatf(STAT_HIT_TIME);
+       if (damage_dealt_time != damage_dealt_time_prev)
        {
-               dprint("resetting dmg total: ", ftos(damage_dealt_total), " prev: ", ftos(damage_dealt_total_prev), "\n");
-               damage_dealt_total_prev = 0;
+               unaccounted_damage += unaccounted_damage_new;
+               dprint("dmg total: ", ftos(unaccounted_damage), " (+", ftos(unaccounted_damage_new), ")", "\n");
        }
+       damage_dealt_time_prev = damage_dealt_time;
 
        // prevent hitsound when switching spectatee
+       static float spectatee_status_prev = 0;
        if (spectatee_status != spectatee_status_prev)
-       {
-               damage_dealt_total_prev = damage_dealt_total;
-       }
+               unaccounted_damage = 0;
        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)
+       static float hitsound_time_prev = 0;
+       if (COMPARE_INCREASING(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)
+               if (autocvar_cl_hitsound && unaccounted_damage)
                {
-                       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);
+                       // customizable gradient function that crosses (0,a), (c,1) and asymptotically approaches b
+                       float a = autocvar_cl_hitsound_max_pitch;
+                       float b = autocvar_cl_hitsound_min_pitch;
+                       float c = autocvar_cl_hitsound_nom_damage;
+                       float 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(unaccounted_damage), " (+", ftos(unaccounted_damage_new), "), 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
+
+                       sound7(world, CH_INFO, "misc/hit.wav", VOL_BASE, ATTN_NONE, pitch_shift * 100, 0);
                }
-               
-               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
+               unaccounted_damage = 0;
                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;
-       }
-       
-       typehit_time = getstatf(STAT_TYPEHIT_TIME);
-       if(typehit_time - typehit_time_prev > autocvar_cl_hitsound_antispam_time)
+
+       static float typehit_time_prev = 0;
+       float typehit_time = getstatf(STAT_TYPEHIT_TIME);
+       if (COMPARE_INCREASING(typehit_time, typehit_time_prev) > autocvar_cl_hitsound_antispam_time)
        {
                sound(world, CH_INFO, "misc/typehit.wav", VOL_BASE, ATTN_NONE);
                typehit_time_prev = typehit_time;
@@ -1517,6 +1518,10 @@ void CSQC_UpdateView(float w, float h)
                                        weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD);
                                        weapon_clipsize = getstati(STAT_WEAPON_CLIPSIZE);
 
+                                       float ok_ammo_charge, ok_ammo_chargepool;
+                                       ok_ammo_charge = getstatf(STAT_OK_AMMO_CHARGE);
+                                       ok_ammo_chargepool = getstatf(STAT_OK_AMMO_CHARGEPOOl);
+
                                        float vortex_charge, vortex_chargepool;
                                        vortex_charge = getstatf(STAT_VORTEX_CHARGE);
                                        vortex_chargepool = getstatf(STAT_VORTEX_CHARGEPOOL);
@@ -1562,8 +1567,14 @@ void CSQC_UpdateView(float w, float h)
                                                ring_rgb = wcross_color;
                                                ring_image = "gfx/crosshair_ring.tga";
                                        }
-
-                                       if(autocvar_crosshair_ring_reload && weapon_clipsize) // forces there to be only an ammo ring
+                                       else if (ok_ammo_charge)
+                                       {
+                                               ring_value = ok_ammo_chargepool;
+                                               ring_alpha = autocvar_crosshair_ring_reload_alpha;
+                                               ring_rgb = wcross_color;
+                                               ring_image = "gfx/crosshair_ring.tga";
+                                       }
+                                       else if(autocvar_crosshair_ring_reload && weapon_clipsize) // forces there to be only an ammo ring 
                                        {
                                                ring_value = bound(0, weapon_clipload / weapon_clipsize, 1);
                                                ring_scale = autocvar_crosshair_ring_reload_size;