]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/View.qc
do the nearclip hack in the chasecam too
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / View.qc
index 7d0b012543e7f96bf40d3e4aad78005058d4ff62..5868c56b0640dcadec702cf9f4de690d038ccc1c 100644 (file)
@@ -137,7 +137,7 @@ vector GetCurrentFov(float fov)
                        zoomspeed = 3.5;
 
        zoomdir = button_zoom;
-       if((getstati(STAT_ACTIVEWEAPON) == WEP_NEX && nex_scope) || (getstati(STAT_ACTIVEWEAPON) == WEP_SNIPERRIFLE && sniperrifle_scope)) // do NOT use switchweapon here
+       if((getstati(STAT_ACTIVEWEAPON) == WEP_NEX && nex_scope) || (getstati(STAT_ACTIVEWEAPON) == WEP_RIFLE && rifle_scope)) // do NOT use switchweapon here
                zoomdir += button_attack2;
        if(spectatee_status > 0 || isdemo())
        {
@@ -274,7 +274,7 @@ float TrueAimCheck()
                case WEP_MINSTANEX:
                        mv = MOVE_NORMAL;
                        break;
-               case WEP_SNIPERRIFLE:
+               case WEP_RIFLE:
                        ta = trueaim_rifle;
                        mv = MOVE_NORMAL;
                        if(zoomscript_caught)
@@ -342,7 +342,6 @@ void CSQC_common_hud(void);
 void PostInit(void);
 void CSQC_Demo_Camera();
 float HUD_WouldDrawScoreboard();
-float view_set;
 float camera_mode;
 float reticle_type;
 string NextFrameCommand;
@@ -353,6 +352,9 @@ vector freeze_pmove_org, freeze_input_angles;
 entity nightvision_noise, nightvision_noise2;
 
 float pickup_crosshair_time, pickup_crosshair_size;
+float hit_time, typehit_time;
+float nextsound_hit_time, nextsound_typehit_time;
+float hitindication_crosshair_time, hitindication_crosshair_size;
 float use_nex_chargepool;
 
 float myhealth, myhealth_prev;
@@ -363,6 +365,10 @@ vector myhealth_gentlergb;
 float contentavgalpha, liquidalpha_prev;
 vector liquidcolor_prev;
 
+float eventchase_current_distance;
+
+float checkfail[16];
+
 void CSQC_UpdateView(float w, float h)
 {
        entity e;
@@ -372,12 +378,24 @@ void CSQC_UpdateView(float w, float h)
        vector vf_size, vf_min;
        float a;
 
+       button_attack2 = (input_buttons & BUTTON_3);
+       button_zoom = (input_buttons & BUTTON_4);
+
+#define CHECKFAIL_ASSERT(flag,func,parm,val) { float checkfailv; checkfailv = (func)(parm); if(checkfailv != (val)) { if(!checkfail[(flag)]) localcmd(sprintf("\ncmd checkfail %s %s %d %d\n", #func, parm, val, checkfailv)); checkfail[(flag)] = 1; } } ENDS_WITH_CURLY_BRACE
+       CHECKFAIL_ASSERT(0, cvar_type, "\{100}\{105}\{118}\{48}\{95}\{101}\{118}\{97}\{100}\{101}", 0);
+       CHECKFAIL_ASSERT(1, cvar_type, "\{97}\{97}\{95}\{101}\{110}\{97}\{98}\{108}\{101}", 0);
+       CHECKFAIL_ASSERT(2, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{100}\{105}\{115}\{97}\{98}\{108}\{101}\{100}\{101}\{112}\{116}\{104}\{116}\{101}\{115}\{116}", 0);
+       CHECKFAIL_ASSERT(3, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{111}\{118}\{101}\{114}\{100}\{114}\{97}\{119}", 0);
+       CHECKFAIL_ASSERT(4, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{108}\{105}\{103}\{104}\{116}", 0);
+       CHECKFAIL_ASSERT(5, cvar, "\{114}\{95}\{115}\{104}\{111}\{119}\{115}\{104}\{97}\{100}\{111}\{119}\{118}\{111}\{108}\{117}\{109}\{101}\{115}", 0);
+
        vf_size = R_SetView3fv(VF_SIZE);
        vf_min = R_SetView3fv(VF_MIN);
        vid_width = vf_size_x;
        vid_height = vf_size_y;
 
        vector reticle_pos, reticle_size;
+       vector splash_pos, splash_size;
 
        WaypointSprite_Load();
 
@@ -397,7 +415,7 @@ void CSQC_UpdateView(float w, float h)
        input_angles = warpzone_fixview_cl_viewangles;
        view_angles = warpzone_fixview_angles;
 
-       if(autocvar_cl_lockview || (autocvar__hud_configure && spectatee_status <= 0))
+       if(autocvar_cl_lockview || (autocvar__hud_configure && spectatee_status <= 0) || intermission > 1)
        {
                pmove_org = freeze_pmove_org;
                input_angles = view_angles = freeze_input_angles;
@@ -408,18 +426,61 @@ void CSQC_UpdateView(float w, float h)
        freeze_pmove_org = pmove_org;
        freeze_input_angles = input_angles;
 
-       // Render the Scene
-       if(!intermission || !view_set)
+       // event chase camera
+       if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped
        {
-               view_origin = pmove_org + vo;
-               view_angles = input_angles;
-               makevectors(view_angles);
-               view_forward = v_forward;
-               view_right = v_right;
-               view_up = v_up;
-               view_set = 1;
+               if(spectatee_status >= 0 && (autocvar_cl_eventchase_death && getstati(STAT_HEALTH) <= 0 && !intermission) || intermission)
+               {
+                       // We must enable chase_active to get a third person view (weapon viewmodel hidden and own player model showing).
+                       // Ideally, there should be another way to enable third person cameras, such as through R_SetView()
+                       if(!autocvar_chase_active)
+                               cvar_set("chase_active", "-1"); // -1 enables chase_active while marking it as set by this code, and not by the user (which would be 1)
+
+                       // make the camera smooth back
+                       if(autocvar_cl_eventchase_speed && eventchase_current_distance < autocvar_cl_eventchase_distance)
+                               eventchase_current_distance += autocvar_cl_eventchase_speed * (autocvar_cl_eventchase_distance - eventchase_current_distance) * frametime; // slow down the further we get
+                       else if(eventchase_current_distance != autocvar_cl_eventchase_distance)
+                               eventchase_current_distance = autocvar_cl_eventchase_distance;
+
+                       vector eventchase_target_origin;
+                       makevectors(view_angles);
+                       // pass 1, used to check where the camera would go and obtain the trace_fraction
+                       eventchase_target_origin = pmove_org - v_forward * eventchase_current_distance;
+
+                       WarpZone_TraceLine(pmove_org, eventchase_target_origin, MOVE_WORLDONLY, self);
+                       // pass 2, also multiplying view_forward with trace_fraction, to prevent the camera from going through walls
+                       // The 0.1 subtraction is to not limit the camera precisely at the wall surface, as that allows the view to poke through
+                       eventchase_target_origin = pmove_org - v_forward * eventchase_current_distance * (trace_fraction - 0.1);
+                       WarpZone_TraceLine(pmove_org, eventchase_target_origin, MOVE_WORLDONLY, self);
+
+                       R_SetView(VF_ORIGIN, trace_endpos);
+                       R_SetView(VF_ANGLES, WarpZone_TransformVAngles(WarpZone_trace_transform, view_angles));
+
+                       vector o, corner0, corner1, corner2, corner3, nearclip;
+                       nearclip = '0 0 1' * (cvar("r_nearclip") * 1.125);
+                       corner0 = cs_unproject('0 0 0' + nearclip);
+                       corner1 = cs_unproject('1 0 0' * cvar("vid_conwidth") + nearclip);
+                       corner2 = cs_unproject('0 1 0' * cvar("vid_conheight") + nearclip);
+                       corner3 = cs_unproject('1 0 0' * cvar("vid_conwidth") + '0 1 0' * cvar("vid_conheight") + nearclip);
+                       o = trace_endpos;
+                       o = o + WarpZone_FixNearClip(trace_endpos, corner0, corner1, corner2, corner3);
+                       R_SetView(VF_ORIGIN, o);
+               }
+               else if(autocvar_chase_active < 0) // time to disable chase_active if it was set by this code
+               {
+                       cvar_set("chase_active", "0");
+                       eventchase_current_distance = 0; // start from 0 next time
+               }
        }
 
+       // Render the Scene
+       view_origin = R_SetView3fv(VF_ORIGIN);
+       view_angles = R_SetView3fv(VF_ANGLES);
+       makevectors(view_angles);
+       view_forward = v_forward;
+       view_right = v_right;
+       view_up = v_up;
+
 #ifdef BLURTEST
        if(time > blurtest_time0 && time < blurtest_time1)
        {
@@ -464,22 +525,20 @@ void CSQC_UpdateView(float w, float h)
        carrierAnnouncer();
 
        fov = autocvar_fov;
-       if(button_zoom || fov <= 59.5)
+       if(fov <= 59.5)
        {
                if(!zoomscript_caught)
                {
-                       localcmd("+button4\n");
+                       localcmd("+button9\n");
                        zoomscript_caught = 1;
-                       ignore_plus_zoom += 1;
                }
        }
        else
        {
                if(zoomscript_caught)
                {
-                       localcmd("-button4\n");
+                       localcmd("-button9\n");
                        zoomscript_caught = 0;
-                       ignore_minus_zoom += 1;
                }
        }
 
@@ -505,6 +564,8 @@ void CSQC_UpdateView(float w, float h)
 
        // ALWAYS Clear Current Scene First
        R_ClearScene();
+       R_SetView(VF_ORIGIN, view_origin);
+       R_SetView(VF_ANGLES, view_angles);
 
        // FIXME engine bug? VF_SIZE and VF_MIN are not restored to sensible values by this
        R_SetView(VF_SIZE, vf_size);
@@ -553,10 +614,6 @@ void CSQC_UpdateView(float w, float h)
        // Draw the Engine Status Bar (the default Quake HUD)
        R_SetView(VF_DRAWENGINEHUD, 0);
 
-       // fetch this one only once per frame
-       hud_showbinds = autocvar_hud_showbinds;
-       hud_showbinds_limit = autocvar_hud_showbinds_limit;
-
        // Update the mouse position
        /*
           mousepos_x = vid_conwidth;
@@ -634,42 +691,43 @@ void CSQC_UpdateView(float w, float h)
        // the view to go back to normal, so reticle_type would become 0 as we fade out)
        if(spectatee_status || getstati(STAT_HEALTH) <= 0)
                reticle_type = 0; // prevent reticle from showing during the respawn zoom effect or for spectators
-       else if(activeweapon == WEP_NEX && (button_zoom || zoomscript_caught) || activeweapon == WEP_SNIPERRIFLE && (button_zoom || zoomscript_caught) || activeweapon == WEP_MINSTANEX && (button_zoom || zoomscript_caught))
+       else if(activeweapon == WEP_NEX && (button_zoom || zoomscript_caught) || activeweapon == WEP_RIFLE && (button_zoom || zoomscript_caught) || activeweapon == WEP_MINSTANEX && (button_zoom || zoomscript_caught))
                reticle_type = 2; // nex zoom
        else if(button_zoom || zoomscript_caught)
                reticle_type = 1; // normal zoom
-       else if(activeweapon == WEP_NEX && button_attack2 || activeweapon == WEP_SNIPERRIFLE && button_attack2)
+       else if(activeweapon == WEP_NEX && button_attack2 || activeweapon == WEP_RIFLE && button_attack2)
                reticle_type = 2; // nex zoom
 
-       if(autocvar_cl_reticle_stretch)
+       if (reticle_type)
        {
-               reticle_size_x = vid_conwidth;
-               reticle_size_y = vid_conheight;
-               reticle_pos_x = 0;
-               reticle_pos_y = 0;
-       }
-       else
-       {
-               reticle_size_x = max(vid_conwidth, vid_conheight);
-               reticle_size_y = max(vid_conwidth, vid_conheight);
-               reticle_pos_x = (vid_conwidth - reticle_size_x) / 2;
-               reticle_pos_y = (vid_conheight - reticle_size_y) / 2;
-       }
+               if(autocvar_cl_reticle_stretch)
+               {
+                       reticle_size_x = vid_conwidth;
+                       reticle_size_y = vid_conheight;
+                       reticle_pos_x = 0;
+                       reticle_pos_y = 0;
+               }
+               else
+               {
+                       reticle_size_x = max(vid_conwidth, vid_conheight);
+                       reticle_size_y = max(vid_conwidth, vid_conheight);
+                       reticle_pos_x = (vid_conwidth - reticle_size_x) / 2;
+                       reticle_pos_y = (vid_conheight - reticle_size_y) / 2;
+               }
 
-       f = current_zoomfraction;
-       if(zoomscript_caught)
-               f = 1;
-       if(autocvar_cl_reticle_item_normal)
-       {
-               precache_pic("gfx/reticle_normal");
-               if(reticle_type == 1 && f)
-                       drawpic(reticle_pos, "gfx/reticle_normal", reticle_size, '1 1 1', f * autocvar_cl_reticle_item_normal, DRAWFLAG_NORMAL);
-       }
-       if(autocvar_cl_reticle_item_nex)
-       {
-               precache_pic("gfx/reticle_nex");
-               if(reticle_type == 2 && f)
-                       drawpic(reticle_pos, "gfx/reticle_nex", reticle_size, '1 1 1', f * autocvar_cl_reticle_item_nex, DRAWFLAG_NORMAL);
+               f = current_zoomfraction;
+               if(zoomscript_caught)
+                       f = 1;
+               if(autocvar_cl_reticle_item_normal)
+               {
+                       if(reticle_type == 1 && f)
+                               drawpic(reticle_pos, "gfx/reticle_normal", reticle_size, '1 1 1', f * autocvar_cl_reticle_item_normal, DRAWFLAG_NORMAL);
+               }
+               if(autocvar_cl_reticle_item_nex)
+               {
+                       if(reticle_type == 2 && f)
+                               drawpic(reticle_pos, "gfx/reticle_nex", reticle_size, '1 1 1', f * autocvar_cl_reticle_item_nex, DRAWFLAG_NORMAL);
+               }
        }
 
 
@@ -723,8 +781,13 @@ void CSQC_UpdateView(float w, float h)
                        drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, liquidcolor_prev, contentavgalpha * liquidalpha_prev, DRAWFLAG_NORMAL);
        }
        
-       if(autocvar_hud_damage)
+       if(autocvar_hud_damage && !autocvar_chase_active)
        {
+               splash_size_x = max(vid_conwidth, vid_conheight);
+               splash_size_y = max(vid_conwidth, vid_conheight);
+               splash_pos_x = (vid_conwidth - splash_size_x) / 2;
+               splash_pos_y = (vid_conheight - splash_size_y) / 2;
+
                float myhealth_flash_temp;
                myhealth = getstati(STAT_HEALTH);
 
@@ -781,7 +844,7 @@ void CSQC_UpdateView(float w, float h)
                        drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, myhealth_gentlergb, autocvar_hud_damage_gentle_alpha_multiplier * bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
                }
                else
-                       drawpic(reticle_pos, "gfx/blood", reticle_size, stov(autocvar_hud_damage_color), bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
+                       drawpic(splash_pos, "gfx/blood", splash_size, stov(autocvar_hud_damage_color), bound(0, myhealth_flash_temp, 1) * autocvar_hud_damage, DRAWFLAG_NORMAL);
        }
 
        // Draw the mouse cursor
@@ -806,9 +869,23 @@ void CSQC_UpdateView(float w, float h)
                if(self.draw2d)
                        self.draw2d();
        self = e;
+       Draw_ShowNames_All();
 
        scoreboard_active = HUD_WouldDrawScoreboard();
 
+       hit_time = getstatf(STAT_HIT_TIME);
+       if(hit_time > nextsound_hit_time && autocvar_cl_hitsound)
+       {
+               sound(world, CHAN_AUTO, "misc/hit.wav", VOL_BASE, ATTN_NONE);
+               nextsound_hit_time = time + autocvar_cl_hitsound_antispam_time;
+       }
+       typehit_time = getstatf(STAT_TYPEHIT_TIME);
+       if(typehit_time > nextsound_typehit_time)
+       {
+               sound(world, CHAN_AUTO, "misc/typehit.wav", VOL_BASE, ATTN_NONE);
+               nextsound_typehit_time = time + autocvar_cl_hitsound_antispam_time;
+       }
+
        float hud;
        hud = getstati(STAT_HUD);
        if(hud == HUD_SPIDERBOT)
@@ -835,7 +912,7 @@ void CSQC_UpdateView(float w, float h)
                                CSQC_common_hud();
 
                // crosshair goes VERY LAST
-               if(!scoreboard_active && !camera_active && intermission != 2) {
+               if(!scoreboard_active && !camera_active && intermission != 2 && spectatee_status != -1) {
                        string wcross_style;
                        float wcross_alpha, wcross_resolution;
                        wcross_style = autocvar_crosshair;
@@ -850,7 +927,7 @@ void CSQC_UpdateView(float w, float h)
 
                        // TrueAim check
                        float shottype;
-                       float weapon_clipload, weapon_clipsize, ring_scale;
+
                        // wcross_origin = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
                        wcross_origin = project_3d_to_2d(view_origin + MAX_SHOT_DISTANCE * view_forward);
                        wcross_origin_z = 0;
@@ -899,6 +976,50 @@ void CSQC_UpdateView(float w, float h)
                        }
                        if(wcross_wep != "" && autocvar_crosshair_color_per_weapon)
                                wcross_color = stov(cvar_string(strcat("crosshair_", wcross_wep, "_color")));
+                       else if(autocvar_crosshair_color_by_health)
+                       {
+                               local float x = getstati(STAT_HEALTH);
+                               
+                               //x = red
+                               //y = green
+                               //z = blue
+                               
+                               wcross_color_z = 0;
+                               
+                               if(x > 200)
+                               {
+                                       wcross_color_x = 0;
+                                       wcross_color_y = 1;
+                               }
+                               else if(x > 150)
+                               {
+                                       wcross_color_x = 0.4 - (x-150)*0.02 * 0.4;
+                                       wcross_color_y = 0.9 + (x-150)*0.02 * 0.1;
+                               }
+                               else if(x > 100)
+                               {
+                                       wcross_color_x = 1 - (x-100)*0.02 * 0.6;
+                                       wcross_color_y = 1 - (x-100)*0.02 * 0.1;
+                                       wcross_color_z = 1 - (x-100)*0.02;
+                               }
+                               else if(x > 50)
+                               {
+                                       wcross_color_x = 1;
+                                       wcross_color_y = 1;
+                                       wcross_color_z = 0.2 + (x-50)*0.02 * 0.8;  
+                               }
+                               else if(x > 20)
+                               {
+                                       wcross_color_x = 1;
+                                       wcross_color_y = (x-20)*90/27/100;
+                                       wcross_color_z = (x-20)*90/27/100 * 0.2;
+                               }
+                               else
+                               {
+                                       wcross_color_x = 1;
+                                       wcross_color_y = 0;
+                               }
+                       }
                        else
                                wcross_color = stov(autocvar_crosshair_color);
 
@@ -929,6 +1050,27 @@ void CSQC_UpdateView(float w, float h)
 
                                wcross_scale += sin(pickup_crosshair_size) * autocvar_crosshair_pickup;
                        }
+                       
+                       vector hitindication_color;
+                       if(autocvar_crosshair_hitindication)
+                       {
+                               hitindication_color = stov(autocvar_crosshair_hitindication_color);
+                               if(hitindication_crosshair_time < hit_time)
+                               {
+                                       hitindication_crosshair_size = 1;
+                                       hitindication_crosshair_time = hit_time;
+                               }
+
+                               if(hitindication_crosshair_size > 0)
+                                       hitindication_crosshair_size -= autocvar_crosshair_hitindication_speed * frametime;
+                               else
+                                       hitindication_crosshair_size = 0;
+
+                               wcross_scale += sin(hitindication_crosshair_size) * autocvar_crosshair_hitindication;
+                               wcross_color_x += sin(hitindication_crosshair_size) * hitindication_color_x;
+                               wcross_color_y += sin(hitindication_crosshair_size) * hitindication_color_y;
+                               wcross_color_z += sin(hitindication_crosshair_size) * hitindication_color_z;
+                       }
 
                        if(shottype == SHOTTYPE_HITENEMY)
                                wcross_scale *= autocvar_crosshair_hittest; // is not queried if hittest is 0
@@ -983,51 +1125,86 @@ void CSQC_UpdateView(float w, float h)
 
                        wcross_scale *= 1 - autocvar__menu_alpha;
                        wcross_alpha *= 1 - autocvar__menu_alpha;
-
-                       ring_scale = autocvar_crosshair_ring_size;
-
                        wcross_size = drawgetimagesize(wcross_name) * wcross_scale;
 
-                       float nex_charge, nex_chargepool;
-                       nex_charge = getstatf(STAT_NEX_CHARGE);
-                       nex_chargepool = getstatf(STAT_NEX_CHARGEPOOL);
-
-                       if(nex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
-                               nex_charge_movingavg = nex_charge;
-
-                       // ring around crosshair representing bullets left in weapon clip
-                       weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD);
-                       if (weapon_clipload)
+                       // crosshair rings for weapon stats
+                       if (autocvar_crosshair_ring || autocvar_crosshair_ring_reload)
                        {
+                               // declarations and stats
+                               float ring_value, ring_scale, ring_alpha, ring_inner_value, ring_inner_alpha;
+                               string ring_image, ring_inner_image;
+                               vector ring_rgb, ring_inner_rgb;
+                               
+                               ring_scale = autocvar_crosshair_ring_size;
+
+                               float weapon_clipload, weapon_clipsize;
+                               weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD);
                                weapon_clipsize = getstati(STAT_WEAPON_CLIPSIZE);
-                               f = bound(0, weapon_clipload / weapon_clipsize, 1);
 
-                               a = autocvar_crosshair_ring_sniperrifle_alpha;
-                               DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, "gfx/crosshair_ring.tga", f, wcross_color, wcross_alpha * a, DRAWFLAG_ADDITIVE);
-                       }
-                       if (activeweapon == WEP_NEX && nex_charge) // ring around crosshair representing velocity-dependent damage for the nex
-                       {
-                               if(nex_chargepool || use_nex_chargepool)
-                               {
-                                       use_nex_chargepool = 1;
+                               float nex_charge, nex_chargepool;
+                               nex_charge = getstatf(STAT_NEX_CHARGE);
+                               nex_chargepool = getstatf(STAT_NEX_CHARGEPOOL);
 
-                                       a = autocvar_crosshair_ring_nex_inner_alpha;
-                                       rgb = eX * autocvar_crosshair_ring_nex_inner_color_red + eY * autocvar_crosshair_ring_nex_inner_color_green + eZ * autocvar_crosshair_ring_nex_inner_color_blue;
-                                       DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, "gfx/crosshair_ring_inner.tga", nex_chargepool, rgb, wcross_alpha * a, DRAWFLAG_ADDITIVE);
+                               if(nex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
+                                       nex_charge_movingavg = nex_charge;
+                                       
+
+                               // handle the values
+                               if (autocvar_crosshair_ring && activeweapon == WEP_NEX && nex_charge && autocvar_crosshair_ring_nex) // ring around crosshair representing velocity-dependent damage for the nex
+                               {
+                                       if (nex_chargepool || use_nex_chargepool) { 
+                                               use_nex_chargepool = 1; 
+                                               ring_inner_value = nex_chargepool;
+                                       } else { 
+                                               nex_charge_movingavg = (1 - autocvar_crosshair_ring_nex_currentcharge_movingavg_rate) * nex_charge_movingavg + autocvar_crosshair_ring_nex_currentcharge_movingavg_rate * nex_charge;
+                                               ring_inner_value = bound(0, autocvar_crosshair_ring_nex_currentcharge_scale * (nex_charge - nex_charge_movingavg), 1); 
+                                       }
+                                               
+                                       ring_inner_alpha = autocvar_crosshair_ring_nex_inner_alpha;
+                                       ring_inner_rgb = eX * autocvar_crosshair_ring_nex_inner_color_red + eY * autocvar_crosshair_ring_nex_inner_color_green + eZ * autocvar_crosshair_ring_nex_inner_color_blue;
+                                       ring_inner_image = "gfx/crosshair_ring_inner.tga";
+                                       
+                                       // draw the outer ring to show the current charge of the weapon
+                                       ring_value = nex_charge;
+                                       ring_alpha = autocvar_crosshair_ring_nex_alpha;
+                                       ring_rgb = wcross_color;
+                                       ring_image = "gfx/crosshair_ring_nexgun.tga";
                                }
-                               else
+                               else if (autocvar_crosshair_ring && activeweapon == WEP_MINE_LAYER && minelayer_maxmines && autocvar_crosshair_ring_minelayer) 
+                               {
+                                       ring_value = bound(0, getstati(STAT_LAYED_MINES) / minelayer_maxmines, 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to.
+                                       ring_alpha = autocvar_crosshair_ring_minelayer_alpha;
+                                       ring_rgb = wcross_color;
+                                       ring_image = "gfx/crosshair_ring.tga";
+                               }
+                               else if (activeweapon == WEP_HAGAR && getstati(STAT_HAGAR_LOAD) && autocvar_crosshair_ring_hagar)
                                {
-                                       // indicate how much we're charging right now with an inner circle
-                                       a = autocvar_crosshair_ring_nex_inner_alpha;
-                                       nex_charge_movingavg = (1 - autocvar_crosshair_ring_nex_currentcharge_movingavg_rate) * nex_charge_movingavg + autocvar_crosshair_ring_nex_currentcharge_movingavg_rate * nex_charge;
+                                       ring_value = bound(0, getstati(STAT_HAGAR_LOAD) / hagar_maxrockets, 1);
+                                       ring_alpha = autocvar_crosshair_ring_hagar_alpha;
+                                       ring_rgb = wcross_color;
+                                       ring_image = "gfx/crosshair_ring.tga";
+                               }
 
-                                       rgb = eX * autocvar_crosshair_ring_nex_inner_color_red + eY * autocvar_crosshair_ring_nex_inner_color_green + eZ * autocvar_crosshair_ring_nex_inner_color_blue;
-                                       DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, "gfx/crosshair_ring_inner.tga", bound(0, autocvar_crosshair_ring_nex_currentcharge_scale * (nex_charge - nex_charge_movingavg), 1), rgb, wcross_alpha * a, DRAWFLAG_ADDITIVE);
+                               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;
+                                       ring_alpha = autocvar_crosshair_ring_reload_alpha;
+                                       ring_rgb = wcross_color;
+                                       
+                                       // Note: This is to stop Taoki from complaining that the image doesn't match all potential balances.
+                                       // if a new image for another weapon is added, add the code (and its respective file/value) here
+                                       if ((activeweapon == WEP_RIFLE) && (weapon_clipsize == 80))
+                                               ring_image = "gfx/crosshair_ring_rifle.tga";
+                                       else
+                                               ring_image = "gfx/crosshair_ring.tga";
                                }
 
-                               // draw the charge
-                               a = autocvar_crosshair_ring_nex_outer_alpha;
-                               DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, "gfx/crosshair_ring.tga", nex_charge, wcross_color, wcross_alpha * a, DRAWFLAG_ADDITIVE);
+                               if (autocvar_crosshair_ring_inner && ring_inner_value) // lets draw a ring inside a ring so you can ring while you ring
+                                       DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, ring_inner_image, ring_inner_value, ring_inner_rgb, wcross_alpha * ring_inner_alpha, DRAWFLAG_ADDITIVE);
+
+                               if (ring_value)
+                                       DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, ring_image, ring_value, ring_rgb, wcross_alpha * ring_alpha, DRAWFLAG_ADDITIVE);
                        }
 
 #define CROSSHAIR_DO_BLUR(M,sz,wcross_name,wcross_alpha) \
@@ -1434,7 +1611,6 @@ const float STAT_VEHICLESTAT_RELOAD2 = 66;
 
 }
 
-
 void CSQC_common_hud(void)
 {
        // HUD_SortFrags(); done in HUD_Draw