]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into z411/bai-server
authorz411 <z411@omaera.org>
Mon, 9 Nov 2020 01:59:18 +0000 (22:59 -0300)
committerz411 <z411@omaera.org>
Mon, 9 Nov 2020 01:59:18 +0000 (22:59 -0300)
41 files changed:
1  2 
qcsrc/client/hud/hud.qh
qcsrc/client/hud/panel/centerprint.qh
qcsrc/client/hud/panel/chat.qc
qcsrc/client/hud/panel/infomessages.qc
qcsrc/client/hud/panel/modicons.qc
qcsrc/client/hud/panel/score.qc
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/client/hud/panel/spect.qc
qcsrc/client/hud/panel/timer.qc
qcsrc/client/hud/panel/weapons.qc
qcsrc/client/main.qh
qcsrc/client/view.qc
qcsrc/common/gamemodes/gamemode/clanarena/cl_clanarena.qh
qcsrc/common/gamemodes/gamemode/freezetag/cl_freezetag.qh
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qc
qcsrc/common/gamemodes/gamemode/freezetag/sv_freezetag.qh
qcsrc/common/mapinfo.qh
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/notifications/all.inc
qcsrc/common/notifications/all.qc
qcsrc/common/notifications/all.qh
qcsrc/common/stats.qh
qcsrc/ecs/systems/sv_physics.qc
qcsrc/server/chat.qh
qcsrc/server/client.qc
qcsrc/server/client.qh
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/vote.qc
qcsrc/server/command/vote.qh
qcsrc/server/damage.qc
qcsrc/server/damage.qh
qcsrc/server/items/items.qc
qcsrc/server/scores.qh
qcsrc/server/teamplay.qc
qcsrc/server/teamplay.qh
qcsrc/server/weapons/accuracy.qh
qcsrc/server/weapons/tracing.qc
qcsrc/server/world.qc
qcsrc/server/world.qh

diff --combined qcsrc/client/hud/hud.qh
index 7f38072ced945d63b9bfdc760ff885d2efb4b032,14e1af0a0df3f0ba27f6a43ce5cc53f063da8394..d7b0d015a33948f10f2c115143a0cba2d6cbed85
@@@ -122,7 -122,6 +122,7 @@@ int ts_primary, ts_secondary
  float weapontime;
  float weaponprevtime;
  
 +float timer;
  float teamnagger;
  
  int hudShiftState;
@@@ -183,6 -182,26 +183,26 @@@ float chat_sizey
  
  float current_player;
  
+ float autocvar__menu_alpha; // updated by the menu VM, useful to tell when the menu is being drawn
+ string autocvar__hud_panelorder;
+ bool autocvar_hud_cursormode = true;
+ string autocvar_hud_dock;
+ float autocvar_hud_dock_alpha;
+ string autocvar_hud_dock_color;
+ bool autocvar_hud_dock_color_team;
+ string autocvar_hud_panel_bg;
+ float autocvar_hud_panel_bg_alpha;
+ float autocvar_hud_panel_bg_border;
+ vector autocvar_hud_panel_bg_color;
+ float autocvar_hud_panel_bg_color_team;
+ float autocvar_hud_panel_bg_padding;
+ float autocvar_hud_panel_fg_alpha;
+ string autocvar_hud_skin;
+ float autocvar_hud_progressbar_alpha;
+ float autocvar_hud_panel_update_interval;
  float autocvar_hud_dynamic_follow;
  float autocvar_hud_dynamic_follow_scale;
  vector autocvar_hud_dynamic_follow_scale_xyz;
@@@ -255,7 -274,6 +275,7 @@@ REGISTER_HUD_PANEL(ITEMSTIME,       HUD
  REGISTER_HUD_PANEL(QUICKMENU,       HUD_QuickMenu,      PANEL_CONFIG_MAIN                        , PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME                                          ) // QUICKMENU
  REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    PANEL_CONFIG_NO                          , PANEL_SHOW_MAINGAME | PANEL_SHOW_MINIGAME | PANEL_SHOW_MAPVOTE | PANEL_SHOW_WITH_SB) // SCOREBOARD
  REGISTER_HUD_PANEL(STRAFEHUD,       HUD_StrafeHUD,      PANEL_CONFIG_MAIN | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME                                                                ) // STRAFEHUD
 +REGISTER_HUD_PANEL(SPECTHUD,        HUD_SpectHUD,       PANEL_CONFIG_NO | PANEL_CONFIG_CANBEOFF, PANEL_SHOW_MAINGAME) // SPECTHUD
  // always add new panels to the end of list
  
  // Because calling lots of functions in QC apparently cuts fps in half on many machines:
index 2594b60255633eff7ebcc497e8e6fdb23dd361d3,f9e23b726fb61c0188ec948defd293530b3f81a7..0d8bc95f4a71fecd572c9385890f0e69b863035a
@@@ -1,9 -1,23 +1,27 @@@
  #pragma once
  #include "../panel.qh"
  
 -float autocvar_hud_panel_centerprint_fade_in = 0.2;
+ bool autocvar_hud_panel_centerprint;
+ float autocvar_hud_panel_centerprint_align;
 -float autocvar_hud_panel_centerprint_fade_subsequent_minfontsize = 0.75;
 -float autocvar_hud_panel_centerprint_fade_minfontsize = 0;
++//float autocvar_hud_panel_centerprint_fade_in = 0.2;
+ float autocvar_hud_panel_centerprint_fade_out = 0.5;
+ float autocvar_hud_panel_centerprint_fade_subsequent = 1;
+ float autocvar_hud_panel_centerprint_fade_subsequent_passone = 3;
+ float autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha = 0.5;
+ float autocvar_hud_panel_centerprint_fade_subsequent_passtwo = 10;
+ float autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha = 0.5;
++//float autocvar_hud_panel_centerprint_fade_subsequent_minfontsize = 0.75;
++//float autocvar_hud_panel_centerprint_fade_minfontsize = 0;
+ bool autocvar_hud_panel_centerprint_flip;
+ float autocvar_hud_panel_centerprint_fontscale;
+ float autocvar_hud_panel_centerprint_fontscale_bold = 1.4;
+ bool autocvar_hud_panel_centerprint_dynamichud  = true;
+ float autocvar_hud_panel_centerprint_time;
 +void centerprint_ClearTitle();
 +void centerprint_SetTitle(string title);
 +void centerprint_Medal(string icon, int times);
++
  void centerprint_Add(int new_id, string strMessage, float duration, int countdown_num);
  void centerprint_AddStandard(string strMessage);
  void centerprint_Kill(int id);
index cb7729d49089756dab630d339d8de4ecdeade2bc,954a3676afe74cec7dd1c4c8381b9049a5efedec..33f8b6a13923d2179d411a9003f97a1740c4ebac
@@@ -1,8 -1,6 +1,7 @@@
  #include "chat.qh"
  
- #include <client/autocvars.qh>
  #include <client/draw.qh>
 +#include <common/items/inventory.qh>
  
  // Chat (#12)
  
@@@ -82,9 -80,9 +81,9 @@@ void HUD_Chat(
        cvar_set("con_chatwidth", ftos(mySize.x/vid_conwidth));
        cvar_set("con_chat", ftos(floor(mySize.y/autocvar_con_chatsize - 0.5)));
  
 +      vector chatsize = '1 1 0' * autocvar_con_chatsize;
        if(autocvar__hud_configure)
        {
 -              vector chatsize = '1 1 0' * autocvar_con_chatsize;
                cvar_set("con_chatrect_x", "9001"); // over 9000, we'll fake it instead for more control over alpha and such
                string str = textShortenToWidth(_("^3Player^7: This is the chat area."), mySize.x, chatsize, stringwidth_colors);
                for(int i = 0; i < autocvar_con_chat; ++i)
                        pos.y += chatsize.y;
                }
        }
 +      
 +      // z411 items
 +      float stat_last_pickup = STAT(LAST_PICKUP);
 +      pos.y += mySize.y;
 +      entity it = last_pickup_item;
 +      
 +      if(stat_last_pickup && stat_last_pickup > time - 3 && it) {
 +              float a, y;
 +              string str1, str2, icon;
 +              vector sz, sz2;
 +              vector pickupsize = chatsize * 1.25;
 +              vector iconsize = chatsize * 2;
 +              
 +              icon = strcat(hud_skin_path, "/", ((it.model2) ? it.model2 : it.m_icon));
 +              sz = draw_getimagesize(icon);
 +              sz2 = vec2(iconsize.y*(sz.x/sz.y), iconsize.y);
 +              str1 = seconds_tostring(last_pickup_timer);
 +              str2 = ((last_pickup_times > 1) ? sprintf("%s (x%d)", it.m_name, last_pickup_times) : it.m_name);
 +              y = (iconsize.y - pickupsize.y) / 2;
 +              
 +              if(time < stat_last_pickup + 3 - 0.5)
 +                      a = 1;
 +              else
 +                      a = (stat_last_pickup + 3 - time) / 0.5;
 +              
 +              drawstring(pos + eY * y, str1, pickupsize, '1 1 1', a, DRAWFLAG_NORMAL);
 +              pos.x += stringwidth(str1, false, pickupsize) + pickupsize.x * 0.25;
 +              drawpic(pos, icon, sz2, '1 1 1', a, DRAWFLAG_NORMAL);
 +              pos.x += sz2.x + pickupsize.x * 0.25;
 +              drawstring(pos + eY * y, str2, pickupsize, '1 1 1', a, DRAWFLAG_NORMAL);
 +      }
  }
index 7590ce5d4b93fea4f5d7ae8e26e68fd003d277bb,5169ea5f384d34ae16ea80f3b46da767fae0ed5d..56b6869c63ec2603d32ef4368ecab5d0fe135e83
@@@ -1,6 -1,5 +1,5 @@@
  #include "infomessages.qh"
  
- #include <client/autocvars.qh>
  #include <client/draw.qh>
  #include <common/ent_cs.qh>
  
@@@ -89,11 -88,11 +88,11 @@@ void HUD_InfoMessages(
        {
                if(spectatee_status)
                {
 -                      if(spectatee_status == -1)
 +                      /*if(spectatee_status == -1)
                                s = _("^1Observing");
                        else
                                s = sprintf(_("^1Spectating: ^7%s"), entcs_GetName(current_player));
 -                      InfoMessage(s);
 +                      InfoMessage(s);*/
  
                        if(autocvar_hud_panel_infomessages_group0)
                        {
                                InfoMessage(s);
                        }
  
 -                      bool mutator_returnvalue = MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
 -                      pos = M_ARGV(0, vector);
 -                      img_curr_group = M_ARGV(2, int);
 +                      //bool mutator_returnvalue = MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
 +                      //pos = M_ARGV(0, vector);
 +                      //img_curr_group = M_ARGV(2, int);
  
 -                      if(!mutator_returnvalue)
 -                      {
 +                      //if(!mutator_returnvalue)
 +                      //{
                                s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey(_("jump"), "+jump"));
                                InfoMessage(s);
 -                      }
 +                      //}
                }
  
                if (time < STAT(GAMESTARTTIME))
                                InfoMessage(s);
                        }
                }
 +
 +              // z411
 +              MUTATOR_CALLHOOK(DrawInfoMessages, pos, mySize, img_curr_group);
        }
        else
        {
index 29c4bfcaafacae90126d5b7f0d79d938e28cb1fc,fdaf50de2270005b2bede8b151015947dc7c7e33..eea4930de9dc4b2c6ee3d96baf8ba22b33700988
@@@ -1,6 -1,5 +1,5 @@@
  #include "modicons.qh"
  
- #include <client/autocvars.qh>
  #include <client/draw.qh>
  #include <common/ent_cs.qh>
  #include <common/gamemodes/_mod.qh>
@@@ -31,7 -30,7 +30,7 @@@ void HUD_ModIcons(
                if(!autocvar_hud_panel_modicons) return;
                if(!HUD_ModIcons_GameType) return;
        }
 -
 +      
        if(mod_active || autocvar__hud_configure)
                mod_alpha = min(mod_alpha + frametime * 2, 1);
        else
index b4d6095e8c26af0e83b274d3a3c7692ac331f633,24a059a6c9460592fec67b461b411b21c3026fd9..be0946fe83b0443e861697f56f1df139b8736d53
@@@ -1,6 -1,5 +1,5 @@@
  #include "score.qh"
  
- #include <client/autocvars.qh>
  #include <client/draw.qh>
  #include <client/hud/panel/scoreboard.qh>
  #include <common/ent_cs.qh>
@@@ -15,7 -14,7 +14,7 @@@ void HUD_Score_Export(int fh
  }
  
  void HUD_Score_Rankings(vector pos, vector mySize, entity me)
 -{
 +{     
        float score;
        entity tm = NULL, pl;
        int SCOREPANEL_MAX_ENTRIES = 6;
@@@ -77,8 -76,9 +76,8 @@@
                }
                return;
        }
 -
 -      if (!scoreboard_fade_alpha) // the scoreboard too calls Scoreboard_UpdatePlayerTeams
 -              Scoreboard_UpdatePlayerTeams();
 +      
 +      /*
        if (team_count)
        {
                // show team scores in the first line
                first_pl = 1;
                pos.y += fontsize.y;
                tm = teams.sort_next;
 -      }
 -      i = first_pl;
 -
 -      do
 -      for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
 +      }*/
 +      
 +      
 +      // z411 Basic team stats
 +      if (team_count)
        {
 -              if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
 -                      continue;
 -
 -              if (i == entries-1 && !me_printed && pl != me)
 -              if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
 -              {
 -                      for (pl = me.sort_next; pl; pl = pl.sort_next)
 -                              if (pl.team != NUM_SPECTATOR)
 -                                      break;
 +              i = 0;
 +              for(tm = teams.sort_next; tm; tm = tm.sort_next) {
 +                      if(tm.team == NUM_SPECTATOR)
 +                              continue;
 +                      if(!tm.team)
 +                              continue;
  
 -                      if (pl)
 -                              rgb = '1 1 0'; //not last but not among the leading players: yellow
 -                      else
 -                              rgb = '1 0 0'; //last: red
 -                      pl = me;
 +                      /*if (tm.team == myteam)
 +                              drawfill(pos + eX * score_size * i, vec2(score_size, fontsize.y), '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores(ts_primary))), vec2(score_size, fontsize.y), Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      ++i;*/
 +                      
 +                      if (tm.team == myteam)
 +                      {
 +                              if (i == 0)
 +                                      rgb = '0 1 0'; //first: green
 +                              me_printed = true;
 +                              drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      }
 +                      
 +                      score_color = Team_ColorRGB(tm.team) * 0.8;
 +                      
 +                      // TODO secondary scores test, remove
 +                      if(gametype.m_modscores)
 +                      {
 +                              string icon;
 +                              if(tm.team == NUM_TEAM_1)
 +                                      icon = "gfx/hud/luma/player_red";
 +                              else if(tm.team == NUM_TEAM_2)
 +                                      icon = "gfx/hud/luma/player_blue";
 +                              else
 +                                      icon = "gfx/hud/luma/player_neutral";
 +                              
 +                              vector icon_sz = draw_getimagesize(icon);
 +                              vector icon_sz_new = vec2(fontsize.y*(icon_sz.x/icon_sz.y), fontsize.y);
 +                              
 +                              s = ftos(gametype.m_modscores(tm.team));
 +                              float s_width = stringwidth(s, false, fontsize) + icon_sz_new.x;
 +                              
 +                              //drawfill(pos, eX * s_width + eY * fontsize.y, score_color, panel_fg_alpha * 0.3, DRAWFLAG_NORMAL);
 +                              drawpic(pos, icon, icon_sz_new, '1 1 1', panel_fg_alpha * 0.7, DRAWFLAG_NORMAL);
 +                              drawstring(pos + eX * icon_sz_new.x, s, fontsize, '1 1 1', panel_fg_alpha * 0.7, DRAWFLAG_NORMAL);
 +                              
 +                              s = textShortenToWidth(Team_CustomName(tm.team), name_size - s_width, fontsize, stringwidth_colors);
 +                      } else
 +                              s = textShortenToWidth(Team_CustomName(tm.team), name_size, fontsize, stringwidth_colors);
 +                      // TODO end
 +                      
 +                      drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      
 +                      draw_beginBoldFont();
 +                      drawstring(pos + eX * (name_size + spacing_size), ftos(tm.(teamscores(ts_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      draw_endBoldFont();
 +                      
 +                      pos.y += fontsize.y;
 +                      ++i;
                }
 -
 -              if (pl == me)
 +      } else {
 +              i = first_pl;
 +              
 +              do
 +              for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
                {
 -                      if (i == first_pl)
 -                              rgb = '0 1 0'; //first: green
 -                      me_printed = true;
 -                      drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      if ((team_count && pl.team != tm.team) || pl.team == NUM_SPECTATOR)
 +                              continue;
 +
 +                      if (i == entries-1 && !me_printed && pl != me)
 +                      if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
 +                      {
 +                              for (pl = me.sort_next; pl; pl = pl.sort_next)
 +                                      if (pl.team != NUM_SPECTATOR)
 +                                              break;
 +
 +                              if (pl)
 +                                      rgb = '1 1 0'; //not last but not among the leading players: yellow
 +                              else
 +                                      rgb = '1 0 0'; //last: red
 +                              pl = me;
 +                      }
 +              
 +                      if (team_count)
 +                              score_color = Team_ColorRGB(pl.team) * 0.8;
 +                      
 +                      entity entcs = entcs_receiver(pl.sv_entnum);
 +                      if(entcs.m_entcs_private) {
 +                              // z411 draw health/armor bar
 +                              vector bar_sz = vec2(mySize.x, fontsize.y);
 +                              
 +                              bar_sz.x *= entcs.healthvalue / autocvar_hud_panel_healtharmor_maxhealth;
 +                              drawfill(pos, bar_sz, ((team_count) ? score_color : '0.8 0.8 0'), 0.5, DRAWFLAG_NORMAL);
 +                              
 +                              bar_sz.x *= GetResource(entcs, RES_ARMOR) / autocvar_hud_panel_healtharmor_maxarmor;
 +                              drawfill(pos + eY * (bar_sz.y * 0.7), bar_sz - eY * (bar_sz.y * 0.7), ((team_count) ? score_color : '0 0.8 0.8'), 1, DRAWFLAG_NORMAL);
 +                      }
 +                      
 +                      if (pl == me)
 +                      {
 +                              if (i == first_pl)
 +                                      rgb = '0 1 0'; //first: green
 +                              me_printed = true;
 +                              drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      }
 +                      
 +                      s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
 +                      drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      pos.y += fontsize.y;
 +                      ++i;
                }
 -              if (team_count)
 -                      score_color = Team_ColorRGB(pl.team) * 0.8;
 -              s = textShortenToWidth(entcs_GetName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
 -              drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 -              drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores(ps_primary))), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
 -              pos.y += fontsize.y;
 -              ++i;
 +              while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
        }
 -      while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
  }
  
  void HUD_Score()
                if(!autocvar_hud_panel_score) return;
                if(MUTATOR_CALLHOOK(HUD_Score_show)) return;
        }
 +      
 +      if (!scoreboard_fade_alpha) // the scoreboard too calls Scoreboard_UpdatePlayerTeams
 +              Scoreboard_UpdatePlayerTeams();
 +      
 +      if(spectatee_status && teamplay) return;
  
        HUD_Panel_LoadCvars();
        vector pos, mySize;
index f4dbe7eff9c29548609b55b74a284cb70f1ae8c4,5821dc46946808598f58f01f77d28b0e7e73ac59..43df946cf7c98c90b4ae38fd28920f02a65b3148
@@@ -1,7 -1,7 +1,7 @@@
  #include "scoreboard.qh"
  
- #include <client/autocvars.qh>
  #include <client/draw.qh>
+ #include <client/hud/panel/chat.qh>
  #include <client/hud/panel/quickmenu.qh>
  #include <client/hud/panel/racetimer.qh>
  #include <client/hud/panel/weapons.qh>
@@@ -13,7 -13,6 +13,7 @@@
  #include <common/scores.qh>
  #include <common/stats.qh>
  #include <common/teams.qh>
 +#include <common/items/inventory.qh>
  
  // Scoreboard (#24)
  
@@@ -46,14 -45,6 +46,14 @@@ string autocvar_hud_fontsize
  string hud_fontsize_str;
  float max_namesize;
  
 +vector duel_score_fontsize;
 +vector duel_name_fontsize;
 +vector duel_score_size;
 +vector team_score_fontsize;
 +vector team_name_fontsize;
 +vector team_score_size;
 +int total_medals;
 +
  float sbt_bg_alpha;
  float sbt_fg_alpha;
  float sbt_fg_alpha_self;
@@@ -100,8 -91,6 +100,8 @@@ bool autocvar_hud_panel_scoreboard_spec
  bool autocvar_hud_panel_scoreboard_spectators_aligned = false;
  float autocvar_hud_panel_scoreboard_minwidth = 0.4;
  
 +int average_ping[NUM_TEAMS];
 +
  // mode 0: returns translated label
  // mode 1: prints name and description of all the labels
  string Label_getInfo(string label, int mode)
@@@ -440,14 -429,6 +440,14 @@@ void Cmd_Scoreboard_SetFields(int argc
        sbt_num_fields = 0;
  
        hud_fontsize = HUD_GetFontsize("hud_fontsize");
 +      
 +      duel_score_fontsize = hud_fontsize * 3;
 +      duel_name_fontsize = hud_fontsize * 1.5;
 +      duel_score_size = vec2(duel_score_fontsize.x * 1.5, duel_score_fontsize.y * 1.25);
 +      
 +      team_score_fontsize = hud_fontsize * 2;
 +      team_name_fontsize = hud_fontsize * 1.5;
 +      team_score_size = vec2(team_score_fontsize.x * 1.5, team_score_fontsize.y * 1.25);
  
        for(i = 1; i < argc - 1; ++i)
        {
@@@ -601,7 -582,7 +601,7 @@@ string Scoreboard_GetName(entity pl
        {
                sbt_field_icon0 = "gfx/scoreboard/player_ready";
        }
 -      else if(!teamplay)
 +      /*else if(!teamplay)
        {
                int f = entcs_GetClientColors(pl.sv_entnum);
                {
                        sbt_field_icon2 = "gfx/scoreboard/playercolor_pants";
                        sbt_field_icon2_rgb = colormapPaletteColor(f % 16, 1);
                }
 +      }*/
 +      else
 +      {
 +              int ccode = entcs_GetCountryCode(pl.sv_entnum);
 +              if(ccode)
 +                      sbt_field_icon0 = strcat("gfx/flags/", ftos(ccode));
        }
 +      
        return entcs_GetName(pl.sv_entnum);
  }
  
 +vector getPingColor(float f)
 +{
 +      if(f < 80) {
 +              // 20-80 range is green
 +              return '0 1 0' + '1 0 1' * max(0, min(60, f-20)) / 60;
 +      } else {
 +              // 80-300 range is red
 +              return '1 1 1' - '0 1 1' * max(0, min(220, f-80)) / 220;
 +      }
 +}
  string Scoreboard_GetField(entity pl, PlayerScoreField field)
  {
        float tmp, num, denom;
                        f = pl.ping;
                        if(f == 0)
                                return _("N/A");
 -                      tmp = max(0, min(220, f-80)) / 220;
 -                      sbt_field_rgb = '1 1 1' - '0 1 1' * tmp;
 +                      sbt_field_rgb = getPingColor(f);
 +                      
                        return ftos(f);
 +                      //return ftos(pl.team);
  
                case SP_PL:
                        if (!pl.gotscores)
@@@ -828,13 -791,10 +828,13 @@@ void Scoreboard_initFieldSizes(
        }
  }
  
 -vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players)
 +vector Scoreboard_DrawHeader(vector pos, vector rgb, bool other_players, int team)
  {
        int i;
 +      string title_str;
 +      vector title_rgb;
        vector column_dim = eY * panel_size.y;
 +      
        if(other_players)
                column_dim.y -= 1.25 * hud_fontsize.y;
        vector text_offset = eY * (1.25 - 1) / 2 * hud_fontsize.y;
        {
                if(sbt_field[i] == SP_SEPARATOR)
                        break;
 +              
 +              vector text_offset_center = '0 0 0';
 +              
 +              if(sbt_field[i] == SP_PING && teamplay) {
 +                      title_str = sprintf("(%d)", average_ping[Team_TeamToIndex(team) - 1]);
 +                      title_rgb = getPingColor(average_ping[Team_TeamToIndex(team) - 1]);
 +                      text_offset_center.x = sbt_field_size[i] - stringwidth(title_str, false, hud_fontsize);
 +              } else {
 +                      title_str = sbt_field_title[i];
 +                      title_rgb = rgb * 1.5;
 +              }
 +              
                column_dim.x = sbt_field_size[i] + hud_fontsize.x;
                if (sbt_highlight)
                        if (i % 2)
                                drawfill(pos - eX * hud_fontsize.x * 0.5, column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
 -              drawstring(pos + text_offset, sbt_field_title[i], hud_fontsize, rgb * 1.5, sbt_fg_alpha, DRAWFLAG_NORMAL);
 +              drawstring(pos + text_offset + text_offset_center, title_str, hud_fontsize, title_rgb, sbt_fg_alpha, DRAWFLAG_NORMAL);
                pos.x += column_dim.x;
        }
        if(sbt_field[i] == SP_SEPARATOR)
@@@ -1093,287 -1041,6 +1093,287 @@@ vector Scoreboard_DrawOthers(vector ite
        return vec2(item_pos.x, item_pos.y + i * hud_fontsize.y * 1.25);
  }
  
 +vector Scoreboard_DrawMedal(vector pos, string icon, float height, float number)
 +{
 +      if(!number) return pos;
 +      total_medals += number;
 +      
 +      vector tmp_sz, tmp_sz2;
 +      tmp_sz = draw_getimagesize(icon);
 +      tmp_sz2 = vec2(height*(tmp_sz.x/tmp_sz.y), height);
 +      string val = ftos(number);
 +      
 +      drawpic(pos, icon, tmp_sz2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      pos.x += tmp_sz2.x + hud_fontsize.x * 0.25;
 +      drawstring(pos + eY * ((tmp_sz2.y - hud_fontsize.y) / 2), val, hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      pos.x += stringwidth(val, false, hud_fontsize) + hud_fontsize.x * 0.5;
 +      return pos;
 +}
 +
 +vector Scoreboard_Duel_DrawPickup(vector pos, bool skinned, string icon, vector sz, float number, bool invert)
 +{
 +      vector tmp_in = pos;
 +      vector tmp_sz, tmp_sz2;
 +      string picpath;
 +      
 +      // Icon
 +      if(skinned) {
 +              picpath = strcat(hud_skin_path, "/", icon);
 +              if(precache_pic(picpath) == "")
 +                      picpath = strcat("gfx/hud/default/", icon);
 +      } else {
 +              picpath = icon;
 +      }
 +              
 +      tmp_sz = draw_getimagesize(picpath);
 +      tmp_sz2 = vec2(sz.y*(tmp_sz.x/tmp_sz.y), sz.y);
 +      
 +      tmp_in.x = pos.x + ((sz.x - tmp_sz2.x) / 2);
 +      drawpic(tmp_in, picpath, tmp_sz2, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      // Number
 +      if(invert)
 +              tmp_in.x += tmp_sz2.x + hud_fontsize.x * 0.25;
 +      else
 +              tmp_in.x -= hud_fontsize.x * 0.25 + hud_fontsize.x;
 +      
 +      tmp_in.y += (tmp_sz2.y - hud_fontsize.y) / 2;
 +      drawstring(tmp_in,
 +              ((number == -1) ? "?" : ftos(number)),
 +              hud_fontsize, ((number > 0) ? '1 1 1' : '0.5 0.5 0.5'),
 +              panel_fg_alpha,
 +              DRAWFLAG_NORMAL);
 +      
 +      pos.y += sz.y * 1.1;
 +      return pos;
 +}
 +
 +void Scoreboard_Duel_DrawTable(vector pos, bool invert, entity pl, entity tm)
 +{
 +      vector tmp, tmp_in, tmp_sz, tmp_acc;
 +      string tmp_str;
 +      float sz;
 +      float average_acc = 0;
 +      
 +      panel_pos = pos;
 +      
 +      HUD_Panel_DrawBg();
 +      
 +      // Stop here if there are no scores available
 +      if(pl.team != tm.team) return;
 +      
 +      tmp = pos;
 +      tmp.x += panel_bg_padding;
 +      tmp.y += panel_bg_padding;
 +      panel_size.x -= panel_bg_padding * 2;
 +      
 +      //if (sbt_bg_alpha)
 +      //      drawpic_tiled(pos, "gfx/scoreboard/scoreboard_bg", tmp, panel_size, rgb, sbt_bg_alpha, DRAWFLAG_NORMAL);
 +
 +      // Score: highlight
 +      if(invert) { tmp.x += panel_size.x; tmp.x -= duel_score_size.x; }
 +      drawfill(tmp, duel_score_size, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
 +      
 +      // Score: text
 +      tmp_str = ftos(pl.(scores(SP_SCORE)));
 +      tmp_in = tmp;
 +      tmp_in.x += (duel_score_size.x / 2) - (stringwidth(tmp_str, true, duel_score_fontsize) / 2);
 +      tmp_in.y += (duel_score_size.y / 2) - (duel_score_fontsize.y / 2);
 +      
 +      draw_beginBoldFont();
 +      drawstring(tmp_in, tmp_str, duel_score_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      draw_endBoldFont();
 +      
 +      // Player name
 +      tmp_str = Scoreboard_GetField(pl, SP_NAME);
 +      tmp_in = tmp;
 +      if(invert)
 +              tmp_in.x -= stringwidth_colors(tmp_str, duel_name_fontsize) + duel_name_fontsize.x * 0.5;
 +      else
 +              tmp_in.x += duel_score_size.x + duel_name_fontsize.x * 0.5;
 +      tmp_in.y += (duel_score_size.y - duel_name_fontsize.y) / 2;
 +      drawcolorcodedstring(tmp_in, tmp_str, duel_name_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      // Player icon/flag
 +      if(sbt_field_icon0 != "") {
 +              vector rsz = draw_getimagesize(sbt_field_icon0);
 +              sbt_fixcolumnwidth_iconlen = rsz.x / rsz.y;
 +              if(invert)
 +                      tmp_in.x -= hud_fontsize.x * sbt_fixcolumnwidth_iconlen + duel_name_fontsize.x * 0.5;
 +              else
 +                      tmp_in.x += stringwidth_colors(tmp_str, duel_name_fontsize) + duel_name_fontsize.x * 0.5;
 +              tmp_in.y += (duel_name_fontsize.y - hud_fontsize.y) / 2;
 +              drawpic(tmp_in, sbt_field_icon0, vec2(hud_fontsize.x * sbt_fixcolumnwidth_iconlen, hud_fontsize.y), sbt_field_icon1_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      }
 +      
 +      // Header
 +      float column_width = panel_size.x / 5;
 +      tmp.x = pos.x + panel_bg_padding;
 +      tmp.y += hud_fontsize.y * 3 + hud_fontsize.y;
 +      
 +      vector column_dim;
 +      int i;
 +
 +      i = (invert ? 4 : 0);
 +      column_dim = vec2(column_width * 4, hud_fontsize.y);
 +      
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("kills", false, hud_fontsize) / 2),
 +              "kills", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("dmg", false, hud_fontsize) / 2),
 +              "dmg", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("acc", false, hud_fontsize) / 2),
 +              "acc", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("hits", false, hud_fontsize) / 2),
 +              "hits", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth("ping", false, hud_fontsize) / 2),
 +              "ping", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      tmp.x = pos.x + panel_bg_padding;
 +      tmp.y += hud_fontsize.y;
 +      
 +      // Main row
 +      i = (invert ? 4 : 0);
 +      
 +      tmp_str = ftos(pl.(scores(SP_KILLS)));
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
 +              tmp_str, hud_fontsize  * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      tmp_str = ftos(pl.(scores(SP_DMG)));
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
 +              tmp_str, hud_fontsize  * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +              
 +      tmp_acc = tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2);
 +              
 +      if(invert)
 +              i--;
 +      else
 +              i++;
 +      
 +      tmp_str = Scoreboard_GetField(pl, SP_PING);
 +      drawstring(tmp + eX * column_width * (invert ? i-- : i++) + (eX * column_width / 2) - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
 +              tmp_str, hud_fontsize * 1.25, sbt_field_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      tmp.x = pos.x + panel_bg_padding;
 +      tmp.y += hud_fontsize.y * 2;
 +      
 +      tmp_in = tmp;
 +      
 +      int total_weapons = 0;
 +      
 +      // Accuracy rows
 +      WepSet weapons_inmap = WepSet_GetFromStat_InMap();
 +      FOREACH(Weapons, it != WEP_Null, {
 +              WepSet set = it.m_wepset;
 +              if (!(weapons_inmap & set))
 +                      continue;
 +              if (it.spawnflags & WEP_TYPE_OTHER)
 +                      continue;
 +              
 +              int weapon_cnt_fired = pl.accuracy_cnt_fired[i - WEP_FIRST];
 +              int weapon_cnt_hit   = pl.accuracy_cnt_hit[i - WEP_FIRST];
 +              int weapon_acc = 0;
 +              if(weapon_cnt_fired)
 +                      weapon_acc = floor((weapon_cnt_hit / weapon_cnt_fired) * 100);
 +              average_acc += weapon_acc;
 +              
 +              string draw_str;
 +              
 +              // weapon stats
 +              int c = (invert ? 4 : 0);
 +              
 +              drawfill(tmp_in + eX * column_width * (invert ? 1 : 0), column_dim, '0 0 0', sbt_highlight_alpha, DRAWFLAG_NORMAL);
 +              
 +              draw_str = ftos(pl.accuracy_frags[i - WEP_FIRST]);
 +              drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
 +                      draw_str, hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL);
 +              
 +              draw_str = ftos(pl.accuracy_hit[i - WEP_FIRST]);
 +              drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
 +                      draw_str, hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      
 +              draw_str = sprintf("%d%%", weapon_acc);
 +              drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * ((column_width - stringwidth(draw_str, false, hud_fontsize)) / 2),
 +                      draw_str, hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      
 +              draw_str = strcat(ftos(weapon_cnt_hit), " / ", ftos(weapon_cnt_fired));
 +              drawstring(tmp_in + eX * column_width * (invert ? c-- : c++) + eX * (column_width / 2) - eX * stringwidth("36 /", false, hud_fontsize),
 +                      draw_str,hud_fontsize, (weapon_cnt_fired ? '1 1 1' : '0.5 0.5 0.5'), panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +              // weapon icon
 +              if(invert) {
 +                      tmp_in.x = pos.x + panel_size.x - panel_bg_padding - hud_fontsize.x / 2;
 +                      drawpic_aspect_skin(tmp_in, it.model2, vec2(50, hud_fontsize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +              }
 +              
 +              tmp_in.x = pos.x + panel_bg_padding;
 +              tmp_in.y += hud_fontsize.y * 1.25;
 +              
 +              if(weapon_cnt_fired)
 +                      total_weapons++;
 +      });
 +      if(total_weapons)
 +              average_acc = floor((average_acc / total_weapons) + 0.5);
 +      
 +      // draw total accuracy now
 +      tmp_str = sprintf("%d%%", average_acc);
 +      drawstring(tmp_acc - eX * (stringwidth(tmp_str, false, hud_fontsize * 1.25) / 2),
 +              tmp_str, hud_fontsize * 1.25, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      // Icon column
 +      vector icon_sz = vec2(column_width, hud_fontsize.y*1.5);
 +      
 +      if(!invert)
 +              tmp.x += column_width * 4;
 +      // Medal rows
 +      drawstring(tmp + eX * ((column_width - stringwidth("medals", false, hud_fontsize)) / 2),
 +              "medals", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      tmp.y += hud_fontsize.y * 1.25;
 +      
 +      tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/humiliation", icon_sz, pl.(scores(SP_MEDAL_HUMILIATION)), invert);
 +      tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/impressive", icon_sz, pl.(scores(SP_MEDAL_IMPRESSIVE)), invert);
 +      tmp = Scoreboard_Duel_DrawPickup(tmp, false, "gfx/medal/excellent", icon_sz, pl.(scores(SP_MEDAL_EXCELLENT)), invert);
 +      
 +      // Item rows
 +      drawstring(tmp + eX * ((column_width - stringwidth("items", false, hud_fontsize)) / 2),
 +              "items", hud_fontsize, '0.5 0.5 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      tmp.y += hud_fontsize.y * 1.25;
 +      
 +      float inv_num = -1;
 +      FOREACH(Items,
 +              it.m_id == ITEM_ArmorMega.m_id ||
 +              it.m_id == ITEM_HealthMega.m_id ||
 +              it.m_id == ITEM_ArmorBig.m_id, {
 +              // If the match isn't over, Only show pickups if we're spectating or they're our own
 +              if(intermission || warmup_stage || spectatee_status || pl.sv_entnum == current_player)
 +                      inv_num = inventoryslots[pl.sv_entnum].inv_items[it.m_id];
 +              tmp = Scoreboard_Duel_DrawPickup(tmp, true, it.m_icon, icon_sz, inv_num, invert);
 +              
 +              if(it.m_id == REGISTRY_MAX(Items))
 +              break;
 +      });
 +}
 +vector Scoreboard_MakeDuelTable(vector pos, entity tm, vector rgb, vector bg_size)
 +{
 +      vector end_pos = pos;
 +      float screen_half = panel_size.x / 2;
 +      float weapon_margin = hud_fontsize.x;
 +      
 +      panel_size.x = screen_half - weapon_margin;
 +      panel_size.y = (duel_score_size.y * 5.5);
 +      
 +      entity pl_left = players.sort_next;
 +      entity pl_right = pl_left.sort_next;
 +      
 +      Scoreboard_Duel_DrawTable(pos, true, pl_left, tm);
 +      Scoreboard_Duel_DrawTable(pos + eX * screen_half + eX * weapon_margin, false, pl_right, tm);
 +      
 +      end_pos.y += panel_size.y + (panel_bg_padding * 2);
 +      panel_size.x = screen_half * 2;
 +      return end_pos;
 +}
 +
  vector Scoreboard_MakeTable(vector pos, entity tm, vector rgb, vector bg_size)
  {
        int max_players = 999;
  
  
        // print header row and highlight columns
 -      pos = Scoreboard_DrawHeader(panel_pos, rgb, (max_players < tm.team_size));
 +      pos = Scoreboard_DrawHeader(panel_pos, rgb, (max_players < tm.team_size), tm.team);
  
        // fill the table and draw the rows
        bool is_self = false;
        bool self_shown = false;
        int i = 0;
 +      int with_ping = 0;
 +      if(Team_IsValidTeam(tm.team)) average_ping[Team_TeamToIndex(tm.team) - 1] = 0;
        for(pl = players.sort_next; pl; pl = pl.sort_next)
        {
                if(pl.team != tm.team)
                }
                is_self = (pl.sv_entnum == current_player);
                Scoreboard_DrawItem(pos, rgb, pl, is_self, i);
 +              
 +              if(Team_IsValidTeam(tm.team) && pl.ping) {
 +                      average_ping[Team_TeamToIndex(tm.team) - 1] += pl.ping;
 +                      ++with_ping;
 +              }
                if(is_self)
                        self_shown = true;
                pos.y += 1.25 * hud_fontsize.y;
                ++i;
        }
 +      if(with_ping) average_ping[Team_TeamToIndex(tm.team) - 1] /= with_ping;
  
        panel_size.x += panel_bg_padding * 2; // restore initial width
        return end_pos;
@@@ -1497,46 -1156,6 +1497,46 @@@ bool Scoreboard_WouldDraw(
        return false;
  }
  
 +vector Scoreboard_MedalStats_Draw(vector pos)
 +{
 +      vector orig = pos;
 +      float height = hud_fontsize.y * 2;
 +      
 +      entity pl = playerslots[current_player];
 +      
 +      vector title_pos = pos;
 +      pos.x += 0.5 * hud_fontsize.x + panel_bg_padding;
 +      pos.y += 1.25 * hud_fontsize.y;
 +      
 +      total_medals = 0;
 +      
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/airshot",            height, pl.(scores(SP_MEDAL_AIRSHOT)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/damage",             height, pl.(scores(SP_MEDAL_DAMAGE)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/electrobitch",       height, pl.(scores(SP_MEDAL_ELECTROBITCH)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/excellent",          height, pl.(scores(SP_MEDAL_EXCELLENT)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/firstblood",         height, pl.(scores(SP_MEDAL_FIRSTBLOOD)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/headshot",           height, pl.(scores(SP_MEDAL_HEADSHOT)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/humiliation",        height, pl.(scores(SP_MEDAL_HUMILIATION)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/impressive",         height, pl.(scores(SP_MEDAL_IMPRESSIVE)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/yoda",                       height, pl.(scores(SP_MEDAL_YODA)));
 +      
 +      pos.x += hud_fontsize.x;
 +      
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/accuracy",           height, pl.(scores(SP_MEDAL_ACCURACY)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/assist",             height, pl.(scores(SP_MEDAL_ASSIST)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/defense",            height, pl.(scores(SP_MEDAL_DEFENSE)));
 +      pos = Scoreboard_DrawMedal(pos, "gfx/medal/perfect",            height, pl.(scores(SP_MEDAL_PERFECT)));
 +      
 +      if(!total_medals) return orig;
 +      
 +      drawstring(title_pos, sprintf(_("Medal stats (total %d)"), total_medals),
 +              hud_fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      pos.x = orig.x;
 +      pos.y += height + hud_fontsize.y * 0.5;
 +      return pos;
 +}
 +
  float average_accuracy;
  vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
  {
@@@ -1705,7 -1324,6 +1705,7 @@@ vector MapStats_DrawKeyValue(vector pos
        return pos;
  }
  
 +/*
  vector Scoreboard_MapStats_Draw(vector pos, vector rgb, vector bg_size) {
        float stat_secrets_found, stat_secrets_total;
        float stat_monsters_killed, stat_monsters_total;
        panel_size.x += panel_bg_padding * 2; // restore initial width
        return end_pos;
  }
 -
 +*/
  
  vector Scoreboard_Rankings_Draw(vector pos, string ranktitle, entity pl, vector rgb, vector bg_size)
  {
@@@ -1995,32 -1613,12 +1995,32 @@@ void Scoreboard_Draw(
        sb_gameinfo_type_fontsize = hud_fontsize * 2.5;
        sb_gameinfo_detail_fontsize = hud_fontsize * 1.3;
  
 +      // z411 server name
 +      //drawcolorcodedstring(pos, "bienvenidoainternet.org", sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      //drawpic_aspect(pos + '1 0 0' * (panel_size.x - 150), "gfx/bai_logo", vec2(150, sb_gameinfo_type_fontsize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      //pos.y += sb_gameinfo_type_fontsize.y;
 +      
        // Game Info: Game Type
        str = MapInfo_Type_ToText(gametype);
 +      
        draw_beginBoldFont();
 -      drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_type_fontsize)), str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      //drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_type_fontsize)), str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      drawcolorcodedstring(pos, str, sb_gameinfo_type_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
        draw_endBoldFont();
 +      
 +      vector tmp_old_sz = draw_getimagesize("gfx/bai_logo");
 +      float tmp_aspect = tmp_old_sz.x/tmp_old_sz.y;
 +      vector tmp_new_sz = vec2(sb_gameinfo_type_fontsize.y * tmp_aspect, sb_gameinfo_type_fontsize.y);
  
 +      drawpic(pos + '1 0 0' * (panel_size.x - tmp_new_sz.x), "gfx/bai_logo", tmp_new_sz, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      pos.y += sb_gameinfo_type_fontsize.y;
 +      
 +      // z411 servername
 +      drawcolorcodedstring(pos + '0.5 0 0' * (panel_size.x - stringwidth_colors(hostname_full, sb_gameinfo_detail_fontsize)), hostname_full, sb_gameinfo_detail_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      pos.y += sb_gameinfo_detail_fontsize.y;
 +      
        // Game Info: Game Detail
        float tl = STAT(TIMELIMIT);
        float fl = STAT(FRAGLIMIT);
                }
        }
  
 -      pos.y += sb_gameinfo_type_fontsize.y;
        drawcolorcodedstring(pos + '1 0 0' * (panel_size.x - stringwidth(str, true, sb_gameinfo_detail_fontsize)), str, sb_gameinfo_detail_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); // align right
        // map name
        str = sprintf(_("^7Map: ^2%s"), shortmapname);
                if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
                {
                        // put team score to the left of scoreboard (and team size to the right)
 -                      team_score_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 0.5;
 +                      team_score_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 1.5;
                        team_size_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 0.5;
                        if(panel.current_panel_bg != "0")
                        {
                else
                {
                        // put team score to the right of scoreboard (and team size to the left)
 -                      team_score_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 0.5;
 +                      team_score_baseoffset = eY * hud_fontsize.y + eX * hud_fontsize.x * 1.5;
                        team_size_baseoffset = eY * hud_fontsize.y - eX * hud_fontsize.x * 0.5;
                        if(panel.current_panel_bg != "0")
                        {
                        if(!tm.team)
                                continue;
  
 -                      draw_beginBoldFont();
                        vector rgb = Team_ColorRGB(tm.team);
 +                      /*draw_beginBoldFont();
                        str = ftos(tm.(teamscores(ts_primary)));
                        if (autocvar_hud_panel_scoreboard_team_size_position != 1) // team size not on left
                        {
                                // team score on the left (default)
 -                              str_pos = pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 1.5);
 +                              str_pos = pos + team_score_baseoffset - eX * stringwidth(str, false, hud_fontsize * 3);
                        }
                        else
                        {
                                // team score on the right
 -                              str_pos = pos + team_score_baseoffset + eX * (panel_size.x + hud_fontsize.x * 1.5);
 +                              str_pos = pos + team_score_baseoffset + eX * (panel_size.x + hud_fontsize.x * 3);
                        }
 -                      drawstring(str_pos, str, hud_fontsize * 1.5, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      drawstring(str_pos, str, hud_fontsize * 3, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
  
                        // team size (if set to show on the side)
                        if (autocvar_hud_panel_scoreboard_team_size_position != 0) // team size not off
                                drawstring(str_pos, str, hud_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        draw_endBoldFont();
 +                      */
 +                      
 +                      // z411 My team header
 +                      // Score: highlight
 +                      drawfill(pos, team_score_size, rgb * 0.5, sbt_highlight_alpha, DRAWFLAG_NORMAL);
 +                      
 +                      // Score: text
 +                      str = ftos(tm.(teamscores(ts_primary)));
 +                      str_pos = pos;
 +                      str_pos.x += (team_score_size.x / 2) - (stringwidth(str, true, team_score_fontsize) / 2);
 +                      str_pos.y += (team_score_size.y / 2) - (team_score_fontsize.y / 2);
 +                      
 +                      draw_beginBoldFont();
 +                      drawstring(str_pos, str, team_score_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      draw_endBoldFont();
 +                      
 +                      // Team name
 +                      str = Team_CustomName(tm.team);
 +                      str_pos = pos;
 +                      str_pos.x += team_score_size.x + team_name_fontsize.x * 0.5;
 +                      str_pos.y += (team_score_size.y / 2) - (team_name_fontsize.y / 2);
 +                      drawcolorcodedstring(str_pos, str, team_name_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      
 +                      pos.y += team_score_size.y + (hud_fontsize.y * 0.5);
 +                      
                        if(autocvar_hud_panel_scoreboard_bg_teams_color_team > 0)
                                panel_bg_color = rgb * autocvar_hud_panel_scoreboard_bg_teams_color_team;
                        else if(panel_bg_color_team > 0)
                }
                panel_bg_color = panel_bg_color_save;
        }
 +      else if(gametype == MAPINFO_TYPE_DUEL)
 +      {
 +              for(tm = teams.sort_next; tm; tm = tm.sort_next)
 +                      if(tm.team != NUM_SPECTATOR)
 +                              break;
 +              
 +              // z411 make DUEL TABLE
 +              pos = Scoreboard_MakeDuelTable(pos, tm, panel_bg_color, bg_size);
 +      }
        else
        {
                for(tm = teams.sort_next; tm; tm = tm.sort_next)
                pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
        }
  
 +      pos = Scoreboard_MedalStats_Draw(pos);
 +      
        if (Scoreboard_AccuracyStats_WouldDraw(pos.y))
                pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size);
  
                pos = Scoreboard_Rankings_Draw(pos, ranktitle, playerslots[player_localnum], panel_bg_color, bg_size);
        }
  
 -      pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
 +      //pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
  
        // List spectators
        for(pl = players.sort_next; pl; pl = pl.sort_next)
index d70847fe13981392df5e9aeaf01cb4d0bf2c694c,0000000000000000000000000000000000000000..8f1e3cd41f061c01565ffba2803185fc7fb22795
mode 100644,000000..100644
--- /dev/null
@@@ -1,199 -1,0 +1,198 @@@
- #include <client/autocvars.qh>
 +#include "spect.qh"
 +
 +#include <client/hud/hud.qh>
 +#include <client/view.qh>
 +
 +vector teamscore_size;
 +vector teamscore_fontsize;
 +vector teamname_fontsize;
 +
 +void HUD_SpectHUD_Export(int fh)
 +{
 +      // allow saving cvars that aesthetically change the panel into hud skin files
 +}
 +
 +void HUD_SpectHUD_drawCurrentName(vector pos)
 +{
 +      string s = entcs_GetName(current_player);
 +      pos.x -= stringwidth_colors(s, hud_fontsize * 2) / 2;
 +      drawcolorcodedstring(pos, s, hud_fontsize * 2, panel_fg_alpha, DRAWFLAG_NORMAL);
 +}
 +      
 +void HUD_SpectHUD_drawTeamPlayers(vector pos, entity tm, vector rgb, bool invert)
 +{
 +      vector tmp_over;
 +      vector line_sz = vec2((vid_conwidth - 1) / 7, hud_fontsize.y * 1.5);
 +      vector line_sz_sub = vec2((vid_conwidth - 1) / 7, hud_fontsize.y);
 +      
 +      string playername;
 +      float a = panel_fg_alpha * 0.8;
 +      entity pl;
 +      
 +      if(invert)
 +              pos.x -= line_sz.x + hud_fontsize.x;
 +      else
 +              pos.x += hud_fontsize.x;        
 +      
 +      for(pl = players.sort_next; pl; pl = pl.sort_next)
 +      {
 +              if(pl.team != tm.team)
 +                      continue;
 +              
 +              float health = 0;
 +              float armor = 0;
 +              string icon = "";
 +              vector icon_size = '0 0 0';
 +              vector icon_rgb = '1 1 1';
 +              
 +              // Position and size calculation vectors
 +              tmp_over = pos;
 +              vector total_sz = vec2(line_sz.x, line_sz.y + line_sz_sub.y);
 +              
 +              if(pl.eliminated) {
 +                      // z411 TODO : Unhardcode luma
 +                      icon = "gfx/hud/luma/notify_death.tga";
 +                      icon_rgb = rgb;
 +              } else {
 +                      entity entcs = entcs_receiver(pl.sv_entnum);
 +                      if(entcs.m_entcs_private) {
 +                              health = (entcs.healthvalue / autocvar_hud_panel_healtharmor_maxhealth) * line_sz.x;
 +                              armor = (GetResource(entcs, RES_ARMOR) / autocvar_hud_panel_healtharmor_maxarmor) * line_sz_sub.x;
 +                                      
 +                              Weapon wep = REGISTRY_GET(Weapons, entcs.activewepid);
 +                              icon = strcat("gfx/hud/luma/", wep.model2);
 +                      } else {
 +                              if(tm.team == NUM_TEAM_1)
 +                                      icon = "gfx/hud/luma/player_red";
 +                              else if(tm.team == NUM_TEAM_2)
 +                                      icon = "gfx/hud/luma/player_blue";
 +                              else
 +                                      icon = "gfx/hud/luma/player_neutral";
 +                      }
 +              }
 +              
 +              // Draw weapon
 +              if(icon != "")  {
 +                      vector tmp_sz = draw_getimagesize(icon);
 +                      icon_size = vec2(total_sz.y*(tmp_sz.x/tmp_sz.y), total_sz.y);
 +                      total_sz.x += icon_size.x;
 +                              
 +                      if(invert) {
 +                              pos.x -= icon_size.x;
 +                              tmp_over.x -= icon_size.x;
 +                      }
 +                      drawpic(pos, icon, icon_size, icon_rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 +                      pos.x += icon_size.x;
 +              }
 +              
 +              // Get player's name
 +              playername = textShortenToWidth(entcs_GetName(pl.sv_entnum), line_sz.x * 0.8, hud_fontsize, stringwidth_colors);
 +              
 +              // Draw health and name
 +              drawfill(pos, line_sz, rgb * 0.7, a * 0.3, DRAWFLAG_NORMAL);
 +              if(health)
 +                      drawfill(pos, vec2(health, line_sz.y), rgb * 0.7, a, DRAWFLAG_NORMAL);
 +              drawcolorcodedstring(pos + eY * ((line_sz.y - hud_fontsize.y) / 2) + eX * (hud_fontsize.x * 0.5), playername, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +              pos.y += line_sz.y;
 +              
 +              // Draw armor
 +              if(armor)
 +                      drawfill(pos, vec2(armor, line_sz_sub.y), rgb, a, DRAWFLAG_NORMAL);
 +              
 +              // Highlight current player
 +              if(pl.sv_entnum == current_player && spectatee_status != -1)
 +                      drawfill(tmp_over, total_sz, '1 1 1', 0.3, DRAWFLAG_NORMAL);
 +              if(pl.eliminated)
 +                      drawfill(tmp_over, total_sz, '0 0 0', 0.4, DRAWFLAG_NORMAL);
 +              
 +              if(!invert)
 +                      pos.x -= icon_size.x;
 +              pos.y += line_sz_sub.y * 2;
 +      }
 +}
 +
 +
 +void HUD_SpectHUD_drawTeamScore(vector pos, entity tm, vector rgb, bool invert)
 +{
 +      if(!tm) return;
 +      
 +      vector tmp;
 +      string tmp_str;
 +      
 +      // Team score
 +      tmp_str = ftos(tm.(teamscores(ts_primary)));
 +      
 +      if(invert)
 +              pos.x -= teamscore_size.x;
 +      
 +      drawfill(pos, teamscore_size, rgb * 0.8, 0.3, DRAWFLAG_NORMAL);
 +      
 +      tmp = pos;
 +      tmp.x += (teamscore_size.x - stringwidth(tmp_str, true, teamscore_fontsize)) / 2;
 +      tmp.y += (teamscore_size.y - teamscore_fontsize.y) / 2;
 +              
 +      draw_beginBoldFont();
 +      drawstring(tmp, tmp_str, teamscore_fontsize, rgb, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      draw_endBoldFont();
 +      
 +      // Team name
 +      tmp_str = Team_CustomName(tm.team);
 +      
 +      tmp = pos;
 +      if(invert)
 +              tmp.x -= stringwidth_colors(tmp_str, teamname_fontsize) + teamname_fontsize.x * 0.5;
 +      else
 +              tmp.x += teamscore_size.x + teamname_fontsize.x * 0.5;
 +      tmp.y += (teamscore_size.y - teamname_fontsize.y) / 2;
 +      
 +      drawcolorcodedstring(tmp, tmp_str, teamname_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 +}
 +
 +void HUD_SpectHUD()
 +{
 +      if(!spectatee_status) return;
 +      
 +      vector pos, rgb;
 +      float ammo_y, timer_width;
 +      entity tm;
 +      
 +      // Set main vars
 +      HUD_Panel_LoadCvars();
 +      HUD_Scale_Enable();
 +      hud_fontsize = HUD_GetFontsize("hud_fontsize");
 +      
 +      // Spectator name
 +      if(spectatee_status != -1) {
 +              ammo_y = stov(cvar_string("hud_panel_ammo_pos")).y * vid_conheight;
 +              pos = panel_pos + vec2((vid_conwidth - 1) / 2, (ammo_y - (hud_fontsize.y * 2)));
 +              HUD_SpectHUD_drawCurrentName(pos);
 +      }
 +      
 +      if(!teamplay) return;
 +      
 +      // Set vars
 +      teamscore_fontsize = hud_fontsize * 3;
 +      teamname_fontsize = hud_fontsize * 2;
 +      teamscore_size = vec2(teamscore_fontsize.x * 1.5, teamscore_fontsize.y * 1.25);
 +      timer_width = stov(cvar_string("hud_panel_timer_size")).x * vid_conwidth;
 +      
 +      // Team 1
 +      pos = panel_pos + vec2((vid_conwidth - 1) / 2, 0);
 +      tm = GetTeam(NUM_TEAM_1, false);
 +      rgb = Team_ColorRGB(tm.team);
 +      pos.x -= (timer_width * 1.3) / 2;
 +      HUD_SpectHUD_drawTeamScore(pos, tm, rgb, true);
 +      
 +      pos = panel_pos + vec2(0, (vid_conheight - 1) / 4 + hud_fontsize.y);
 +      HUD_SpectHUD_drawTeamPlayers(pos, tm, rgb, false);
 +      
 +      // Team 2
 +      pos = panel_pos + vec2((vid_conwidth - 1) / 2, 0);
 +      tm = GetTeam(NUM_TEAM_2, false);
 +      rgb = Team_ColorRGB(tm.team);
 +      pos.x += (timer_width * 1.3) / 2;
 +      HUD_SpectHUD_drawTeamScore(pos, tm, rgb, false);
 +      
 +      pos = panel_pos + vec2(vid_conwidth - 1, (vid_conheight - 1) / 4 + hud_fontsize.y);
 +      HUD_SpectHUD_drawTeamPlayers(pos, tm, rgb, true);
 +}
index 68c28ac5a72e4a0c7bc2a2ac02df53f8a98e7003,0cdfefa7899af591aaf4f3ef3c567152d02e41ac..8679742b49a4f46e4482d163fd9fc802da9fea28
@@@ -1,7 -1,6 +1,6 @@@
  #include "timer.qh"
  
- #include <client/autocvars.qh>
- #include <client/hud/hud.qh>
+ #include <client/draw.qh>
  #include <client/view.qh>
  
  // Timer (#5)
@@@ -37,14 -36,10 +36,14 @@@ void HUD_Timer(
                mySize -= '2 2 0' * panel_bg_padding;
        }
  
 -      string timer;
 -      float timelimit, timeleft, minutesLeft;
 +      string timer_sub = "";
 +      bool game_timeout;
 +      float timelimit, timeleft, minutesLeft, overtimes, timeout_last;
  
        timelimit = STAT(TIMELIMIT);
 +      overtimes = STAT(OVERTIMESADDED);
 +      game_timeout = STAT(GAME_TIMEOUT);
 +      timeout_last = STAT(TIMEOUT_LAST);
  
        timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time);
        timeleft = ceil(timeleft);
                timer_color = '1 0 0'; //red
  
        if (intermission_time) {
 -              timer = seconds_tostring(max(0, floor(intermission_time - STAT(GAMESTARTTIME))));
 -      } else if (warmup_stage && warmup_timeleft >= 60) {
 -              timer = _("WARMUP");
 -      } else if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
 -              if (time < STAT(GAMESTARTTIME))
 -                      timer = seconds_tostring(0); //while restart is still active, show 00:00
 +              timer = max(0, floor(intermission_time - STAT(GAMESTARTTIME)));
 +              timer_sub = "Intermission";
 +      //} else if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
 +      } else if (game_timeout) {
 +              if(autocvar_hud_panel_timer_increment)
 +                      timer = max(0, floor(timeout_last - STAT(GAMESTARTTIME)));
                else
 -                      timer = seconds_tostring(floor(time - STAT(GAMESTARTTIME)));
 -      } else {
 -              if(warmup_stage)
 -                      timer = seconds_tostring(warmup_timeleft);
 +                      timer = ceil(max(0, timelimit * 60 + STAT(GAMESTARTTIME) - timeout_last));
 +              timer_sub = "Timeout";
 +      } else if (autocvar_hud_panel_timer_increment || timelimit == 0) {
 +              // Time elapsed timer
 +              if((warmup_stage && warmup_timeleft <= 0) || time < STAT(GAMESTARTTIME))
 +                      timer = 0;
                else
 -                      timer = seconds_tostring(timeleft);
 +                      timer = floor(time - STAT(GAMESTARTTIME));
 +      } else {
 +              // Time left timer
 +              if(warmup_stage) {
 +                      if(warmup_timeleft <= 0)
 +                              timer = floor(timelimit * 60);
 +                      else
 +                              timer = warmup_timeleft;
 +              } else {
 +                      if (time < STAT(GAMESTARTTIME))
 +                              timer = floor(timelimit * 60);
 +                      //else if (overtimes > 0)
 +                      //      timer = floor(time - STAT(OVERTIMESTARTTIME));
 +                      else
 +                              timer = timeleft;
 +              }
 +      }
 +      
 +      if(warmup_stage)
 +              timer_sub = "Warmup";
 +      else if(overtimes == 1)
 +              timer_sub = "Overtime";
 +      else if (overtimes > 1)
 +              timer_sub = sprintf("Overtime #%d", overtimes);
 +      
 +      drawstring_aspect(pos, seconds_tostring(timer), mySize, timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
 +      
 +      if(timer_sub != "") {
 +              pos.y += mySize.y;
 +              mySize.y = mySize.y / 2;
 +              drawstring_aspect(pos, timer_sub, mySize, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL);
        }
 -
 -      drawstring_aspect(pos, timer, mySize, timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
  
        draw_endBoldFont();
  }
index 014905ec834a67b510cde141598fd703423598ee,7ac8b8dae6bf20cc8da807fbba6ef7733dff874d..3374e2499c8371c5830d8de7e31746e7579b356c
@@@ -1,6 -1,5 +1,5 @@@
  #include "weapons.qh"
  
- #include <client/autocvars.qh>
  #include <client/draw.qh>
  #include <client/view.qh>
  #include <common/wepent.qh>
@@@ -119,8 -118,6 +118,8 @@@ string cl_weaponpriority_old
  bool weapons_orderbyimpulse_old;
  void HUD_Weapons()
  {
 +      if(spectatee_status && teamplay) return; // z411
 +      
        // declarations
        WepSet weapons_stat = WepSet_GetFromStat();
        int i;
                }
  
                // draw the weapon accuracy
 -              if(autocvar_hud_panel_weapons_accuracy)
 +              /* z411 if(autocvar_hud_panel_weapons_accuracy)
                {
                        float panel_weapon_accuracy = weapon_accuracy[it.m_id-WEP_FIRST];
                        if(panel_weapon_accuracy >= 0)
                                color = Accuracy_GetColor(panel_weapon_accuracy);
                                drawpic_aspect_skin(weapon_pos, "weapon_accuracy", weapon_size, color, panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
 -              }
 +              }*/
  
                vector weapon_size_real = noncurrent_size;
                float weapon_alpha_real = noncurrent_alpha;
diff --combined qcsrc/client/main.qh
index 7fae5ff9bc8d88a67a1cc58f9d72a4a1131d26fa,83417c08d9c59ecd7a54c493f8c1bc40ec999d7f..90fc6b63694bc794b0719268ac578c9c5c1b460b
@@@ -2,11 -2,24 +2,28 @@@
  
  #include <common/constants.qh>
  #include <common/weapons/_all.qh>
 +#include <common/items/inventory.qh>
 +
 +// z411
 +string hostname_full;
  
+ bool autocvar_cl_db_saveasdump;
+ bool autocvar_cl_spawn_event_particles;
+ bool autocvar_cl_spawn_event_sound = 1;
+ // float autocvar_cl_spawn_point_model;
+ bool autocvar_cl_spawn_point_particles;
+ float autocvar_cl_spawn_point_dist_max = 1200;
+ bool autocvar_cl_unpress_zoom_on_spawn = true;
+ bool autocvar_cl_unpress_zoom_on_death = true;
+ bool autocvar_cl_unpress_zoom_on_weapon_switch = true;
+ bool autocvar_cl_unpress_attack_on_weapon_switch = false;
+ bool autocvar_hud_showbinds;
+ bool autocvar_hud_showbinds_limit;
+ bool autocvar__hud_showbinds_reload;
+ bool autocvar_developer_csqcentities;
+ bool autocvar_cl_race_cptimes_onlyself; // TODO: move to race gamemode
+ bool autocvar_cl_race_cptimes_showself = false;
  // Map coordinate base calculations need these
  vector mi_center;
  vector mi_scale;
@@@ -141,15 -154,8 +158,15 @@@ string GetSpeedUnit(int speed_unit)
  .int enttype; // entity type sent from server
  .int sv_entnum; // entity number sent from server
  
 +// z411 accuracy info
 +.float accuracy_frags[REGISTRY_MAX(Weapons)];
 +.float accuracy_hit[REGISTRY_MAX(Weapons)];
 +.float accuracy_cnt_hit[REGISTRY_MAX(Weapons)];
 +.float accuracy_cnt_fired[REGISTRY_MAX(Weapons)];
 +
  .int team;
  .int team_size;
 +.int countrycode;
  
  int binddb;
  
diff --combined qcsrc/client/view.qc
index 55f7feb96a1b9dda1c46418eda61a83837286ee5,c3a93cd052dac5aec44f354521596e826a33a9df..b3d35ab3f23ea298fe4b000d1dd5b44d62ee2606
@@@ -1,7 -1,6 +1,6 @@@
  #include "view.qh"
  
  #include <client/announcer.qh>
- #include <client/autocvars.qh>
  #include <client/csqcmodel_hooks.qh>
  #include <client/draw.qh>
  #include <client/hud/_mod.qh>
@@@ -852,7 -851,7 +851,7 @@@ void HitSound(
        float kill_time = STAT(KILL_TIME);
        if (COMPARE_INCREASING(kill_time, kill_time_prev) > autocvar_cl_hitsound_antispam_time)
        {
 -              sound(NULL, CH_INFO, SND_KILL, VOL_BASE, ATTN_NONE);
 +              sound(NULL, CH_INFO, SND_KILL, VOL_BASE * 1.15, ATTN_NONE);
                kill_time_prev = kill_time;
        }
  }
@@@ -945,9 -944,11 +944,11 @@@ void HUD_Draw(entity this
        else if(STAT(FROZEN))
        {
                vector col = '0.25 0.90 1';
-               if(STAT(REVIVE_PROGRESS))
-                       col += vec3(STAT(REVIVE_PROGRESS), -STAT(REVIVE_PROGRESS), -STAT(REVIVE_PROGRESS));
-               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+               float col_fade = max(0, STAT(REVIVE_PROGRESS) * 2 - 1);
+               float alpha_fade = 0.3 + 0.7 * (1 - max(0, STAT(REVIVE_PROGRESS) * 4 - 3));
+               if(col_fade)
+                       col += vec3(col_fade, -col_fade, -col_fade);
+               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha * alpha_fade, DRAWFLAG_ADDITIVE);
        }
  
        HUD_Scale_Enable();
        UpdateDamage();
        HUD_Crosshair(this);
        HitSound();
 +      Local_Notification_Queue_Process();
  }
  
  void ViewLocation_Mouse()
@@@ -1224,12 -1224,6 +1225,12 @@@ void HUD_Damage(
                        myhealth_flash += autocvar_hud_damage_fade_rate * frametime; // dead
                }
        }
 +      
 +      if(myhealth_prev > 1 && myhealth <= 0 && !intermission)
 +      {
 +              // Just died
 +              sound(NULL, CH_INFO, SND_DEATH, VOL_BASE, ATTN_NONE);
 +      }
  
        if(spectatee_status == -1 || intermission)
        {
index 6e7027de748f63dd45ef8d4f7569a154428612ce,586d7eb17eb8e5fa025ef0fd70adef0b4095f90b..f55c3585f7de941397ca677bbd129160e9efba82
@@@ -1,6 -1,7 +1,3 @@@
  #pragma once
  
- //void HUD_Mod_CA(vector myPos, vector mySize);
- //void HUD_Mod_CA_Draw(vector myPos, vector mySize, int layout);
- //void HUD_Mod_CA_Export(int fh);
 -int autocvar_hud_panel_modicons_ca_layout;
 -
 -void HUD_Mod_CA(vector myPos, vector mySize);
 -void HUD_Mod_CA_Draw(vector myPos, vector mySize, int layout);
 -void HUD_Mod_CA_Export(int fh);
 +int HUD_Scores_CA(int team);
index b464e50573eb77b93531bf01b05d2dbaad504fce,75bfeefd483541c7c63e88edde625730b31d2848..3f59c932d39b02caf58f2abac65bdd9246f0a7da
@@@ -1,3 -1,5 +1,2 @@@
  #pragma once
  
- //void HUD_Mod_FreezeTag_Export(int fh);
 -int autocvar_hud_panel_modicons_freezetag_layout;
 -
 -void HUD_Mod_FreezeTag_Export(int fh);
index e7cbc662fe90bdc29017ecb6267c15bbd776f7d3,ea00927abd908ae3856092f51b8d81d4ab80301b..fee45755df403349017ef28d1163f86059885f72
@@@ -106,35 -106,18 +106,36 @@@ int freezetag_getWinnerTeam(
  void nades_Clear(entity);
  void nades_GiveBonus(entity player, float score);
  
 +entity freezetag_LastPlayer(float tm)
 +{
 +      entity last_pl = NULL;
 +      FOREACH_CLIENT(IS_PLAYER(it) && it.team == tm, {
 +              if (STAT(FROZEN, it) != FROZEN_NORMAL && GetResource(it, RES_HEALTH) >= 1)
 +              {
 +                      if (!last_pl)
 +                              last_pl = it;
 +                      else
 +                              return NULL;
 +              }
 +      });
 +      return last_pl;
 +}
 +
  bool freezetag_CheckWinner()
  {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
 +              Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_ROUND_OVER);
 +              
                FOREACH_CLIENT(IS_PLAYER(it), {
                        it.freezetag_frozen_timeout = 0;
+                       it.freezetag_revive_time = 0;
                        nades_Clear(it);
                });
 -              game_stopped = true;
 +              if(autocvar_g_freezetag_round_stop)
 +                      game_stopped = true;
                round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
                return true;
        }
        int winner_team = freezetag_getWinnerTeam();
        if(winner_team > 0)
        {
 -              Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
 -              Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
 +              entity last_pl = freezetag_LastPlayer(winner_team);
 +              if(last_pl) {
 +                      Give_Medal(last_pl, DEFENSE);
 +              }
 +      
 +              Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_SCORES));
 +              Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_SCORES));
 +              if(fragsleft > 1) Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, APP_TEAM_NUM(winner_team, ANNCE_ROUND_TEAM_WIN));
                TeamScore_AddToTeam(winner_team, ST_FT_ROUNDS, +1);
        }
        else if(winner_team == -1)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
 +              Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_ROUND_TIED);
        }
  
        FOREACH_CLIENT(IS_PLAYER(it), {
                it.freezetag_frozen_timeout = 0;
+               it.freezetag_revive_time = 0;
                nades_Clear(it);
        });
  
 -      game_stopped = true;
 +      if(autocvar_g_freezetag_round_stop)
 +              game_stopped = true;
        round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
        return true;
  }
@@@ -196,10 -172,8 +198,10 @@@ void freezetag_LastPlayerForTeam_Notify
        if(round_handler_IsRoundStarted())
        {
                entity pl = freezetag_LastPlayerForTeam(this);
 -              if(pl)
 +              if(pl) {
                        Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
 +                      Send_Notification(NOTIF_ONE, pl, MSG_ANNCE, ANNCE_ALONE);
 +              }
        }
  }
  
@@@ -207,7 -181,7 +209,7 @@@ void freezetag_Add_Score(entity targ, e
  {
        if(attacker == targ)
        {
-               // you froze your own dumb targ
+               // you froze your own dumb self
                // counted as "suicide" already
                GameRules_scoring_add(targ, SCORE, -1);
        }
@@@ -227,7 -201,8 +229,8 @@@ void freezetag_Freeze(entity targ, enti
        if(STAT(FROZEN, targ))
                return;
  
-       if(autocvar_g_freezetag_frozen_maxtime > 0)
+       targ.freezetag_frozen_time = time;
+       if (autocvar_g_freezetag_revive_auto && autocvar_g_freezetag_frozen_maxtime > 0)
                targ.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
  
        Freeze(targ, 0, FROZEN_NORMAL, true);
@@@ -465,14 -440,9 +468,14 @@@ MUTATOR_HOOKFUNCTION(ft, reset_map_play
  {
        FOREACH_CLIENT(IS_PLAYER(it), {
                CS(it).killcount = 0;
 -              it.freezetag_revive_time = 0;
 -              it.freezetag_frozen_timeout = -1;
 -              PutClientInServer(it);
 +              
 +              if(autocvar_g_freezetag_round_respawn) {
 +                      it.freezetag_frozen_timeout = -1;
 +                      PutClientInServer(it);
 +              } else {
 +                      ResetPlayerResources(it);
 +              }
 +              
                it.freezetag_frozen_timeout = 0;
        });
        freezetag_count_alive_players();
@@@ -489,15 -459,33 +492,39 @@@ MUTATOR_HOOKFUNCTION(ft, Unfreeze
  {
        entity targ = M_ARGV(0, entity);
        targ.freezetag_frozen_time = 0;
 +      
 +      if(autocvar_g_freezetag_revive_respawn) {
 +              targ.freezetag_frozen_timeout = -1;
 +              PutClientInServer(targ);
 +      }
 +      
        targ.freezetag_frozen_timeout = 0;
  }
  
+ MUTATOR_HOOKFUNCTION(ft, Damage_Calculate)
+ {
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       //float frag_deathtype = M_ARGV(3, float);
+       //float frag_damage = M_ARGV(4, float);
+       vector frag_force = M_ARGV(6, vector);
+       if (STAT(FROZEN, frag_target) == FROZEN_NORMAL && autocvar_g_freezetag_revive_auto_reducible
+               && autocvar_g_freezetag_frozen_maxtime > 0 && autocvar_g_freezetag_revive_auto)
+       {
+               float t = 0;
+               if ((autocvar_g_freezetag_revive_auto_reducible < 0 || DIFF_TEAM(frag_attacker, frag_target))
+                       && frag_target.freezetag_frozen_timeout > time)
+               {
+                       if (fabs(autocvar_g_freezetag_revive_auto_reducible) == 1)
+                               t = vlen(frag_force) * autocvar_g_freezetag_revive_auto_reducible_forcefactor;
+                       frag_target.freezetag_frozen_timeout -= t;
+                       if (frag_target.freezetag_frozen_timeout < time)
+                               frag_target.freezetag_frozen_timeout = time;
+               }
+       }
+ }
  #ifdef IS_REVIVING
        #undef IS_REVIVING
  #endif
@@@ -530,6 -518,15 +557,15 @@@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink
        int n = 0;
        vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
        FOREACH_CLIENT(IS_PLAYER(it) && IS_REVIVING(player, it, revive_extra_size), {
+               if (autocvar_g_freezetag_revive_time_to_score > 0 && STAT(FROZEN, player) == FROZEN_NORMAL)
+               {
+                       it.freezetag_revive_time += frametime / autocvar_g_freezetag_revive_time_to_score;
+                       while (it.freezetag_revive_time > 1)
+                       {
+                               GameRules_scoring_add(it, SCORE, +1);
+                               it.freezetag_revive_time -= 1;
+                       }
+               }
                if (reviving_players_last)
                        reviving_players_last.chain = it;
                reviving_players_last = it;
        if (!n && player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
                n = -1;
  
+       float base_progress = 0;
+       if  (STAT(FROZEN, player) == FROZEN_NORMAL && autocvar_g_freezetag_revive_auto
+               && autocvar_g_freezetag_frozen_maxtime > 0 && autocvar_g_freezetag_revive_auto_progress)
+       {
+               // NOTE if auto-revival is in progress, manual revive speed is reduced so that it always takes the same amount of time
+               base_progress = bound(0, (1 - (player.freezetag_frozen_timeout - time) / autocvar_g_freezetag_frozen_maxtime), 1);
+       }
        if (!n) // no teammate nearby
        {
+               float clearspeed = autocvar_g_freezetag_revive_clearspeed;
+               if (autocvar_g_freezetag_revive_time_to_score > 0)
+                       clearspeed = 0; // prevent stacking points by entering and exiting the revival zone many times
                if (STAT(FROZEN, player) == FROZEN_NORMAL)
-               {
-                       STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
-                       SetResourceExplicit(player, RES_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
-               }
+                       STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) - frametime * clearspeed * (1 - base_progress), 1);
                else if (!STAT(FROZEN, player))
-                       STAT(REVIVE_PROGRESS, player) = 0; // thawing nobody
+                       STAT(REVIVE_PROGRESS, player) = base_progress; // thawing nobody
        }
        else if (STAT(FROZEN, player) == FROZEN_NORMAL) // OK, there is at least one teammate reviving us
        {
-               STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               SetResourceExplicit(player, RES_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
+               STAT(REVIVE_PROGRESS, player) = bound(base_progress, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed * (1 - base_progress)), 1);
  
                if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
+                       float frozen_time = time - player.freezetag_frozen_time;
                        Unfreeze(player, false);
+                       SetResourceExplicit(player, RES_HEALTH, ((warmup_stage) ? warmup_start_health : start_health));
                        freezetag_count_alive_players();
  
                        if(n == -1)
                        {
-                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, autocvar_g_freezetag_frozen_maxtime);
+                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, frozen_time);
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, frozen_time);
                                return true;
                        }
  
                        Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, first.netname);
                        Send_Notification(NOTIF_ONE, first, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED, player.netname, first.netname);
 +                      Give_Medal(first, ASSIST);
                }
  
                for(entity it = reviving_players_first; it; it = it.chain)
                        STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
        }
  
+       if (STAT(FROZEN, player) == FROZEN_NORMAL)
+       {
+               entity player_wp = player.waypointsprite_attached;
+               if (n > 0 || (n == 0 && STAT(REVIVE_PROGRESS, player) > 0.95))
+               {
+                       WaypointSprite_UpdateSprites(player_wp, WP_Reviving, WP_Null, WP_Null);
+                       WaypointSprite_UpdateTeamRadar(player_wp, RADARICON_WAYPOINT, WP_REVIVING_COLOR);
+               }
+               else
+               {
+                       WaypointSprite_UpdateSprites(player_wp, WP_Frozen, WP_Null, WP_Null);
+                       WaypointSprite_UpdateTeamRadar(player_wp, RADARICON_WAYPOINT, WP_FROZEN_COLOR);
+               }
+               WaypointSprite_UpdateMaxHealth(player_wp, 1);
+               WaypointSprite_UpdateHealth(player_wp, STAT(REVIVE_PROGRESS, player));
+       }
        return true;
  }
  
index 91e783c78952b28dbac99ffef0036bc3e6aabdce,4c88b20de448ebafc0d8aa6195e4da21e0404c2a..00082fd618ce9c2b6afc3f29b348539020bfc6ed
@@@ -8,9 -8,6 +8,9 @@@ int autocvar_g_freezetag_point_leadlimi
  bool autocvar_g_freezetag_team_spawns;
  string autocvar_g_freezetag_weaponarena = "most_available";
  
 +bool autocvar_g_freezetag_round_respawn;
 +bool autocvar_g_freezetag_round_stop;
 +
  const int ST_FT_ROUNDS = 1;
  
  void freezetag_Initialize();
@@@ -30,14 -27,19 +30,20 @@@ REGISTER_MUTATOR(ft, false
        return 0;
  }
  
+ .float freezetag_revive_time;
  .float freezetag_frozen_time;
  .float freezetag_frozen_timeout;
  const float ICE_MAX_ALPHA = 1;
  const float ICE_MIN_ALPHA = 0.1;
  float freezetag_teams;
  
+ bool autocvar_g_freezetag_revive_auto = 1;
+ int autocvar_g_freezetag_revive_auto_progress = 1;
+ int autocvar_g_freezetag_revive_auto_reducible;
+ float autocvar_g_freezetag_revive_auto_reducible_forcefactor;
  float autocvar_g_freezetag_revive_extra_size;
  float autocvar_g_freezetag_revive_speed;
+ float autocvar_g_freezetag_revive_time_to_score = 1.5;
  bool autocvar_g_freezetag_revive_nade;
  float autocvar_g_freezetag_revive_nade_health;
 +bool autocvar_g_freezetag_revive_respawn;
diff --combined qcsrc/common/mapinfo.qh
index 2f0fc1be093dd1c819023e5983caf93b98363981,be1a4ef7c686dd8bb7861b8edb764ff4cbac3c3f..7657d755932fc6b25bb13872f37c78c0f62b4854
@@@ -21,6 -21,7 +21,7 @@@ const int GAMETYPE_FLAG_USEPOINT
  const int GAMETYPE_FLAG_PREFERRED       = BIT(2); // preferred (when available) in random selections
  const int GAMETYPE_FLAG_PRIORITY        = BIT(3); // priority selection when preferred gametype isn't available in random selections
  const int GAMETYPE_FLAG_HIDELIMITS      = BIT(4); // don't display a score limit needed for winning the match in the scoreboard
+ const int GAMETYPE_FLAG_WEAPONARENA     = BIT(5); // gametype has a forced weapon arena, weapon arena mutators should disable themselves when this is set
  
  int MAPINFO_TYPE_ALL;
  .int m_flags;
@@@ -41,6 -42,8 +42,8 @@@ CLASS(Gametype, Object
      ATTRIB(Gametype, frags, bool, true);
      /** should this gametype display a score limit in the scoreboard? */
      ATTRIB(Gametype, m_hidelimits, bool, false);
+     /** does this gametype enforce its own weapon arena? */
+     ATTRIB(Gametype, m_weaponarena, bool, false);
      /** game type defaults */
      ATTRIB(Gametype, model2, string);
      /** game type description */
      /** game type priority in random selections */
      ATTRIB(Gametype, m_priority, int, 0);
  #ifdef CSQC
 -    ATTRIB(Gametype, m_modicons, void(vector pos, vector mySize));
 -    ATTRIB(Gametype, m_modicons_reset, void());
 -    ATTRIB(Gametype, m_modicons_export, void(int fh));
 +    //ATTRIB(Gametype, m_modicons, void(vector pos, vector mySize));
 +    //ATTRIB(Gametype, m_modicons_reset, void());
 +    //ATTRIB(Gametype, m_modicons_export, void(int fh));
 +      ATTRIB(Gametype, m_modscores, int(int team));
  #endif
  
      /** DO NOT USE, this is compatibility for legacy maps! */
          this.frags = (gflags & GAMETYPE_FLAG_USEPOINTS);
          this.m_priority = ((gflags & GAMETYPE_FLAG_PREFERRED) ? 2 : ((gflags & GAMETYPE_FLAG_PRIORITY) ? 1 : 0));
          this.m_hidelimits = (gflags & GAMETYPE_FLAG_HIDELIMITS);
+         this.m_weaponarena = (gflags & GAMETYPE_FLAG_WEAPONARENA);
  
          // same as `1 << m_id`
          MAPINFO_TYPE_ALL |= this.items = this.m_flags = (MAPINFO_TYPE_ALL + 1);
index 996f9603c88e35fe52b0a1155b6b9ff2dc747511,0ce51f21aca47354cfdaf45d5ddda9d557c13a9b..b8161223a3aa9247cb97f0b57ce28e324d766684
@@@ -6,6 -6,7 +6,7 @@@
  #include <common/mapobjects/teleporters.qh>
  #include <common/mapobjects/triggers.qh>
  #include <common/monsters/all.qh>
+ #include <common/mutators/mutator/nades/nades.qh>
  #include <common/physics/movelib.qh>
  #include <common/stats.qh>
  #include <common/teams.qh>
@@@ -17,9 -18,9 +18,9 @@@
  #include <common/weapons/_mod.qh>
  #include <lib/csqcmodel/sv_model.qh>
  #include <lib/warpzone/common.qh>
- #include <server/autocvars.qh>
  #include <server/campaign.qh>
  #include <server/cheats.qh>
+ #include <server/client.qh>
  #include <server/command/_mod.qh>
  #include <server/damage.qh>
  #include <server/items/items.qh>
@@@ -30,8 -31,8 +31,8 @@@
  
  void monsters_setstatus(entity this)
  {
 -      STAT(MONSTERS_TOTAL, this) = monsters_total;
 -      STAT(MONSTERS_KILLED, this) = monsters_killed;
 +      //STAT(MONSTERS_TOTAL, this) = monsters_total;
 +      //STAT(MONSTERS_KILLED, this) = monsters_killed;
  }
  
  void monster_dropitem(entity this, entity attacker)
index fbaa9655e65c03c191bc04561e9a33f16425a073,66cd9007216fc9febac289c4bf115434b57afa52..8a88007900a8c0d6eddf872c22979e91ec29a527
@@@ -1,22 -1,10 +1,10 @@@
  #include "sv_buffs.qh"
  
  #include <common/mapobjects/target/music.qh>
+ #include <common/mutators/mutator/instagib/_mod.qh>
  #include <common/gamemodes/_mod.qh>
  #include <server/items/items.qh>
  
- void buffs_DelayedInit(entity this);
- AUTOCVAR(g_buffs, int, -1, "Enable buffs, -1: enabled but no auto location or replacing powerups, 1: enabled and can replace them");
- REGISTER_MUTATOR(buffs, autocvar_g_buffs)
- {
-       MUTATOR_ONADD
-       {
-               if(autocvar_g_buffs > 0)
-                       InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
-       }
- }
  bool buffs_BuffModel_Customize(entity this, entity client)
  {
        entity player = WaypointSprite_getviewentity(client);
@@@ -121,7 -109,7 +109,7 @@@ void buff_SetCooldown(entity this, floa
  
  void buff_Respawn(entity this)
  {
 -      if(game_stopped) return;
 +      if(game_stopped || game_timeout) return;
  
        vector oldbufforigin = this.origin;
        this.velocity = '0 0 200';
  
  void buff_Touch(entity this, entity toucher)
  {
 -      if(game_stopped) return;
 +      if(game_stopped || game_timeout) return;
  
        if(ITEM_TOUCH_NEEDKILL())
        {
@@@ -271,7 -259,7 +259,7 @@@ void buff_Think(entity this
                this.oldbuffs = STAT(BUFFS, this);
        }
  
 -      if(!game_stopped)
 +      if(!game_stopped && !game_timeout)
        if((round_handler_IsActive() && round_handler_IsRoundStarted()) || time >= game_starttime)
        if(!this.buff_activetime_updated)
        {
        }
  
        if(this.buff_activetime)
 -      if(!game_stopped)
 +      if(!game_stopped && !game_timeout)
        if((round_handler_IsActive() && round_handler_IsRoundStarted()) || time >= game_starttime)
        {
                this.buff_activetime = max(0, this.buff_activetime - frametime);
@@@ -443,25 -431,6 +431,6 @@@ void buff_Vengeance_DelayedDamage(entit
        return;
  }
  
- // note: only really useful in teamplay
- void buff_Medic_Heal(entity this)
- {
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this && vdist(it.origin - this.origin, <=, autocvar_g_buffs_medic_heal_range),
-       {
-               if (DIFF_TEAM(it, this))
-               {
-                       continue;
-               }
-               float hp = GetResource(it, RES_HEALTH);
-               if(hp >= autocvar_g_balance_health_regenstable)
-               {
-                       continue;
-               }
-               Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
-               SetResource(it, RES_HEALTH, bound(0, hp + autocvar_g_buffs_medic_heal_amount, autocvar_g_balance_health_regenstable));
-       });
- }
  float buff_Inferno_CalculateTime(float damg, float offset_x, float offset_y, float intersect_x, float intersect_y, float base)
  {
        return offset_y + (intersect_y - offset_y) * logn(((damg - offset_x) * ((base - 1) / intersect_x)) + 1, base);
@@@ -557,32 -526,28 +526,28 @@@ MUTATOR_HOOKFUNCTION(buffs, Damage_Calc
                Fire_AddDamage(frag_target, frag_attacker, (frag_damage * autocvar_g_buffs_inferno_damagemultiplier), btime, DEATH_BUFF.m_id);
        }
  
-       // this... is ridiculous (TODO: fix!)
-       if(STAT(BUFFS, frag_attacker) & BUFF_VAMPIRE.m_itemid)
-       if(!frag_target.vehicle)
-       if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
-       if(!IS_DEAD(frag_target))
-       if(IS_PLAYER(frag_target) || IS_MONSTER(frag_target))
-       if(frag_attacker != frag_target)
-       if(!STAT(FROZEN, frag_target))
-       if(frag_target.takedamage)
-       if(DIFF_TEAM(frag_attacker, frag_target))
-       {
-               float amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
-                       GetResource(frag_target, RES_HEALTH));
-               GiveResourceWithLimit(frag_attacker, RES_HEALTH, amount, g_pickup_healthsmall_max);
-               if (GetResource(frag_target, RES_ARMOR))
-               {
-                       amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
-                               GetResource(frag_target, RES_ARMOR));
-                       GiveResourceWithLimit(frag_attacker, RES_ARMOR, amount, g_pickup_armorsmall_max);
-               }
-       }
        M_ARGV(4, float) = frag_damage;
        M_ARGV(6, vector) = frag_force;
  }
  
+ MUTATOR_HOOKFUNCTION(buffs, PlayerDamage_SplitHealthArmor)
+ {
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       if(!(STAT(BUFFS, frag_attacker) & BUFF_VAMPIRE.m_itemid))
+               return;
+       float health_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
+       if(time >= frag_target.spawnshieldtime &&
+               frag_target != frag_attacker &&
+               IS_PLAYER(frag_attacker) &&
+               !IS_DEAD(frag_target) && !STAT(FROZEN, frag_target))
+       {
+               GiveResource(frag_attacker, RES_HEALTH,
+                       autocvar_g_buffs_vampire_damage_steal * health_take);
+       }
+ }
  MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
  {
        entity player = M_ARGV(0, entity);
@@@ -665,7 -630,7 +630,7 @@@ MUTATOR_HOOKFUNCTION(buffs, PlayerUseKe
  
  MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
  {
 -      if(MUTATOR_RETURNVALUE || game_stopped) return;
 +      if(MUTATOR_RETURNVALUE || game_stopped || game_timeout) return;
        entity player = M_ARGV(0, entity);
  
        if(STAT(BUFFS, player) & BUFF_SWAPPER.m_itemid)
@@@ -821,7 -786,7 +786,7 @@@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreTh
  {
        entity player = M_ARGV(0, entity);
  
 -      if(game_stopped || IS_DEAD(player) || frametime || !IS_PLAYER(player)) return;
 +      if(game_stopped || game_timeout || IS_DEAD(player) || frametime || !IS_PLAYER(player)) return;
  
        if(STAT(BUFFS, player) & BUFF_FLIGHT.m_itemid)
        {
        if((STAT(BUFFS, player) & BUFF_INVISIBLE.m_itemid) && (player.oldbuffs & BUFF_INVISIBLE.m_itemid))
                player.alpha = ((autocvar_g_buffs_invisible_alpha) ? autocvar_g_buffs_invisible_alpha : -1); // powerups reset alpha, so we must enforce this (TODO)
  
-       if(STAT(BUFFS, player) & BUFF_MEDIC.m_itemid)
-       if(time >= player.buff_medic_healtime)
-       {
-               buff_Medic_Heal(player);
-               player.buff_medic_healtime = time + autocvar_g_buffs_medic_heal_delay;
-       }
  #define BUFF_ONADD(b) if ( (STAT(BUFFS, player) & (b).m_itemid) && !(player.oldbuffs & (b).m_itemid))
  #define BUFF_ONREM(b) if (!(STAT(BUFFS, player) & (b).m_itemid) &&  (player.oldbuffs & (b).m_itemid))
  
@@@ -1069,3 -1027,10 +1027,10 @@@ void buffs_DelayedInit(entity this
                }
        }
  }
+ void buffs_Initialize()
+ {
+       // if buffs are above 0, allow random spawning
+       if(autocvar_g_buffs > 0 && autocvar_g_buffs_spawn_count > 0)
+               InitializeEntity(NULL, buffs_DelayedInit, INITPRIO_FINDTARGET);
+ }
index 32f9fd0b7f64a97bf6749fb7db98772f18b9ce19,d692d73c8df82aa1f5463f31e03e50b20aeb8901..70818b856a1d165f09399bc1e85f171c8c49235b
  #define N___NEVER 0
  #define N_GNTLOFF 1
  #define N__ALWAYS 2
 +#define ANNCE_DEFTIME 2
  
 -#define MULTITEAM_ANNCE(prefix, defaultvalue, sound, channel, volume, position) \
 +#define MULTITEAM_ANNCE(prefix, defaultvalue, sound, channel, volume, position, queuetime) \
      NOTIF_ADD_AUTOCVAR(ANNCE_##prefix, defaultvalue) \
 -    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_1)), channel, volume, position) \
 -    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_2)), channel, volume, position) \
 -    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_3)), channel, volume, position) \
 -    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_4)), channel, volume, position)
 +    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_1)), channel, volume, position, queuetime) \
 +    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_2)), channel, volume, position, queuetime) \
 +    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_3)), channel, volume, position, queuetime) \
 +    MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_4)), channel, volume, position, queuetime)
  
  // MSG_ANNCE_NOTIFICATIONS
 -    MSG_ANNCE_NOTIF(ACHIEVEMENT_AIRSHOT,        N_GNTLOFF, "airshot",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(ACHIEVEMENT_AMAZING,        N_GNTLOFF, "amazing",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(ACHIEVEMENT_AWESOME,        N_GNTLOFF, "awesome",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(ACHIEVEMENT_BOTLIKE,        N_GNTLOFF, "botlike",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(ACHIEVEMENT_ELECTROBITCH,   N__ALWAYS, "electrobitch",      CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(ACHIEVEMENT_IMPRESSIVE,     N_GNTLOFF, "impressive",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(ACHIEVEMENT_YODA,           N_GNTLOFF, "yoda",              CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(BEGIN,                      N__ALWAYS, "begin",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(HEADSHOT,                   N__ALWAYS, "headshot",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(KILLSTREAK_03,              N_GNTLOFF, "03kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(KILLSTREAK_05,              N_GNTLOFF, "05kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(KILLSTREAK_10,              N_GNTLOFF, "10kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(KILLSTREAK_15,              N_GNTLOFF, "15kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(KILLSTREAK_20,              N_GNTLOFF, "20kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(KILLSTREAK_25,              N_GNTLOFF, "25kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(KILLSTREAK_30,              N_GNTLOFF, "30kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(INSTAGIB_LASTSECOND,        N_GNTLOFF, "lastsecond",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(INSTAGIB_NARROWLY,          N_GNTLOFF, "narrowly",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(INSTAGIB_TERMINATED,        N_GNTLOFF, "terminated",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(MULTIFRAG,                  N___NEVER, "multifrag",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(NUM_1,                      N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_2,                      N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_3,                      N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_4,                      N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_5,                      N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_6,                      N__ALWAYS, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_7,                      N__ALWAYS, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_8,                      N__ALWAYS, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_9,                      N__ALWAYS, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_10,                     N__ALWAYS, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_1,            N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_2,            N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_3,            N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_4,            N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_5,            N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_6,            N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_7,            N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_8,            N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_9,            N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_GAMESTART_10,           N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(NUM_IDLE_1,                 N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_2,                 N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_3,                 N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_4,                 N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_5,                 N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_6,                 N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_7,                 N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_8,                 N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_9,                 N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_IDLE_10,                N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(NUM_KILL_1,                 N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_2,                 N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_3,                 N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_4,                 N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_5,                 N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_6,                 N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_7,                 N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_8,                 N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_9,                 N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_KILL_10,                N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_1,              N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_2,              N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_3,              N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_4,              N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_5,              N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_6,              N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_7,              N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_8,              N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_9,              N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_RESPAWN_10,             N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_1,           N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_2,           N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_3,           N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_4,           N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_5,           N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_6,           N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_7,           N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_8,           N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_9,           N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_10,          N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(PREPARE,                    N__ALWAYS, "prepareforbattle",  CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(REMAINING_FRAG_1,           N_GNTLOFF, "1fragleft",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(REMAINING_FRAG_2,           N_GNTLOFF, "2fragsleft",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(REMAINING_FRAG_3,           N_GNTLOFF, "3fragsleft",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(REMAINING_MIN_1,            N__ALWAYS, "1minuteremains",    CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(REMAINING_MIN_5,            N__ALWAYS, "5minutesremain",    CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(TIMEOUT,                    N__ALWAYS, "timeoutcalled",     CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -
 -    MSG_ANNCE_NOTIF(VOTE_ACCEPT,                N__ALWAYS, "voteaccept",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(VOTE_CALL,                  N__ALWAYS, "votecall",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 -    MSG_ANNCE_NOTIF(VOTE_FAIL,                  N__ALWAYS, "votefail",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
 +    MSG_ANNCE_NOTIF(ACHIEVEMENT_AIRSHOT,        N_GNTLOFF, "airshot",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(ACHIEVEMENT_AMAZING,        N_GNTLOFF, "amazing",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ACHIEVEMENT_ASSIST,         N_GNTLOFF, "assist",            CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ACHIEVEMENT_AWESOME,        N_GNTLOFF, "awesome",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ACHIEVEMENT_DAMAGE,         N_GNTLOFF, "damage",            CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ACHIEVEMENT_DEFENSE,        N_GNTLOFF, "defense",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ACHIEVEMENT_EXCELLENT,      N_GNTLOFF, "excellent",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(ACHIEVEMENT_BOTLIKE,        N_GNTLOFF, "botlike",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(ACHIEVEMENT_ELECTROBITCH,   N__ALWAYS, "electrobitch",      CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(ACHIEVEMENT_IMPRESSIVE,     N_GNTLOFF, "impressive",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(ACHIEVEMENT_YODA,           N_GNTLOFF, "yoda",              CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ACHIEVEMENT_PERFECT,        N_GNTLOFF, "perfect",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ACHIEVEMENT_ACCURACY,       N_GNTLOFF, "accuracy",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +    MSG_ANNCE_NOTIF(BEGIN,                      N__ALWAYS, "begin",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(HEADSHOT,                   N__ALWAYS, "headshot",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(HUMILIATION,                N__ALWAYS, "humiliation",       CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +    MSG_ANNCE_NOTIF(KILLSTREAK_03,              N_GNTLOFF, "03kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(KILLSTREAK_05,              N_GNTLOFF, "05kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(KILLSTREAK_10,              N_GNTLOFF, "10kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(KILLSTREAK_15,              N_GNTLOFF, "15kills",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +    MSG_ANNCE_NOTIF(INSTAGIB_LASTSECOND,        N_GNTLOFF, "lastsecond",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(INSTAGIB_NARROWLY,          N_GNTLOFF, "narrowly",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(INSTAGIB_TERMINATED,        N_GNTLOFF, "terminated",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +    MSG_ANNCE_NOTIF(MULTIFRAG,                  N_GNTLOFF, "multifrag",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(FIRSTBLOOD,                 N_GNTLOFF, "firstblood",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +    MSG_ANNCE_NOTIF(NUM_1,                      N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_2,                      N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_3,                      N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_4,                      N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_5,                      N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_6,                      N__ALWAYS, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_7,                      N__ALWAYS, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_8,                      N__ALWAYS, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_9,                      N__ALWAYS, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_10,                     N__ALWAYS, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_1,            N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_2,            N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_3,            N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_4,            N__ALWAYS, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_5,            N__ALWAYS, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_6,            N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_7,            N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_8,            N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_9,            N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_GAMESTART_10,           N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(NUM_IDLE_1,                 N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_2,                 N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_3,                 N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_4,                 N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_5,                 N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_6,                 N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_7,                 N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_8,                 N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_9,                 N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_IDLE_10,                N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(NUM_KILL_1,                 N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_2,                 N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_3,                 N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_4,                 N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_5,                 N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_6,                 N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_7,                 N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_8,                 N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_9,                 N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_KILL_10,                N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_1,              N___NEVER, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_2,              N___NEVER, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_3,              N___NEVER, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_4,              N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_5,              N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_6,              N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_7,              N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_8,              N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_9,              N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_RESPAWN_10,             N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_1,           N__ALWAYS, "1",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_2,           N__ALWAYS, "2",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_3,           N__ALWAYS, "3",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_4,           N___NEVER, "4",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_5,           N___NEVER, "5",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_6,           N___NEVER, "6",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_7,           N___NEVER, "7",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_8,           N___NEVER, "8",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_9,           N___NEVER, "9",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +    MSG_ANNCE_NOTIF(NUM_ROUNDSTART_10,          N___NEVER, "10",                CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(PREPARE,                    N__ALWAYS, "prepareforbattle",  CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +      MSG_ANNCE_NOTIF(PREPARE_TEAM,               N__ALWAYS, "prepareyourteam",   CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(REMAINING_FRAG_1,           N_GNTLOFF, "1fragleft",         CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(REMAINING_FRAG_2,           N_GNTLOFF, "2fragsleft",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(REMAINING_FRAG_3,           N_GNTLOFF, "3fragsleft",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +    MSG_ANNCE_NOTIF(REMAINING_MIN_1,            N__ALWAYS, "1minuteremains",    CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(REMAINING_MIN_5,            N__ALWAYS, "5minutesremain",    CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +    MSG_ANNCE_NOTIF(TIMEOUT,                    N__ALWAYS, "timeoutcalled",     CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +      MSG_ANNCE_NOTIF(OVERTIME,                   N__ALWAYS, "overtime",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(SUDDENDEATH,                N__ALWAYS, "suddendeath",       CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(SUICIDE,                    N_GNTLOFF, "suicide",           CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +      MSG_ANNCE_NOTIF(ACCIDENT,                   N_GNTLOFF, "accident",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, -1)
 +
 +    MSG_ANNCE_NOTIF(VOTE_ACCEPT,                N__ALWAYS, "voteaccept",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(VOTE_CALL,                  N__ALWAYS, "votecall",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +    MSG_ANNCE_NOTIF(VOTE_FAIL,                  N__ALWAYS, "votefail",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      
 +      MSG_ANNCE_NOTIF(LEAD_GAINED,                N__ALWAYS, "leadgained",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(LEAD_LOST,                  N__ALWAYS, "leadlost",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(LEAD_TIED,                  N__ALWAYS, "leadtied",          CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      
 +      MULTITEAM_ANNCE(ROUND_TEAM_WIN,                         N__ALWAYS, "round_win_%s",              CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MULTITEAM_ANNCE(ROUND_TEAM_SCORES,                      N__ALWAYS, "scores_%s",                 CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MULTITEAM_ANNCE(WINS,                                           N__ALWAYS, "wins_%s",                   CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ROUND_OVER,                 N__ALWAYS, "round_over",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ROUND_TIED,                 N__ALWAYS, "round_tied",        CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +      MSG_ANNCE_NOTIF(ALONE,                      N__ALWAYS, "alone",             CH_INFO, VOL_BASEVOICE, ATTEN_NONE, ANNCE_DEFTIME)
 +
 +// MSG_MEDAL_NOTIFICATIONS
 +
 +#define MSG_MEDAL_TIME 2
 +#define MSG_MEDAL_FADE_TIME 0.5
 +#define MSG_MEDAL_SCREEN 10
 +
 +      MSG_MEDAL_NOTIF(AIRSHOT, N__ALWAYS,        "airshot",       ANNCE_ACHIEVEMENT_AIRSHOT)
 +      MSG_MEDAL_NOTIF(ASSIST, N__ALWAYS,         "assist",        ANNCE_ACHIEVEMENT_ASSIST)
 +      MSG_MEDAL_NOTIF(DAMAGE, N__ALWAYS,         "damage",        ANNCE_ACHIEVEMENT_DAMAGE)
 +      MSG_MEDAL_NOTIF(DEFENSE, N__ALWAYS,        "defense",       ANNCE_ACHIEVEMENT_DEFENSE)
 +      MSG_MEDAL_NOTIF(ELECTROBITCH, N__ALWAYS,   "electrobitch",  ANNCE_ACHIEVEMENT_ELECTROBITCH)
 +      MSG_MEDAL_NOTIF(EXCELLENT, N__ALWAYS,      "excellent",     ANNCE_ACHIEVEMENT_EXCELLENT)
 +      MSG_MEDAL_NOTIF(FIRSTBLOOD, N__ALWAYS,     "firstblood",    ANNCE_FIRSTBLOOD)
 +      MSG_MEDAL_NOTIF(HEADSHOT, N__ALWAYS,       "headshot",      ANNCE_HEADSHOT)
 +      MSG_MEDAL_NOTIF(HUMILIATION, N__ALWAYS,    "humiliation",   ANNCE_HUMILIATION)
 +      MSG_MEDAL_NOTIF(IMPRESSIVE, N__ALWAYS,     "impressive",    ANNCE_ACHIEVEMENT_IMPRESSIVE)
 +      MSG_MEDAL_NOTIF(YODA, N__ALWAYS,           "yoda",          ANNCE_ACHIEVEMENT_YODA)
 +      
 +      MSG_MEDAL_NOTIF(PERFECT, N__ALWAYS,        "perfect",       ANNCE_ACHIEVEMENT_PERFECT)
 +      MSG_MEDAL_NOTIF(ACCURACY, N__ALWAYS,       "accuracy",      ANNCE_ACHIEVEMENT_ACCURACY)
 +      
 +      MSG_MEDAL_NOTIF(KILLSTREAK_03, N__ALWAYS, "killstreak_03", ANNCE_KILLSTREAK_03)
 +      MSG_MEDAL_NOTIF(KILLSTREAK_05, N__ALWAYS, "killstreak_05", ANNCE_KILLSTREAK_05)
 +      MSG_MEDAL_NOTIF(KILLSTREAK_10, N__ALWAYS, "killstreak_10", ANNCE_KILLSTREAK_10)
 +      MSG_MEDAL_NOTIF(KILLSTREAK_15, N__ALWAYS, "killstreak_15", ANNCE_KILLSTREAK_15)
 +      
  
  #undef N___NEVER
  #undef N_GNTLOFF
@@@ -410,7 -361,6 +410,7 @@@ string multiteam_info_sprintf(string in
      MSG_INFO_NOTIF(FREEZETAG_SELF,                          N_CONSOLE,  1, 0, "s1", "",         "",     _("^BG%s^K1 froze themself"), "")
  
      MULTITEAM_INFO(ROUND_TEAM_WIN,                          N_CONSOLE,  0, 0, "", "",           "",     _("^TC^TT^BG team wins the round"), "", NAME)
 +      MULTITEAM_INFO(ROUND_TEAM_SCORES,                       N_CONSOLE,  0, 0, "", "",           "",     _("^TC^TT^BG scores"), "", NAME)
      MSG_INFO_NOTIF(ROUND_PLAYER_WIN,                        N_CONSOLE,  1, 0, "s1", "",         "",     _("^BG%s^BG wins the round"), "")
      MSG_INFO_NOTIF(ROUND_TIED,                              N_CONSOLE,  0, 0, "", "",           "",     _("^BGRound tied"), "")
      MSG_INFO_NOTIF(ROUND_OVER,                              N_CONSOLE,  0, 0, "", "",           "",     _("^BGRound over, there's no winner"), "")
      MSG_INFO_NOTIF(POWERUP_STRENGTH,                        N_CONSOLE,  1, 0, "s1", "s1",       "strength",     _("^BG%s^K1 picked up Strength"), "")
  
      MSG_INFO_NOTIF(QUIT_DISCONNECT,                         N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 disconnected"), "")
 +      MSG_INFO_NOTIF(QUIT_KICK,                               N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked"), "")
      MSG_INFO_NOTIF(QUIT_KICK_IDLING,                        N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked for idling"), "")
      MSG_INFO_NOTIF(QUIT_KICK_SPECTATING,                    N_CONSOLE,  0, 0, "", "",           "",             _("^F2You were kicked from the server because you are a spectator and spectators aren't allowed at the moment."), "")
      MSG_INFO_NOTIF(QUIT_KICK_TEAMKILL,                      N_CHATCON,  1, 0, "s1", "",         "",             _("^BG%s^F3 was kicked for excessive teamkilling"), "")
  
      #define MURDER_FRAG             strcat(BOLD_OPERATOR, _("^K3%sYou fragged ^BG%s"))
      #define MURDER_FRAG2            strcat(BOLD_OPERATOR, _("^K3%sYou scored against ^BG%s"))
 +      #define MURDER_FRAG3            strcat(BOLD_OPERATOR, _("^K3%sYou fragged ^BG%s"), "\n", "%s^BG place with %s")
      #define MURDER_FRAGGED          _("^K1%sYou were fragged by ^BG%s")
      #define MURDER_FRAGGED2         _("^K1%sYou were scored against by ^BG%s")
      MSG_CENTER_NOTIF(DEATH_MURDER_FRAG,                   N_ENABLE,  1, 1, "spree_cen s1",               CPID_Null,  "0 0",  MURDER_FRAG,                    MURDER_FRAG2                   )
 +      MSG_CENTER_NOTIF(DEATH_MURDER_DM,                     N_ENABLE,  1, 2, "spree_cen s1 frag_pos f2",   CPID_Null,  "0 0",  MURDER_FRAG3, "")
      MSG_CENTER_NOTIF(DEATH_MURDER_FRAGGED,                N_ENABLE,  1, 1, "spree_cen s1",               CPID_Null,  "0 0",  MURDER_FRAGGED,                 MURDER_FRAGGED2                )
      MSG_CENTER_NOTIF(DEATH_MURDER_FRAGGED_VERBOSE,        N_ENABLE,  1, 4, "spree_cen s1 frag_stats",    CPID_Null,  "0 0",  VERBOSE_MURDER(FRAGGED),        VERBOSE_MURDER(FRAGGED2)       )
      MSG_CENTER_NOTIF(DEATH_MURDER_FRAG_VERBOSE,           N_ENABLE,  1, 2, "spree_cen s1 frag_ping",     CPID_Null,  "0 0",  VERBOSE_MURDER(FRAG),           VERBOSE_MURDER(FRAG2)          )
      MSG_CENTER_NOTIF(FREEZETAG_REVIVE,                  N_ENABLE,    1, 0, "s1",             CPID_Null,              "0 0",  _("^K3You revived ^BG%s"), "")
      MSG_CENTER_NOTIF(FREEZETAG_REVIVE_SELF,             N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^K3You revived yourself"), "")
      MSG_CENTER_NOTIF(FREEZETAG_REVIVED,                 N_ENABLE,    1, 0, "s1",             CPID_Null,              "0 0",  _("^K3You were revived by ^BG%s"), "")
-     MSG_CENTER_NOTIF(FREEZETAG_AUTO_REVIVED,            N_ENABLE,    0, 1, "f1",             CPID_Null,              "0 0",  _("^K3You were automatically revived after %s seconds"), "")
+     MSG_CENTER_NOTIF(FREEZETAG_AUTO_REVIVED,            N_ENABLE,    0, 1, "f1",             CPID_Null,              "0 0",  _("^BGYou were automatically revived after %s seconds"), "")
  
      MSG_CENTER_NOTIF(GENERATOR_UNDERATTACK,             N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^BGThe generator is under attack!"), "")
  
      MULTITEAM_CENTER(ROUND_TEAM_LOSS,                   N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^TC^TT^BG team loses the round"), "", NAME)
      MULTITEAM_CENTER(ROUND_TEAM_WIN,                    N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^TC^TT^BG team wins the round"), "", NAME)
 +      MULTITEAM_CENTER(ROUND_TEAM_SCORES,                 N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^TC^TT^BG scores"), "", NAME)
      MSG_CENTER_NOTIF(ROUND_PLAYER_WIN,                  N_ENABLE,    1, 0, "s1",             CPID_ROUND,             "0 0",  _("^BG%s^BG wins the round"), "")
  
      MSG_CENTER_NOTIF(FREEZETAG_SELF,                    N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^K1You froze yourself"), "")
  
      MSG_CENTER_NOTIF(MISSING_TEAMS,                     N_ENABLE,    0, 1, "missing_teams",  CPID_MISSING_TEAMS,     "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "")
      MSG_CENTER_NOTIF(MISSING_PLAYERS,                   N_ENABLE,    0, 1, "f1",             CPID_MISSING_PLAYERS,   "-1 0", _("^BGWaiting for %s player(s) to join..."), "")
 +      MSG_CENTER_NOTIF(MISSING_READY,                     N_ENABLE,    0, 0, "",               CPID_MISSING_READY,     "-1 0", _("^BGThe match will begin\nwhen more players are ready.\n\nPress ^F2F4^BG to get ready"), "")
  
      MSG_CENTER_NOTIF(INSTAGIB_DOWNGRADE,                N_ENABLE,    0, 0, "",               CPID_INSTAGIB_FINDAMMO, "5 0",  _("^BGYour weapon has been downgraded until you find some ammo!"), "")
      MSG_CENTER_NOTIF(INSTAGIB_FINDAMMO,                 N_ENABLE,    0, 0, "",               CPID_INSTAGIB_FINDAMMO, "1 9",  _("^F4^COUNT^BG left to find some ammo!"), "")
  
      MSG_CENTER_NOTIF(TIMEOUT_BEGINNING,                 N_ENABLE,    0, 1, "",               CPID_TIMEOUT,           "1 f1", _("^F4Timeout begins in ^COUNT"), "")
      MSG_CENTER_NOTIF(TIMEOUT_ENDING,                    N_ENABLE,    0, 1, "",               CPID_TIMEIN,            "1 f1", _("^F4Timeout ends in ^COUNT"), "")
 +      MSG_CENTER_NOTIF(TIMEOUT_ONGOING,                   N_ENABLE,    0, 0, "",               CPID_TIMEIN,            "1 f1", _("^F4Match paused"), "")
  
      MSG_CENTER_NOTIF(JOIN_PREVENT_MINIGAME,             N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^K1Cannot join given minigame session!"), "" )
  
index 2a10b4d4305a4cce770716a46c47fa45be8a88d9,b2e278a18472c7ff498c3abd465d9ee375610bfc..9fb158dbb1391c7b7174aad1ecdf2d1c030f3c95
@@@ -7,7 -7,6 +7,6 @@@
        #include <common/constants.qh>
        #include <common/net_linked.qh>
        #include <common/teams.qh>
-       #include <server/autocvars.qh>
        #include <server/command/getreplies.qh>
        #include <server/mutators/_mod.qh>
        #include <server/world.qh>
@@@ -417,7 -416,6 +416,7 @@@ void Create_Notification_Entity(entity 
                case MSG_CENTER:
                case MSG_MULTI:
                case MSG_CHOICE:
 +              case MSG_MEDAL:
                        break;
                default:
                        LOG_INFOF(
@@@ -449,8 -447,7 +448,8 @@@ void Create_Notification_Entity_Annce(e
                                                                                float channel,
                                                                                string snd,
                                                                                float vol,
 -                                                                              float position)
 +                                                                              float position,
 +                                                                              float queuetime)
                {
                        // Set MSG_ANNCE information and handle precaching
                        #ifdef CSQC
                                                notif.nent_snd = strzone(snd);
                                                notif.nent_vol = vol;
                                                notif.nent_position = position;
 +                                              notif.nent_queuetime = queuetime;
                                        }
                                }
                                else
@@@ -756,17 -752,6 +755,17 @@@ void Create_Notification_Entity_Choice(
                        }
                }
  
 +void Create_Notification_Entity_Medal(entity notif,
 +                                                                              float var_cvar,
 +                                                                              string namestring,
 +                                                                              /* MSG_MEDAL */
 +                                                                              string icon,
 +                                                                              Notification anncename)
 +      {
 +              notif.nent_floatcount = 1;
 +              if (icon != "") { notif.nent_icon = strzone(icon); }
 +              if (anncename) { notif.nent_msgannce = anncename; }
 +      }
  
  // ===============
  //  Cvar Handling
@@@ -839,7 -824,6 +838,7 @@@ void Dump_Notifications(int fh, bool al
        int NOTIF_CENTER_COUNT = 0;
        int NOTIF_MULTI_COUNT = 0;
        int NOTIF_CHOICE_COUNT = 0;
 +      int NOTIF_MEDAL_COUNT = 0;
        FOREACH(Notifications, true, {
                switch (it.nent_type)
                {
                        case MSG_CENTER: ++NOTIF_CENTER_COUNT; break;
                        case MSG_MULTI: ++NOTIF_MULTI_COUNT; break;
                        case MSG_CHOICE: ++NOTIF_CHOICE_COUNT; break;
 +                      case MSG_MEDAL: ++NOTIF_MEDAL_COUNT; break;
                }
        });
  
                        "Allow choice for this notification 0 = off, 1 = only in warmup mode, 2 = always"
                );
        });
 +      
 +      NOTIF_WRITE(sprintf("\n// MSG_MEDAL notifications (count = %d):\n", NOTIF_MEDAL_COUNT));
 +      FOREACH(Notifications, it.nent_type == MSG_MEDAL && (!it.nent_teamnum || it.nent_teamnum == NUM_TEAM_1), {
 +              NOTIF_WRITE_ENTITY(it,
 +                      "Enable this multiple notification"
 +              );
 +      });
  
        // edit these to match whichever cvars are used for specific notification options
        NOTIF_WRITE("\n// HARD CODED notification variables:\n");
                        NOTIF_INFO_COUNT +
                        NOTIF_CENTER_COUNT +
                        NOTIF_MULTI_COUNT +
 -                      NOTIF_CHOICE_COUNT
 +                      NOTIF_CHOICE_COUNT +
 +                      NOTIF_MEDAL_COUNT
                ),
                NOTIF_ANNCE_COUNT,
                NOTIF_INFO_COUNT,
                NOTIF_CENTER_COUNT,
                NOTIF_MULTI_COUNT,
 -              NOTIF_CHOICE_COUNT
 +              NOTIF_CHOICE_COUNT,
 +              NOTIF_MEDAL_COUNT
        ));
        #undef NOTIF_WRITE_HARDCODED
        #undef NOTIF_WRITE_ENTITY
@@@ -1203,70 -1177,6 +1202,70 @@@ void Local_Notification_centerprint_Add
        #endif
        centerprint_Add(ORDINAL(cpid), input, stof(arg_slot[0]), stof(arg_slot[1]));
  }
 +
 +void Local_Notification_Queue_Run(MSG net_type, entity notif, float f1)
 +{             
 +      switch (net_type)
 +      {
 +              case MSG_ANNCE:
 +              {
 +                      Local_Notification_sound(notif.nent_channel, notif.nent_snd, notif.nent_vol, notif.nent_position);
 +                      break;
 +              }
 +              
 +              case MSG_MEDAL:
 +              {
 +                      centerprint_Medal(notif.nent_icon, f1);
 +                      Local_Notification_sound(notif.nent_msgannce.nent_channel, notif.nent_msgannce.nent_snd, notif.nent_msgannce.nent_vol, notif.nent_msgannce.nent_position);
 +                      break;
 +              }
 +      }
 +}
 +
 +void Local_Notification_Queue_Add(MSG net_type, entity notif, float queue_time, float f1)
 +{     
 +      //LOG_INFOF("Comparison %d > %d", time, notif_queue_next_time);
 +      if(queue_time == -1 || time > notif_queue_next_time) {
 +              //LOG_INFOF("Running NOW!");
 +              Local_Notification_Queue_Run(net_type, notif, f1);
 +              notif_queue_next_time = time + queue_time;
 +      } else {
 +              //LOG_INFOF("Queueing: %d %d", notif_queue_length, notif_queue_next_time);
 +              if(notif_queue_length >= NOTIF_QUEUE_MAX) return;
 +      
 +              notif_queue_type[notif_queue_length] = net_type;
 +              notif_queue_entity[notif_queue_length] = notif;
 +              notif_queue_time[notif_queue_length] = notif_queue_next_time;
 +              notif_queue_f1[notif_queue_length] = f1;
 +              
 +              notif_queue_next_time += queue_time;
 +              ++notif_queue_length;
 +      }
 +}
 +
 +void Local_Notification_Queue_Process()
 +{
 +      if(!notif_queue_length)
 +              return;
 +
 +      int j;
 +      
 +      if(notif_queue_time[0] <= time) {
 +              //LOG_INFOF("Process running: %d <= %d", notif_queue_time[0], time);
 +              Local_Notification_Queue_Run(notif_queue_type[0], notif_queue_entity[0], notif_queue_f1[0]);
 +              
 +              // Shift queue to the left
 +              for (j = 0; j < notif_queue_length - 1; j++) { 
 +                      notif_queue_type[j] = notif_queue_type[j+1];
 +                      notif_queue_entity[j] = notif_queue_entity[j+1];
 +                      notif_queue_time[j] = notif_queue_time[j+1];
 +                      notif_queue_f1[j] = notif_queue_f1[j+1];
 +              } 
 +              
 +              --notif_queue_length;
 +      }
 +}
 +
  #endif
  
  void Local_Notification(MSG net_type, Notification net_name, ...count)
                case MSG_ANNCE:
                {
                        #ifdef CSQC
 -                      Local_Notification_sound(notif.nent_channel, notif.nent_snd, notif.nent_vol, notif.nent_position);
 +                      //Local_Notification_sound(notif.nent_channel, notif.nent_snd, notif.nent_vol, notif.nent_position);
 +                      Local_Notification_Queue_Add(
 +                              net_type,
 +                              notif,
 +                              notif.nent_queuetime,
 +                              f1);
                        #else
                        backtrace("MSG_ANNCE on server?... Please notify Samual immediately!\n");
                        #endif
                                found_choice.nent_floatcount,
                                s1, s2, s3, s4,
                                f1, f2, f3, f4);
 +                      break;
                }
 +              
 +              #ifdef CSQC
 +              case MSG_MEDAL:
 +              {
 +                      Local_Notification_Queue_Add(
 +                              net_type,
 +                              notif,
 +                              MSG_MEDAL_TIME,
 +                              f1);
 +                      break;
 +              }
 +              #endif
        }
  }
  
index 0377a342e9c7229c70eeedf342960d3651a7bb39,a94ac9ab93bae4d9b8c7f0cad814cf75b7b49e41..abff1521360665b1a500d52f95c51fba7cc10d8b
@@@ -8,10 -8,6 +8,6 @@@
  #include <common/sounds/sound.qh>
  #include <common/weapons/all.qh>
  
- #ifdef CSQC
- #include <client/autocvars.qh>
- #endif
  // Operator for bold notifications
  #define BOLD_OPERATOR "^BOLD"
  
@@@ -29,8 -25,6 +25,8 @@@ ENUMCLASS(MSG
        CASE(MSG, CHOICE)
        /** Kill centerprint message @deprecated */
        CASE(MSG, CENTER_KILL)
 +      /** Medal notification */
 +      CASE(MSG, MEDAL)
  ENUMCLASS_END(MSG)
  
  string Get_Notif_TypeName(MSG net_type)
@@@ -42,7 -36,6 +38,7 @@@
                case MSG_CENTER: return "MSG_CENTER";
                case MSG_MULTI: return "MSG_MULTI";
                case MSG_CHOICE: return "MSG_CHOICE";
 +              case MSG_MEDAL: return "MSG_MEDAL";
        }
        LOG_WARNF("Get_Notif_TypeName(%d): Improper net type!", ORDINAL(net_type));
        return "";
@@@ -67,7 -60,6 +63,7 @@@ ENUMCLASS(CPID
        CASE(CPID, LMS)
        CASE(CPID, MISSING_TEAMS)
        CASE(CPID, MISSING_PLAYERS)
 +      CASE(CPID, MISSING_READY)
        CASE(CPID, INSTAGIB_FINDAMMO)
        CASE(CPID, CAMPAIGN_MESSAGE)
        CASE(CPID, MOTD)
@@@ -132,8 -124,7 +128,8 @@@ void Create_Notification_Entity_Annce(e
                                                                                float channel,
                                                                                string snd,
                                                                                float vol,
 -                                                                              float position);
 +                                                                              float position,
 +                                                                              float queuetime);
  
  void Create_Notification_Entity_InfoCenter(entity notif,
                                                                                        float var_cvar,
@@@ -167,13 -158,6 +163,13 @@@ void Create_Notification_Entity_Choice(
                                                                                Notification optiona,
                                                                                Notification optionb);
  
 +void Create_Notification_Entity_Medal(entity notif,
 +                                                                              float var_cvar,
 +                                                                              string namestring,
 +                                                                              /* MSG_MEDAL */
 +                                                                              string icon,
 +                                                                              Notification anncename);
 +
  void Dump_Notifications(int fh, bool alsoprint);
  
  GENERIC_COMMAND(dumpnotifs, "Dump all notifications into notifications_dump.txt", false)
@@@ -398,19 -382,6 +394,19 @@@ const float NOTIF_MAX_ARGS = 7
  const float NOTIF_MAX_HUDARGS = 2;
  const float NOTIF_MAX_DURCNT = 2;
  
 +#ifdef CSQC
 +const int NOTIF_QUEUE_MAX = 10;
 +entity notif_queue_entity[NOTIF_QUEUE_MAX];
 +MSG notif_queue_type[NOTIF_QUEUE_MAX];
 +float notif_queue_time[NOTIF_QUEUE_MAX];
 +float notif_queue_f1[NOTIF_QUEUE_MAX];
 +
 +float notif_queue_next_time;
 +int notif_queue_length;
 +
 +void Local_Notification_Queue_Process();
 +#endif
 +
  string arg_slot[NOTIF_MAX_ARGS];
  
  const float ARG_CS_SV_HA = 1; // enabled on CSQC, SVQC, and Hudargs
@@@ -455,7 -426,7 +451,7 @@@ string BUFF_NAME(int i)
        ARG_CASE(ARG_CS,        "join_key",      getcommandkey(_("jump"), "+jump")) \
        ARG_CASE(ARG_CS,        "frag_ping",     notif_arg_frag_ping(true, f2)) \
        ARG_CASE(ARG_CS,        "frag_stats",    notif_arg_frag_stats(f2, f3, f4)) \
 -      /*ARG_CASE(ARG_CS,      "frag_pos",      ((Should_Print_Score_Pos(f1)) ? sprintf("\n^BG%s", Read_Score_Pos(f1)) : ""))*/ \
 +      ARG_CASE(ARG_CS,        "frag_pos",      notif_arg_frag_pos(f2)) \
        ARG_CASE(ARG_CS,        "spree_cen",     (autocvar_notification_show_sprees ? notif_arg_spree_cen(f1) : "")) \
        ARG_CASE(ARG_CS_SV,     "spree_inf",     (autocvar_notification_show_sprees ? notif_arg_spree_inf(1, input, s2, f2) : "")) \
        ARG_CASE(ARG_CS_SV,     "spree_end",     (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
@@@ -481,66 -452,11 +477,66 @@@ MACRO_EN
        SPREE_ITEM(5, 05, _("RAGE! "), _("%s^K1 unlocked RAGE! %s^BG"), _("%s^K1 made FIVE SCORES IN A ROW! %s^BG")) \
        SPREE_ITEM(10, 10, _("MASSACRE! "), _("%s^K1 started a MASSACRE! %s^BG"), _("%s^K1 made TEN SCORES IN A ROW! %s^BG")) \
        SPREE_ITEM(15, 15, _("MAYHEM! "), _("%s^K1 executed MAYHEM! %s^BG"), _("%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG")) \
 -      SPREE_ITEM(20, 20, _("BERSERKER! "), _("%s^K1 is a BERSERKER! %s^BG"), _("%s^K1 made TWENTY SCORES IN A ROW! %s^BG")) \
 -      SPREE_ITEM(25, 25, _("CARNAGE! "), _("%s^K1 inflicts CARNAGE! %s^BG"), _("%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG")) \
 -      SPREE_ITEM(30, 30, _("ARMAGEDDON! "), _("%s^K1 unleashes ARMAGEDDON! %s^BG"), _("%s^K1 made THIRTY SCORES IN A ROW! %s^BG"))
  
  #ifdef CSQC
 +string notif_arg_frag_pos(int score)
 +{
 +      entity pl;
 +      int place = 1;
 +      string str, color, tail;
 +      bool tied = false;
 +      
 +      for(pl = players.sort_next; pl; pl = pl.sort_next) {
 +              if(pl.team == NUM_SPECTATOR) continue;
 +              if(pl.(scores(SP_SCORE)) == score) break;
 +              ++place;
 +      }
 +      
 +      entity prev = pl.sort_prev;
 +      entity next = pl.sort_next;
 +      if(prev && prev.(scores(SP_SCORE)) == score) {
 +              tied = true;
 +              --place; // We're tied always for the best place
 +      }
 +      if(next && next.(scores(SP_SCORE)) == score) {
 +              tied = true;
 +      }
 +      
 +      switch(place) {
 +              case 1:
 +                      color = "^4";
 +                      break;
 +              case 2:
 +                      color = "^1";
 +                      break;
 +              case 3:
 +                      color = "^3";
 +                      break;
 +              default:
 +                      color = "";
 +      }
 +      
 +      switch(place % 10) {
 +              case 1:
 +                      tail = "st";
 +                      break;
 +              case 2:
 +                      tail = "nd";
 +                      break;
 +              case 3:
 +                      tail = "rd";
 +                      break;
 +              default:
 +                      tail = "th";
 +      }
 +      
 +      str = strcat(color, ftos(place), tail);
 +      if(tied)
 +              return strcat("Tied for ", str);
 +      else
 +              return str;
 +}
 +
  string notif_arg_frag_ping(bool newline, float fping)
  {
        string s = newline ? "\n" : " ";
@@@ -746,7 -662,6 +742,7 @@@ string notif_arg_item_wepammo(float f1
  .string nent_snd;
  .float nent_vol;
  .float nent_position;
 +.float nent_queuetime;
  
  // MSG_INFO and MSG_CENTER entity values
  .string nent_args; // used by both
@@@ -825,22 -740,21 +821,22 @@@ Notification Get_Notif_Ent(MSG net_type
        return it;
  }
  
 -#define MSG_ANNCE_NOTIF_TEAM(teamnum, name, cvarname, defaultvalue, sound, channel, volume, position) \
 -      MSG_ANNCE_NOTIF_(teamnum, ANNCE_##name, ANNCE_##cvarname, defaultvalue, sound, channel, volume, position)
 +#define MSG_ANNCE_NOTIF_TEAM(teamnum, name, cvarname, defaultvalue, sound, channel, volume, position, queuetime) \
 +      MSG_ANNCE_NOTIF_(teamnum, ANNCE_##name, ANNCE_##cvarname, defaultvalue, sound, channel, volume, position, queuetime)
  
 -#define MSG_ANNCE_NOTIF(name, defaultvalue, sound, channel, volume, position) \
 +#define MSG_ANNCE_NOTIF(name, defaultvalue, sound, channel, volume, position, queuetime) \
        NOTIF_ADD_AUTOCVAR(ANNCE_##name, defaultvalue) \
 -      MSG_ANNCE_NOTIF_(0, ANNCE_##name, ANNCE_##name, defaultvalue, sound, channel, volume, position)
 +      MSG_ANNCE_NOTIF_(0, ANNCE_##name, ANNCE_##name, defaultvalue, sound, channel, volume, position, queuetime)
  
 -#define MSG_ANNCE_NOTIF_(teamnum, name, cvarname, defaultvalue, sound, channel, volume, position) \
 +#define MSG_ANNCE_NOTIF_(teamnum, name, cvarname, defaultvalue, sound, channel, volume, position, queuetime) \
        REGISTER(Notifications, name, m_id, new_pure(msg_annce_notification)) { \
                Create_Notification_Entity      (this, defaultvalue, ACVNN(cvarname), MSG_ANNCE, strtoupper(#name), teamnum); \
                Create_Notification_Entity_Annce(this, ACVNN(cvarname), strtoupper(#name), \
 -                      channel,   /* channel  */ \
 -                      sound,     /* snd      */ \
 -                      volume,    /* vol      */ \
 -                      position); /* position */ \
 +                      channel,    /* channel   */ \
 +                      sound,      /* snd       */ \
 +                      volume,     /* vol       */ \
 +                      position,   /* position  */ \
 +                      queuetime); /* queuetime */ \
        }
  
  #define MSG_INFO_NOTIF_TEAM(teamnum, name, cvarname, defaultvalue, strnum, flnum, args, hudargs, icon, normal, gentle) \
                        optiona,                                 /* optiona     */ \
                        optionb);                                /* optionb     */ \
        }
 +      
 +#define MSG_MEDAL_NOTIF(name, defaultvalue, icon, anncename) \
 +      NOTIF_ADD_AUTOCVAR(MEDAL_##name, defaultvalue) \
 +      MSG_MEDAL_NOTIF_(0, MEDAL_##name, MEDAL_##name, defaultvalue, icon, anncename)
 +
 +#define MSG_MEDAL_NOTIF_(teamnum, name, cvarname, defaultvalue, icon, anncename) \
 +      REGISTER(Notifications, name, m_id, new_pure(msg_medal_notification)) { \
 +              Create_Notification_Entity      (this, defaultvalue, ACVNN(cvarname), MSG_MEDAL, strtoupper(#name), teamnum); \
 +              Create_Notification_Entity_Medal(this, ACVNN(cvarname), strtoupper(#name), \
 +                      icon, \
 +                      anncename); \
 +      }
  
  REGISTRY_BEGIN(Notifications)
  {
diff --combined qcsrc/common/stats.qh
index 49be5178cebcdc859025f323258963fd538e4ce5,67f7fd60c479217269a4572d236e7f8d84cd8abe..d0f7f2bae34e2f6b7ccbcc72eecc1b6776e348ac
@@@ -1,9 -1,16 +1,16 @@@
  #pragma once
  
+ // you're next
  #ifdef SVQC
- #include <server/autocvars.qh>
  #include <server/client.qh>
+ #include <server/main.qh>
+ #include <common/gamemodes/sv_rules.qh>
+ #include <common/mapobjects/teleporters.qh>
  #include <common/mapobjects/trigger/secret.qh>
+ #include <common/mutators/mutator/doublejump/doublejump.qh>
+ #include <common/mutators/mutator/itemstime/itemstime.qh>
+ #include <common/physics/player.qh>
  #endif
  
  // Full list of all stat constants, included in a single location for easy reference
@@@ -66,22 -73,16 +73,27 @@@ float W_WeaponRateFactor(entity this)
  float game_stopped;
  float game_starttime; //point in time when the countdown to game start is over
  float round_starttime; //point in time when the countdown to round start is over
 +float overtime_starttime; // z411 point in time where first overtime started
 +
 +float checkrules_overtimesadded; // z411 add
 +float timeout_last;
 +float timeout_total_time;
 +bool game_timeout;
 +
  bool autocvar_g_allow_oldvortexbeam;
  int autocvar_leadlimit;
+ // TODO: world.qh can't be included here due to circular includes!
+ #define autocvar_fraglimit cvar("fraglimit")
+ #define autocvar_fraglimit_override cvar("fraglimit_override")
+ #define autocvar_timelimit cvar("timelimit")
+ #define autocvar_timelimit_override cvar("timelimit_override")
  #endif
  REGISTER_STAT(WEAPONRATEFACTOR, float, W_WeaponRateFactor(this))
  REGISTER_STAT(GAME_STOPPED, int, game_stopped)
 +
 +REGISTER_STAT(GAME_TIMEOUT, bool, game_timeout)
 +REGISTER_STAT(TIMEOUT_LAST, float, timeout_last)
 +
  REGISTER_STAT(GAMESTARTTIME, float, game_starttime)
  REGISTER_STAT(STRENGTH_FINISHED, float)
  REGISTER_STAT(INVINCIBLE_FINISHED, float)
@@@ -112,14 -113,12 +124,14 @@@ REGISTER_STAT(VEHICLESTAT_AMMO2, int
  REGISTER_STAT(VEHICLESTAT_RELOAD2, int)
  REGISTER_STAT(VEHICLESTAT_W2MODE, int)
  REGISTER_STAT(NADE_TIMER, float)
 -REGISTER_STAT(SECRETS_TOTAL, int, secrets_total)
 -REGISTER_STAT(SECRETS_FOUND, int, secrets_found)
 +//REGISTER_STAT(SECRETS_TOTAL, int, secrets_total)
 +//REGISTER_STAT(SECRETS_FOUND, int, secrets_found)
  REGISTER_STAT(RESPAWN_TIME, float)
  REGISTER_STAT(ROUNDSTARTTIME, float, round_starttime)
 -REGISTER_STAT(MONSTERS_TOTAL, int)
 -REGISTER_STAT(MONSTERS_KILLED, int)
 +REGISTER_STAT(OVERTIMESTARTTIME, float, overtime_starttime)
 +REGISTER_STAT(OVERTIMESADDED, float, checkrules_overtimesadded)
 +//REGISTER_STAT(MONSTERS_TOTAL, int)
 +//REGISTER_STAT(MONSTERS_KILLED, int)
  REGISTER_STAT(BUFFS, int)
  REGISTER_STAT(NADE_BONUS, float)
  REGISTER_STAT(NADE_BONUS_TYPE, int)
@@@ -214,6 -213,7 +226,7 @@@ int autocvar_sv_gameplayfix_grenadeboun
  int autocvar_sv_gameplayfix_noairborncorpse = 1;
  int autocvar_sv_gameplayfix_noairborncorpse_allowsuspendeditems = 1;
  int autocvar_sv_gameplayfix_delayprojectiles = 0;
+ bool autocvar_sv_gameplayfix_upwardvelocityclearsongroundflag = true;
  #endif
  REGISTER_STAT(GAMEPLAYFIX_DOWNTRACEONGROUND, int, autocvar_sv_gameplayfix_downtracesupportsongroundflag)
  REGISTER_STAT(GAMEPLAYFIX_EASIERWATERJUMP, int, autocvar_sv_gameplayfix_easierwaterjump)
@@@ -232,6 -232,10 +245,10 @@@ REGISTER_STAT(GAMEPLAYFIX_DELAYPROJECTI
  REGISTER_STAT(MOVEVARS_JUMPSTEP, int, cvar("sv_jumpstep"))
  REGISTER_STAT(NOSTEP, int, cvar("sv_nostep"))
  
+ #ifdef SVQC
+ float autocvar_sv_friction_on_land;
+ var float autocvar_sv_friction_slick = 0.5;
+ #endif
  REGISTER_STAT(MOVEVARS_FRICTION, float)
  REGISTER_STAT(MOVEVARS_FRICTION_SLICK, float, autocvar_sv_friction_slick)
  REGISTER_STAT(MOVEVARS_FRICTION_ONLAND, float, autocvar_sv_friction_on_land)
@@@ -285,6 -289,15 +302,15 @@@ REGISTER_STAT(DODGING_CLIENTSELECT, boo
  REGISTER_STAT(DODGING_FROZEN, int, autocvar_sv_dodging_frozen)
  REGISTER_STAT(DODGING_TIMEOUT, float)
  
+ #ifdef SVQC
+ float autocvar_g_jetpack_acceleration_side;
+ float autocvar_g_jetpack_acceleration_up;
+ float autocvar_g_jetpack_antigravity;
+ int autocvar_g_jetpack_fuel;
+ float autocvar_g_jetpack_maxspeed_side;
+ float autocvar_g_jetpack_maxspeed_up;
+ float autocvar_g_jetpack_reverse_thrust;
+ #endif
  REGISTER_STAT(JETPACK_ACCEL_SIDE, float, autocvar_g_jetpack_acceleration_side)
  REGISTER_STAT(JETPACK_ACCEL_UP, float, autocvar_g_jetpack_acceleration_up)
  REGISTER_STAT(JETPACK_ANTIGRAVITY, float, autocvar_g_jetpack_antigravity)
@@@ -327,6 -340,9 +353,9 @@@ REGISTER_STAT(DOM_PPS_BLUE, float
  REGISTER_STAT(DOM_PPS_YELLOW, float)
  REGISTER_STAT(DOM_PPS_PINK, float)
  
+ #ifdef SVQC
+ float autocvar_g_teleport_maxspeed;
+ #endif
  REGISTER_STAT(TELEPORT_MAXSPEED, float, autocvar_g_teleport_maxspeed)
  REGISTER_STAT(TELEPORT_TELEFRAG_AVOID, int, autocvar_g_telefrags_avoid)
  
@@@ -363,7 -379,11 +392,11 @@@ REGISTER_STAT(MOVEVARS_AIRSTRAFEACCEL_Q
  REGISTER_STAT(MOVEVARS_AIRCONTROL_POWER, float)
  REGISTER_STAT(MOVEVARS_AIRCONTROL_BACKWARDS, bool)
  REGISTER_STAT(MOVEVARS_AIRCONTROL_SIDEWARDS, bool)
- noref bool autocvar_sv_gameplayfix_nogravityonground = true;
+ #ifdef SVQC
+ float autocvar_sv_gameplayfix_q2airaccelerate = 1;
+ bool autocvar_sv_gameplayfix_nogravityonground = true;
+ bool autocvar_sv_gameplayfix_gravityunaffectedbyticrate = true;
+ #endif
  REGISTER_STAT(MOVEFLAGS, int, MOVEFLAG_VALID
                                | (autocvar_sv_gameplayfix_q2airaccelerate ? MOVEFLAG_Q2AIRACCELERATE : 0)
                                | (autocvar_sv_gameplayfix_nogravityonground ? MOVEFLAG_NOGRAVITYONGROUND : 0)
@@@ -384,6 -404,8 +417,8 @@@ REGISTER_STAT(TIMELIMIT, float, autocva
  REGISTER_STAT(WARMUP_TIMELIMIT, float, warmup_limit)
  #ifdef SVQC
  float autocvar_sv_wallfriction;
+ #define autocvar_sv_gravity cvar("sv_gravity")
+ float autocvar_sv_stepheight;
  #endif
  REGISTER_STAT(MOVEVARS_WALLFRICTION, int, autocvar_sv_wallfriction)
  REGISTER_STAT(MOVEVARS_TICRATE, float, autocvar_sys_ticrate)
index 28a2741cc0c62fa2e0c146b6a653a7cf1a49994f,0d50baac5797d2810cea19ef2a3f77b382b7a982..568e19e68e5ceb609b210d4853cf241508524d75
@@@ -1,5 -1,9 +1,9 @@@
  #include "physics.qh"
  
+ float autocvar_sv_spectator_speed_multiplier;
+ float autocvar_sv_spectator_speed_multiplier_min = 1;
+ float autocvar_sv_spectator_speed_multiplier_max = 5;
  void sys_phys_fix(entity this, float dt)
  {
        WarpZone_PlayerPhysics_FixVAngle(this);
@@@ -40,9 -44,7 +44,9 @@@ void sys_phys_ai(entity this
  void sys_phys_pregame_hold(entity this)
  {
        if (!IS_PLAYER(this)) { return; }
 -      const bool allowed_to_move = (time >= game_starttime && !game_stopped);
 +      // z411
 +      //const bool allowed_to_move = (time >= game_starttime && !game_stopped);
 +      const bool allowed_to_move = (!game_stopped && !game_timeout);
        if (!allowed_to_move) {
                this.velocity = '0 0 0';
                set_movetype(this, MOVETYPE_NONE);
diff --combined qcsrc/server/chat.qh
index 1c45d3db7f5fb13b58df26a45776bfa7a44d3786,500d757c02c0a80d82f07b1de0d7f08c35d015df..92e4fd2080736623debba48db787a0daa86da8d8
@@@ -1,5 -1,19 +1,23 @@@
  #pragma once
  
+ float autocvar_g_chat_flood_burst;
+ float autocvar_g_chat_flood_burst_team;
+ float autocvar_g_chat_flood_burst_tell;
+ float autocvar_g_chat_flood_lmax;
+ float autocvar_g_chat_flood_lmax_team;
+ float autocvar_g_chat_flood_lmax_tell;
+ bool autocvar_g_chat_flood_notify_flooder;
+ float autocvar_g_chat_flood_spl;
+ float autocvar_g_chat_flood_spl_team;
+ float autocvar_g_chat_flood_spl_tell;
+ int autocvar_g_chat_nospectators;
+ bool autocvar_g_chat_teamcolors;
+ bool autocvar_g_chat_tellprivacy;
++bool autocvar_sv_chat_sounds;
++float autocvar_sv_chat_sounds_flood;
++string autocvar_sv_chat_sounds_list;
++
  const float NUM_NEAREST_ENTITIES = 4;
  entity nearest_entity[NUM_NEAREST_ENTITIES];
  float nearest_length[NUM_NEAREST_ENTITIES];
  .float floodcontrol_chattell;
  .float floodcontrol_voice;
  .float floodcontrol_voiceteam;
 +.float floodcontrol_chatsound;
  
  #define CHAT_NOSPECTATORS() ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage))
  
  int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodcontrol);
 +bool play_chatsound(entity source, string msgin);
  
  string NearestLocation(vector p);
  
diff --combined qcsrc/server/client.qc
index 05ecad2c39aac330b77cca0dd44d07bc3e7b4294,8dd73f66c48938e56750d827c0da29e34f1c046d..249f47c829710c121197c19bb603300452a4af57
@@@ -21,6 -21,7 +21,7 @@@
  #include <common/minigames/sv_minigames.qh>
  #include <common/monsters/sv_monsters.qh>
  #include <common/mutators/mutator/instagib/sv_instagib.qh>
+ #include <common/mutators/mutator/nades/nades.qh>
  #include <common/mutators/mutator/overkill/oknex.qh>
  #include <common/mutators/mutator/waypoints/all.qh>
  #include <common/net_linked.qh>
@@@ -42,6 -43,7 +43,7 @@@
  #include <server/anticheat.qh>
  #include <server/antilag.qh>
  #include <server/bot/api.qh>
+ #include <server/bot/default/cvars.qh>
  #include <server/campaign.qh>
  #include <server/chat.qh>
  #include <server/cheats.qh>
@@@ -71,6 -73,7 +73,7 @@@
  #include <server/weapons/common.qh>
  #include <server/weapons/hitplot.qh>
  #include <server/weapons/selection.qh>
+ #include <server/weapons/tracing.qh>
  #include <server/weapons/weaponsystem.qh>
  #include <server/world.qh>
  
@@@ -94,16 -97,6 +97,16 @@@ void send_CSQC_teamnagger() 
        WriteHeader(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
  }
  
 +void send_TeamNames(int channel, entity to) {
 +      msg_entity = to;
 +      
 +      WriteHeader(channel, TE_CSQC_TEAMNAMES);
 +      WriteString(channel, autocvar_g_teamnames_red);
 +      WriteString(channel, autocvar_g_teamnames_blue);
 +      WriteString(channel, autocvar_g_teamnames_yellow);
 +      WriteString(channel, autocvar_g_teamnames_pink);
 +}
 +
  int CountSpectators(entity player, entity to)
  {
        if(!player) { return 0; } // not sure how, but best to be safe
@@@ -527,36 -520,6 +530,36 @@@ void FixPlayermodel(entity player
                                setcolor(player, stof(autocvar_sv_defaultplayercolors));
  }
  
 +void ResetPlayerResources(entity this)
 +{
 +      if (warmup_stage) {
 +              SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
 +              SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
 +              SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
 +              SetResource(this, RES_CELLS, warmup_start_ammo_cells);
 +              SetResource(this, RES_PLASMA, warmup_start_ammo_plasma);
 +              SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
 +              SetResource(this, RES_HEALTH, warmup_start_health);
 +              SetResource(this, RES_ARMOR, warmup_start_armorvalue);
 +              STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
 +      } else {
 +              SetResource(this, RES_SHELLS, start_ammo_shells);
 +              SetResource(this, RES_BULLETS, start_ammo_nails);
 +              SetResource(this, RES_ROCKETS, start_ammo_rockets);
 +              SetResource(this, RES_CELLS, start_ammo_cells);
 +              SetResource(this, RES_PLASMA, start_ammo_plasma);
 +              SetResource(this, RES_FUEL, start_ammo_fuel);
 +              SetResource(this, RES_HEALTH, start_health);
 +              SetResource(this, RES_ARMOR, start_armorvalue);
 +              STAT(WEAPONS, this) = start_weapons;
 +              if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
 +              {
 +                      GiveRandomWeapons(this, random_start_weapons_count,
 +                              autocvar_g_random_start_weapons, random_start_ammo);
 +              }
 +      }
 +}
 +
  void PutPlayerInServer(entity this)
  {
        if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
        this.takedamage = DAMAGE_AIM;
        this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
  
 -      if (warmup_stage) {
 -              SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
 -              SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
 -              SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
 -              SetResource(this, RES_CELLS, warmup_start_ammo_cells);
 -              SetResource(this, RES_PLASMA, warmup_start_ammo_plasma);
 -              SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
 -              SetResource(this, RES_HEALTH, warmup_start_health);
 -              SetResource(this, RES_ARMOR, warmup_start_armorvalue);
 -              STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
 -      } else {
 -              SetResource(this, RES_SHELLS, start_ammo_shells);
 -              SetResource(this, RES_BULLETS, start_ammo_nails);
 -              SetResource(this, RES_ROCKETS, start_ammo_rockets);
 -              SetResource(this, RES_CELLS, start_ammo_cells);
 -              SetResource(this, RES_PLASMA, start_ammo_plasma);
 -              SetResource(this, RES_FUEL, start_ammo_fuel);
 -              SetResource(this, RES_HEALTH, start_health);
 -              SetResource(this, RES_ARMOR, start_armorvalue);
 -              STAT(WEAPONS, this) = start_weapons;
 -              if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
 -              {
 -                      GiveRandomWeapons(this, random_start_weapons_count,
 -                              autocvar_g_random_start_weapons, random_start_ammo);
 -              }
 -      }
 +      ResetPlayerResources(this);
 +      
        SetSpectatee_status(this, 0);
  
        PS(this).dual_weapons = '0 0 0';
@@@ -837,10 -824,6 +840,10 @@@ void PutClientInServer(entity this
        } else if (IS_PLAYER(this)) {
                PutPlayerInServer(this);
        }
 +      
 +      // send team names
 +      if(teamplay && IS_REAL_CLIENT(this))
 +              send_TeamNames(MSG_ONE, this);
  }
  
  // TODO do we need all these fields, or should we stop autodetecting runtime
@@@ -879,9 -862,6 +882,9 @@@ void ClientInit_misc(entity this
        WriteByte(channel, this.cnt * 255.0); // g_balance_damagepush_speedfactor
        WriteByte(channel, serverflags);
        WriteCoord(channel, autocvar_g_trueaim_minrange);
 +      
 +      // z411 send full hostname
 +      WriteString(channel, (autocvar_hostname_full ? autocvar_hostname_full : autocvar_hostname));
  }
  
  void ClientInit_CheckUpdate(entity this)
@@@ -1068,14 -1048,13 +1071,14 @@@ string getwelcomemessage(entity this
                modifications = strcat(modifications, ", Powerups");
        modifications = substring(modifications, 2, strlen(modifications) - 2);
  
 -      string versionmessage = GetClientVersionMessage(this);
 -      string s = strcat(versionmessage, "^8\n^8\nhost is ^9", autocvar_hostname, "^8\n");
 +      //string versionmessage = GetClientVersionMessage(this);
 +      //string s = strcat(versionmessage, "^8\n^9", (autocvar_hostname_full ? autocvar_hostname_full : autocvar_hostname));
 +      string s = (autocvar_hostname_full ? autocvar_hostname_full : autocvar_hostname);
  
 -      s = strcat(s, "^8\nmatch type is ^1", gamemode_name, "^8\n");
 +      s = strcat(s, "^8\n^7", gamemode_name);
  
        if(modifications != "")
 -              s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
 +              s = strcat(s, "^7 | ^3", modifications);
  
        if(cache_lastmutatormsg != autocvar_g_mutatormsg)
        {
        }
  
        if (cache_mutatormsg != "") {
 -              s = strcat(s, "\n\n^8special gameplay tips: ^7", cache_mutatormsg);
 +              s = strcat(s, "\n^8tips: ^7", cache_mutatormsg);
        }
  
        string mutator_msg = "";
  
        string motd = autocvar_sv_motd;
        if (motd != "") {
 -              s = strcat(s, "\n\n^8MOTD: ^7", strreplace("\\n", "\n", motd));
 +              s = strcat(s, "\n\n^7", strreplace("\\n", "\n", motd));
        }
        return s;
  }
@@@ -2023,11 -2002,6 +2026,11 @@@ void Join(entity this
        else
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, this.netname);
        this.team_selected = false;
 +      
 +      // z411
 +      // send constant ready notification
 +      if(warmup_stage)
 +              Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MISSING_READY);
  }
  
  int GetPlayerLimit()
@@@ -2188,13 -2162,12 +2191,13 @@@ bool PlayerThink(entity this
                return false;
        }
  
 -      if (timeout_status == TIMEOUT_ACTIVE) {
 -              // don't allow the player to turn around while game is paused
 +      if (game_timeout) {
 +        // don't allow the player to turn around while game is paused
                // FIXME turn this into CSQC stuff
                this.v_angle = this.lastV_angle;
                this.angles = this.lastV_angle;
                this.fixangle = true;
 +              return false;
        }
  
        if (frametime) player_powerups(this);
diff --combined qcsrc/server/client.qh
index 2a447b6356a3f0aa19c5792dca6394c72428d8f4,563fdba1b0028350e12d7300207ed7826f4ec841..9d6575d535d51ab6bc4c695aac0ef2b9c4b71a7e
@@@ -5,6 -5,54 +5,61 @@@
  #include <common/replicate.qh>
  #include <common/sounds/all.qh>
  
+ bool autocvar__notarget;
+ int autocvar_g_balance_armor_start;
+ float autocvar_g_balance_pause_armor_rot_spawn;
+ float autocvar_g_balance_pause_fuel_rot_spawn;
+ float autocvar_g_balance_pause_health_regen_spawn;
+ float autocvar_g_balance_pause_health_rot_spawn;
+ bool autocvar_g_botclip_collisions;
+ bool autocvar_g_fullbrightplayers;
+ bool autocvar_g_playerclip_collisions;
+ float autocvar_g_player_alpha;
+ float autocvar_g_player_brightness;
+ float autocvar_g_player_damageforcescale = 2;
+ float autocvar_g_respawn_delay_small;
+ int autocvar_g_respawn_delay_small_count;
+ float autocvar_g_respawn_delay_large;
+ int autocvar_g_respawn_delay_large_count;
+ float autocvar_g_respawn_delay_max;
+ bool autocvar_g_respawn_delay_forced;
+ bool autocvar_g_respawn_ghosts;
+ float autocvar_g_respawn_ghosts_alpha = 1;
+ float autocvar_g_respawn_ghosts_fadetime = 1.5;
+ float autocvar_g_respawn_ghosts_time = 4.5;
+ float autocvar_g_respawn_ghosts_speed;
+ int autocvar_g_respawn_waves;
+ bool autocvar_g_nodepthtestplayers;
+ string autocvar_g_mutatormsg;
+ float autocvar_sv_foginterval;
+ float autocvar_sv_maxidle;
+ bool autocvar_sv_maxidle_spectatorsareidle;
+ int autocvar_sv_maxidle_slots;
+ bool autocvar_sv_maxidle_slots_countbots;
+ bool autocvar_g_forced_respawn;
+ int autocvar_g_maxplayers;
+ float autocvar_g_maxplayers_spectator_blocktime;
+ string autocvar_g_xonoticversion;
+ float autocvar_gameversion;
+ float autocvar_gameversion_min;
+ float autocvar_gameversion_max;
+ string autocvar_hostname;
+ int autocvar_spawn_debug;
+ string autocvar_sv_motd;
+ int autocvar_sv_name_maxlength = 64;
+ bool autocvar_sv_servermodelsonly;
+ int autocvar_sv_spectate;
+ bool autocvar_sv_teamnagger;
+ float autocvar_sv_player_scale;
+ bool autocvar_sv_showspectators;
++// z411
++string autocvar_hostname_full;
++string autocvar_g_teamnames_red;
++string autocvar_g_teamnames_blue;
++string autocvar_g_teamnames_yellow;
++string autocvar_g_teamnames_pink;
++
  // WEAPONTODO
  .string weaponorder_byimpulse;
  
@@@ -40,7 -88,6 +95,7 @@@ CLASS(Client, Object
      ATTRIB(Client, colormap, int, this.colormap);
      ATTRIB(Client, team, int, this.team);
      ATTRIB(Client, clientcolors, int, this.clientcolors);
 +      ATTRIB(Client, countrycode, int, this.countrycode);
      /** Client IP */
      ATTRIB(Client, netaddress, string, this.netaddress);
      ATTRIB(Client, playermodel, string, this.playermodel);
      ATTRIB(Client, cvar_cl_pokenade_type, string, this.cvar_cl_pokenade_type);
      ATTRIB(Client, cvar_cl_spawn_near_teammate, bool, this.cvar_cl_spawn_near_teammate);
      ATTRIB(Client, cvar_cl_gunalign, int, this.cvar_cl_gunalign);
 +      ATTRIB(Client, cvar_cl_chat_sounds, bool, this.cvar_cl_chat_sounds);
      ATTRIB(Client, cvar_cl_handicap, float, this.cvar_cl_handicap);
      ATTRIB(Client, cvar_cl_clippedspectating, bool, this.cvar_cl_clippedspectating);
      ATTRIB(Client, cvar_cl_autoscreenshot, int, this.cvar_cl_autoscreenshot);
@@@ -265,8 -311,6 +320,8 @@@ bool independent_players
  #define IS_INDEPENDENT_PLAYER(e) ((e).solid == SOLID_TRIGGER)
  #define MAKE_INDEPENDENT_PLAYER(e) (((e).solid = SOLID_TRIGGER), ((e).frags = FRAGS_PLAYER_OUT_OF_GAME))
  
 +.float lastkill;
 +.int countrycode;
  .int killcount;
  
  //flood fields
@@@ -355,8 -399,3 +410,8 @@@ void Join(entity this)
  #define SPECTATE_COPYFIELD(fld) SPECTATE_COPY() { this.(fld) = spectatee.(fld); }
  
  const int MAX_SPECTATORS = 7;
 +
 +float _medal_times;
 +#define Give_Medal(entity,medalname) \
 +      _medal_times = GameRules_scoring_add(entity, MEDAL_##medalname, 1); \
 +      Send_Notification(NOTIF_ONE, entity, MSG_MEDAL, MEDAL_##medalname, _medal_times);
index 0daef91ef5b6eef6cc7a11f050759b8aa7126e17,ad3685a1f0a549cc03631011531764dfb900cb34..00f1285ff22743a2e653e5d78a9ed3e27a9eede5
@@@ -18,6 -18,7 +18,7 @@@
  #include <common/vehicles/all.qh>
  #include <lib/warpzone/common.qh>
  #include <server/bot/api.qh>
+ #include <server/bot/default/waypoints.qh>
  #include <server/campaign.qh>
  #include <server/chat.qh>
  #include <server/cheats.qh>
@@@ -274,7 -275,7 +275,7 @@@ void ClientCommand_join(entity caller, 
        {
                case CMD_REQUEST_COMMAND:
                {
 -                      if (!game_stopped && IS_CLIENT(caller) && !IS_PLAYER(caller))
 +                      if (!game_stopped && !game_timeout && IS_CLIENT(caller) && !IS_PLAYER(caller))
                        {
                                if (joinAllowed(caller))
                                        Join(caller);
@@@ -365,13 -366,13 +366,13 @@@ void ClientCommand_physics(entity calle
        }
  }
  
 -void ClientCommand_ready(entity caller, int request)  // todo: anti-spam for toggling readyness
 +void ClientCommand_ready(entity caller, int request)
  {
        switch (request)
        {
                case CMD_REQUEST_COMMAND:
                {
 -                      if (IS_CLIENT(caller))
 +                      if (IS_CLIENT(caller) && caller.last_ready < time - 3) // anti-spam
                        {
                                if (warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2)
                                {
                                                {
                                                        caller.ready = false;
                                                        if(IS_PLAYER(caller) || caller.caplayer == 1)
 -                                                              bprint(playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n");
 +                                                              bprint("\{1}", playername(caller.netname, caller.team, false), "^2 is ^1NOT^2 ready\n");
                                                }
                                                else
                                                {
                                                        caller.ready = true;
                                                        if(IS_PLAYER(caller) || caller.caplayer == 1)
 -                                                              bprint(playername(caller.netname, caller.team, false), "^2 is ready\n");
 +                                                              bprint("\{1}", playername(caller.netname, caller.team, false), "^2 is ready\n");
                                                }
 +                                              
 +                                              caller.last_ready = time;
  
                                                // cannot reset the game while a timeout is active!
                                                if (!timeout_status) ReadyCount();
@@@ -627,7 -626,7 +628,7 @@@ void ClientCommand_spectate(entity call
        {
                case CMD_REQUEST_COMMAND:
                {
 -                      if (!intermission_running && IS_CLIENT(caller))
 +                      if (!intermission_running && IS_CLIENT(caller) && !game_timeout)
                        {
                                if(argv(1) != "")
                                {
        }
  }
  
 +void ClientCommand_sounds(entity caller, int request)
 +{
 +      switch (request)
 +      {
 +              case CMD_REQUEST_COMMAND:
 +              {
 +                      sprint(caller, strcat("Available sounds: \n\n", autocvar_sv_chat_sounds_list, "\n"));
 +                      return; // never fall through to usage
 +              }
 +
 +              default:
 +              case CMD_REQUEST_USAGE:
 +              {
 +                      sprint(caller, "\nUsage:^3 cmd sounds\n");
 +                      return;
 +              }
 +      }
 +}
 +
  void ClientCommand_suggestmap(entity caller, int request, int argc)
  {
        switch (request)
@@@ -862,7 -842,6 +863,7 @@@ void ClientCommand_(entity caller, int 
        CLIENT_COMMAND("selfstuff", ClientCommand_selfstuff(ent, request, command), "Stuffcmd a command to your own client") \
        CLIENT_COMMAND("sentcvar", ClientCommand_sentcvar(ent, request, arguments, command), "New system for sending a client cvar to the server") \
        CLIENT_COMMAND("spectate", ClientCommand_spectate(ent, request), "Become an observer") \
 +      CLIENT_COMMAND("sounds", ClientCommand_sounds(ent, request), "Get list of commsnds") \
        CLIENT_COMMAND("suggestmap", ClientCommand_suggestmap(ent, request, arguments), "Suggest a map to the mapvote at match end") \
        CLIENT_COMMAND("tell", ClientCommand_tell(ent, request, arguments, command), "Send a message directly to a player") \
        CLIENT_COMMAND("voice", ClientCommand_voice(ent, request, arguments, command), "Send voice message via sound") \
index 44ab9834290ec28d992ea24877b5723ac94c17bb,5dff9f5f5b370ed6bb0424c2a76133d49eb879cf..7c30baa02687681805b9f167c9ee2bac29c84ac2
@@@ -8,6 -8,7 +8,7 @@@
  #include <common/vehicles/all.qh>
  #include <common/weapons/_all.qh>
  #include <lib/warpzone/common.qh>
+ #include <server/campaign.qh>
  #include <server/chat.qh>
  #include <server/client.qh>
  #include <server/command/common.qh>
@@@ -212,33 -213,16 +213,33 @@@ void timeout_handler_think(entity this
                                if (timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
                                        Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_PREPARE);
  
 -                              this.nextthink = time + TIMEOUT_SLOWMO_VALUE;       // think again in one second
 +                              //this.nextthink = time + TIMEOUT_SLOWMO_VALUE;       // think again in one second
 +                              this.nextthink = time + 1;
                                timeout_time -= 1;                                  // decrease the time counter
                        }
 +                      else if (timeout_time == -1)  // infinite timer
 +                      {
 +                              Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_TIMEOUT_ONGOING);
 +                              this.nextthink = time + TIMEOUT_SLOWMO_VALUE;
 +                      }
                        else  // time to end the timeout
                        {
                                Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_TIMEIN);
                                timeout_status = TIMEOUT_INACTIVE;
 +                              float total_time = time - timeout_last;
  
                                // reset the slowmo value back to normal
 -                              cvar_set("slowmo", ftos(orig_slowmo));
 +                              // z411 TODO
 +                              //cvar_set("slowmo", ftos(orig_slowmo));
 +                              
 +                              // Disable timeout and fix times
 +                              game_timeout = false;
 +                              timeout_total_time += total_time;
 +                              game_starttime += total_time;
 +                              if(round_handler && round_handler_GetEndTime() > 0)
 +                                      round_handler.round_endtime += total_time;
 +                                      
 +                              LOG_INFOF("Timeout lasted %d secs", total_time);
  
                                // unlock the view for players so they can move around again
                                FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
                                timeout_status = TIMEOUT_ACTIVE;
  
                                // set the slowmo value to the timeout default slowmo value
 -                              cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
 +                              //cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
 +                              game_timeout = true;
 +                              timeout_last = time;
 +                              
 +                              // play timeout sound
 +                              sound(NULL, CH_INFO, SND_TIMEOUT, VOL_BASE, ATTN_NONE);
  
                                // reset all the flood variables
                                FOREACH_CLIENT(true, {
@@@ -703,7 -682,7 +704,7 @@@ void CommonCommand_timein(int request, 
                                                {
                                                        timeout_time = autocvar_sv_timeout_resumetime;
                                                        timeout_handler.nextthink = time;  // timeout_handler has to take care of it immediately
 -                                                      bprint(strcat("^1Attention: ^7", GetCallerName(caller), " resumed the game! Prepare for battle!\n"));
 +                                                      bprint(strcat("\{1}^1Attention: ^7", GetCallerName(caller), " resumed the game! Prepare for battle!\n"));
                                                        return;
                                                }
  
@@@ -767,7 -746,7 +768,7 @@@ void CommonCommand_timeout(int request
                                {
                                        if (caller)   CS(caller).allowed_timeouts -= 1;
                                        // write a bprint who started the timeout (and how many they have left)
 -                                      bprint(GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(CS(caller).allowed_timeouts), " timeout(s) left)") : ""), "!\n");
 +                                      bprint("\{1}", GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(CS(caller).allowed_timeouts), " timeout(s) left)") : ""), "!\n");
  
                                        timeout_status = TIMEOUT_LEADTIME;
                                        timeout_caller = caller;
                                        timeout_handler = new(timeout_handler);
                                        setthink(timeout_handler, timeout_handler_think);
                                        timeout_handler.nextthink = time;  // always let the entity think asap
 -
 +                                      
                                        Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_TIMEOUT);
                                }
                        }
index b34de1b7b4ef4ddf000727ed6333e400597a8047,e3347980d40a530169766f39150a720c44984a84..9b4ceb48cf69649535feaf9fea7e027a305b3a20
@@@ -11,6 -11,7 +11,7 @@@
  #include <common/util.qh>
  #include <common/weapons/_all.qh>
  #include <server/client.qh>
+ #include <server/command/banning.qh>
  #include <server/command/common.qh>
  #include <server/command/vote.qh>
  #include <server/damage.qh>
@@@ -216,10 -217,6 +217,10 @@@ void VoteCount(float first_count
  
        // add up all the votes from each connected client
        FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_CLIENT(it), {
 +              // z411
 +              if(vote_target_type == VOTE_TARGET_TEAM && it.team != vote_caller.team) continue;
 +              if(vote_target_type == VOTE_TARGET_SINGLE && it != vote_target) continue;
 +              
                ++vote_player_count;
                if (IS_PLAYER(it))   ++vote_real_player_count;
                switch (it.vote_selection)
@@@ -410,7 -407,6 +411,7 @@@ void ReadyRestart_think(entity this
        restart_mapalreadyrestarted = true;
        reset_map(true);
        Score_ClearAll();
 +      Inventory_ClearAll();
        delete(this);
  }
  
@@@ -448,10 -444,7 +449,10 @@@ void ReadyRestart_force(
        warmup_stage = 0;                // once the game is restarted the game is in match stage
  
        // reset the .ready status of all players (also spectators)
 -      FOREACH_CLIENT(IS_REAL_CLIENT(it), { it.ready = false; });
 +      FOREACH_CLIENT(IS_REAL_CLIENT(it), {
 +              it.ready = false;
 +              Kill_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CPID_MISSING_READY);
 +      });
        readycount = 0;
        Nagger_ReadyCounted();  // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client
  
                FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { CS(it).allowed_timeouts = autocvar_sv_timeout_number; });
        }
  
 +      round_handler_Activate(true);
        if (!sv_ready_restart_after_countdown) reset_map(true);
        if (autocvar_sv_eventlog) GameLogEcho(":restart");
  }
@@@ -488,10 -480,7 +489,10 @@@ void ReadyRestart(
  
        // Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
        // Otherwise scores could be manipulated during the countdown.
 -      if (!sv_ready_restart_after_countdown) Score_ClearAll();
 +      if (!sv_ready_restart_after_countdown) {
 +              Score_ClearAll();
 +              Inventory_ClearAll();
 +      }
        ReadyRestart_force();
  }
  
@@@ -693,8 -682,6 +694,8 @@@ int VoteCommand_parse(entity caller, st
                case MUT_VOTEPARSE_UNACCEPTABLE: { return 0; }
        }
  
 +      vote_target_type = VOTE_TARGET_ALL;
 +      
        switch (first_command) // now go through and parse the proper commands to adjust as needed.
        {
                case "kick":
                                if (first_command == "kickban")
                                        command_arguments = strcat(ftos(autocvar_g_ban_default_bantime), " ", ftos(autocvar_g_ban_default_masksize), " ~");
  
 -                              vote_parsed_command = strcat(first_command, " # ", ftos(etof(victim)), " ", command_arguments);
 +                              vote_parsed_command = strcat("defer 2 ", first_command, " # ", ftos(etof(victim)), " ", command_arguments);
                                vote_parsed_display = sprintf("^1%s #%d ^7%s^1 %s", first_command, etof(victim), victim.netname, reason);
                        }
                        else { print_to(caller, strcat("vcall: ", GetClientErrorString(accepted, argv(startpos + 1)), ".\n")); return 0; }
                {
                        vote_command = ValidateMap(argv(startpos + 1), caller);
                        if (!vote_command)  return -1;
 -                      vote_parsed_command = strcat("gotomap ", vote_command);
 +                      vote_parsed_command = strcat("defer 2 gotomap ", vote_command);
                        vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
  
                        break;
                }
 +              
 +              // z411 team calls
 +              case "teamname":
 +              {
 +                      if (teamplay && Team_IsValidTeam(caller.team)) {
 +                              vote_target_type = VOTE_TARGET_TEAM;
 +                      
 +                              string tmname = strtolower(Static_Team_ColorName(caller.team));
 +                              string newname = argv(startpos + 1);
 +                              
 +                              vote_parsed_command = strcat(first_command, " ", tmname, " \"", newname, "\"");
 +                              vote_parsed_display = strzone(strcat("^3(Team) ^1", first_command, " ^2", newname));
 +                      } else { print_to(caller, "vcall: Not in a team\n"); return 0; }
 +                      
 +                      break;
 +              }
  
                // TODO: replicate the old behaviour of being able to vote for maps from different modes on multimode servers (possibly support it in gotomap too)
                // maybe fallback instead of aborting if map name is invalid?
                }
  
                case "restart":
 +              case "shuffleteams":
 +              case "allready":
 +              case "endmatch":
                {
                        // add a delay so that vote result can be seen and announcer can be heard
                        // if the vote is accepted
 -                      vote_parsed_command = strcat("defer 1 ", vote_command);
 +                      vote_parsed_command = strcat("defer 2 ", vote_command);
                        vote_parsed_display = strzone(strcat("^1", vote_command));
  
                        break;
index 8d70e769350449f289309d51afde7326dca9f98f,4dfd9e8575f2abf22c9cdc1e639171ca64988e0e..156021b8fb9fa87bd63afaa5ec44c64dbd80aab1
@@@ -1,9 -1,25 +1,25 @@@
  #pragma once
  
- // ================================================
- //  Declarations for the vote system/vote commands
- //  Last updated: December 14th, 2011
- // ================================================
+ bool autocvar_sv_vote_call;
+ bool autocvar_sv_vote_change;
+ string autocvar_sv_vote_commands;
+ int autocvar_sv_vote_limit;
+ float autocvar_sv_vote_majority_factor;
+ float autocvar_sv_vote_majority_factor_of_voted;
+ bool autocvar_sv_vote_master;
+ bool autocvar_sv_vote_master_callable;
+ string autocvar_sv_vote_master_commands;
+ string autocvar_sv_vote_master_password;
+ int autocvar_sv_vote_master_playerlimit;
+ bool autocvar_sv_vote_no_stops_vote;
+ int autocvar_sv_vote_nospectators;
+ //string autocvar_sv_vote_only_commands;
+ bool autocvar_sv_vote_override_mostrecent;
+ bool autocvar_sv_vote_singlecount;
+ float autocvar_sv_vote_stop;
+ float autocvar_sv_vote_timeout;
+ float autocvar_sv_vote_wait;
+ bool autocvar_sv_vote_gamestart;
  
  // definitions for command selection between progs
  const float VC_ASGNMNT_BOTH = 1;
@@@ -21,11 -37,6 +37,11 @@@ const float VOTE_NULL = 0
  const float VOTE_NORMAL = 1;
  const float VOTE_MASTER = 2;
  
 +// z411 vote targets
 +const float VOTE_TARGET_ALL = 0;
 +const float VOTE_TARGET_TEAM = 1;
 +const float VOTE_TARGET_SINGLE = 2;
 +
  // global vote information declarations
  entity vote_caller;         // original caller of the current vote
  string vote_caller_name;    // name of the vote caller
@@@ -35,8 -46,6 +51,8 @@@ float vote_accept_count;    // total am
  float vote_reject_count;    // same as above, but rejected
  float vote_abstain_count;   // same as above, but abstained
  float vote_needed_overall;  // total amount of players NEEDED for a vote to pass (based on sv_vote_majority_factor)
 +float vote_target_type; // z411
 +entity vote_target; // z411
  .float vote_master;         // flag for if the player has vote master privelages
  .float vote_waittime;       // flag for how long the player must wait before they can vote again
  .float vote_selection;      // flag for which vote selection the player has made (See VOTE_SELECT_*)
@@@ -57,7 -66,6 +73,7 @@@ float readycount;                  // a
  float readyrestart_happened;       // keeps track of whether a restart has already happened
  float restart_mapalreadyrestarted; // bool, indicates whether reset_map() was already executed
  .float ready;                      // flag for if a player is ready
 +.float last_ready;                               // z411 time of the last readyup for anti-spam
  .int team_saved;                   // team number to restore upon map reset
  .void(entity this) reset;            // if set, an entity is reset using this
  .void(entity this) reset2;         // if set, an entity is reset using this (after calling ALL the reset functions for other entities)
diff --combined qcsrc/server/damage.qc
index e47c30d4cac3e3f7347a5a498cd5269901ee5ad6,8b77c8b14af755f290c0e4ae83e01984a938ad80..9d1fadc00f76b8915f787ebe24e9601c228613e9
@@@ -36,6 -36,7 +36,7 @@@
  #include <server/weapons/accuracy.qh>
  #include <server/weapons/csqcprojectile.qh>
  #include <server/weapons/selection.qh>
+ #include <server/weapons/weaponsystem.qh>
  #include <server/world.qh>
  
  void UpdateFrags(entity player, int f)
@@@ -170,7 -171,6 +171,7 @@@ void Obituary_SpecialDeath
  
  float Obituary_WeaponDeath(
        entity notif_target,
 +      entity attacker,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
                        s1, s2, s3, "",
                        f1, f2, 0, 0
                );
 +              
 +              // z411 special medals
 +              if(attacker) {
 +                      switch(death_message) {
 +                              case WEAPON_SHOTGUN_MURDER_SLAP:
 +                                      if(!cvar("g_melee_only")) { // don't spam humiliation if we're in melee_only mode
 +                                              Give_Medal(attacker, HUMILIATION);
 +                                      }
 +                                      break;
 +                              case WEAPON_ELECTRO_MURDER_COMBO:
 +                                      Give_Medal(attacker, ELECTROBITCH);
 +                                      break;
 +                      }
 +              }
        }
        else
        {
@@@ -262,7 -248,7 +263,7 @@@ void Obituary(entity attacker, entity i
        notif_anonymous = M_ARGV(5, bool);
  
        if(notif_anonymous)
 -              attacker_name = "Anonymous player";
 +              attacker_name = "???";
  
        #ifdef NOTIFICATIONS_DEBUG
        Debug_Notification(
                                }
                        }
                }
 -              else if (!Obituary_WeaponDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
 +              else if (!Obituary_WeaponDeath(targ, NULL, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0))
                {
                        backtrace("SUICIDE: what the hell happened here?\n");
                        return;
                }
                LogDeath("suicide", deathtype, targ, targ);
 +              Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_SUICIDE);
                if(deathtype != DEATH_AUTOTEAMCHANGE.m_id) // special case: don't negate frags if auto switched
                        GiveFrags(attacker, targ, -1, deathtype, weaponentity);
        }
  
                        Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, targ.netname);
                        Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker_name);
 -                      Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL), targ.netname, attacker_name, deathlocation, CS(targ).killcount);
 +                      Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL),
 +                              playername(targ.netname, targ.team, true), playername(attacker_name, attacker.team, true),
 +                              deathlocation, CS(targ).killcount);
  
                        // In this case, the death message will ALWAYS be "foo was betrayed by bar"
                        // No need for specific death/weapon messages...
                        CS(attacker).killcount = CS(attacker).killcount + 1;
  
                        attacker.killsound += 1;
 -
 +                      
                        // TODO: improve SPREE_ITEM and KILL_SPREE_LIST
                        // these 2 macros are spread over multiple files
                        #define SPREE_ITEM(counta,countb,center,normal,gentle) \
                                case counta: \
 -                                      Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
 +                                      Give_Medal(attacker, KILLSTREAK_##countb); \
                                        if (!warmup_stage) \
                                                PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
                                        break;
                        {
                                checkrules_firstblood = true;
                                notif_firstblood = true; // modify the current messages so that they too show firstblood information
 +                              Give_Medal(attacker, FIRSTBLOOD);
                                PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
                                PlayerStats_GameReport_Event_Player(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
  
                                kill_count_to_attacker = CS(attacker).killcount;
                                kill_count_to_target = 0;
                        }
 +                      
 +                      // Excellent check
 +                      if(attacker.lastkill && attacker.lastkill > time - 2) {
 +                              Give_Medal(attacker, EXCELLENT);
 +                      }
 +                      attacker.lastkill = time;
  
                        if(targ.istypefrag)
                        {
                        if(deathtype == DEATH_BUFF.m_id)
                                f3 = buff_FirstFromFlags(STAT(BUFFS, attacker)).m_id;
  
 -                      if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker))
 -                              Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
 +                      if (!Obituary_WeaponDeath(targ, attacker, true, deathtype, playername(targ.netname, targ.team, true), playername(attacker_name, attacker.team, true), deathlocation, CS(targ).killcount, kill_count_to_attacker))
 +                              Obituary_SpecialDeath(targ, true, deathtype, playername(targ.netname, targ.team, true), playername(attacker_name, attacker.team, true), deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
                }
        }
  
                        case DEATH_HURTTRIGGER:
                        {
                                Obituary_SpecialDeath(targ, false, deathtype,
 -                                      targ.netname,
 +                                      playername(targ.netname, targ.team, true),
                                        inflictor.message,
                                        deathlocation,
                                        CS(targ).killcount,
                        case DEATH_CUSTOM:
                        {
                                Obituary_SpecialDeath(targ, false, deathtype,
 -                                      targ.netname,
 +                                      playername(targ.netname, targ.team, true),
                                        ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage),
                                        deathlocation,
                                        CS(targ).killcount,
  
                        default:
                        {
 -                              Obituary_SpecialDeath(targ, false, deathtype, targ.netname, deathlocation, "", CS(targ).killcount, 0, 0);
 +                              Obituary_SpecialDeath(targ, false, deathtype, playername(targ.netname, targ.team, true), deathlocation, "", CS(targ).killcount, 0, 0);
                                break;
                        }
                }
  
                LogDeath("accident", deathtype, targ, targ);
 +              Send_Notification(NOTIF_ONE, targ, MSG_ANNCE, ANNCE_ACCIDENT);
                GiveFrags(targ, targ, -1, deathtype, weaponentity);
  
                if(GameRules_scoring_add(targ, SCORE, 0) == -5)
@@@ -655,7 -630,7 +656,7 @@@ void Damage(entity targ, entity inflict
                                damage = 0;
                                force = '0 0 0';
                        }
-                       else if(SAME_TEAM(attacker, targ))
+                       else if(!STAT(FROZEN, targ) && SAME_TEAM(attacker, targ))
                        {
                                if(autocvar_teamplay_mode == 1)
                                        damage = 0;
  
                        if(IS_PLAYER(victim) || (IS_TURRET(victim) && victim.active == ACTIVE_ACTIVE) || IS_MONSTER(victim) || MUTATOR_CALLHOOK(PlayHitsound, victim, attacker))
                        {
-                               if(DIFF_TEAM(victim, attacker) && !STAT(FROZEN, victim))
+                               if (DIFF_TEAM(victim, attacker))
                                {
                                        if(damage > 0)
                                        {
                                                }
                                        }
                                }
-                               else if(IS_PLAYER(attacker))
+                               else if (IS_PLAYER(attacker) && !STAT(FROZEN, victim)) // same team
                                {
-                                       // if enemy gets frozen in this frame and receives other damage don't
-                                       // play the typehitsound e.g. when hit by multiple bullets of the shotgun
-                                       if (deathtype != DEATH_FIRE.m_id && (!STAT(FROZEN, victim) || time > victim.freeze_time))
+                                       if (deathtype != DEATH_FIRE.m_id)
                                        {
                                                attacker.typehitsound += 1;
                                        }
diff --combined qcsrc/server/damage.qh
index 86df0e8ccedf92c6dd16de535330a0c3f6e9d512,7284f8c19f53f1250c1792fb015fe428089b5408..3140748245b864de5f0f2ded278050a6157208ae
@@@ -2,6 -2,34 +2,34 @@@
  
  #include <common/weapons/_all.qh>
  
+ bool autocvar_g_throughfloor_debug;
+ float autocvar_g_throughfloor_damage;
+ float autocvar_g_throughfloor_force;
+ float autocvar_g_throughfloor_damage_max_stddev;
+ float autocvar_g_throughfloor_force_max_stddev;
+ float autocvar_g_throughfloor_min_steps_player;
+ float autocvar_g_throughfloor_max_steps_player;
+ float autocvar_g_throughfloor_min_steps_other;
+ float autocvar_g_throughfloor_max_steps_other;
+ float autocvar_g_mirrordamage;
+ bool autocvar_g_mirrordamage_virtual;
+ bool autocvar_g_mirrordamage_onlyweapons;
+ float autocvar_g_maxpushtime;
+ float autocvar_g_balance_damagepush_speedfactor;
+ int autocvar_g_balance_firetransfer_damage;
+ int autocvar_g_balance_firetransfer_time;
+ float autocvar_g_balance_armor_blockpercent;
+ float autocvar_g_teamdamage_resetspeed;
+ float autocvar_g_teamdamage_threshold;
+ float autocvar_g_balance_selfdamagepercent;
+ float autocvar_g_friendlyfire;
+ float autocvar_g_friendlyfire_virtual;
+ float autocvar_g_friendlyfire_virtual_force;
+ float autocvar_g_frozen_revive_falldamage;
+ int autocvar_g_frozen_revive_falldamage_health;
+ bool autocvar_g_frozen_damage_trigger;
+ float autocvar_g_frozen_force;
  .void(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) event_damage;
  
  .bool(entity targ, entity inflictor, float amount, float limit) event_heal;
@@@ -37,7 -65,6 +65,7 @@@ float damage_gooddamage
  .float spawnshieldtime;
  
  .int totalfrags;
 +.float lastkill;
  
  .bool canteamdamage;
  
@@@ -70,7 -97,6 +98,7 @@@ void Obituary_SpecialDeath
  float w_deathtype;
  float Obituary_WeaponDeath(
        entity notif_target,
 +      entity target,
        float murder,
        int deathtype,
        string s1, string s2, string s3,
index 2220810768fa936127a48804a776752c2ecdcfd3,36932f0cef3f490a3bbff2f85e09033e49e25e8e..25ccf39f7e8736b3882c6282cf81cc5633fbb593
@@@ -2,6 -2,7 +2,7 @@@
  
  #include <common/constants.qh>
  #include <common/deathtypes/all.qh>
+ #include <common/gamemodes/gamemode/cts/cts.qh>
  #include <common/items/_mod.qh>
  #include <common/mapobjects/subs.qh>
  #include <common/mapobjects/triggers.qh>
@@@ -213,8 -214,6 +214,8 @@@ void Item_Respawn(entity this
  
  void Item_RespawnCountdown(entity this)
  {
 +      if(game_timeout) { this.nextthink = time + 1; return; }
 +      
        if(this.item_respawncounter >= ITEM_RESPAWN_TICKS)
        {
                if(this.waypointsprite_attached)
        else
        {
                this.nextthink = time + 1;
 -              this.item_respawncounter += 1;
 +              this.item_respawncounter = floor((time - game_starttime) - (this.scheduledrespawntime - ITEM_RESPAWN_TICKS)) + 1;
 +              //this.item_respawncounter += 1;
 +              //LOG_INFOF("Respawncounter: %d", this.item_respawncounter);
 +              if(this.item_respawncounter < 1) return;
 +              
                if(this.item_respawncounter == 1)
                {
                        do {
  
  void Item_RespawnThink(entity this)
  {
 -      this.nextthink = time;
 +      this.nextthink = time + 1;
        if(this.origin != this.oldorigin)
                ItemUpdate(this);
 -
 -      if(time >= this.wait)
 +      
 +      if(!game_timeout && time - game_starttime >= this.wait)
                Item_Respawn(this);
 +      
 +      //LOG_INFOF("time until respawn %d", (this.wait) - (time - game_starttime));
  }
  
  void Item_ScheduleRespawnIn(entity e, float t)
        if ((Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
        {
                setthink(e, Item_RespawnCountdown);
 -              e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
 -              e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
 +              //e.nextthink = time - timeout_total_time + max(0, t - ITEM_RESPAWN_TICKS);
 +              //e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
 +              e.nextthink = time;
 +              e.scheduledrespawntime = time - game_starttime + t;
                e.item_respawncounter = 0;
 +              
                if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
                        t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
        {
                setthink(e, Item_RespawnThink);
                e.nextthink = time;
 -              e.scheduledrespawntime = time + t;
 -              e.wait = time + t;
 +              e.scheduledrespawntime = time - game_starttime + t;
 +              e.wait = time - game_starttime + t;
  
                if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
@@@ -483,15 -473,6 +484,15 @@@ bool Item_GiveAmmoTo(entity item, entit
        return true;
  }
  
 +void Item_NotifyWeapon(entity player, int wep)
 +{
 +      if(IS_REAL_CLIENT(player)) {
 +              msg_entity = player;
 +              WriteHeader(MSG_ONE, TE_CSQC_WEAPONPICKUP);
 +              WriteByte(MSG_ONE, wep);
 +      }
 +}
 +
  bool Item_GiveTo(entity item, entity player)
  {
        // if nothing happens to player, just return without taking the item
        pickedup |= Item_GiveAmmoTo(item, player, RES_FUEL, g_pickup_fuel_max);
        if (item.itemdef.instanceOfWeaponPickup)
        {
 -              WepSet w;
 +              WepSet w, wp;
                w = STAT(WEAPONS, item);
 -              w &= ~STAT(WEAPONS, player);
 +              wp = w & ~STAT(WEAPONS, player);
  
                if (w || (item.spawnshieldtime && item.pickup_anyway > 0))
                {
                        pickedup = true;
                        FOREACH(Weapons, it != WEP_Null, {
 -                              if(w & (it.m_wepset))
 +                              Weapon wep = it;
 +                              
 +                              if(w & (wep.m_wepset)) {
 +                                      // z411 Seriously find a better way to do this
 +                                      Item_NotifyWeapon(player, wep.m_id);
 +                                      FOREACH_CLIENT(IS_SPEC(it) && it.enemy == player, { Item_NotifyWeapon(it, wep.m_id); });
 +                              }
 +                              
 +                              if(wp & (wep.m_wepset))
                                {
                                        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                                        {
                                                .entity weaponentity = weaponentities[slot];
                                                if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
 -                                                      W_DropEvent(wr_pickup, player, it.m_id, item, weaponentity);
 +                                                      W_DropEvent(wr_pickup, player, wep.m_id, item, weaponentity);
                                        }
 -                                      W_GiveWeapon(player, it.m_id);
 +                                      W_GiveWeapon(player, wep.m_id);
                                }
                        });
                }
diff --combined qcsrc/server/scores.qh
index 74c0739d82852be531c86543badea043cafbbdfa,2287815f5acd2e43fc8c7b24d443344a83b28040..288eaf0c11a717d7a9f1a91668eb8c25b91ac49c
@@@ -2,6 -2,8 +2,8 @@@
  
  #include <common/scores.qh>
  
+ bool autocvar_g_full_getstatus_responses;
  entity scores_initialized; // non-NULL when scores labels/rules have been set
  .float scoreboard_pos;
  
@@@ -110,9 -112,6 +112,9 @@@ float WinningConditionHelper_secondteam
  float WinningConditionHelper_equality;      ///< we have no winner
  entity WinningConditionHelper_winner;       ///< the winning player, or NULL if none
  entity WinningConditionHelper_second;       ///< the second player, or NULL if none
 +entity WinningConditionHelper_winner_last;
 +entity WinningConditionHelper_equality_one;
 +entity WinningConditionHelper_equality_two;
  float WinningConditionHelper_lowerisbetter; ///< lower is better, duh
  float WinningConditionHelper_zeroisworst;   ///< zero is worst, duh
  #define WINNINGCONDITIONHELPER_LOWERISBETTER_WORST 999999999
diff --combined qcsrc/server/teamplay.qc
index 6499d1f46bcc1b0ee5fd0f47289ce04897fc0ab7,43d4d2461fbb141585102ca9735f9e071b9b6339..855db83ac48c413107fe6bcfe990d618bab06b01
@@@ -4,6 -4,8 +4,8 @@@
  #include <common/gamemodes/_mod.qh>
  #include <common/teams.qh>
  #include <server/bot/api.qh>
+ #include <server/bot/default/cvars.qh>
+ #include <server/campaign.qh>
  #include <server/client.qh>
  #include <server/command/vote.qh>
  #include <server/damage.qh>
@@@ -31,7 -33,6 +33,7 @@@ const int TEAM_NOT_ALLOWED = -1
  .int m_team_balance_state; ///< Holds the state of the team balance entity.
  .entity m_team_balance_team[NUM_TEAMS]; ///< ???
  
 +.string m_team_name; // z411 team name
  .float m_team_score; ///< The score of the team.
  .int m_num_players; ///< Number of players (both humans and bots) in a team.
  .int m_num_bots; ///< Number of bots in a team.
@@@ -71,16 -72,6 +73,16 @@@ entity Team_GetTeam(int team_num
        return g_team_entities[Team_TeamToIndex(team_num) - 1];
  }
  
 +string Team_GetTeamName(entity team_ent)
 +{
 +      return team_ent.m_team_name;
 +}
 +
 +void Team_SetTeamName(entity team_ent, string name)
 +{
 +      team_ent.m_team_name = name;
 +}
 +
  float Team_GetTeamScore(entity team_ent)
  {
        return team_ent.m_team_score;
@@@ -101,16 -92,6 +103,16 @@@ void Team_SetNumberOfAlivePlayers(entit
        team_ent.m_num_players_alive = number;
  }
  
 +int Team_GetNumberOfPlayers(entity team_ent)
 +{
 +      return team_ent.m_num_players;
 +}
 +
 +void Team_SetNumberOfPlayers(entity team_ent, int number)
 +{
 +      team_ent.m_num_players = number;
 +}
 +
  int Team_GetNumberOfAliveTeams()
  {
        int result = 0;
diff --combined qcsrc/server/teamplay.qh
index 25fd2561a9e9e0b6987c159ce2a79fec8a44ec53,1b1562976b6cea4a38906b07ca896afe86c556ce..ccb5b87adb7f88a43cc81f9b58c4a7570c61195e
@@@ -8,6 -8,8 +8,8 @@@ bool autocvar_teamplay_lockonrestart
  bool autocvar_g_balance_teams;
  bool autocvar_g_balance_teams_prevent_imbalance;
  
+ string autocvar_g_forced_team_otherwise;
  bool lockteams;
  
  // ========================== Global teams API ================================
@@@ -39,13 -41,11 +41,13 @@@ void Team_SetTeamScore(entity team_ent
  /// \param[in] team_ent Team entity.
  /// \return Number of alive players in a team.
  int Team_GetNumberOfAlivePlayers(entity team_ent);
 +int Team_GetNumberOfPlayers(entity team_ent);
  
  /// \brief Sets the number of alive players in a team.
  /// \param[in,out] team_ent Team entity.
  /// \param[in] number Number of players to set.
  void Team_SetNumberOfAlivePlayers(entity team_ent, int number);
 +void Team_SetNumberOfPlayers(entity team_ent, int number);
  
  /// \brief Returns the number of alive teams.
  /// \return Number of alive teams.
index 2bcaadbce7c0c4f2e71cb501a3215c935069526d,6005813fee1710ef05f9dd72354f2c7c2a4bcc2b..63c9a34320f020a773ab54024351c77cf39301f5
@@@ -3,13 -3,14 +3,15 @@@
  #include <common/weapons/_all.qh>
  #include <common/stats.qh>
  
+ float autocvar_sv_accuracy_data_share = 1;
  .bool cvar_cl_accuracy_data_share;
  REPLICATE(cvar_cl_accuracy_data_share, bool, "cl_accuracy_data_share");
  .bool cvar_cl_accuracy_data_receive;
  REPLICATE(cvar_cl_accuracy_data_receive, bool, "cl_accuracy_data_receive");
  
  .entity accuracy;
 +.entity roundaccuracy;
  .float accuracy_frags[REGISTRY_MAX(Weapons)];
  
  .float accuracy_hit[REGISTRY_MAX(Weapons)];
@@@ -27,7 -28,6 +29,7 @@@ void accuracy_resend(entity e)
  
  // update accuracy stats
  void accuracy_add(entity e, Weapon w, float fired, float hit);
 +void roundaccuracy_clear(entity this);
  
  // helper
  bool accuracy_isgooddamage(entity attacker, entity targ);
index 9658af0562830b4eae5add5c89a00b70c0256994,b345b0984018ec8ccd77df2d03df5396f058630f..15da87068e7d3257e37ae2e3e3fb879a27d4ce31
@@@ -72,10 -72,18 +72,18 @@@ void W_SetupShot_Dir_ProjectileSize_Ran
        vector md = ent.(weaponentity).movedir;
        vector vecs = ((md.x > 0) ? md : '0 0 0');
  
-       // TODO this is broken - see 637056bea7bf7f5c9c0fc6113e94731a2767476 for an attempted fix
-       // which fixes issue #1957 but causes #2129
        vector dv = right * -vecs.y + up * vecs.z;
-       w_shotorg = ent.origin + ent.view_ofs + dv;
+       w_shotorg = ent.origin + ent.view_ofs;
+       if(antilag)
+       {
+               if(CS(ent).antilag_debug)
+                       tracebox_antilag(ent, w_shotorg, mi, ma, w_shotorg + dv, MOVE_NORMAL, ent, CS(ent).antilag_debug);
+               else
+                       tracebox_antilag(ent, w_shotorg, mi, ma, w_shotorg + dv, MOVE_NORMAL, ent, ANTILAG_LATENCY(ent));
+       }
+       else
+               tracebox(w_shotorg, mi, ma, w_shotorg + dv, MOVE_NORMAL, ent);
+       w_shotorg = trace_endpos;
  
        // now move the shotorg forward as much as requested if possible
        if(antilag)
@@@ -326,9 -334,8 +334,9 @@@ void FireRailgunBullet (entity this, .e
  
        IL_CLEAR(g_railgunhit);
  
 -      if(headshot)
 -              Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT);
 +      if(headshot) {
 +              Give_Medal(this, HEADSHOT);
 +      }
  
        // calculate hits and fired shots for hitscan
        if(this.(weaponentity))
@@@ -482,9 -489,8 +490,9 @@@ void fireBullet_antilag(entity this, .e
                        Damage_DamageInfo(start, 0, 0, 0, max(1, force) * normalize(dir) * -damage_fraction, dtype, 0, this);
        }
  
 -      if(headshot)
 -              Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_HEADSHOT);
 +      if(headshot) {
 +              Give_Medal(this, HEADSHOT);
 +      }
  
        if(lag)
                antilag_restore_all(this);
diff --combined qcsrc/server/world.qc
index 4ab109901fb707c6c841bbd2e008e357ff07dece,5531d223f72c6b226af5bb20633e5ca911671208..3a27c66f0297444d6ba6b0dd59f1bb6fbbb9ee94
@@@ -37,6 -37,7 +37,7 @@@
  #include <server/hook.qh>
  #include <server/intermission.qh>
  #include <server/ipban.qh>
+ #include <server/items/items.qh>
  #include <server/main.qh>
  #include <server/mapvoting.qh>
  #include <server/mutators/_mod.qh>
@@@ -312,12 -313,9 +313,12 @@@ void cvar_changes_init(
  
                // long
                BADCVAR("hostname");
 +              BADCVAR("hostname_full");
                BADCVAR("g_maplist");
                BADCVAR("g_maplist_mostrecent");
                BADCVAR("sv_motd");
 +              
 +              BADPREFIX("g_teamnames_");
  
                v = cvar_string(k);
                d = cvar_defstring(k);
                BADCVAR("g_forced_respawn");
                BADCVAR("g_freezetag_point_leadlimit");
                BADCVAR("g_freezetag_point_limit");
 +              BADCVAR("g_freezetag_revive_respawn");
 +              BADCVAR("g_freezetag_round_stop");
 +              BADCVAR("g_freezetag_round_respawn");
                BADCVAR("g_glowtrails");
                BADCVAR("g_hats");
                BADCVAR("g_casings");
                BADPREFIX("sv_timeout_");
                BADPREFIX("sv_vote_");
                BADPREFIX("timelimit_");
 +              BADPREFIX("sv_chat_");
 +              BADPREFIX("sv_jingle_");
  
                // allowed changes to server admins (please sync this to server.cfg)
                // vi commands:
@@@ -1020,9 -1013,6 +1021,9 @@@ spawnfunc(worldspawn
  
        world_initialized = 1;
        __spawnfunc_spawn_all();
 +      
 +      if(!warmup_stage)
 +              round_handler_Activate(true);
  }
  
  spawnfunc(light)
@@@ -1291,8 -1281,6 +1292,8 @@@ void NextLevel(
        */
  
        //pos = FindIntermission ();
 +      
 +      sound(NULL, CH_INFO, SND_ENDMATCH, VOL_BASE, ATTN_NONE);
  
        VoteReset();
  
        WeaponStats_Shutdown();
  
        Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_Null); // kill all centerprints now
 +      
 +      // send winner notification
 +      if(teamplay) {
 +              Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, APP_TEAM_NUM(WinningConditionHelper_winnerteam, ANNCE_WINS));
 +      }
  
        if(autocvar_sv_eventlog)
                GameLogEcho(":gameover");
        });
  
        target_music_kill();
 +      
 +      // z411
 +      if(autocvar_sv_jingle_end) {
 +              int jingles_len = 0;
 +              string jingles[32];
 +              jingles[0] = "";
 +              
 +              FOREACH_WORD(autocvar_sv_jingle_end_list, it,
 +              {
 +                      jingles[jingles_len] = it;
 +                      jingles_len++;
 +              });
 +              
 +              if(jingles_len) {
 +                      int song_to_play = rint(random() * (jingles_len - 1));
 +              
 +                      FOREACH_CLIENT(IS_REAL_CLIENT(it),
 +                      {
 +                              stuffcmd(it, "cd stop\n");
 +                              _sound(it, CH_INFO, strcat("jingle/", jingles[song_to_play], ".ogg"), VOL_BASE * autocvar_sv_jingle_end_volume, ATTEN_NORM);
 +                      });
 +              }
 +      }
  
        if(autocvar_g_campaign)
                CampaignPreIntermission();
@@@ -1387,12 -1347,6 +1388,12 @@@ void InitiateOvertime() // ONLY call th
        //add one more overtime by simply extending the timelimit
        cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime));
        Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
 +      
 +      sound(NULL, CH_INFO, SND_OVERTIME, VOL_BASE, ATTN_NONE);
 +      if(checkrules_overtimesadded == 1) {
 +              Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_OVERTIME);
 +              overtime_starttime = time;
 +      }
  }
  
  float GetWinningCode(float fraglimitreached, float equality)
@@@ -1444,6 -1398,7 +1445,6 @@@ void ClearWinners(
        FOREACH_CLIENT(IS_PLAYER(it), { it.winning = 0; });
  }
  
 -int fragsleft_last;
  float WinningCondition_Scores(float limit, float leadlimit)
  {
        // TODO make everything use THIS winning condition (except LMS)
  
        if(MUTATOR_CALLHOOK(Scores_CountFragsRemaining))
        {
 -              float fragsleft;
                if (checkrules_suddendeathend && time >= checkrules_suddendeathend)
                {
                        fragsleft = 1;
                        fragsleft_last = fragsleft;
                }
        }
 -
 +      
 +      // z411
 +      if (WinningConditionHelper_winner != WinningConditionHelper_winner_last && (WinningConditionHelper_second || WinningConditionHelper_equality))
 +      {
 +              if (WinningConditionHelper_equality)
 +              {
 +                      Send_Notification(NOTIF_ONE, WinningConditionHelper_equality_one, MSG_ANNCE, ANNCE_LEAD_TIED);
 +                      Send_Notification(NOTIF_ONE, WinningConditionHelper_equality_two, MSG_ANNCE, ANNCE_LEAD_TIED);
 +              }
 +              else
 +              {
 +                      Send_Notification(NOTIF_ONE, WinningConditionHelper_winner, MSG_ANNCE, ANNCE_LEAD_GAINED);
 +                      Send_Notification(NOTIF_ONE, WinningConditionHelper_second, MSG_ANNCE, ANNCE_LEAD_LOST);
 +              }
 +              
 +              WinningConditionHelper_winner_last = WinningConditionHelper_winner;
 +      }
 +      
        bool fraglimit_reached = (limit && WinningConditionHelper_topscore >= limit);
        bool leadlimit_reached = (leadlimit && WinningConditionHelper_topscore - WinningConditionHelper_secondscore >= leadlimit);
  
@@@ -1640,9 -1579,6 +1641,9 @@@ void CheckRules_World(
                        // again, but this shouldn't hurt
                return;
        }
 +      
 +      // z411 don't check rules if we're in a timeout
 +      if (game_timeout) return;
  
        float timelimit = autocvar_timelimit * 60;
        float fraglimit = autocvar_fraglimit;
                                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_RACE_FINISHLAP);
                        else
                                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_FRAG);
 +                      sound(NULL, CH_INFO, SND_OVERTIME, VOL_BASE, ATTN_NONE);
 +                      Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_SUDDENDEATH);
                }
        }
        else
diff --combined qcsrc/server/world.qh
index 20d456990e5a8264e2a36659785323aabb4ea1d3,4141c99e29182a49daff6c1678b52dadad704c3d..a43c8dac1a98ef246b8856240405218b8569b907
@@@ -2,10 -2,35 +2,40 @@@
  
  #include <common/weapons/_all.qh>
  
+ bool autocvar__sv_init;
+ bool autocvar_g_use_ammunition;
+ bool autocvar_g_jetpack;
+ bool autocvar_g_warmup_allguns;
+ bool autocvar_g_warmup_allow_timeout;
+ #define autocvar_g_weaponarena cvar_string("g_weaponarena")
+ string autocvar_quit_and_redirect;
+ float autocvar_quit_and_redirect_timer;
+ bool autocvar_quit_when_empty;
+ string autocvar_sessionid;
+ bool autocvar_sv_curl_serverpackages_auto;
+ bool autocvar_sv_db_saveasdump;
+ bool autocvar_sv_logscores_bots;
+ bool autocvar_sv_logscores_console;
+ bool autocvar_sv_logscores_file;
+ string autocvar_sv_logscores_filename;
+ float autocvar_sv_mapchange_delay;
+ float autocvar_timelimit_increment;
+ float autocvar_timelimit_decrement;
+ float autocvar_timelimit_min;
+ float autocvar_timelimit_max;
+ float autocvar_timelimit_overtime;
+ int autocvar_timelimit_overtimes;
+ float autocvar_timelimit_suddendeath;
++// z411
++bool autocvar_sv_jingle_end;
++string autocvar_sv_jingle_end_list;
++float autocvar_sv_jingle_end_volume;
++
  float checkrules_equality;
  float checkrules_suddendeathwarning;
  float checkrules_suddendeathend;
 -float checkrules_overtimesadded; //how many overtimes have been already added
 +//float checkrules_overtimesadded; //how many overtimes have been already added
  
  // flag set on worldspawn so that the code knows if it is dedicated or not
  bool server_is_dedicated;
@@@ -18,9 -43,6 +48,9 @@@ string modname
  
  string gamemode_name;
  
 +int fragsleft;
 +int fragsleft_last;
 +
  string clientstuff;
  
  string matchid;