]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote branch 'origin/master' into samual/keepaway
authorunknown <samual@xonotic.org>
Thu, 25 Nov 2010 01:39:19 +0000 (20:39 -0500)
committerunknown <samual@xonotic.org>
Thu, 25 Nov 2010 01:39:19 +0000 (20:39 -0500)
1  2 
qcsrc/client/hud.qc
qcsrc/client/scoreboard.qc
qcsrc/common/constants.qh
qcsrc/server/cl_client.qc
qcsrc/server/clientcommands.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/progs.src

diff --combined qcsrc/client/hud.qc
index 3d69a78b375c129993406d568f1a123e7caec280,01dc0166305f20a7b30ef955958444d1ab71b196..ddffdcc8d1075c41d706d507f7ed19f43e3bee46
@@@ -1692,18 -1692,10 +1692,10 @@@ void HUD_Weapons(void
        }
  
        float show_accuracy;
-       float weapon_stats, weapon_number;
+       float weapon_stats;
        if(cvar("hud_panel_weapons_accuracy") && acc_levels)
        {
                show_accuracy = true;
-               // hits
-               weapon_stats = getstati(STAT_DAMAGE_HITS);
-               weapon_number = weapon_stats & 63;
-               weapon_hits[weapon_number-WEP_FIRST] = floor(weapon_stats / 64);
-               // fired
-               weapon_stats = getstati(STAT_DAMAGE_FIRED);
-               weapon_number = weapon_stats & 63;
-               weapon_fired[weapon_number-WEP_FIRST] = floor(weapon_stats / 64);
                if (acc_col_x[0] == -1)
                        for (i = 0; i < acc_levels; ++i)
                                acc_col[i] = stov(cvar_string(strcat("accuracy_color", ftos(i))));
                // draw the weapon accuracy
                if(show_accuracy)
                {
-                       float weapon_hit, weapon_damage;
-                       weapon_damage = weapon_fired[self.weapon-WEP_FIRST];
-                       if(weapon_damage)
+                       weapon_stats = weapon_accuracy[self.weapon-WEP_FIRST];
+                       if(weapon_stats >= 0)
                        {
-                               weapon_hit = weapon_hits[self.weapon-WEP_FIRST];
-                               weapon_stats = floor(100 * weapon_hit / weapon_damage);
                                // find the max level lower than weapon_stats
                                float j;
                                j = acc_levels-1;
@@@ -4315,19 -4303,6 +4303,19 @@@ void HUD_Mod_KH(vector pos, vector mySi
        }
  }
  
 +// Keepaway HUD mod icon
 +void HUD_Mod_Keepaway(vector pos, vector mySize)
 +{
 +      float stat_items;
 +      stat_items = getstati(STAT_ITEMS);
 +
 +      mod_active = 1;
 +
 +      if(stat_items & IT_KEY1)
 +              drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +}
 +
 +
  // Nexball HUD mod icon
  void HUD_Mod_NexBall(vector pos, vector mySize)
  {
@@@ -4528,7 -4503,7 +4516,7 @@@ void HUD_ModIcons(void
        if(!autocvar_hud_panel_modicons && !autocvar__hud_configure)
                return;
  
 -      if (gametype != GAME_KEYHUNT && gametype != GAME_CTF && gametype != GAME_NEXBALL && gametype != GAME_CTS && gametype != GAME_RACE && gametype != GAME_CA && !autocvar__hud_configure)
 +      if (gametype != GAME_KEYHUNT && gametype != GAME_CTF && gametype != GAME_NEXBALL && gametype != GAME_CTS && gametype != GAME_RACE && gametype != GAME_CA && gametype != GAME_KEEPAWAY && !autocvar__hud_configure)
                return;
  
        active_panel = HUD_PANEL_MODICONS;
                HUD_Mod_Race(pos, mySize);
        else if(gametype == GAME_CA)
                HUD_Mod_CA(pos, mySize);
 +      else if(gametype == GAME_KEEPAWAY)
 +              HUD_Mod_Keepaway(pos, mySize);
  }
  
  // Draw pressed keys (#11)
index 9089d5df449b19fe22405095547777a539e27c40,5f4c64eee924ebdd8ace1bb7329c84199cd63ec5..0476428d7b836e9978cc10913ec8c7a546ee314c
@@@ -248,12 -248,12 +248,12 @@@ string HUD_DefaultColumnLayout(
  {
        return strcat( // fteqcc sucks
                "ping pl name | ",
 -              "-teams,race,lms/kills -teams,lms/deaths -teams,lms,race/suicides -race,dm,tdm/frags ", // tdm already has this in "score"
 +              "-teams,race,lms/kills -teams,lms/deaths -teams,lms,race,ka/suicides -race,dm,tdm,ka/frags ", // tdm already has this in "score"
                "+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns ",
                "+lms/lives +lms/rank ",
                "+kh/caps +kh/pushes +kh/destroyed ",
                "?+race/laps ?+race/time ?+race/fastest ",
 -              "+as/objectives +nexball/faults +nexball/goals ",
 +              "+as/objectives +nexball/faults +nexball/goals +ka/drops +ka/pickups +ka/bckills ",
                "-lms,race,nexball/score");
  }
  
@@@ -941,15 -941,7 +941,7 @@@ vector HUD_DrawScoreboardAccuracyStats(
        if(getstati(STAT_SWITCHWEAPON) == WEP_MINSTANEX)
                g_minstagib = 1; // TODO: real detection for minstagib?
  
-       float weapon_hit, weapon_damage, weapon_stats, weapon_number;
-       // hits
-       weapon_stats = getstati(STAT_DAMAGE_HITS);
-       weapon_number = weapon_stats & 63;
-       weapon_hits[weapon_number-WEP_FIRST] = floor(weapon_stats / 64);
-       // fired
-       weapon_stats = getstati(STAT_DAMAGE_FIRED);
-       weapon_number = weapon_stats & 63;
-       weapon_fired[weapon_number-WEP_FIRST] = floor(weapon_stats / 64);
+       float weapon_stats, weapon_number;
  
        if (!acc_levels)
                rgb = '1 1 1';
                        continue;
                if ((i == WEP_NEX && g_minstagib) || i == WEP_PORTO || (i == WEP_MINSTANEX && !g_minstagib) || i == WEP_TUBA) // skip port-o-launch, nex || minstanex and tuba
                        continue;
-               weapon_hit = weapon_hits[i-WEP_FIRST];
-               weapon_damage = weapon_fired[i-WEP_FIRST];
+               weapon_stats = weapon_accuracy[i-WEP_FIRST];
  
                float weapon_alpha;
-               if(weapon_damage)
-               {
-                       weapon_stats = bound(0, floor(100 * weapon_hit / weapon_damage), 100);
+               if(weapon_stats >= 0)
                        weapon_alpha = scoreboard_alpha_fg;
-               }
                else
                        weapon_alpha = 0.2 * scoreboard_alpha_fg;
  
                // weapon icon
                drawpic_aspect_skin(pos, strcat("weapon", self.netname), '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
                // the accuracy
-               if(weapon_damage) {
+               if(weapon_stats >= 0) {
                        weapons_with_stats += 1;
                        average_accuracy += weapon_stats; // store sum of all accuracies in average_accuracy
  
                        string s;
-                       s = strcat(ftos(weapon_stats),"%");
+                       s = sprintf("%d%%", weapon_stats*100);
  
                        float padding;
                        padding = (weapon_width - stringwidth(s, FALSE, '1 0 0' * fontsize)) / 2; // center the accuracy value
  
-                       weapon_damage = weapon_fired[self.weapon-WEP_FIRST];
-                       if(weapon_damage)
-                       {
-                               weapon_hit = weapon_hits[self.weapon-WEP_FIRST];
-                               weapon_stats = floor(100 * weapon_hit / weapon_damage);
-                       }
                        if (acc_levels)
                        {
                                // find the max level lower than weapon_stats
@@@ -1298,183 -1279,3 +1279,3 @@@ void HUD_DrawScoreboard(
  
        scoreboard_bottom = pos_y + 2 * hud_fontsize_y;
  }
- void HUD_DrawAccuracyStats_Description_Hitscan(vector position)
- {
-       drawstring(position + '0 3 0' * hud_fontsize_y, "Shots fired:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-       drawstring(position + '0 5 0' * hud_fontsize_y, "Shots hit:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-       drawstring(position + '0 7 0' * hud_fontsize_y, "Accuracy:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-       drawstring(position + '0 9 0' * hud_fontsize_y, "Shots missed:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- }
- void HUD_DrawAccuracyStats_Description_Splash(vector position)
- {
-       drawstring(position + '0 3 0' * hud_fontsize_y, "Maximum damage:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-       drawstring(position + '0 5 0' * hud_fontsize_y, "Actual damage:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-       drawstring(position + '0 7 0' * hud_fontsize_y, "Accuracy:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-       drawstring(position + '0 9 0' * hud_fontsize_y, "Damage wasted:", hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
- }
- void HUD_DrawAccuracyStats()
- {
-       float i, count_hitscan, count_splash, row;  // count is the number of 'colums'
-       float weapon_hit, weapon_damage, weapon_stats;
-       float left_border;  // position where the weapons start, the description is in the border
-       vector fill_colour, fill_size;
-       vector pos;
-       vector border_colour;
-       float col_margin = 20;  // pixels between the columns
-       float row_margin = 20;  // pixels between the rows
-       fill_size_x = 5 * hud_fontsize_x;  // width of the background
-       fill_size_y = 10 * hud_fontsize_y;  // height of the background
-       drawfont = hud_bigfont;
-       pos_x = 0;
-       pos_y = SCOREBOARD_OFFSET;
-       pos_z = 0;
-       drawstringcenter(pos, "Weapon Accuracy", 2 * hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-       left_border = col_margin + 11 * hud_fontsize_x;
-       drawfont = hud_font;
-       if(warmup_stage)
-       {
-               pos_y += 40;
-               if(mod(time, 1) >= 0.4)
-                       drawstringcenter(pos, "Stats are not tracked during warmup stage", hud_fontsize, '1 1 0', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-               return;
-       }
-       if(gametype == GAME_RACE || gametype == GAME_CTS)
-       {
-               pos_y += 40;
-               if(mod(time, 1) >= 0.4)
-                       drawstringcenter(pos, "Stats are not tracked in Race/CTS", hud_fontsize, '1 1 0', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-               return;
-       }
-       float top_border_hitscan = SCOREBOARD_OFFSET + 55;  // position where the hitscan row starts: pixels down the screen
-       HUD_DrawAccuracyStats_Description_Hitscan('1 0 0' * col_margin + '0 1 0' * top_border_hitscan);
-       float top_border_splash = SCOREBOARD_OFFSET + 175;  // position where the splash row starts: pixels down the screen
-       HUD_DrawAccuracyStats_Description_Splash('1 0 0' * col_margin + '0 1 0' * top_border_splash);
-       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
-       {
-               self = get_weaponinfo(i);
-               if not(self.weapons)
-                       continue;
-               weapon_hit = weapon_hits[i-WEP_FIRST];
-               weapon_damage = weapon_fired[i-WEP_FIRST];
-               border_colour = (i == activeweapon) ? '1 1 1' : '0 0 0';  // white or black border
-               if (weapon_damage) {
-                       if (self.spawnflags & WEP_TYPE_SPLASH) {
-                               weapon_stats = bound(0, floor(100 * weapon_hit / weapon_damage), 100);
-                               fill_colour_x = 1 - 0.015 * weapon_stats;
-                               fill_colour_y = 1 - 0.015 * (100 - weapon_stats);
-                               // how the background colour is calculated
-                               // %    red             green   red_2                   green_2
-                               // 0    1               0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 10   0.85    0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 20   0.70    0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 30   0.55    0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 40   0.40    0.10    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 50   0.25    0.25    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 60   0.10    0.40    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 70   0               0.55    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 80   0               0.70    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 90   0               0.85    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 100  0               1               1 - % * 0.015   1 - (100 - %) * 0.015
-                               if ((left_border + count_splash * (fill_size_x + col_margin) + fill_size_x) >= vid_conwidth)
-                               {
-                                       count_splash = 0;
-                                       ++row;
-                                       HUD_DrawAccuracyStats_Description_Splash('1 0 0' * col_margin + '0 1 0' * (top_border_splash + row * (fill_size_y + row_margin)));
-                               }
-                               pos_x = left_border + count_splash * (fill_size_x + col_margin);
-                               pos_y = top_border_splash + row * (fill_size_y + row_margin);
-                               // background
-                               drawpic(pos, "gfx/scoreboard/accuracy_bg", fill_size , fill_colour, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
-                               drawborderlines(autocvar_scoreboard_border_thickness, pos, fill_size, border_colour, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
-                               // the weapon
-                               drawpic(pos, strcat("gfx/weapons/weapon", self.netname), '1 0.5 0' * fill_size_x , '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the amount of shots fired or max damage
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 3 0' * hud_fontsize_y, ftos(weapon_damage), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the amount of hits or actual damage
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 5 0' * hud_fontsize_y, ftos(weapon_hit), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the accuracy
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 7 0' * hud_fontsize_y, strcat(ftos(weapon_stats),"%"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the amount of shots missed or damage wasted
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 9 0' * hud_fontsize_y, ftos(max(0, weapon_damage - weapon_hit)), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               ++count_splash;
-                       } else if (self.spawnflags & WEP_TYPE_HITSCAN) {
-                               weapon_stats = bound(0, floor(100 * weapon_hit / weapon_damage), 100);
-                               fill_colour_x = 1 - 0.015 * weapon_stats;
-                               fill_colour_y = 1 - 0.015 * (100 - weapon_stats);
-                               // how the background colour is calculated
-                               // %    red             green   red_2                   green_2
-                               // 0    1               0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 10   0.850   0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 20   0.70    0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 30   0.55    0               1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 40   0.40    0.10    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 50   0.25    0.25    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 60   0.10    0.40    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 70   0               0.55    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 80   0               0.70    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 90   0               0.85    1 - % * 0.015   1 - (100 - %) * 0.015
-                               // 100  0               1               1 - % * 0.015   1 - (100 - %) * 0.015
-                               if ((left_border + count_hitscan * (fill_size_x + col_margin) + fill_size_x + cvar("stats_right_margin")) >= vid_conwidth)
-                               {
-                                       count_hitscan = 0;
-                                       ++row;
-                                       HUD_DrawAccuracyStats_Description_Hitscan('1 0 0' * col_margin + '0 1 0' * (top_border_hitscan + row * (fill_size_y + row_margin)));
-                               }
-                               pos_x = left_border + count_hitscan * (fill_size_x + col_margin);
-                               pos_y = top_border_hitscan + row * (fill_size_y + row_margin);
-                               // background
-                               drawpic(pos, "gfx/scoreboard/accuracy_bg", fill_size , fill_colour, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
-                               drawborderlines(autocvar_scoreboard_border_thickness, pos, fill_size, border_colour, scoreboard_alpha_bg, DRAWFLAG_NORMAL);
-                               // the weapon
-                               drawpic(pos, strcat("gfx/weapons/weapon", self.netname), '1 0.5 0' * fill_size_x , '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the amount of shots fired or max damage
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 3 0' * hud_fontsize_y, ftos(weapon_damage), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the amount of hits or actual damage
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 5 0' * hud_fontsize_y, ftos(weapon_hit), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the accuracy
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 7 0' * hud_fontsize_y, strcat(ftos(weapon_stats),"%"), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               // the amount of shots missed or damage wasted
-                               drawstringright(pos + '4.5 0 0' * hud_fontsize_x + '0 9 0' * hud_fontsize_y, ftos(max(0, weapon_damage - weapon_hit)), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
-                               ++count_hitscan;
-                       }
-               }
-       }
- }
index 94089951e890760956366e2e8f48eed28c2df77b,8cc24634c307d7d929f376e068f21412f958d589..da40ae2cb3965413d5ea2f887076bafab75839e0
@@@ -34,12 -34,11 +34,12 @@@ const float GAME_LMS                       = 6
  const float GAME_ARENA                = 7;
  const float GAME_KEYHUNT              = 8;
  const float GAME_ASSAULT              = 9;
 -const float GAME_ONSLAUGHT    = 10;
 -const float GAME_RACE = 11;
 -const float GAME_NEXBALL = 12;
 -const float GAME_CTS = 13;
 -const float GAME_CA           = 14;
 +const float GAME_ONSLAUGHT            = 10;
 +const float GAME_RACE                 = 11;
 +const float GAME_NEXBALL              = 12;
 +const float GAME_CTS                  = 13;
 +const float GAME_CA                   = 14;
 +const float GAME_KEEPAWAY             = 15;
  
  const float AS_STRING         = 1;
  const float AS_INT            = 2;
@@@ -112,6 -111,7 +112,7 @@@ const float ENT_CLIENT_TRIGGER_MUSIC = 
  const float ENT_CLIENT_HOOK = 27;
  const float ENT_CLIENT_LGBEAM = 28;
  const float ENT_CLIENT_GAUNTLET = 29;
+ const float ENT_CLIENT_ACCURACY = 30;
  
  const float ENT_CLIENT_TURRET = 40;
  
@@@ -301,8 -301,6 +302,6 @@@ const float STAT_SWITCHWEAPON = 36
  const float STAT_GAMESTARTTIME = 37;
  const float STAT_STRENGTH_FINISHED = 38;
  const float STAT_INVINCIBLE_FINISHED = 39;
- const float STAT_DAMAGE_HITS = 40; // Used by the weapon stats code, represents the total amount of damage done to other players
- const float STAT_DAMAGE_FIRED = 41;// Used by the weapon stats code, represents the total amount of potential damage fired
  const float STAT_PRESSED_KEYS = 42;
  const float STAT_ALLOW_OLDNEXBEAM = 43; // this stat could later contain some other bits of info, like, more server-side particle config
  const float STAT_FUEL = 44;
index 61c65fdaa8deb79583187ac12592408f82166d79,2985b45b41262b4f9ac4ed51749d34323203a639..f7764c07e82ff1a84b95f99b9661047f810f5d6d
@@@ -606,7 -606,7 +606,7 @@@ void PutObserverInServer (void
        if(self.flagcarried)
                DropFlag(self.flagcarried, world, world);
  
 -      if(self.ballcarried)
 +      if(self.ballcarried && g_nexball)
                DropBall(self.ballcarried, self.origin + self.ballcarried.origin, self.velocity);
  
        WaypointSprite_PlayerDead();
  
        PlayerScore_Clear(self); // clear scores when needed
  
+       accuracy_resend(self);
        self.spectatortime = time;
  
        self.classname = "observer";
@@@ -853,6 -855,8 +855,8 @@@ void PutClientInServer (void
                entity spot, oldself;
                float j;
  
+               accuracy_resend(self);
                if(self.team < 0)
                        JoinBestTeam(self, FALSE, TRUE);
  
@@@ -1496,6 -1500,7 +1500,7 @@@ void ClientConnect (void
  
        PlayerScore_Attach(self);
        ClientData_Attach();
+       accuracy_init(self);
  
        bot_clientconnect();
  
@@@ -1748,7 -1753,7 +1753,7 @@@ void ClientDisconnect (void
  
        if(self.flagcarried)
                DropFlag(self.flagcarried, world, world);
 -      if(self.ballcarried)
 +      if(self.ballcarried && g_nexball)
                DropBall(self.ballcarried, self.origin + self.ballcarried.origin, self.velocity);
  
        // Here, everything has been done that requires this player to be a client.
                Spawnqueue_Remove(self);
        }
  
+       accuracy_free(self);
        ClientData_Detach();
        PlayerScore_Detach(self);
  
@@@ -2271,33 -2277,13 +2277,13 @@@ void GetPressedKeys(void) 
                self.pressedkeys &~= KEY_CROUCH;
  }
  
- void update_stats (float number, float hit, float fired) {
- // self.stat_hit   = number + ((number==0) ? 1 : 64) * hit   * sv_accuracy_data_share;
- // self.stat_fired = number + ((number==0) ? 1 : 64) * fired * sv_accuracy_data_share;
-       if(number) {
-               self.stat_hit = number + 64 * hit * sv_accuracy_data_share;
-               self.stat_fired = number + 64 * fired * sv_accuracy_data_share;
-       } else {
-               self.stat_hit = hit * sv_accuracy_data_share;
-               self.stat_fired = fired * sv_accuracy_data_share;
-       }
- }
  /*
  ======================
  spectate mode routines
  ======================
  */
  
- .float weapon_count;
  void SpectateCopy(entity spectatee) {
-       if(spectatee.weapon_count < WEP_LAST) {
-               update_stats (spectatee.weapon_count, spectatee.cvar_cl_accuracy_data_share * floor(spectatee.stats_hit[spectatee.weapon_count - 1]), spectatee.cvar_cl_accuracy_data_share * floor(spectatee.stats_fired[spectatee.weapon_count - 1]));
-               spectatee.weapon_count ++;
-       } else
-               update_stats (0, spectatee.cvar_cl_accuracy_data_share * spectatee.stat_hit, spectatee.cvar_cl_accuracy_data_share * spectatee.stat_fired);
        other = spectatee;
        MUTATOR_CALLHOOK(SpectateCopy);
        self.armortype = spectatee.armortype;
@@@ -2365,8 -2351,7 +2351,7 @@@ float SpectateNext() 
                WriteEntity(MSG_ONE, self.enemy);
                //stuffcmd(self, "set viewsize $tmpviewsize \n");
                self.movetype = MOVETYPE_NONE;
-               self.enemy.weapon_count = 0;
+               accuracy_resend(self);
  
                if(!SpectateUpdate())
                        PutObserverInServer();
@@@ -2415,8 -2400,6 +2400,6 @@@ void LeaveSpectatorMode(
                        if(cvar("g_campaign"))
                                campaign_bots_may_start = 1;
  
-                       self.stat_count = WEP_LAST;
                        PutClientInServer();
  
                        if(self.classname == "player")
@@@ -2520,14 -2503,12 +2503,12 @@@ void SpectatorThink(
                                self.classname = "spectator";
                        } else {
                                self.classname = "observer";
-                               self.stat_count = WEP_LAST;
                                PutClientInServer();
                        }
                } else if (self.BUTTON_ATCK2) {
                        self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        self.classname = "observer";
-                       self.stat_count = WEP_LAST;
                        PutClientInServer();
                } else {
                        if(!SpectateUpdate())
@@@ -2965,15 -2946,6 +2946,6 @@@ void PlayerPostThink (void
                stuffcmd(self, strcat("name ", self.netname, substring(ftos(random()), 2, -1), "\n"));
        }
  
-       // send the clients accuracy stats to the client
-       if(self.stat_count > 0)
-       if(frametime)
-       {
-               self.stat_hit = self.stat_count + 64 * floor(self.(stats_hit[self.stat_count - 1]));
-               self.stat_fired = self.stat_count + 64 * floor(self.(stats_fired[self.stat_count - 1]));
-               self.stat_count -= 1;
-       }
        if(sv_maxidle && frametime)
        {
                // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
index 3ef630dd4a88eaa83e77512de9283f95b859f15e,e221911d30aaa6f8a056c274e22e01052ba30493..1a46ed8b51deccbc0925641996bfa6da6bfbc553
@@@ -213,7 -213,7 +213,7 @@@ void SV_ParseClientCommand(string s) 
                if(self.classname == "player" && cvar("sv_spectate") == 1) {
                        if(self.flagcarried)
                                DropFlag(self.flagcarried, world, world);
 -                      if(self.ballcarried)
 +                      if(self.ballcarried && g_nexball)
                                DropBall(self.ballcarried, self.origin, self.velocity);
                        WaypointSprite_PlayerDead();
                        self.classname = "observer";
                                        self.caplayer = 1;
                                PlayerScore_Clear(self);
                                bprint ("^4", self.netname, "^4 is playing now\n");
-                               self.stat_count = WEP_LAST;
                                PutClientInServer();
                                if(cvar("g_campaign"))
                                        campaign_bots_may_start = 1;
diff --combined qcsrc/server/defs.qh
index c556e83dbbfc5d9d892c006c2ae875df86b81f44,a0718d839a69b2530b29d9a3b6b7125e0f6de1c1..fc9523dd12ae54cb5b214961e1debbc4e8b5b376
@@@ -17,7 -17,7 +17,7 @@@ float require_spawnfunc_prefix; // if t
  
  float ctf_score_value(string parameter);
  
 -float g_dm, g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught, g_assault, g_arena, g_ca, g_lms, g_runematch, g_race, g_nexball, g_cts;
 +float g_dm, g_domination, g_ctf, g_tdm, g_keyhunt, g_onslaught, g_assault, g_arena, g_ca, g_lms, g_runematch, g_race, g_nexball, g_cts, g_keepaway;
  float g_cloaked, g_footsteps, g_jump_grunt, g_grappling_hook, g_midair, g_minstagib, g_pinata, g_norecoil, g_minstagib_invis_alpha, g_bloodloss;
  float g_warmup_limit;
  float g_warmup_allguns;
@@@ -554,8 -554,8 +554,8 @@@ void target_voicescript_clear(entity pl
  .string target4;
  .float trigger_reverse;
  
 -// Nexball
 -.entity ballcarried;
 +// Nexball 
 +.entity ballcarried; // Also used for keepaway
  .float metertime;
  float g_nexball_meter_period;
  
@@@ -598,18 -598,8 +598,8 @@@ string matchid
  .float hitplotfh;
  .string noise4;
  
- .float stat_hit;
- .float stat_fired;
- .float stat_count;
- .float stats_hit[WEP_MAXCOUNT];  // for hitscan bullets hit
- .float stats_fired[WEP_MAXCOUNT];  // for hitscan bullets fired
  .float last_pickup;
  
- FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_hit);
- FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_fired);
  .float stat_leadlimit;
  
  float radar_showennemies;
diff --combined qcsrc/server/g_world.qc
index 5f7614c7a21014b31f895328a3e994474c385a24,4628aef459f4a798df89dcb2868c972a0ff225f6..473f5b6384494e24003c4bc54aca9b8f2301823a
@@@ -329,7 -329,6 +329,7 @@@ void cvar_changes_init(
                BADCVAR("g_runematch");
                BADCVAR("g_tdm");
                BADCVAR("g_nexball");
 +              BADCVAR("g_keepaway");
                BADCVAR("teamplay");
  
                // long
@@@ -802,8 -801,6 +802,6 @@@ void spawnfunc_worldspawn (void
        addstat(STAT_INVINCIBLE_FINISHED, AS_FLOAT, invincible_finished);
        addstat(STAT_PRESSED_KEYS, AS_FLOAT, pressedkeys);
        addstat(STAT_FUEL, AS_INT, ammo_fuel);
-       addstat(STAT_DAMAGE_HITS, AS_INT, stat_hit);
-       addstat(STAT_DAMAGE_FIRED, AS_INT, stat_fired);
        addstat(STAT_SHOTORG, AS_INT, stat_shotorg);
        addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit);
        addstat(STAT_BULLETS_LOADED, AS_INT, campingrifle_bulletcounter);
@@@ -1545,8 -1542,6 +1543,6 @@@ only called if a time or frag limit ha
  */
  void NextLevel()
  {
-       float i;
        gameover = TRUE;
  
        intermission_running = 1;
  
        GameLogClose();
  
- // TO DO
- // save the stats to a text file on the client
- // stuffcmd(other, log_stats "stats/file_name");
- // bprint stats
- // stuffcmd(other, log_stats "");
- // use a filename similar to the demo name
-       // string file_name;
-       // file_name = strcat("\nlog_file \"stats/", strftime(TRUE, "%Y-%m-%d_%H-%M"), "_", mapname, ".txt\"");  // open the log file
- // write a stats parser for the menu
-       if(cvar("sv_accuracy_data_send")) {
-               string stats_to_send;
-               FOR_EACH_CLIENT(other) {  // make the string to send
-                       FixIntermissionClient(other);
-                       if(other.cvar_cl_accuracy_data_share) {
-                               stats_to_send = strcat(stats_to_send, ":hits:", other.netname);
-                               for(i = WEP_FIRST; i <= WEP_LAST; ++i)
-                                       stats_to_send = strcat(stats_to_send, ":", ftos(other.stats_hit[i-1]));
-                               stats_to_send = strcat(stats_to_send, "\n:fired:", other.netname);
-                               for(i = WEP_FIRST; i <= WEP_LAST; ++i)
-                                       stats_to_send = strcat(stats_to_send, ":", ftos(other.stats_fired[i-1]));
-                               stats_to_send = strcat(stats_to_send, "\n");
-                       }
-               }
-               FOR_EACH_REALCLIENT(other) {  // only spam humans
-                       Score_NicePrint(other);  // print the score
-                       if(other.cvar_cl_accuracy_data_receive)  // send the stats string to all the willing clients
-                               bprint(stats_to_send);
-               }
-       } else { // ye olde message
-               FOR_EACH_PLAYER(other) {
-                       FixIntermissionClient(other);
-                       if(other.winning)
-                               bprint(other.netname, " ^7wins.\n");
-               }
+       FOR_EACH_PLAYER(other) {
+               FixIntermissionClient(other);
+               if(other.winning)
+                       bprint(other.netname, " ^7wins.\n");
        }
  
        if(cvar("g_campaign"))
diff --combined qcsrc/server/progs.src
index 93f9bf56d92c1bf20b79beb88a0767cb7634bdc8,104f58c3886de7ae036c4d806dacfcc82642608b..1e6e057b2f7b030635be77885c6d305de3e13925
@@@ -35,6 -35,7 +35,7 @@@ campaign.q
  ../common/mapinfo.qh
  ../common/util.qc
  
+ accuracy.qh
  csqcprojectile.qh
  csqceffects.qc
  
@@@ -168,6 -169,7 +169,7 @@@ monsters/fight.q
  monsters/ai.qc
  monsters/m_monsters.qc
  monsters/monster_zombie.qc
+ accuracy.qc
  csqcprojectile.qc
  
  playerdemo.qc
@@@ -177,7 -179,6 +179,7 @@@ cheats.q
  
  mutators/base.qc
  mutators/gamemode_keyhunt.qc
 +mutators/gamemode_keepaway.qc
  mutators/mutator_nix.qc
  mutators/mutator_dodging.qc
  mutators/mutator_rocketflying.qc