]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into terencehill/ca_arena_mutators
authorterencehill <piuntn@gmail.com>
Thu, 7 Mar 2013 00:11:34 +0000 (01:11 +0100)
committerterencehill <piuntn@gmail.com>
Thu, 7 Mar 2013 00:11:34 +0000 (01:11 +0100)
Conflicts:
qcsrc/client/announcer.qc
qcsrc/common/constants.qh
qcsrc/server/arena.qc
qcsrc/server/cl_client.qc
qcsrc/server/defs.qh
qcsrc/server/mutators/gamemode_freezetag.qc

30 files changed:
1  2 
_hud_descriptions.cfg
gamemodes.cfg
hud_luminos.cfg
hud_luminos_minimal.cfg
hud_luminos_minimal_xhair.cfg
hud_luminos_old.cfg
hud_nexuiz.cfg
qcsrc/client/View.qc
qcsrc/client/announcer.qc
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/hud_config.qc
qcsrc/common/constants.qh
qcsrc/server/autocvars.qh
qcsrc/server/bot/bot.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/cl_weapons.qc
qcsrc/server/command/cmd.qc
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode_freezetag.qc
qcsrc/server/mutators/gamemode_keyhunt.qh
qcsrc/server/mutators/mutator_superspec.qc
qcsrc/server/progs.src
qcsrc/server/scores.qc
qcsrc/server/teamplay.qc
qcsrc/server/w_minstanex.qc

diff --combined _hud_descriptions.cfg
index c77be4eed700bf1110182115e89710db74684b3b,f4ecc143e522670bfe225b1f09c9ddc6831fcffc..16e8116101d65993d9691c6b82bb8aec697e03aa
@@@ -126,7 -126,6 +126,6 @@@ seta hud_panel_notify_bg_border "" "if 
  seta hud_panel_notify_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
  seta hud_panel_notify_flip "" "order the list top to bottom instead of bottom to top"
  seta hud_panel_notify_fontsize "" "multiplier for the font size used for player names in the panel"
- seta hud_panel_notify_print "" "also con_notify print the messages that are shown on the notify panel"
  seta hud_panel_notify_fadetime "" "fade out time"
  seta hud_panel_notify_time "" "time that a new entry stays until it fades out"
  
@@@ -156,6 -155,8 +155,8 @@@ seta hud_panel_radar_zoommode "" "zoom 
  seta hud_panel_radar_scale "" "distance you can see on the team radar"
  seta hud_panel_radar_maximized_scale "" "distance you can see on the radar when maximized"
  seta hud_panel_radar_maximized_size "" "size of the radar when maximized"
+ seta hud_panel_radar_maximized_rotation "" "rotation mode: you set what points up. 0 = player, 1 = west, 2 = south, 3 = east, 4 = north"
+ seta hud_panel_radar_maximized_zoommode "" "zoom mode: 0 = zoomed by default, 1 = zoomed when +zoom, 2 = always zoomed, 3 = always zoomed out"
  
  seta hud_panel_score "" "enable/disable this panel"
  seta hud_panel_score_pos "" "position of this base of the panel"
@@@ -198,9 -199,7 +199,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
  seta hud_panel_modicons_bg_border "" "if set to something else than \"\" = override default size of border around the background"
  seta hud_panel_modicons_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
 +seta hud_panel_modicons_ca_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
  seta hud_panel_modicons_dom_layout "" "3 possible layouts: 0) only icons; 1) icons and percentage of average pps (points per second); 2) icons and average pps"
 +seta hud_panel_modicons_freezetag_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
  
  seta hud_panel_pressedkeys "" "enable/disable this panel, 1 = show only when spectating other players, 2 = show always"
  seta hud_panel_pressedkeys_pos "" "position of this base of the panel"
diff --combined gamemodes.cfg
index 68f633d5716ce5da10a11bc3945a0362450c7462,05aaf3df40530d1379b0976ed83fbbb334d0b017..8fac6458489f1d4e041557798981b6ab0eb9fa58
@@@ -149,7 -149,6 +149,7 @@@ set g_ft_weapon_stay 
  set g_arena 0 "Arena: many one-on-one rounds are played to find the winner"
  set g_arena_maxspawned 2      "maximum number of players to spawn at once (the rest is spectating, waiting for their turn)"
  set g_arena_roundbased 1      "if disabled, the next player will spawn as soon as someone dies"
 +set g_arena_round_timelimit 180
  set g_arena_warmup 5  "time, newly spawned players have to prepare themselves in round based matches"
  
  
@@@ -169,9 -168,6 +169,9 @@@ set g_ca_spectate_enemies 0 "Allow spec
  set g_ca_warmup 10 "how long the players will have time to run around the map before the round starts"
  set g_ca_damage2score_multiplier 0.01
  set g_ca_round_timelimit 180
 +seta g_ca_teams_override 0
 +set g_ca_teams 0
 +
  
  
  // ==================
@@@ -201,7 -197,6 +201,6 @@@ set g_ctf_flag_collect_delay 
  set g_ctf_flag_health 0
  set g_ctf_flag_dropped_waypoint 2 "show dropped flag waypointsprite when a flag is lost. 1 = team only, 2 = for all players"
  set g_ctf_flag_dropped_floatinwater 200 "move upwards while in water at this velocity"
- set g_ctf_flag_pickup_verbosename 0 "show the name of the person who picked up the flag too"
  set g_ctf_throw 1 "throwing allows circumventing carrierkill score, so enable this with care!"
  set g_ctf_throw_angle_max 90 "maximum upwards angle you can throw the flag"
  set g_ctf_throw_angle_min -90 "minimum downwards angle you can throw the flag"
@@@ -280,17 -275,13 +279,17 @@@ set g_domination_point_glow             0 "dominat
  //  freezetag
  // ===========
  set g_freezetag 0 "Freeze Tag: Freeze the opposing team(s) to win, unfreeze teammates by standing next to them"
 -seta g_freezetag_warmup 5 "Time players get to run around before the round starts"
 +set g_freezetag_warmup 5 "Time players get to run around before the round starts"
  seta g_freezetag_point_limit -1       "Freeze Tag point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
  seta g_freezetag_point_leadlimit -1   "Freeze Tag point lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
 -seta g_freezetag_revive_speed 0.4 "Speed for reviving a frozen teammate"
 -seta g_freezetag_revive_clearspeed 1.6 "Speed at which reviving progress gets lost when out of range"
 -seta g_freezetag_revive_extra_size 100 "Distance in qu that you can stand from a frozen teammate to keep reviving him"
 -seta g_freezetag_frozen_force 0.6 "How much to multiply the force on a frozen player with"
 +set g_freezetag_revive_speed 0.4 "Speed for reviving a frozen teammate"
 +set g_freezetag_revive_clearspeed 1.6 "Speed at which reviving progress gets lost when out of range"
 +set g_freezetag_revive_extra_size 100 "Distance in qu that you can stand from a frozen teammate to keep reviving him"
 +set g_freezetag_round_timelimit 180
 +set g_freezetag_frozen_force 0.6 "How much to multiply the force on a frozen player with"
 +set g_freezetag_frozen_maxtime 60 "frozen players will be automatically unfrozen after this time in seconds"
 +seta g_freezetag_teams_override 0
 +set g_freezetag_teams 0
  
  
  // ==========
@@@ -351,7 -342,6 +350,6 @@@ set g_lms 0 "Last Man Standing: everyon
  set g_lms_lives_override -1
  set g_lms_regenerate 0
  set g_lms_campcheck_interval 10
- set g_lms_campcheck_message "^1Don't camp!"
  set g_lms_campcheck_damage 100
  set g_lms_campcheck_distance 1800
  set g_lms_last_join 3 "if g_lms_join_anytime is false, new players can only join if the worst active player has more than (fraglimit - g_lms_last_join) lives"
@@@ -413,6 -403,11 +411,11 @@@ set g_onslaught_cp_health 100
  set g_onslaught_cp_buildhealth 100
  set g_onslaught_cp_buildtime 5
  set g_onslaught_cp_regen 20
+ set g_onslaught_cp_proxydecap 0 "de-capture controlpoints by standing close to them"
+ set g_onslaught_cp_proxydecap_distance 512
+ set g_onslaught_cp_proxydecap_dps 100
+ set g_onslaught_spawn_at_controlpoints 0
+ set g_onslaught_spawn_at_generator 0
  
  
  // ======
diff --combined hud_luminos.cfg
index 862b8ccf982e958fa25bfec56d557a7ae6e01625,bb0c97e0998af1f8a4d88cf7f3aef2e236f9e52b..f99494a1cc154d5c39115e1c347d73fc73de8d39
@@@ -42,9 -42,9 +42,9 @@@ seta hud_panel_weapons_bg_padding "4
  seta hud_panel_weapons_accuracy "1"
  seta hud_panel_weapons_label "1"
  seta hud_panel_weapons_complainbubble "1"
- seta hud_panel_weapons_complainbubble_padding "2"
- seta hud_panel_weapons_complainbubble_time "4"
- seta hud_panel_weapons_complainbubble_fadetime "2"
+ seta hud_panel_weapons_complainbubble_padding "-1"
+ seta hud_panel_weapons_complainbubble_time "0"
+ seta hud_panel_weapons_complainbubble_fadetime "1"
  seta hud_panel_weapons_complainbubble_color_outofammo "0.8 0 0"
  seta hud_panel_weapons_complainbubble_color_donthave "0.8 0.5 0"
  seta hud_panel_weapons_complainbubble_color_unavailable "0 0.3 0.8"
@@@ -124,7 -124,6 +124,6 @@@ seta hud_panel_notify_bg_border "
  seta hud_panel_notify_bg_padding ""
  seta hud_panel_notify_flip "0"
  seta hud_panel_notify_fontsize "0.8"
- seta hud_panel_notify_print "1"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
  
@@@ -154,6 -153,8 +153,8 @@@ seta hud_panel_radar_zoommode "0
  seta hud_panel_radar_scale "4096"
  seta hud_panel_radar_maximized_scale "8192"
  seta hud_panel_radar_maximized_size "0.5 0.5"
+ seta hud_panel_radar_maximized_rotation "1"
+ seta hud_panel_radar_maximized_zoommode "3"
  
  seta hud_panel_score 1
  seta hud_panel_score_pos "0.890000 0.030000"
@@@ -196,9 -197,7 +197,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding "0"
 +seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
 +seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.450000 0.720000"
diff --combined hud_luminos_minimal.cfg
index e344cbb27a8bbc2b52744ffa64fe868b2a393857,775ddaf8f16f3779f77ace00f834c7c4015a418b..bfa0c0b3e4c510536133ebd520010576001b14ea
@@@ -42,9 -42,9 +42,9 @@@ seta hud_panel_weapons_bg_padding "
  seta hud_panel_weapons_accuracy "1"
  seta hud_panel_weapons_label "1"
  seta hud_panel_weapons_complainbubble "1"
- seta hud_panel_weapons_complainbubble_padding "-10"
- seta hud_panel_weapons_complainbubble_time "1"
- seta hud_panel_weapons_complainbubble_fadetime "0.25"
+ seta hud_panel_weapons_complainbubble_padding "-1"
+ seta hud_panel_weapons_complainbubble_time "0"
+ seta hud_panel_weapons_complainbubble_fadetime "1"
  seta hud_panel_weapons_complainbubble_color_outofammo "0.8 0 0"
  seta hud_panel_weapons_complainbubble_color_donthave "0.8 0.5 0"
  seta hud_panel_weapons_complainbubble_color_unavailable "0 0.3 0.8"
@@@ -124,7 -124,6 +124,6 @@@ seta hud_panel_notify_bg_border "
  seta hud_panel_notify_bg_padding ""
  seta hud_panel_notify_flip "1"
  seta hud_panel_notify_fontsize "0.8"
- seta hud_panel_notify_print "0"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
  
@@@ -154,6 -153,8 +153,8 @@@ seta hud_panel_radar_zoommode "0
  seta hud_panel_radar_scale "4096"
  seta hud_panel_radar_maximized_scale "8192"
  seta hud_panel_radar_maximized_size "0.5 0.5"
+ seta hud_panel_radar_maximized_rotation "1"
+ seta hud_panel_radar_maximized_zoommode "3"
  
  seta hud_panel_score 1
  seta hud_panel_score_pos "0.465000 0.045000"
@@@ -196,9 -197,7 +197,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
 +seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
 +seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.450000 0.650000"
index df652104cf3aed52d45d189450adfbd7a08738bf,b7a208dbdbccb0a924fe50bcd37f9b7e460685c7..27ca9ab80d0e0133937453d8314579a433b388de
@@@ -42,9 -42,9 +42,9 @@@ seta hud_panel_weapons_bg_padding "
  seta hud_panel_weapons_accuracy "1"
  seta hud_panel_weapons_label "1"
  seta hud_panel_weapons_complainbubble "1"
- seta hud_panel_weapons_complainbubble_padding "-10"
- seta hud_panel_weapons_complainbubble_time "1"
- seta hud_panel_weapons_complainbubble_fadetime "0.25"
+ seta hud_panel_weapons_complainbubble_padding "-1"
+ seta hud_panel_weapons_complainbubble_time "0"
+ seta hud_panel_weapons_complainbubble_fadetime "1"
  seta hud_panel_weapons_complainbubble_color_outofammo "0.8 0 0"
  seta hud_panel_weapons_complainbubble_color_donthave "0.8 0.5 0"
  seta hud_panel_weapons_complainbubble_color_unavailable "0 0.3 0.8"
@@@ -124,7 -124,6 +124,6 @@@ seta hud_panel_notify_bg_border "
  seta hud_panel_notify_bg_padding ""
  seta hud_panel_notify_flip "1"
  seta hud_panel_notify_fontsize "0.8"
- seta hud_panel_notify_print "0"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
  
@@@ -154,6 -153,8 +153,8 @@@ seta hud_panel_radar_zoommode "0
  seta hud_panel_radar_scale "4096"
  seta hud_panel_radar_maximized_scale "8192"
  seta hud_panel_radar_maximized_size "0.5 0.5"
+ seta hud_panel_radar_maximized_rotation "1"
+ seta hud_panel_radar_maximized_zoommode "3"
  
  seta hud_panel_score 1
  seta hud_panel_score_pos "0.465000 0.045000"
@@@ -196,9 -197,7 +197,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
 +seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
 +seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.450000 0.690000"
diff --combined hud_luminos_old.cfg
index f7bdb61f99d41b02b7e245f0c14f760c6dfe300f,2e718b288b240dacd582d711835b0ba3ed16e14c..3a489a04e44c95dd2b1e6aef6379bfba7c4a96c3
@@@ -42,9 -42,9 +42,9 @@@ seta hud_panel_weapons_bg_padding "
  seta hud_panel_weapons_accuracy "1"
  seta hud_panel_weapons_label "1"
  seta hud_panel_weapons_complainbubble "1"
- seta hud_panel_weapons_complainbubble_padding "-10"
- seta hud_panel_weapons_complainbubble_time "1"
- seta hud_panel_weapons_complainbubble_fadetime "0.25"
+ seta hud_panel_weapons_complainbubble_padding "-1"
+ seta hud_panel_weapons_complainbubble_time "0"
+ seta hud_panel_weapons_complainbubble_fadetime "1"
  seta hud_panel_weapons_complainbubble_color_outofammo "0.8 0 0"
  seta hud_panel_weapons_complainbubble_color_donthave "0.8 0.5 0"
  seta hud_panel_weapons_complainbubble_color_unavailable "0 0.3 0.8"
@@@ -124,7 -124,6 +124,6 @@@ seta hud_panel_notify_bg_border "
  seta hud_panel_notify_bg_padding ""
  seta hud_panel_notify_flip "0"
  seta hud_panel_notify_fontsize "0.8"
- seta hud_panel_notify_print "1"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
  
@@@ -154,6 -153,8 +153,8 @@@ seta hud_panel_radar_zoommode "0
  seta hud_panel_radar_scale "4096"
  seta hud_panel_radar_maximized_scale "8192"
  seta hud_panel_radar_maximized_size "0.5 0.5"
+ seta hud_panel_radar_maximized_rotation "1"
+ seta hud_panel_radar_maximized_zoommode "3"
  
  seta hud_panel_score 1
  seta hud_panel_score_pos "0.020000 0.920000"
@@@ -196,9 -197,7 +197,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
 +seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
 +seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.410000 0.710000"
diff --combined hud_nexuiz.cfg
index 058f2749e10e5f85ff553252179667d097141512,d4e71d876268cac6b7cccd8e60b9bb7573563ca0..57053411d74d9e91fabc67c42a294b6f6574ad39
@@@ -42,9 -42,9 +42,9 @@@ seta hud_panel_weapons_bg_padding "-5
  seta hud_panel_weapons_accuracy "1"
  seta hud_panel_weapons_label "1"
  seta hud_panel_weapons_complainbubble "1"
- seta hud_panel_weapons_complainbubble_padding "-10"
- seta hud_panel_weapons_complainbubble_time "1"
- seta hud_panel_weapons_complainbubble_fadetime "0.25"
+ seta hud_panel_weapons_complainbubble_padding "-1"
+ seta hud_panel_weapons_complainbubble_time "0"
+ seta hud_panel_weapons_complainbubble_fadetime "1"
  seta hud_panel_weapons_complainbubble_color_outofammo "0.8 0 0"
  seta hud_panel_weapons_complainbubble_color_donthave "0.8 0.5 0"
  seta hud_panel_weapons_complainbubble_color_unavailable "0 0.3 0.8"
@@@ -124,7 -124,6 +124,6 @@@ seta hud_panel_notify_bg_border "
  seta hud_panel_notify_bg_padding ""
  seta hud_panel_notify_flip "0"
  seta hud_panel_notify_fontsize "1"
- seta hud_panel_notify_print "1"
  seta hud_panel_notify_time "10"
  seta hud_panel_notify_fadetime "3"
  
@@@ -154,6 -153,8 +153,8 @@@ seta hud_panel_radar_zoommode "0
  seta hud_panel_radar_scale "4096"
  seta hud_panel_radar_maximized_scale "8192"
  seta hud_panel_radar_maximized_size "0.5 0.5"
+ seta hud_panel_radar_maximized_rotation "1"
+ seta hud_panel_radar_maximized_zoommode "3"
  
  seta hud_panel_score 1
  seta hud_panel_score_pos "0.760000 0.910000"
@@@ -196,9 -197,7 +197,9 @@@ seta hud_panel_modicons_bg_color_team "
  seta hud_panel_modicons_bg_alpha ""
  seta hud_panel_modicons_bg_border ""
  seta hud_panel_modicons_bg_padding ""
 +seta hud_panel_modicons_ca_layout "1"
  seta hud_panel_modicons_dom_layout "1"
 +seta hud_panel_modicons_freezetag_layout "1"
  
  seta hud_panel_pressedkeys 1
  seta hud_panel_pressedkeys_pos "0.440000 0.760000"
diff --combined qcsrc/client/View.qc
index 25a47e21756d407c178b8f17142669afdebdcb88,3362ce42231193210b22b6ad0fe52f5cf8cbd1bd..833693e0c61402681a3d3963927e92e6d8af415a
@@@ -249,7 -249,7 +249,7 @@@ float EnemyHitCheck(
        if(teamplay)
                if(t == myteam)
                        return SHOTTYPE_HITTEAM;
-       if(t == COLOR_SPECTATOR)
+       if(t == NUM_SPECTATOR)
                return SHOTTYPE_HITWORLD;
        return SHOTTYPE_HITENEMY;
  }
@@@ -862,8 -862,8 +862,8 @@@ void CSQC_UpdateView(float w, float h
                        }
                }
        }
 -      
 -      if(autocvar_hud_damage)
 +
 +      if(autocvar_hud_damage && !getstati(STAT_FROZEN))
        {
                splash_size_x = max(vid_conwidth, vid_conheight);
                splash_size_y = max(vid_conwidth, vid_conheight);
index 5ca75123cd8840c86b0299c2977cfc00bab86172,240d424c6a5ee255eb4eb8135ff4e7137733a0c1..51c67ccabe53d9a0d25eef6cc8a41f2317bd5a0a
@@@ -22,36 -22,23 +22,36 @@@ void Announcer_Play(string announcement
  void Announcer_Countdown() 
  {
        float starttime = getstatf(STAT_GAMESTARTTIME);
 +      float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
 +      if(roundstarttime == -1)
 +      {
 +              // stop countdown immediately
 +              centerprint_generic(CPID_GAME_STARTING, "", 1, 0);
 +              remove(self);
 +              return;
 +      }
 +      if(roundstarttime >= starttime)
 +              starttime = roundstarttime;
 +      if(starttime <= time && roundstarttime != starttime) // game start time has passed
 +              announcer_5min = announcer_1min = FALSE; // reset maptime announcers now as well
 +
        float countdown = (starttime - time);
        float countdown_rounded = floor(0.5 + countdown);
 -      
 +
        if(countdown <= 0) // countdown has finished, starttime is now
        {
-               centerprint_generic(CPID_GAME_STARTING, _("^1Begin!"), 1, 0);
 -              if (!spectatee_status)
 -                      Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN); 
++              Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN); 
  
                Announcer_Play("begin");
 -              announcer_5min = announcer_1min = FALSE; // reset maptime announcers now as well
                remove(self);
                return;
        }
        else // countdown is still going
        {
 -              if (!spectatee_status)
 +              if(roundstarttime == starttime)
 +                      centerprint_generic(CPID_GAME_STARTING, _("^1Round starts in %d seconds"), 1, countdown_rounded);
 +              else
-                       centerprint_generic(CPID_GAME_STARTING, _("^1Game starts in %d seconds"), 1, countdown_rounded);
+                       Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_GAMESTART, countdown_rounded);
  
                if(countdown_rounded <= 3 && countdown_rounded >= 1) 
                        Announcer_Play(ftos(countdown_rounded));
  void Announcer_Gamestart() 
  {
        float startTime = getstatf(STAT_GAMESTARTTIME);
 -      
 +      float roundstarttime = getstatf(STAT_ROUNDSTARTTIME);
 +      if(roundstarttime > startTime)
 +              startTime = roundstarttime;
 +
        if(previous_game_starttime != startTime) 
        {
                if((time + 5.0) < startTime) // if connecting to server while restart was active don't always play prepareforbattle
                        Announcer_Play("prepareforbattle");
 -              
 +
                if(time < startTime) 
                {
                        entity e;
index 6753123f9390ff42c3afff209315d65afce0e9c7,ba6abadc018868762228d1875b5180244fe9ce2a..9ff2b00493d5905d63f9a24d8277f6a1500bc1d5
@@@ -249,14 -249,11 +249,13 @@@ float autocvar_hud_panel_healtharmor_te
  float autocvar_hud_panel_infomessages;
  float autocvar_hud_panel_infomessages_flip;
  float autocvar_hud_panel_modicons;
 +float autocvar_hud_panel_modicons_ca_layout;
  float autocvar_hud_panel_modicons_dom_layout;
 +float autocvar_hud_panel_modicons_freezetag_layout;
  float autocvar_hud_panel_notify;
  float autocvar_hud_panel_notify_fadetime;
  float autocvar_hud_panel_notify_flip;
  float autocvar_hud_panel_notify_fontsize;
- float autocvar_hud_panel_notify_print;
  float autocvar_hud_panel_notify_time;
  float autocvar_hud_panel_physics;
  float autocvar_hud_panel_physics_acceleration_progressbar_mode;
@@@ -295,6 -292,8 +294,8 @@@ vector autocvar_hud_panel_radar_maximiz
  float autocvar_hud_panel_radar_rotation;
  float autocvar_hud_panel_radar_scale;
  float autocvar_hud_panel_radar_zoommode;
+ float autocvar_hud_panel_radar_maximized_rotation;
+ float autocvar_hud_panel_radar_maximized_zoommode;
  float autocvar_hud_panel_score;
  float autocvar_hud_panel_score_rankings;
  float autocvar_hud_panel_timer;
diff --combined qcsrc/client/hud.qc
index cfc3bc9711cc332017de14b09e1b0589deaac901,82467348e588de0b7463885bf8e6de406566fb7b..77623d5a7bd4867350ea9e43362ecc45dfd5a807
@@@ -154,18 -154,6 +154,6 @@@ void drawstringcenter(vector position, 
        drawstring(position, text, scale, rgb, theAlpha, flag);
  }
  
- // return the string of the given race place
- string race_PlaceName(float pos) {
-       if(pos == 1)
-               return _("1st");
-       else if(pos == 2)
-               return _("2nd");
-       else if(pos == 3)
-               return _("3rd");
-       else
-               return sprintf(_("%dth"), pos);
- }
  // return the string of the onscreen race timer
  string MakeRaceString(float cp, float mytime, float histime, float lapdelta, string hisname)
  {
@@@ -244,6 -232,30 +232,30 @@@ float race_CheckName(string net_name) 
        return 0;
  }
  
+ float GetPlayerColorForce(float i)
+ {
+       if(!teamplay)
+               return 0;
+       else
+               return stof(getplayerkeyvalue(i, "colors")) & 15;
+ }
+ float GetPlayerColor(float i)
+ {
+       if not(playerslots[i].gotscores) // unconnected
+               return NUM_SPECTATOR;
+       else if(stof(getplayerkeyvalue(i, "frags")) == FRAGS_SPECTATOR)
+               return NUM_SPECTATOR;
+       else
+               return GetPlayerColorForce(i);
+ }
+ string GetPlayerName(float i)
+ {
+       return ColorTranslateRGB(getplayerkeyvalue(i, "name"));
+ }
  /*
  ==================
  HUD panels
@@@ -440,7 -452,7 +452,7 @@@ void HUD_Weapons(void
        float i, f, a;
        float screen_ar, center_x = 0, center_y;
        float weapon_count, weapon_id;
-       float row, column, rows, columns;
+       float row, column, rows = 0, columns;
        float aspect = autocvar_hud_panel_weapons_aspect;
  
        float panel_weapon_accuracy;
        vector ammo_color = '1 0 1';
        float ammo_alpha = 1;
  
-       float when = autocvar_hud_panel_weapons_complainbubble_time;
-       float fadetime = autocvar_hud_panel_weapons_complainbubble_fadetime;
+       float when = max(1, autocvar_hud_panel_weapons_complainbubble_time);
+       float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
  
-       vector weapon_pos, weapon_size;
+       vector weapon_pos, weapon_size = '0 0 0';
        local noref vector old_panel_size; // fteqcc sucks
        vector color;
  
                weaponorder_cmp_str = string_null;
        }
  
+       if(autocvar_hud_panel_weapons_complainbubble)
+       if(autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
+               complain_weapon = 0;
        // determine which weapons are going to be shown
        if (autocvar_hud_panel_weapons_onlyowned)
        {
                                ++weapon_count;
  
                // add it anyway if weaponcomplain is shown
-               if((!autocvar__hud_configure) 
-                       && (autocvar_hud_panel_weapons_complainbubble 
-                               && time - complain_weapon_time < when + fadetime))
-                                       ++weapon_count;
+               if(complain_weapon)
+                       ++weapon_count;
  
                // might as well commit suicide now, no reason to live ;)
-               if (weapon_count == 0) { return; }
-               // reduce size of the panel
-               if (panel_size_y > panel_size_x)
+               if (weapon_count == 0)
                {
-                       old_panel_size_y = panel_size_y;
-                       panel_size_y *= weapon_count / WEP_COUNT;
-                       panel_pos_y += (old_panel_size_y - panel_size_y) / 2;
+                       draw_endBoldFont();
+                       return;
                }
-               else
+               old_panel_size = panel_size;
+               if(panel_bg_padding)
+                       old_panel_size -= '2 2 0' * panel_bg_padding;
+               // first find values for the standard table (with all the weapons)
+               rows = old_panel_size_y/old_panel_size_x;
+               rows = bound(1, floor((sqrt(4 * aspect * rows * WEP_COUNT + rows * rows) + rows + 0.5) / 2), WEP_COUNT);
+               columns = ceil(WEP_COUNT/rows);
+               weapon_size_x = old_panel_size_x / columns;
+               weapon_size_y = old_panel_size_y / rows;
+               // change table values to include only the owned weapons
+               // weapon_size won't be changed
+               if(weapon_count <= rows)
                {
-                       old_panel_size_x = panel_size_x;
-                       panel_size_x *= weapon_count / WEP_COUNT;
-                       panel_pos_x += (old_panel_size_x - panel_size_x) / 2;
+                       rows = weapon_count;
+                       columns = 1;
                }
+               else
+                       columns = ceil(weapon_count / rows);
+               // reduce size of the panel
+               panel_size_x = columns * weapon_size_x;
+               panel_size_y = rows * weapon_size_y;
+               panel_pos_x += (old_panel_size_x - panel_size_x) / 2;
+               panel_pos_y += (old_panel_size_y - panel_size_y) / 2;
+               if(panel_bg_padding)
+                       panel_size += '2 2 0' * panel_bg_padding;
        }
        else
                weapon_count = WEP_COUNT;
        HUD_Panel_DrawBg(1);
  
        if(center_x == -1)
+       {
+               draw_endBoldFont();
                return;
+       }
  
        if(panel_bg_padding)
        {
        }
  
        // after the sizing and animations are done, update the other values
-       rows = panel_size_y/panel_size_x;
-       rows = bound(1, floor((sqrt(4 * aspect * rows * weapon_count + rows * rows) + rows + 0.5) / 2), weapon_count);
-       columns = ceil(weapon_count/rows);
-       weapon_size = eX * panel_size_x*(1/columns) + eY * panel_size_y*(1/rows);
+       if(!rows) // if rows is > 0 onlyowned code has already updated these vars
+       {
+               rows = panel_size_y/panel_size_x;
+               rows = bound(1, floor((sqrt(4 * aspect * rows * weapon_count + rows * rows) + rows + 0.5) / 2), weapon_count);
+               columns = ceil(weapon_count/rows);
+               weapon_size = eX * panel_size_x*(1/columns) + eY * panel_size_y*(1/rows);
+       }
  
        // calculate position/size for visual bar displaying ammount of ammo status
        if (autocvar_hud_panel_weapons_ammo)
                if (!self || self.impulse < 0) { continue; }
  
                // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
-               if (autocvar_hud_panel_weapons_onlyowned
-                       && !(WEPSET_CONTAINS_AW(weapons_stat, self.weapon) 
-                       || (self.weapon == complain_weapon 
-                               && time - complain_weapon_time < when + fadetime 
-                               && autocvar_hud_panel_weapons_complainbubble)))
-                                       continue;
+               if(autocvar_hud_panel_weapons_onlyowned)
+               if not(WEPSET_CONTAINS_AW(weapons_stat, self.weapon) || (self.weapon == complain_weapon))
+                       continue;
  
                // figure out the drawing position of weapon
                weapon_pos = (panel_pos 
                }
  
                // draw the complain message
-               if(time - complain_weapon_time < when + fadetime && self.weapon == complain_weapon && autocvar_hud_panel_weapons_complainbubble)
+               if(self.weapon == complain_weapon)
                {
                        if(fadetime)
                                a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
                        else
                                a = ((complain_weapon_time + when > time) ? 1 : 0);
  
                        string s;
                        if(complain_weapon_type == 0) {
                                s = _("Out of ammo");
@@@ -1593,555 -1629,29 +1629,29 @@@ void HUD_HealthArmor(void
  // Notification area (#4)
  //
  
string Weapon_SuicideMessage(float deathtype)
void HUD_Notify_Push(string icon, string attacker, string victim)
  {
-       w_deathtype = deathtype;
-       get_weaponinfo(DEATH_WEAPONOF(deathtype)).weapon_func(WR_SUICIDEMESSAGE);
-       return w_deathtypestring;
- }
- string Weapon_KillMessage(float deathtype)
- {
-       w_deathtype = deathtype;
-       get_weaponinfo(DEATH_WEAPONOF(deathtype)).weapon_func(WR_KILLMESSAGE);
-       return w_deathtypestring;
- }
+       if(icon != "")
+       {
+               --kn_index;
+               if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
+               notify_times[kn_index] = time;
  
- #define KN_MAX_ENTRIES 10
- float kn_index;
- float killnotify_times[KN_MAX_ENTRIES];
- float killnotify_deathtype[KN_MAX_ENTRIES];
- float killnotify_actiontype[KN_MAX_ENTRIES]; // 0 = "Y [used by] X", 1 = "X [did action to] Y"
- string killnotify_attackers[KN_MAX_ENTRIES];
- string killnotify_victims[KN_MAX_ENTRIES];
- void HUD_KillNotify_Push(string attacker, string victim, float actiontype, float wpn)
- {
-       --kn_index;
-       if (kn_index == -1)
-               kn_index = KN_MAX_ENTRIES-1;
-       killnotify_times[kn_index] = time;
-       killnotify_deathtype[kn_index] = wpn;
-       killnotify_actiontype[kn_index] = actiontype;
-       if(killnotify_attackers[kn_index])
-               strunzone(killnotify_attackers[kn_index]);
-       killnotify_attackers[kn_index] = strzone(attacker);
-       if(killnotify_victims[kn_index])
-               strunzone(killnotify_victims[kn_index]);
-       killnotify_victims[kn_index] = strzone(victim);
- }
+               // icon
+               if(notify_icon[kn_index]) { strunzone(notify_icon[kn_index]); }
+               notify_icon[kn_index] = strzone(icon);
  
- void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s1 = attacker, s2 = victim
- {
-       float w;
-       float alsoprint, gentle;
-       alsoprint = (autocvar_hud_panel_notify_print || !panel_enabled); // print message to console if: notify panel disabled, or cvar to do so enabled
-       gentle = (autocvar_cl_gentle || autocvar_cl_gentle_messages);
-       
-       if ((msg == MSG_SUICIDE || msg == MSG_KILL || msg == MSG_KILL_ACTION) && gametype == MAPINFO_TYPE_CTS) // selfkill isn't interesting in CTS and only spams up the notify panel
-               return;
+               // attacker
+               if(notify_attackers[kn_index]) { strunzone(notify_attackers[kn_index]); }
+               notify_attackers[kn_index] = strzone(attacker);
  
-       if(msg == MSG_SUICIDE) {
-               w = DEATH_WEAPONOF(type);
-               if(WEP_VALID(w)) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if (alsoprint)
-                               print("^1", sprintf(Weapon_SuicideMessage(type), strcat(s1, "^1")), "\n");
-               } else if (type == DEATH_KILL) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_KILL);
-                       if (alsoprint)
-                               print (sprintf(_("^1%s^1 couldn't take it anymore\n"), s1));
-               } else if (type == DEATH_ROT) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if (alsoprint)
-                               print (sprintf(_("^1%s^1 died\n"), s1));
-               } else if (type == DEATH_NOAMMO) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_NOAMMO);
-                       if (alsoprint)
-                               print (sprintf(_("^7%s^7 committed suicide. What's the point of living without ammo?\n"), s1));
-               } else if (type == DEATH_CAMP) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_CAMP);
-                       if (alsoprint)
-                               print (sprintf(_("^1%s^1 thought they found a nice camping ground\n"), s1));
-               } else if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) {
-                       HUD_KillNotify_Push(s1, "", 0, type);
-                       if (alsoprint)
-                               print (sprintf(_("^1%s^1 didn't become friends with the Lord of Teamplay\n"), s1));
-               } else if (type == DEATH_CHEAT) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if (alsoprint)
-                               print (sprintf(_("^1%s^1 unfairly eliminated themself\n"), s1));
-               } else if (type == DEATH_FIRE) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if (alsoprint)
-                               print (sprintf(_("^1%s^1 burned to death\n"), s1));
-               } else if (type != DEATH_TEAMCHANGE && type != DEATH_QUIET) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if (alsoprint)
-                               print (sprintf(_("^1%s^1 couldn't resist the urge to self-destruct\n"), s1));
-               } 
-               
-               if (stof(s2) > 2) // killcount > 2
-                       print (sprintf(_("^1%s^1 ended it all after a %d kill spree\n"), s1, stof(s2)));
-       } else if(msg == MSG_KILL) {
-               w = DEATH_WEAPONOF(type);
-               if(WEP_VALID(w)) {
-                       HUD_KillNotify_Push(s1, s2, 1, type);
-                       if (alsoprint)
-                               print("^1", sprintf(Weapon_KillMessage(type), strcat(s2, "^1"), strcat(s1, "^1")), "\n"); // default order: victim, killer
-               }
-               else if(type == KILL_TEAM_RED || type == KILL_TEAM_BLUE || type == KILL_TEAM_SPREE) {
-                       HUD_KillNotify_Push(s1, s2, 1, type);
-                       if(alsoprint)
-                       {
-                               if(gentle) {
-                                       print (sprintf(_("^1%s^1 took action against a team mate\n"), s1));
-                               } else {
-                                       print (sprintf(_("^1%s^1 mows down a team mate\n"), s1));
-                               }
-                       }
-                       if (stof(s2) > 2 && type == KILL_TEAM_SPREE) {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 ended a %d scoring spree by going against a team mate\n"), s1, stof(s3)));
-                               else
-                                       print (sprintf(_("^1%s^1 ended a %d kill spree by killing a team mate\n"), s1, stof(s3)));
-                       }
-                       else if (stof(s2) > 2) {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1's %s scoring spree was ended by a team mate!\n"), s1, stof(s3)));
-                               else
-                                       print (sprintf(_("^1%s^1's %s kill spree was ended by a team mate!\n"), s1, stof(s3)));
-                       }
-               }
-               else if(type == KILL_FIRST_BLOOD)
-                       print(sprintf(_("^1%s^1 drew first blood\n"), s1));
-               else if (type == DEATH_TELEFRAG) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_TELEFRAG);
-                       if(gentle)
-                               print (sprintf(_("^1%s^1 tried to occupy %s^1's teleport destination space\n"), s2, s1));
-                       else
-                               print (sprintf(_("^1%s^1 was telefragged by %s\n"), s2, s1));
-               }
-               else if (type == DEATH_DROWN) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_DROWN);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was drowned by %s\n"), s2, s1));
-               }
-               else if (type == DEATH_SLIME) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_SLIME);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was slimed by %s\n"), s2, s1));
-               }
-               else if (type == DEATH_LAVA) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_LAVA);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was cooked by %s\n"), s2, s1));
-               }
-               else if (type == DEATH_FALL) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_FALL);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was grounded by %s\n"), s2, s1));
-               }
-               else if (type == DEATH_SHOOTING_STAR) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_SHOOTING_STAR);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was shot into space by %s\n"), s2, s1));
-               }
-               else if (type == DEATH_SWAMP) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was conserved by %s\n"), s2, s1));
-               }
-               else if (type == DEATH_HURTTRIGGER)
-               {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_HURTTRIGGER);
-                       if(alsoprint)
-                               print(sprintf(_("^1%s^1 was thrown into a world of hurt by %s\n"), s2, s1));
-               } else if(type == DEATH_VHCRUSH) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was crushed by %s\n"), s2, s1));
-               } else if(type == DEATH_SBMINIGUN) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 got shredded by %s\n"), s2, s1));
-               } else if(type == DEATH_SBROCKET) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was blasted to bits by %s\n"), s2, s1));
-               } else if(type == DEATH_SBBLOWUP) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 got caught in the blast when %s^1's destroys a vehicle\n"), s2, s1));
-               } else if(type == DEATH_WAKIGUN) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was bolted down by %s\n"), s2, s1));
-               } else if(type == DEATH_BUMB_GUN) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 saw %s's preddy lights.\n"), s2, s1));
-               } else if(type == DEATH_WAKIROCKET) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 could find no shelter from %s^1's rockets\n"), s2, s1));
-               } else if(type == DEATH_WAKIBLOWUP) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 got caught in the blast when %s^1's destroys a vehicle\n"), s2, s1));
-               } else if(type == DEATH_RAPTOR_CANNON) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 nailed to hell by %s\n"), s2, s1));
-               } else if(type == DEATH_RAPTOR_BOMB) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 cluster crushed by %s\n"), s2, s1));
-               } else if(type == DEATH_RAPTOR_DEATH) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 got caught in the blast when %s^1's destroys a vehicle\n"), s2, s1));
-               } else if(type == DEATH_TURRET) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was pushed into the line of fire by %s\n"), s2, s1));
-               } else if(type == DEATH_TOUCHEXPLODE) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was pushed into an accident by %s\n"), s2, s1));
-               } else if(type == DEATH_CHEAT) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was unfairly eliminated by %s\n"), s2, s1));
-               } else if (type == DEATH_FIRE) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was burnt to death by %s\n"), s2, s1));
-               } else if (type == DEATH_CUSTOM) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_CUSTOM);
-                       if(alsoprint)
-                               print("^1", sprintf(s3, strcat(s2, "^1"), strcat(s1, "^1")), "\n");
-               } else if (type == DEATH_HURTTRIGGER) {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_HURTTRIGGER);
-                       if(alsoprint)
-                               print("^1", sprintf(s3, strcat(s2, "^1"), strcat(s1, "^1")), "\n");
-               } else {
-                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was fragged by %s\n"), s2, s1));
-               }
-       } else if(msg == MSG_SPREE) {
-               if(type == KILL_END_SPREE) {
-                       if(gentle)
-                               print (sprintf(_("^1%s^1's %s scoring spree was ended by %s\n"), s1, s2, s3));
-                       else
-                               print (sprintf(_("^1%s^1's %s kill spree was ended by %s\n"), s1, s2, s3));
-               } else if(type == KILL_SPREE) {
-                       if(gentle)
-                               print (sprintf(_("^1%s^1 made %s scores in a row\n"), s1, s2));
-                       else
-                               print (sprintf(_("^1%s^1 has %s frags in a row\n"), s1, s2));
-               } else if(type == KILL_SPREE_3) {
-                       if(gentle)
-                               print (sprintf(_("%s^7 made a ^1TRIPLE SCORE\n"), s1));
-                       else
-                               print (sprintf(_("%s^7 made a ^1TRIPLE FRAG\n"), s1));
-               } else if(type == KILL_SPREE_5) {
-                       if(gentle)
-                               print (sprintf(_("%s^7 unleashes ^1SCORING RAGE\n"), s1));
-                       else
-                               print (sprintf(_("%s^7 unleashes ^1RAGE\n"), s1));
-               } else if(type == KILL_SPREE_10) {
-                       if(gentle)
-                               print (sprintf(_("%s^7 made ^1TEN SCORES IN A ROW!\n"), s1));
-                       else
-                               print (sprintf(_("%s^7 starts the ^1MASSACRE!\n"), s1));
-               } else if(type == KILL_SPREE_15) {
-                       if(gentle)
-                               print (sprintf(_("%s^7 made ^1FIFTEEN SCORES IN A ROW!\n"), s1));
-                       else
-                               print (sprintf(_("%s^7 executes ^1MAYHEM!\n"), s1));
-               } else if(type == KILL_SPREE_20) {
-                       if(gentle)
-                               print (sprintf(_("%s^7 made ^1TWENTY SCORES IN A ROW!\n"), s1));
-                       else
-                               print (sprintf(_("%s^7 is a ^1BERSERKER!\n"), s1));
-               } else if(type == KILL_SPREE_25) {
-                       if(gentle)
-                               print (sprintf(_("%s^7 made ^1TWENTY FIVE SCORES IN A ROW!\n"), s1));
-                       else
-                               print (sprintf(_("%s^7 inflicts ^1CARNAGE!\n"), s1));
-               } else if(type == KILL_SPREE_30) {
-                       if(gentle)
-                               print (sprintf(_("%s^7 made ^1THIRTY SCORES IN A ROW!\n"), s1));
-                       else
-                               print (sprintf(_("%s^7 unleashes ^1ARMAGEDDON!\n"), s1));
-               }
-       } else if(msg == MSG_KILL_ACTION) { // wtf is this? isnt it basically the same as MSG_SUICIDE?
-               if (type == DEATH_DROWN) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_DROWN);
-                       if(alsoprint)
-                       {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 was in the water for too long\n"), s1));
-                               else
-                                       print (sprintf(_("^1%s^1 drowned\n"), s1));
-                       }
-               } else if (type == DEATH_SLIME) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_SLIME);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was slimed\n"), s1));
-               } else if (type == DEATH_LAVA) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_LAVA);
-                       if(alsoprint)
-                       {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 found a hot place\n"), s1));
-                               else
-                                       print (sprintf(_("^1%s^1 turned into hot slag\n"), s1));
-                       }
-               } else if (type == DEATH_FALL) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if(alsoprint)
-                       {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 tested gravity (and it worked)\n"), s1));
-                               else
-                                       print (sprintf(_("^1%s^1 hit the ground with a crunch\n"), s1));
-                       }
-               } else if (type == DEATH_SHOOTING_STAR) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_SHOOTING_STAR);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 became a shooting star\n"), s1));
-               } else if (type == DEATH_SWAMP) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if(alsoprint)
-                       {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 discovered a swamp\n"), s1));
-                               else
-                                       print (sprintf(_("^1%s^1 is now conserved for centuries to come\n"), s1));
-                       }
-               } else if(DEATH_ISTURRET(type)) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if(alsoprint)
-                       {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 ran into a turret\n"), s1));
-                               else
-                               {
-                                       switch(type)
-                                       {
-                                               case DEATH_TURRET_EWHEEL:
-                                                       print (sprintf(_("^1%s^1 was laserd down by a eWheel turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_FLAC:
-                                                       print (sprintf(_("^1%s^1 got caught in the flac \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_MACHINEGUN:
-                                                       print (sprintf(_("^1%s^1 was riddeld full of riddled by a machinegun turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_WALKER_GUN:
-                                                       print (sprintf(_("^1%s^1 got served a led enrichment by a walker turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_WALKER_MEELE:
-                                                       print (sprintf(_("^1%s^1 was impaled by a walker turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_WALKER_ROCKET:
-                                                       print (sprintf(_("^1%s^1 was rocketed to hell by a walker turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_HELLION:
-                                                       print (sprintf(_("^1%s^1 was blasted away hellion turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_HK:
-                                                       print (sprintf(_("^1%s^1 could not hide from the hunter turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_MLRS:
-                                                       print (sprintf(_("^1%s^1 got turned into smoldering gibs by a mlrs turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_PLASMA:
-                                                       print (sprintf(_("^1%s^1 got served some superheated plasma from a plasma turret \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_PHASER:
-                                                       print (sprintf(_("^1%s^1 was phased out \n"), s1));
-                                                       break;
-                                               case DEATH_TURRET_TESLA:                        
-                                                       print (sprintf(_("^1%s^1 was electrocuted by a tesla turret \n"), s1));
-                                                       break;
-                                       }
-                               }
-                       }
-               } else if (type == DEATH_CUSTOM) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_CUSTOM);
-                       if(alsoprint)
-                               print("^1", sprintf(s2, strcat(s1, "^1")), "\n");
-               } else if (type == DEATH_HURTTRIGGER) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_HURTTRIGGER);
-                       if(alsoprint)
-                               print("^1", sprintf(s2, strcat(s1, "^1")), "\n");
-               } else if(type == DEATH_TOUCHEXPLODE) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 died in an accident\n"), s1));
-               } else if(type == DEATH_CHEAT) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if(alsoprint)
-                               print (sprintf(_("^1%s^1 was unfairly eliminated\n"), s1));
-               } else if(type == DEATH_FIRE) {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if(alsoprint)
-                       {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 felt a little hot\n"), s1));
-                               else
-                                       print (sprintf(_("^1%s^1 burnt to death\n"), s1));
-                               }
-               } else {
-                       HUD_KillNotify_Push(s1, "", 0, DEATH_GENERIC);
-                       if(alsoprint)
-                       {
-                               if(gentle)
-                                       print (sprintf(_("^1%s^1 needs a restart\n"), s1));
-                               else
-                                       print (sprintf(_("^1%s^1 died\n"), s1));
-                       }
-               }
-       } else if(msg == MSG_KILL_ACTION_SPREE) {
-               if(gentle)
-                       print (sprintf(_("^1%s^1 needs a restart after a %d scoring spree\n"), s1, stof(s2)));
-               else
-                       print (sprintf(_("^1%s^1 died with a %d kill spree\n"), s1, stof(s2)));
-       } else if(msg == MSG_INFO) {
-               if(type == INFO_GOTFLAG) { // here, s2 is the flag name
-                       HUD_KillNotify_Push(s1, s2, 0, INFO_GOTFLAG);
-                       print(sprintf(_("%s^7 got the %s\n"), s1, s2));
-               } else if(type == INFO_LOSTFLAG) {
-                       HUD_KillNotify_Push(s1, s2, 0, INFO_LOSTFLAG);
-                       print(sprintf(_("%s^7 lost the %s\n"), s1, s2));
-               } else if(type == INFO_PICKUPFLAG) {
-                       HUD_KillNotify_Push(s1, s2, 0, INFO_GOTFLAG);
-                       print(sprintf(_("%s^7 picked up the %s\n"), s1, s2));
-               } else if(type == INFO_RETURNFLAG) {
-                       HUD_KillNotify_Push(s1, s2, 0, INFO_RETURNFLAG);
-                       print(sprintf(_("%s^7 returned the %s\n"), s1, s2));
-               } else if(type == INFO_CAPTUREFLAG) {
-                       HUD_KillNotify_Push(s1, s2, 0, INFO_CAPTUREFLAG);
-                       print(sprintf(_("%s^7 captured the %s%s\n"), s1, s2, s3));
-               }
-       } else if(msg == MSG_RACE) {
-               if(type == RACE_SERVER_RECORD) {
-                       HUD_KillNotify_Push(s1, s2, 1, RACE_SERVER_RECORD);
-               }
-               else if(type == RACE_NEW_RANK) {
-                       HUD_KillNotify_Push(s1, s2, 1, RACE_NEW_RANK);
-               }
-               else if(type == RACE_NEW_TIME) {
-                       HUD_KillNotify_Push(s1, s2, 1, RACE_NEW_TIME);
-               }
-               else if(type == RACE_FAIL) {
-                       HUD_KillNotify_Push(s1, s2, 1, RACE_FAIL);
-               }
-       } else if(msg == MSG_KA) {
-               if(type == KA_PICKUPBALL) {
-                       HUD_KillNotify_Push(s1, s2, 0, KA_PICKUPBALL);
-                       if(alsoprint)
-                               print (sprintf(_("%s^7 has picked up the ball!\n"), s1));
-               }
-               else if(type == KA_DROPBALL) {
-                       HUD_KillNotify_Push(s1, s2, 0, KA_DROPBALL);
-                       if(alsoprint)
-                               print(sprintf(_("%s^7 has dropped the ball!\n"), s1));
-               }
-       }
- }
- void HUD_KillCenterprint(string s1, string s2, float type, float msg)
- {
-       float gentle;
-       gentle = (autocvar_cl_gentle || autocvar_cl_gentle_messages);
-       if(msg == MSG_SUICIDE) {
-               if (type == DEATH_TEAMCHANGE) {
-                       centerprint_hud(sprintf(_("You are now on: %s"), s1));
-               } else if (type == DEATH_AUTOTEAMCHANGE) {
-                       centerprint_hud(sprintf(_("You have been moved into a different team to improve team balance\nYou are now on: %s"), s1));
-               } else if (type == DEATH_CAMP) {
-                       if(gentle)
-                               centerprint_hud(_("^1Reconsider your tactics, camper!"));
-                       else
-                               centerprint_hud(_("^1Die camper!"));
-               } else if (type == DEATH_NOAMMO) {
-                       if(gentle)
-                               centerprint_hud(_("^1You are reinserted into the game for running out of ammo..."));
-                       else
-                               centerprint_hud(_("^1You were killed for running out of ammo..."));
-               } else if (type == DEATH_ROT) {
-                       if(gentle)
-                               centerprint_hud(_("^1You need to preserve your health"));
-                       else
-                               centerprint_hud(_("^1You grew too old without taking your medicine"));
-               } else if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) {
-                       if(gentle)
-                               centerprint_hud(_("^1Don't go against team mates!"));
-                       else
-                               centerprint_hud(_("^1Don't shoot your team mates!"));
-               } else if (type == DEATH_QUIET) {
-                       // do nothing
-               } else { // generic message
-                       if(gentle)
-                               centerprint_hud(_("^1You need to be more careful!"));
-                       else
-                               centerprint_hud(_("^1You killed your own dumb self!"));
-               }
-       } else if(msg == MSG_KILL) {
-               if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) {
-                       if(gentle) {
-                               centerprint_hud(sprintf(_("^1Moron! You went against ^7%s^1, a team mate!"), s1));
-                       } else {
-                               centerprint_hud(sprintf(_("^1Moron! You fragged ^7%s^1, a team mate!"), s1));
-                       }
-               } else if (type == KILL_FIRST_BLOOD) {
-                       if(gentle) {
-                               centerprint_hud(_("^1First score"));
-                       } else {
-                               centerprint_hud(_("^1First blood"));
-                       }
-               } else if (type == KILL_FIRST_VICTIM) {
-                       if(gentle) {
-                               centerprint_hud(_("^1First casualty"));
-                       } else {
-                               centerprint_hud(_("^1First victim"));
-                       }
-               } else if (type == KILL_TYPEFRAG) { // s2 contains "advanced kill messages" such as ping, handicap...
-                       if(gentle) {
-                               centerprint_hud(strcat(sprintf(_("^1You scored against ^7%s^1 who was typing!"), s1), s2));
-                       } else {
-                               centerprint_hud(strcat(sprintf(_("^1You typefragged ^7%s"), s1), s2));
-                       }
-               } else if (type == KILL_TYPEFRAGGED) {
-                       if(gentle) {
-                               centerprint_hud(strcat(sprintf(_("^1You were scored against by ^7%s^1 while you were typing!"), s1), s2));
-                       } else {
-                               centerprint_hud(strcat(sprintf(_("^1You were typefragged by ^7%s"), s1), s2));
-                       }
-               } else if (type == KILL_FRAG) {
-                       if(gentle) {
-                               centerprint_hud(strcat(sprintf(_("^4You scored against ^7%s"), s1), s2));
-                       } else {
-                               centerprint_hud(strcat(sprintf(_("^4You fragged ^7%s"), s1), s2));
-                       }
-               } else { // generic message
-                       if(gentle) {
-                               centerprint_hud(strcat(sprintf(_("^1You were scored against by ^7%s"), s1), s2));
-                       } else {
-                               centerprint_hud(strcat(sprintf(_("^1You were fragged by ^7%s"), s1), s2));
-                       }
-               }
-       } else if(msg == MSG_KILL_ACTION) {
-               // TODO: invent more centerprints here?
-               centerprint_hud(_("^1Watch your step!"));
+               // victim
+               if(notify_victims[kn_index]) { strunzone(notify_victims[kn_index]); }
+               notify_victims[kn_index] = strzone(victim);
        }
  }
  
- void HUD_Notify (void)
+ void HUD_Notify(void)
  {
        if(!autocvar__hud_configure)
        {
        float fadetime;
        fadetime = autocvar_hud_panel_notify_fadetime;
  
-       string s;
-       vector pos_attacker, pos_victim;
-       vector weap_pos;
+       vector pos_attacker, pos_victim, pos_icon;
        float width_attacker;
-       string attacker, victim;
+       string attacker, victim, icon;
  
-       float i, j, w, type, step, limit;
+       float i, j, step, limit;
        if(autocvar_hud_panel_notify_flip) //order items from the top down
        {
                i = 0;
                                a = entries - 1 - i;
                        attacker = textShortenToWidth(sprintf(_("Player %d"), a+1), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
                        victim = textShortenToWidth(sprintf(_("Player %d"), a+2), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       s = strcat("weapon", get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).netname);
+                       icon = strcat("weapon", get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).netname);
                        a = bound(0, (when - a) / 4, 1);
                        goto hud_config_notifyprint;
                }
-               if (j == KN_MAX_ENTRIES)
-                       j = 0;
-               if(killnotify_times[j] + when > time)
-                       a = 1;
-               else if(fadetime)
-               {
-                       a = bound(0, (killnotify_times[j] + when + fadetime - time) / fadetime, 1);
-                       if(!a)
-                       {
-                               break;
-                       }
-               }
                else
                {
-                       break;
-               }
-               s = "";
+                       if (j == KN_MAX_ENTRIES)
+                               j = 0;
  
-               type = killnotify_deathtype[j];
-               w = DEATH_WEAPONOF(type);
-               // TODO: maybe print in team colors?
-               //
-               // Y [used by] X
-               if(killnotify_actiontype[j] == 0) 
-               {
-                       if(type == DEATH_GENERIC)
-                       {
-                               s = "notify_death";
-                       }
-                       else if(type == DEATH_NOAMMO)
-                       {
-                               s = "notify_outofammo";
-                       }
-                       else if(type == DEATH_KILL)
-                       {
-                               s = "notify_selfkill";
-                       }
-                       else if(type == DEATH_CAMP)
-                       {
-                               s = "notify_camping";
-                       }
-                       else if(type == KILL_TEAM_RED)
-                       {
-                               s = "notify_teamkill_red";
-                       }
-                       else if(type == KILL_TEAM_BLUE)
-                       {
-                               s = "notify_teamkill_blue";
-                       }
-                       else if(type == DEATH_DROWN)
-                       {
-                               s = "notify_water";
-                       }
-                       else if(type == DEATH_SLIME)
-                       {
-                               s = "notify_slime";
-                       }
-                       else if(type == DEATH_LAVA)
-                       {
-                               s = "notify_lava";
-                       }
-                       else if(type == DEATH_FALL)
-                       {
-                               s = "notify_fall";
-                       }
-                       else if(type == DEATH_SHOOTING_STAR)
-                       {
-                               s = "notify_shootingstar";
-                       }
-                       else if(type == DEATH_HURTTRIGGER || type == DEATH_CUSTOM)
-                       {
-                               s = "notify_death";
-                       }
-                       else if(type == INFO_GOTFLAG)
-                       {
-                               if(killnotify_victims[j] == "^1RED^7 flag")
-                               {
-                                       s = "notify_red_taken";
-                               }
-                               else
-                               {
-                                       s = "notify_blue_taken";
-                               }
-                       }
-                       else if(type == INFO_RETURNFLAG)
-                       {
-                               if(killnotify_victims[j] == "^1RED^7 flag")
-                               {
-                                       s = "notify_red_returned";
-                               }
-                               else
-                               {
-                                       s = "notify_blue_returned";
-                               }
-                       }
-                       else if(type == INFO_LOSTFLAG)
-                       {
-                               if(killnotify_victims[j] == "^1RED^7 flag")
-                               {
-                                       s = "notify_red_lost";
-                               }
-                               else
-                               {
-                                       s = "notify_blue_lost";
-                               }
-                       }
-                       else if(type == INFO_CAPTUREFLAG)
+                       if(notify_times[j] + when > time)
+                               a = 1;
+                       else if(fadetime)
                        {
-                               if(killnotify_victims[j] == "^1RED^7 flag")
-                               {
-                                       s = "notify_red_captured";
-                               }
-                               else
+                               a = bound(0, (notify_times[j] + when + fadetime - time) / fadetime, 1);
+                               if(!a)
                                {
-                                       s = "notify_blue_captured";
+                                       break;
                                }
                        }
-                       else if(type == KA_DROPBALL)
-                       {
-                               s = "notify_balldropped";
-                       }
-                       else if(type == KA_PICKUPBALL)
+                       else
                        {
-                               s = "notify_ballpickedup";
+                               break;
                        }
                        
-                       attacker = textShortenToWidth(killnotify_attackers[j], 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       pos_attacker = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                       weap_pos = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height;
-                       if(s != "")
-                       {
-                               drawpic_aspect_skin(weap_pos, s, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                       }
+                       attacker = notify_attackers[j];
+                       victim = notify_victims[j];
+                       icon = notify_icon[j];
                }
-               // X [did action to] Y
-               else
+               //type = notify_deathtype[j];
+               //w = DEATH_WEAPONOF(type);
+               if(icon != "")
                {
-                       if(type & HITTYPE_SECONDARY && w == WEP_LASER)
-                       {
-                               s = "notify_melee_laser";
-                       }
-                       else if(type & HITTYPE_SECONDARY && w == WEP_SHOTGUN)
-                       {
-                               s = "notify_melee_shotgun";
-                       }
-                       else if(WEP_VALID(w))
-                       {
-                               self = get_weaponinfo(w);
-                               s = strcat("weapon", self.netname);
-                       }
-                       else if(type == KILL_TEAM_RED)
-                       {
-                               s = "notify_teamkill_red";
-                       }
-                       else if(type == KILL_TEAM_BLUE)
-                       {
-                               s = "notify_teamkill_red";
-                       }
-                       else if(type == DEATH_TELEFRAG)
+                       if((attacker != "") && (victim == ""))
                        {
-                               s = "notify_telefrag";
-                       }
-                       else if(type == DEATH_DROWN)
-                       {
-                               s = "notify_water";
-                       }
-                       else if(type == DEATH_SLIME)
-                       {
-                               s = "notify_slime";
-                       }
-                       else if(type == DEATH_LAVA)
-                       {
-                               s = "notify_lava";
-                       }
-                       else if(type == DEATH_FALL)
-                       {
-                               s = "notify_fall";
-                       }
-                       else if(type == DEATH_SHOOTING_STAR)
-                       {
-                               s = "notify_shootingstar";
-                       }
-                       else if(type == DEATH_HURTTRIGGER || type == DEATH_CUSTOM) // DEATH_CUSTOM is also void, right?
-                       {
-                               s = "notify_void";
-                       }
-                       else if(type == RACE_SERVER_RECORD)
-                       {
-                               s = "race_newrecordserver";
-                       }
-                       else if(type == RACE_NEW_RANK)
-                       {
-                               s = "race_newrankyellow";
-                       }
-                       else if(type == RACE_NEW_TIME)
-                       {
-                               s = "race_newtime";
+                               // Y [used by] X
+                               attacker = textShortenToWidth(attacker, 0.73 * mySize_x - height, fontsize, stringwidth_colors);
+                               pos_attacker = pos + eX * (0.27 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
+                               pos_icon = pos + eX * 0.25 * mySize_x - eX * height + eY * i * height;
+                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                        }
-                       else if(type == RACE_FAIL)
+                       else if((attacker != "") && (victim != ""))
                        {
-                               s = "race_newfail";
-                       }
-                       attacker = textShortenToWidth(killnotify_attackers[j], 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       victim = textShortenToWidth(killnotify_victims[j], 0.48 * mySize_x - height, fontsize, stringwidth_colors);
+                               // X [did action to] Y
+                               attacker = textShortenToWidth(attacker, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
+                               victim = textShortenToWidth(victim, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
  :hud_config_notifyprint
-                       width_attacker = stringwidth(attacker, TRUE, fontsize);
-                       pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                       pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                       weap_pos = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height;
+                               width_attacker = stringwidth(attacker, TRUE, fontsize);
+                               pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
+                               pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
+                               pos_icon = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height;
  
-                       if(s != "")
-                       {
-                               drawpic_aspect_skin(weap_pos, s, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
                                drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                                drawcolorcodedstring(pos_victim, victim, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                        }
@@@ -2532,6 -1871,8 +1871,8 @@@ void HUD_Radar(void
  
        HUD_Panel_UpdateCvars(radar);
        HUD_Panel_ApplyFadeAlpha();
+       
+       float f = 0;
  
        if (hud_panel_radar_maximized && !autocvar__hud_configure)
        {
                
                panel_bg = strcat(hud_skin_path, "/border_default"); // always use the default border when maximized
                if(precache_pic(panel_bg) == "") { panel_bg = "gfx/hud/default/border_default"; } // fallback
+               
+               switch(hud_panel_radar_maximized_zoommode)
+               {
+                       default:
+                       case 0:
+                               f = current_zoomfraction;
+                               break;
+                       case 1:
+                               f = 1 - current_zoomfraction;
+                               break;
+                       case 2:
+                               f = 0;
+                               break;
+                       case 3:
+                               f = 1;
+                               break;
+               }
+               
+               switch(hud_panel_radar_maximized_rotation)
+               {
+                       case 0:
+                               teamradar_angle = view_angles_y - 90;
+                               break;
+                       default:
+                               teamradar_angle = 90 * hud_panel_radar_maximized_rotation;
+                               break;
+               }
+       }
+       if (!hud_panel_radar_maximized && !autocvar__hud_configure)
+       {
+               switch(hud_panel_radar_zoommode)
+               {
+                       default:
+                       case 0:
+                               f = current_zoomfraction;
+                               break;
+                       case 1:
+                               f = 1 - current_zoomfraction;
+                               break;
+                       case 2:
+                               f = 0;
+                               break;
+                       case 3:
+                               f = 1;
+                               break;
+               }
+               
+               switch(hud_panel_radar_rotation)
+               {
+                       case 0:
+                               teamradar_angle = view_angles_y - 90;
+                               break;
+                       default:
+                               teamradar_angle = 90 * hud_panel_radar_rotation;
+                               break;
+               }
        }
  
        vector pos, mySize;
        float color2;
        entity tm;
        float scale2d, normalsize, bigsize;
-       float f;
  
        teamradar_origin2d = pos + 0.5 * mySize;
        teamradar_size2d = mySize;
  
        teamradar_loadcvars();
  
-       switch(hud_panel_radar_zoommode)
-       {
-               default:
-               case 0:
-                       f = current_zoomfraction;
-                       break;
-               case 1:
-                       f = 1 - current_zoomfraction;
-                       break;
-               case 2:
-                       f = 0;
-                       break;
-               case 3:
-                       f = 1;
-                       break;
-       }
-       switch(hud_panel_radar_rotation)
-       {
-               case 0:
-                       teamradar_angle = view_angles_y - 90;
-                       break;
-               default:
-                       teamradar_angle = 90 * hud_panel_radar_rotation;
-                       break;
-       }
        scale2d = vlen_maxnorm2d(mi_picmax - mi_picmin);
        teamradar_size2d = mySize;
  
        teamradar_extraclip_mins = teamradar_extraclip_maxs = '0 0 0'; // we always center
  
        // pixels per world qu to match the teamradar_size2d_x range in the longest dimension
-       if(hud_panel_radar_rotation == 0)
+       if((hud_panel_radar_rotation == 0 && !hud_panel_radar_maximized) || (hud_panel_radar_maximized_rotation == 0 && hud_panel_radar_maximized))
        {
                // max-min distance must fit the radar in any rotation
                bigsize = vlen_minnorm2d(teamradar_size2d) * scale2d / (1.05 * vlen2d(mi_scale));
        for(tm = world; (tm = find(tm, classname, "entcs_receiver")); )
        {
                color2 = GetPlayerColor(tm.sv_entnum);
-               //if(color == COLOR_SPECTATOR || color == color2)
-                       draw_teamradar_player(tm.origin, tm.angles, GetTeamRGB(color2));
+               //if(color == NUM_SPECTATOR || color == color2)
+                       draw_teamradar_player(tm.origin, tm.angles, Team_ColorRGB(color2));
        }
        draw_teamradar_player(view_origin, view_angles, '1 1 1');
  
@@@ -2692,7 -2061,7 +2061,7 @@@ void HUD_Score_Rankings(vector pos, vec
                        for(i=0; i<team_count; ++i) {
                                if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
                                        HUD_Panel_DrawHighlight(pos + eX * score_size * i, eX * score_size + eY * fontsize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize_y, GetTeamRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize_y, Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        first_pl = 1;
                        pos_y += fontsize_y;
                        }
  
                        if (team_count)
-                               score_color = GetTeamRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
+                               score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
                        s = textShortenToWidth(s, 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(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
                // show team scores in the first line
                float score_size = mySize_x / team_count;
                for(tm = teams.sort_next; tm; tm = tm.sort_next) {
-                       if(tm.team == COLOR_SPECTATOR)
+                       if(tm.team == NUM_SPECTATOR)
                                continue;
                        if (tm.team == myteam)
                                drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize_y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize_y, GetTeamRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize_y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                        ++i;
                }
                first_pl = 1;
        do
        for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
        {
-               if ((team_count && pl.team != tm.team) || pl.team == COLOR_SPECTATOR)
+               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 != COLOR_SPECTATOR)
+                               if (pl.team != NUM_SPECTATOR)
                                        break;
  
                        if (pl)
                        drawfill(pos, eX * mySize_x + eY * fontsize_y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                }
                if (team_count)
-                       score_color = GetTeamRGB(pl.team) * 0.8;
+                       score_color = Team_ColorRGB(pl.team) * 0.8;
                s = textShortenToWidth(GetPlayerName(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 != COLOR_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(void)
                vector score_pos, score_size; //for scores other than myteam
                if (spectatee_status == -1 || autocvar_hud_panel_score_rankings)
                {
-                       for(tm = teams.sort_next; tm, tm.team != COLOR_SPECTATOR; tm = tm.sort_next)
+                       for(tm = teams.sort_next; tm, tm.team != NUM_SPECTATOR; tm = tm.sort_next)
                                ++scores_count;
                        if (autocvar_hud_panel_score_rankings)
                        {
                draw_beginBoldFont();
                row = column = 0;
                for(tm = teams.sort_next; tm; tm = tm.sort_next) {
-                       if(tm.team == COLOR_SPECTATOR)
+                       if(tm.team == NUM_SPECTATOR)
                                continue;
                        score = tm.(teamscores[ts_primary]);
                        if(autocvar__hud_configure)
                                score_pos = pos + eX * column * (score_size_x + offset_x) + eY * row * (score_size_y + offset_y);
                                if (max_fragcount == score)
                                        HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(score_pos, ftos(score), score_size, GetTeamRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                                ++row;
                                if(row >= rows)
                                {
                        else if(tm.team == myteam) {
                                if (max_fragcount == score)
                                        HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize_x + eY * mySize_y, GetTeamRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize_x + eY * mySize_y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                        } else {
                                if (max_fragcount == score)
                                        HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, ftos(score), score_size, GetTeamRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                                ++rows;
                        }
                }
@@@ -3285,100 -2654,32 +2654,100 @@@ void HUD_VoteWindow(void
  
  float mod_active; // is there any active mod icon?
  
 -// Clan Arena HUD modicons
 -void HUD_Mod_CA(vector pos, vector mySize)
 +void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, float i)
  {
 -      mod_active = 1; // CA should never hide the mod icons panel
 -      float redalive, bluealive;
 -      redalive = getstati(STAT_REDALIVE);
 -      bluealive = getstati(STAT_BLUEALIVE);
 +      float stat;
 +      string pic;
 +      vector color;
 +#ifdef GMQCC
 +      stat = -1;
 +      pic = "";
 +      color = '0 0 0';
 +#endif
 +      switch(i)
 +      {
 +              case 0:
 +                      stat = getstati(STAT_REDALIVE);
 +                      pic = "player_red.tga";
 +                      color = '1 0 0';
 +                      break;
 +              case 1:
 +                      stat = getstati(STAT_BLUEALIVE);
 +                      pic = "player_blue.tga";
 +                      color = '0 0 1';
 +                      break;
 +              case 2:
 +                      stat = getstati(STAT_YELLOWALIVE);
 +                      pic = "player_yellow.tga";
 +                      color = '1 1 0';
 +                      break;
 +              default:
 +              case 3:
 +                      stat = getstati(STAT_PINKALIVE);
 +                      pic = "player_pink.tga";
 +                      color = '1 0 1';
 +                      break;
 +      }
  
 -      vector redpos, bluepos;
 -      if(mySize_x > mySize_y)
 +      if(mySize_x/mySize_y > aspect_ratio)
 +      {
 +              i = aspect_ratio * mySize_y;
 +              myPos_x = myPos_x + (mySize_x - i) / 2;
 +              mySize_x = i;
 +      }
 +      else
        {
 -              redpos = pos;
 -              bluepos = pos + eY * 0.5 * mySize_y;
 -              drawpic_aspect_skin(redpos, "player_red.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 -              drawstring_aspect(redpos + eX * 0.5 * mySize_x, ftos(redalive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 -              drawpic_aspect_skin(bluepos, "player_blue.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 -              drawstring_aspect(bluepos + eX * 0.5 * mySize_x, ftos(bluealive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +              i = 1/aspect_ratio * mySize_x;
 +              myPos_y = myPos_y + (mySize_y - i) / 2;
 +              mySize_y = i;
 +      }
 +
 +      if(layout)
 +      {
 +              drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +              drawstring_aspect(myPos + eX * 0.7 * mySize_x, ftos(stat), eX * 0.3 * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
        }
        else
 +              drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
 +}
 +
 +// Clan Arena and Freeze Tag HUD modicons
 +void HUD_Mod_CA(vector myPos, vector mySize)
 +{
 +      mod_active = 1; // required in each mod function that always shows something
 +      entity tm;
 +      float teams_count = 0;
 +      for(tm = teams.sort_next; tm; tm = tm.sort_next)
 +              if(tm.team != COLOR_SPECTATOR)
 +                      ++teams_count;
 +
 +      float layout;
 +      if(gametype == MAPINFO_TYPE_CA)
 +              layout = autocvar_hud_panel_modicons_ca_layout;
 +      else //if(gametype == MAPINFO_TYPE_FREEZETAG)
 +              layout = autocvar_hud_panel_modicons_freezetag_layout;
 +      float rows, columns, aspect_ratio;
 +      rows = mySize_y/mySize_x;
 +      aspect_ratio = (layout) ? 2 : 1;
 +      rows = bound(1, floor((sqrt((4 * aspect_ratio * teams_count + rows) * rows) + rows + 0.5) / 2), teams_count);
 +      columns = ceil(teams_count/rows);
 +
 +      int i;
 +      float row = 0, column = 0;
 +      vector pos, itemSize;
 +      itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
 +      for(i=0; i<teams_count; ++i)
        {
 -              redpos = pos;
 -              bluepos = pos + eY * 0.5 * mySize_y;
 -              drawpic_aspect_skin(redpos, "player_red.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 -              drawstring_aspect(redpos + eY * 0.3 * mySize_y, ftos(redalive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 -              drawpic_aspect_skin(bluepos, "player_blue.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 -              drawstring_aspect(bluepos + eY * 0.3 * mySize_y, ftos(bluealive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 +              pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
 +
 +              DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
 +
 +              ++row;
 +              if(row >= rows)
 +              {
 +                      row = 0;
 +                      ++column;
 +              }
        }
  }
  
@@@ -3452,7 -2753,7 +2821,7 @@@ void HUD_Mod_CTF(vector pos, vector myS
                case 2: red_icon = "flag_red_lost"; break;
                case 3: red_icon = "flag_red_carrying"; red_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
                default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM2))
+                       if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2))
                                red_icon = "flag_red_shielded";
                        else
                                red_icon = string_null;
                default:
                        if(redflag == 3)
                                red_icon_prevstatus = "flag_red_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM2))
+                       else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2))
                                red_icon_prevstatus = "flag_red_shielded";
                        else
                                red_icon_prevstatus = string_null;
                case 2: blue_icon = "flag_blue_lost"; break;
                case 3: blue_icon = "flag_blue_carrying"; blue_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
                default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM1))
+                       if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1))
                                blue_icon = "flag_blue_shielded";
                        else
                                blue_icon = string_null;
                default:
                        if(blueflag == 3)
                                blue_icon_prevstatus = "flag_blue_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam == COLOR_TEAM1))
+                       else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1))
                                blue_icon_prevstatus = "flag_blue_shielded";
                        else
                                blue_icon_prevstatus = string_null;
        }
  
        if(mySize_x > mySize_y) {
-               if (myteam == COLOR_TEAM1) { // always draw own flag on left
+               if (myteam == NUM_TEAM_1) { // always draw own flag on left
                        redflag_pos = pos;
                        blueflag_pos = pos + eX * 0.5 * mySize_x;
                } else {
                }
                flag_size = eX * 0.5 * mySize_x + eY * mySize_y;
        } else {
-               if (myteam == COLOR_TEAM1) { // always draw own flag on left
+               if (myteam == NUM_TEAM_1) { // always draw own flag on left
                        redflag_pos = pos;
                        blueflag_pos = pos + eY * 0.5 * mySize_y;
                } else {
@@@ -3624,16 -2925,16 +2993,16 @@@ void HUD_Mod_KH(vector pos, vector mySi
                {
                        switch(keyteam)
                        {
-                               case COLOR_TEAM1:
+                               case NUM_TEAM_1:
                                        drawpic_aspect_skin(pa, "kh_redarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
                                        break;
-                               case COLOR_TEAM2:
+                               case NUM_TEAM_2:
                                        drawpic_aspect_skin(pa, "kh_bluearrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
                                        break;
-                               case COLOR_TEAM3:
+                               case NUM_TEAM_3:
                                        drawpic_aspect_skin(pa, "kh_yellowarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
                                        break;
-                               case COLOR_TEAM4:
+                               case NUM_TEAM_4:
                                        drawpic_aspect_skin(pa, "kh_pinkarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
                                        break;
                                default:
@@@ -3867,7 -3168,7 +3236,7 @@@ void HUD_Mod_Race(vector pos, vector my
        else
                rank = 0;
        string rankname;
-       rankname = race_PlaceName(rank);
+       rankname = count_ordinal(rank);
  
        vector namepos;
        namepos = medalPos + '0 0.8 0' * squareSize;
@@@ -3980,7 -3281,7 +3349,7 @@@ void HUD_Mod_Dom(vector myPos, vector m
        entity tm;
        float teams_count = 0;
        for(tm = teams.sort_next; tm; tm = tm.sort_next)
-               if(tm.team != COLOR_SPECTATOR)
+               if(tm.team != NUM_SPECTATOR)
                        ++teams_count;
  
        float layout = autocvar_hud_panel_modicons_dom_layout;
  
        int i;
        float row = 0, column = 0;
 +      vector pos, itemSize;
 +      itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
        for(i=0; i<teams_count; ++i)
        {
 -              vector pos, itemSize;
 -              pos = myPos + eX * column * mySize_x*(1/columns) + eY * row * mySize_y*(1/rows);
 -              itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
 +              pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
  
                DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
  
@@@ -4439,7 -3740,7 +3808,7 @@@ void HUD_InfoMessages(void
                        {
                                for(; tm.sort_next; tm = tm.sort_next)
                                {
-                                       if(!tm.team_size || tm.team == COLOR_SPECTATOR)
+                                       if(!tm.team_size || tm.team == NUM_SPECTATOR)
                                                continue;
                                        if(!ts_min) ts_min = tm.team_size;
                                        else ts_min = min(ts_min, tm.team_size);
                                        s = strcat(blinkcolor, _("Teamnumbers are unbalanced!"));
                                        tm = GetTeam(myteam, false);
                                        if (tm)
-                                       if (tm.team != COLOR_SPECTATOR)
+                                       if (tm.team != NUM_SPECTATOR)
                                        if (tm.team_size == ts_max)
                                                s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
                                        drawInfoMessage(s)
@@@ -4763,6 -4064,7 +4132,7 @@@ float centerprint_showing
  
  void centerprint_generic(float new_id, string strMessage, float duration, float countdown_num)
  {
+       //print(sprintf("centerprint_generic(%d, '%s^7', %d, %d);\n", new_id, strMessage, duration, countdown_num));
        float i, j;
  
        if(strMessage == "" && new_id == 0)
        centerprint_messages[j] = strzone(strMessage);
        centerprint_msgID[j] = new_id;
        if (duration < 0)
+       {
                centerprint_time[j] = -1;
+               centerprint_expire_time[j] = time;
+       }
        else
        {
                if(duration == 0)
@@@ -4923,7 -4228,7 +4296,7 @@@ void HUD_CenterPrint (void
        fontsize = '1 1 0' * height;
        entries = bound(1, floor(panel_size_y/height), CENTERPRINT_MAX_ENTRIES);
  
-       float i, j, k, n;
+       float i, j, k, n, g;
        float a, sz, align, current_msg_pos_y = 0, msg_size;
        vector pos;
        string ts;
        if (autocvar_hud_panel_centerprint_flip)
                pos_y += panel_size_y;
        align = bound(0, autocvar_hud_panel_centerprint_align, 1);
-       for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
+       for (g=0, i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
        {
                if (j == CENTERPRINT_MAX_MSGS)
                        j = 0;
                                        continue;
                                centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
                        }
-                       else
+                       else if(centerprint_time[j] != -1)
                                continue;
                }
-               
                // fade the centerprint_hud in/out 
-               if (centerprint_time[j] < 0 || centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time)
+               if(centerprint_time[j] < 0)
+                       a = bound(0, (time - centerprint_expire_time[j]) / max(0.0001, autocvar_hud_panel_centerprint_fade_in), 1);
+               else if(centerprint_expire_time[j] - autocvar_hud_panel_centerprint_fade_out > time)
                        a = bound(0, (time - (centerprint_expire_time[j] - centerprint_time[j])) / max(0.0001, autocvar_hud_panel_centerprint_fade_in), 1);
-               else if (centerprint_expire_time[j] > time)
+               else if(centerprint_expire_time[j] > time)
                        a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
                else
                        a = 0;
                // also fade it based on positioning
                if(autocvar_hud_panel_centerprint_fade_subsequent)
                {
-                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (i / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
-                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (i / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
+                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passone_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passone))), 1); // pass one: all messages after the first have half theAlpha
+                       a = a * bound(autocvar_hud_panel_centerprint_fade_subsequent_passtwo_minalpha, (1 - (g / max(1, autocvar_hud_panel_centerprint_fade_subsequent_passtwo))), 1); // pass two: after that, gradually lower theAlpha even more for each message
                }
                
                // finally set the size based on the new theAlpha from subsequent fading
                drawfontscale = sz * '1 1 0';
                
                if (centerprint_countdown_num[j])
-                       n = tokenizebyseparator(sprintf(centerprint_messages[j], centerprint_countdown_num[j]), "\n");
+                       n = tokenizebyseparator(strreplace("^COUNT", count_seconds(centerprint_countdown_num[j]), centerprint_messages[j]), "\n");
                else
                        n = tokenizebyseparator(centerprint_messages[j], "\n");
  
                                        pos_y += fontsize_y * CENTERPRINT_SPACING/2;
                        }
                }
+               ++g; // move next position number up 
+               
                msg_size = pos_y - msg_size;
                if (autocvar_hud_panel_centerprint_flip)
                {
index c831c17f58b3d0e7285fdb07998f5d3806bbc3d6,21ab08fa709c51aceb213849a47b6058f413747c..74bf36e893a944a73301be889bc03b635da26008
@@@ -117,7 -117,6 +117,6 @@@ void HUD_Panel_ExportCfg(string cfgname
                                case HUD_PANEL_NOTIFY:
                                        HUD_Write_PanelCvar_q("_flip");
                                        HUD_Write_PanelCvar_q("_fontsize");
-                                       HUD_Write_PanelCvar_q("_print");
                                        HUD_Write_PanelCvar_q("_time");
                                        HUD_Write_PanelCvar_q("_fadetime");
                                        break;
                                        HUD_Write_PanelCvar_q("_scale");
                                        HUD_Write_PanelCvar_q("_maximized_scale");
                                        HUD_Write_PanelCvar_q("_maximized_size");
+                                       HUD_Write_PanelCvar_q("_maximized_rotation");
+                                       HUD_Write_PanelCvar_q("_maximized_zoommode"); 
                                        break;
                                case HUD_PANEL_SCORE:
                                        HUD_Write_PanelCvar_q("_rankings");
                                        HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
                                        break;
                                case HUD_PANEL_MODICONS:
 +                                      HUD_Write_PanelCvar_q("_ca_layout");
                                        HUD_Write_PanelCvar_q("_dom_layout");
 +                                      HUD_Write_PanelCvar_q("_freezetag_layout");
                                        break;
                                case HUD_PANEL_PRESSEDKEYS:
                                        HUD_Write_PanelCvar_q("_aspect");
index 2e6f1469d05f5d0a2d40a33c9ed6525e9e6b9d93,c25fb059f6ebc2d52b017541eeb39e084ab4166b..9668166e1c498f1a04da533892b55bfede66ca58
@@@ -36,17 -36,14 +36,14 @@@ const float TE_CSQC_NEXGUNBEAMPARTICLE 
  const float TE_CSQC_LIGHTNINGARC = 105;
  const float TE_CSQC_TEAMNAGGER = 106;
  const float TE_CSQC_PINGPLREPORT = 107;
- const float TE_CSQC_ANNOUNCE = 110;
- const float TE_CSQC_TARGET_MUSIC = 111;
- const float TE_CSQC_KILLNOTIFY = 112;
- const float TE_CSQC_KILLCENTERPRINT = 113;
- const float TE_CSQC_CENTERPRINT_GENERIC = 114;
- const float TE_CSQC_WEAPONCOMPLAIN = 115;
- const float TE_CSQC_NEX_SCOPE = 116;
- const float TE_CSQC_MINELAYER_MAXMINES = 117;
- const float TE_CSQC_HAGAR_MAXROCKETS = 118;
- const float TE_CSQC_VEHICLESETUP = 119;
- const float TE_CSQC_SVNOTICE = 120;
+ const float TE_CSQC_ANNOUNCE = 108;
+ const float TE_CSQC_TARGET_MUSIC = 109;
+ const float TE_CSQC_WEAPONCOMPLAIN = 110;
+ const float TE_CSQC_NEX_SCOPE = 111;
+ const float TE_CSQC_MINELAYER_MAXMINES = 112;
+ const float TE_CSQC_HAGAR_MAXROCKETS = 113;
+ const float TE_CSQC_VEHICLESETUP = 114;
+ const float TE_CSQC_SVNOTICE = 115;
  
  const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
  const float RACE_NET_CHECKPOINT_CLEAR = 1;
@@@ -99,6 -96,7 +96,7 @@@ const float ENT_CLIENT_WARPZONE_TELEPOR
  const float ENT_CLIENT_MODEL = 33;
  const float ENT_CLIENT_ITEM = 34;
  const float ENT_CLIENT_BUMBLE_RAYGUN = 35;
+ const float ENT_CLIENT_NOTIFICATION = 36;
  
  const float ENT_CLIENT_TURRET = 40;
  const float ENT_CLIENT_AUXILIARYXHAIR = 50;
@@@ -180,7 -178,6 +178,7 @@@ const float STAT_SECRETS_TOTAL = 70
  const float STAT_SECRETS_FOUND = 71;
  
  const float STAT_RESPAWN_TIME = 72;
 +const float STAT_ROUNDSTARTTIME = 73;
  
  // mod stats (1xx)
  const float STAT_REDALIVE = 100;
@@@ -365,85 -362,6 +363,6 @@@ float SPECIES_ROBOT_RUSTY  =  4
  float SPECIES_ROBOT_SHINY  =  5;
  float SPECIES_RESERVED     = 15;
  
- // Deathtypes (weapon deathtypes are the IT_* constants below)
- // NOTE: when adding death types, please add an explanation to Docs/spamlog.txt too.
- float DEATH_SPECIAL_START = 10000;
- float DEATH_FALL = 10000;
- float DEATH_TELEFRAG = 10001;
- float DEATH_DROWN = 10002;
- float DEATH_HURTTRIGGER = 10003;
- float DEATH_LAVA = 10004;
- float DEATH_SLIME = 10005;
- float DEATH_KILL = 10006;
- float DEATH_NOAMMO = 10007;
- float DEATH_SWAMP = 10008;
- float DEATH_TEAMCHANGE = 10009;
- float DEATH_AUTOTEAMCHANGE = 10010;
- float DEATH_CAMP = 10011;
- float DEATH_SHOOTING_STAR = 10012;
- float DEATH_ROT = 10013;
- float DEATH_MIRRORDAMAGE = 10014;
- float DEATH_TOUCHEXPLODE = 10015;
- float DEATH_CHEAT = 10016;
- float DEATH_FIRE = 10017;
- float DEATH_QUIET = 10021;
- float  DEATH_VHFIRST       = 10030;
- float  DEATH_VHCRUSH       = 10030;
- float  DEATH_SBMINIGUN     = 10031;
- float  DEATH_SBROCKET      = 10032;
- float  DEATH_SBBLOWUP      = 10033;
- float  DEATH_WAKIGUN       = 10034;
- float  DEATH_WAKIROCKET    = 10035;
- float  DEATH_WAKIBLOWUP    = 10036;
- float  DEATH_RAPTOR_CANNON = 10037;
- float  DEATH_RAPTOR_BOMB   = 10038;
- float  DEATH_RAPTOR_BOMB_SPLIT = 10039;
- float  DEATH_RAPTOR_DEATH   = 10040;
- float  DEATH_BUMB_GUN       = 10041;
- float  DEATH_BUMB_RAY       = 10042;
- float  DEATH_BUMB_RAY_HEAL  = 10043;
- float  DEATH_BUMB_DEATH     = 10044;
- float  DEATH_VHLAST         = 10044;
- #define DEATH_ISVEHICLE(t)  ((t) >= DEATH_VHFIRST && (t) <= DEATH_VHLAST)
- float DEATH_GENERIC = 10050;
- float DEATH_WEAPON = 10100;
- float DEATH_CUSTOM = 10300;
- float DEATH_TURRET                  = 10500;
- float DEATH_TURRET_EWHEEL           = 10501;
- float DEATH_TURRET_FLAC             = 10502;
- float DEATH_TURRET_MACHINEGUN       = 10503;
- float DEATH_TURRET_WALKER_GUN       = 10504;
- float DEATH_TURRET_WALKER_MEELE     = 10505;
- float DEATH_TURRET_WALKER_ROCKET    = 10506;
- float DEATH_TURRET_HELLION          = 10507;
- float DEATH_TURRET_HK               = 10508;
- float DEATH_TURRET_MLRS             = 10509;
- float DEATH_TURRET_PLASMA           = 10510;
- float DEATH_TURRET_PHASER           = 10511;
- float DEATH_TURRET_TESLA            = 10512;
- float DEATH_TURRET_LAST            = 10512;
- float DEATH_WEAPONMASK = 0xFF;
- float DEATH_HITTYPEMASK = 0x1F00; // which is WAY below 10000 used for normal deaths
- float HITTYPE_SECONDARY = 0x100;
- float HITTYPE_SPLASH = 0x200; // automatically set by RadiusDamage
- float HITTYPE_BOUNCE = 0x400;
- float HITTYPE_RESERVED2 = 0x800;
- float HITTYPE_RESERVED = 0x1000; // unused yet
- // macros to access these
- #define DEATH_ISTURRET(t)            ((t) >= DEATH_TURRET && (t) <= DEATH_TURRET_LAST)
- #define DEATH_ISSPECIAL(t)            ((t) >= DEATH_SPECIAL_START)
- #define DEATH_WEAPONOFWEAPONDEATH(t)  ((t) & DEATH_WEAPONMASK)
- #define DEATH_ISWEAPON(t,w)           (!DEATH_ISSPECIAL(t) && DEATH_WEAPONOFWEAPONDEATH(t) == (w))
- #define DEATH_WEAPONOF(t)             (DEATH_ISSPECIAL(t) ? 0 : DEATH_WEAPONOFWEAPONDEATH(t))
- #define WEP_VALID(w)                  ((w) >= WEP_FIRST && (w) <= WEP_LAST)
  #define FRAGS_PLAYER 0
  #define FRAGS_SPECTATOR -666
  #define FRAGS_LMS_LOSER -616
@@@ -458,63 -376,6 +377,6 @@@ float WATERLEVEL_SUBMERGED = 3
  
  float MAX_SHOT_DISTANCE = 32768;
  
- //centerprint ID list
- float CPID_TEAMCHANGE = 1;
- float CPID_CTF_CAPTURESHIELD = 2;
- float CPID_MINSTA_FINDAMMO = 3;
- float CPID_NIX_WPNCHANGE = 4;
- float CPID_DISCONNECT_IDLING = 5;
- float CPID_GAME_STARTING = 7;
- float CPID_TIMEOUT_COUNTDOWN = 8;
- float CPID_MOTD = 9;
- float CPID_KH_MSG = 10;
- float CPID_PREVENT_JOIN = 11;
- float CPID_WAITING_PLAYERS = 12;
- // CSQC centerprint/notify message types
- float MSG_SUICIDE = 0;
- float MSG_KILL = 1;
- float MSG_SPREE = 2;
- float MSG_KILL_ACTION = 3;
- float MSG_KILL_ACTION_SPREE = 4;
- float MSG_INFO = 5;
- float MSG_KA = 6;
- float MSG_RACE = 10;
- float KILL_TEAM_RED = 12001;
- float KILL_TEAM_BLUE = 12002;
- float KILL_TEAM_SPREE = 12003;
- float KILL_FIRST_BLOOD = 12004;
- float KILL_FIRST_VICTIM = 12005;
- float KILL_TYPEFRAG = 12006;
- float KILL_TYPEFRAGGED = 12007;
- float KILL_FRAG = 12008;
- float KILL_FRAGGED = 12009;
- float KILL_SPREE = 12010;
- float KILL_END_SPREE = 12011;
- float KILL_SPREE_3 = 12012;
- float KILL_SPREE_5 = 12013;
- float KILL_SPREE_10 = 12014;
- float KILL_SPREE_15 = 12015;
- float KILL_SPREE_20 = 12016;
- float KILL_SPREE_25 = 12017;
- float KILL_SPREE_30 = 12018;
- float INFO_GOTFLAG = 13001;
- float INFO_PICKUPFLAG = 13002;
- float INFO_LOSTFLAG = 13003;
- float INFO_RETURNFLAG = 13004;
- float INFO_CAPTUREFLAG = 13005;
- float KA_PICKUPBALL = 14001;
- float KA_DROPBALL = 14002;
- float RACE_SERVER_RECORD = 15001;
- float RACE_NEW_TIME = 15002;
- float RACE_NEW_RANK = 15003;
- float RACE_FAIL = 15004;
  // weapon requests
  float WR_SETUP                = 1; // (SVQC) setup weapon data
  float WR_THINK                = 2; // (SVQC) logic to run every frame
@@@ -522,8 -383,8 +384,8 @@@ float WR_CHECKAMMO1        = 3; // (SVQC) chec
  float WR_CHECKAMMO2   = 4; // (SVQC) checks ammo for weapon
  float WR_AIM          = 5; // (SVQC) runs bot aiming code for this weapon
  float WR_PRECACHE     = 6; // (CSQC and SVQC) precaches models/sounds used by this weapon
- float WR_SUICIDEMESSAGE = 7; // (CSQC) sets w_deathtypestring or leaves it alone (and may inspect w_deathtype for details)
- float WR_KILLMESSAGE    = 8; // (CSQC) sets w_deathtypestring or leaves it alone
+ float WR_SUICIDEMESSAGE = 7; // (SVQC) notification number for suicide message (may inspect w_deathtype for details)
+ float WR_KILLMESSAGE    = 8; // (SVQC) notification number for kill message (may inspect w_deathtype for details)
  float WR_RELOAD         = 9; // (SVQC) does not need to do anything
  float WR_RESETPLAYER    = 10; // (SVQC) does not need to do anything
  float WR_IMPACTEFFECT = 11; // (CSQC) impact effect
index 3874e169ae7109a5062923fd54f2796b99f84a45,1ea2615eadc2e846e807fd074b13fc6954e32e61..97ce6139c10a3b908f53052be83d5b4045b4f769
@@@ -75,7 -75,6 +75,7 @@@ float autocvar_g_arena_maxspawned
  float autocvar_g_arena_point_leadlimit;
  float autocvar_g_arena_point_limit;
  float autocvar_g_arena_roundbased;
 +float autocvar_g_arena_round_timelimit;
  float autocvar_g_arena_warmup;
  float autocvar_g_assault;
  float autocvar_g_balance_armor_blockpercent;
@@@ -740,8 -739,6 +740,8 @@@ float autocvar_g_ca_point_leadlimit
  float autocvar_g_ca_point_limit;
  float autocvar_g_ca_round_timelimit;
  float autocvar_g_ca_spectate_enemies;
 +float autocvar_g_ca_teams;
 +float autocvar_g_ca_teams_override;
  float autocvar_g_ca_warmup;
  float autocvar_g_campaign;
  #define autocvar_g_campaign_forceteam cvar("g_campaign_forceteam")
@@@ -760,6 -757,7 +760,7 @@@ float autocvar_g_chat_flood_spl_team
  float autocvar_g_chat_flood_spl_tell;
  float autocvar_g_chat_nospectators;
  float autocvar_g_chat_teamcolors;
+ float autocvar_g_chat_tellprivacy;
  float autocvar_g_ctf_allow_vehicle_carry;
  float autocvar_g_ctf_allow_vehicle_touch;
  float autocvar_g_ctf_throw;
@@@ -785,7 -783,6 +786,6 @@@ float autocvar_g_ctf_pass_request
  float autocvar_g_ctf_pass_turnrate;
  float autocvar_g_ctf_pass_timelimit;
  float autocvar_g_ctf_pass_velocity;
- float autocvar_g_ctf_captimerecord_always;
  float autocvar_g_ctf_dynamiclights;
  string autocvar_g_ctf_flag_blue_model;
  float autocvar_g_ctf_flag_blue_skin;
@@@ -795,7 -792,6 +795,6 @@@ float autocvar_g_ctf_flag_dropped_waypo
  float autocvar_g_ctf_flag_dropped_floatinwater;
  float autocvar_g_ctf_flag_glowtrails;
  float autocvar_g_ctf_flag_health;
- float autocvar_g_ctf_flag_pickup_verbosename;
  string autocvar_g_ctf_flag_red_model;
  float autocvar_g_ctf_flag_red_skin;
  float autocvar_g_ctf_flag_return_time;
@@@ -848,15 -844,11 +847,15 @@@ string autocvar_g_forced_team_pink
  string autocvar_g_forced_team_red;
  string autocvar_g_forced_team_yellow;
  float autocvar_g_freezetag_frozen_force;
 +float autocvar_g_freezetag_frozen_maxtime;
  float autocvar_g_freezetag_point_leadlimit;
  float autocvar_g_freezetag_point_limit;
  float autocvar_g_freezetag_revive_extra_size;
  float autocvar_g_freezetag_revive_speed;
  float autocvar_g_freezetag_revive_clearspeed;
 +float autocvar_g_freezetag_round_timelimit;
 +float autocvar_g_freezetag_teams;
 +float autocvar_g_freezetag_teams_override;
  float autocvar_g_freezetag_warmup;
  #define autocvar_g_friendlyfire cvar("g_friendlyfire")
  #define autocvar_g_friendlyfire_virtual cvar("g_friendlyfire_virtual")
@@@ -900,7 -892,6 +899,6 @@@ float autocvar_g_keyhunt_teams_override
  float autocvar_g_lms_campcheck_damage;
  float autocvar_g_lms_campcheck_distance;
  float autocvar_g_lms_campcheck_interval;
- string autocvar_g_lms_campcheck_message;
  float autocvar_g_lms_join_anytime;
  float autocvar_g_lms_last_join;
  #define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
@@@ -1021,6 -1012,7 +1019,6 @@@ float autocvar_g_spawn_useallspawns
  float autocvar_g_spawnpoints_auto_move_out_of_solid;
  #define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime")
  float autocvar_g_spawnsound;
 -float autocvar_g_start_delay;
  #define autocvar_g_start_weapon_laser cvar("g_start_weapon_laser")
  float autocvar_g_tdm_team_spawns;
  float autocvar_g_tdm_teams;
@@@ -1169,13 -1161,10 +1167,10 @@@ float autocvar_sv_eventlog_files_counte
  string autocvar_sv_eventlog_files_nameprefix;
  string autocvar_sv_eventlog_files_namesuffix;
  float autocvar_sv_eventlog_files_timestamps;
- float autocvar_sv_fraginfo;
- float autocvar_sv_fraginfo_handicap;
- float autocvar_sv_fraginfo_ping;
- float autocvar_sv_fraginfo_stats;
  float autocvar_sv_friction;
  float autocvar_sv_friction_on_land;
  float autocvar_sv_gameplayfix_q2airaccelerate;
+ float autocvar_sv_gentle;
  #define autocvar_sv_gravity cvar("sv_gravity")
  string autocvar_sv_intermission_cdtrack;
  string autocvar_sv_jumpspeedcap_max;
diff --combined qcsrc/server/bot/bot.qc
index bc567ba246cf3147615c1e98d1d33874de0f31f1,d87c72695f32a6a5593def26636eeba93746267f..f6e7f6f1b6921f5745982030050f76e1f350cee4
@@@ -398,13 -398,13 +398,13 @@@ void bot_clientconnect(
                bot_setnameandstuff();
  
        if(self.bot_forced_team==1)
-               self.team = COLOR_TEAM1;
+               self.team = NUM_TEAM_1;
        else if(self.bot_forced_team==2)
-               self.team = COLOR_TEAM2;
+               self.team = NUM_TEAM_2;
        else if(self.bot_forced_team==3)
-               self.team = COLOR_TEAM3;
+               self.team = NUM_TEAM_3;
        else if(self.bot_forced_team==4)
-               self.team = COLOR_TEAM4;
+               self.team = NUM_TEAM_4;
        else
                JoinBestTeam(self, FALSE, TRUE);
  
@@@ -425,13 -425,13 +425,13 @@@ void bot_removefromlargestteam(
        bestcount = 0;
        while (head)
        {
-               if(head.team == COLOR_TEAM1)
+               if(head.team == NUM_TEAM_1)
                        thiscount = c1;
-               else if(head.team == COLOR_TEAM2)
+               else if(head.team == NUM_TEAM_2)
                        thiscount = c2;
-               else if(head.team == COLOR_TEAM3)
+               else if(head.team == NUM_TEAM_3)
                        thiscount = c3;
-               else if(head.team == COLOR_TEAM4)
+               else if(head.team == NUM_TEAM_4)
                        thiscount = c4;
                else
                        thiscount = 0;
@@@ -551,7 -551,7 +551,7 @@@ float bot_fixcount(
  
        FOR_EACH_REALCLIENT(head)
        {
 -              if(head.classname == "player" || g_lms || g_arena || g_ca)
 +              if(head.classname == "player" || g_lms || g_arena || head.caplayer == 1)
                        ++activerealplayers;
                ++realplayers;
        }
index 4ee8bcb51375a5afbff8d71eca9a844978603697,356d444c0c8a46918d573da4b036756243c6b1ef..67190df2d91488b5beff48e89989ab174892613f
@@@ -293,7 -293,7 +293,7 @@@ entity SelectSpawnPoint (float anypoint
        else
        {
                float mindist;
 -              if (arena_roundbased && !g_ca)
 +              if (g_arena && arena_roundbased)
                        mindist = 800;
                else
                        mindist = 100;
@@@ -401,24 -401,6 +401,24 @@@ void PutObserverInServer (void
                WriteEntity(MSG_ONE, self);
        }
  
 +      if(g_lms)
 +      {
 +              // Only if the player cannot play at all
 +              if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
 +                      self.frags = FRAGS_SPECTATOR;
 +              else
 +                      self.frags = FRAGS_LMS_LOSER;
 +      }
 +      else if((g_race && g_race_qualifying) || g_cts)
 +      {
 +              if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
 +                      self.frags = FRAGS_LMS_LOSER;
 +              else
 +                      self.frags = FRAGS_SPECTATOR;
 +      }
 +      else
 +              self.frags = FRAGS_SPECTATOR;
 +
        DropAllRunes(self);
        MUTATOR_CALLHOOK(MakePlayerObserver);
  
  
        if(self.killcount != -666) {
                if(g_lms) {
-                       if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
-                               bprint ("^4", self.netname, "^4 has no more lives left\n");
+                       if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname);
                        else
-                               bprint ("^4", self.netname, "^4 is spectating now\n"); // TODO turn this into a proper forfeit?
-               } else
-                       bprint ("^4", self.netname, "^4 is spectating now\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname);
+               } else { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname); }
  
                if(self.just_joined == FALSE) {
                        LogTeamchange(self.playerid, -1, 4);
        self.punchvector = '0 0 0';
        self.oldvelocity = self.velocity;
        self.fire_endtime = -1;
 -
 -      if(g_arena)
 -      {
 -              if(self.version_mismatch)
 -              {
 -                      self.frags = FRAGS_SPECTATOR;
 -                      Spawnqueue_Unmark(self);
 -                      Spawnqueue_Remove(self);
 -              }
 -              else
 -              {
 -                      self.frags = FRAGS_LMS_LOSER;
 -                      Spawnqueue_Insert(self);
 -              }
 -      }
 -      else if(g_lms)
 -      {
 -              // Only if the player cannot play at all
 -              if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
 -                      self.frags = FRAGS_SPECTATOR;
 -              else
 -                      self.frags = FRAGS_LMS_LOSER;
 -      }
 -      else if(g_ca)
 -      {
 -              if(self.caplayer)
 -                      self.frags = FRAGS_LMS_LOSER;
 -              else
 -                      self.frags = FRAGS_SPECTATOR;
 -      }
 -      else if((g_race && g_race_qualifying) || g_cts)
 -      {
 -              if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
 -                      self.frags = FRAGS_LMS_LOSER;
 -              else
 -                      self.frags = FRAGS_SPECTATOR;
 -      }
 -      else
 -              self.frags = FRAGS_SPECTATOR;
  }
  
  .float model_randomizer;
@@@ -543,7 -563,7 +542,7 @@@ void FixPlayermodel(
                if(teamplay)
                {
                        string s;
-                       s = Team_ColorNameLowerCase(self.team);
+                       s = Team_ColorName_Lower(self.team);
                        if(s != "neutral")
                        {
                                defaultmodel = cvar_string(strcat("sv_defaultplayermodel_", s));
                self.skin = stof(self.playerskin);
        }
  
-       if(chmdl || oldskin != self.skin)
-               self.species = player_getspecies(); // model or skin has changed
+       if(chmdl || oldskin != self.skin) // model or skin has changed
+       {
+               self.species = player_getspecies(); // update species
+               UpdatePlayerSounds(); // update skin sounds
+       }
  
        if(!teamplay)
                if(strlen(autocvar_sv_defaultplayercolors))
@@@ -632,7 -655,11 +634,7 @@@ Called when a client spawns in the serv
  void PutClientInServer (void)
  {
        if(clienttype(self) == CLIENTTYPE_BOT)
 -      {
                self.classname = "player";
 -              if(g_ca)
 -                      self.caplayer = 1;
 -      }
        else if(clienttype(self) == CLIENTTYPE_REAL)
        {
                msg_entity = self;
                        self.classname = "observer";
        }
  
 -      if((g_arena && !self.spawned) || (g_ca && !allowed_to_spawn))
 -              self.classname = "observer";
 +      MUTATOR_CALLHOOK(PutClientInServer);
  
        if(gameover)
                self.classname = "observer";
  
 -      if(self.classname == "player" && (!g_ca || (g_ca && allowed_to_spawn))) {
 +      if(self.classname == "player") {
                entity spot, oldself;
                float j;
  
                spot = SelectSpawnPoint (FALSE);
                if(!spot)
                {
-                       centerprint(self, "Sorry, no spawnpoints available!\nHope your team can fix it...");
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_NOSPAWNS);
                        return; // spawn failed
                }
  
                self.lastteleporttime = time; // prevent insane speeds due to changing origin
          self.hud = HUD_NORMAL;
  
 -              if(g_arena)
 -              {
 -                      Spawnqueue_Remove(self);
 -                      Spawnqueue_Mark(self);
 -              }
 -              else if(g_ca)
 -                      self.caplayer = 1;
 -
                self.event_damage = PlayerDamage;
  
                self.bot_attack = TRUE;
  
                if(g_assault) {
                        if(self.team == assault_attacker_team)
-                               centerprint(self, "You are attacking!");
+                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
                        else
-                               centerprint(self, "You are defending!");
+                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
                }
  
                target_voicescript_clear(self);
@@@ -1046,13 -1082,14 +1048,13 @@@ void ClientKill_Now_TeamChange(
        }
        else if(self.killindicator_teamchange == -2)
        {
 -              if(g_ca)
 -                      self.caplayer = 0;
                if(blockSpectators)
-                       sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
                PutObserverInServer();
        }
        else
                SV_ChangeTeam(self.killindicator_teamchange - 1);
 +      self.killindicator_teamchange = 0;
  }
  
  void ClientKill_Now()
@@@ -1199,28 -1236,28 +1201,28 @@@ void ClientKill_TeamChange (float targe
                        self.killindicator.colormod = '0 0 0';
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "^1Suicide in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SUICIDE, self.killindicator.cnt);
                }
                else if(targetteam == -1) // auto
                {
                        self.killindicator.colormod = '0 1 0';
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Changing team in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_AUTO, self.killindicator.cnt);
                }
                else if(targetteam == -2) // spectate
                {
                        self.killindicator.colormod = '0.5 0.5 0.5';
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Spectating in %d seconds", 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_TEAMCHANGE_SPECTATE, self.killindicator.cnt);
                }
                else
                {
-                       self.killindicator.colormod = TeamColor(targetteam);
+                       self.killindicator.colormod = Team_ColorRGB(targetteam);
                        if(clienttype(self) == CLIENTTYPE_REAL)
                        if(self.killindicator.cnt > 0)
-                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, APP_TEAM_NUM_4(targetteam, CENTER_TEAMCHANGE_), self.killindicator.cnt);
                }
        }
  
  
  void ClientKill (void)
  {
 -      if (gameover)
 -              return;
 +      if(gameover) return;
 +      if(self.player_blocked) return;
 +      if(self.freezetag_frozen) return;
  
 -      if((g_arena || g_ca) && ((champion && champion.classname == "player" && player_count > 1) || player_count == 1)) // don't allow a kill in this case either
 -      {
 -              // do nothing
 -      }
 -    else if(self.freezetag_frozen)
 -    {
 -        // do nothing
 -    }
 -      else
 -              ClientKill_TeamChange(0);
 +      ClientKill_TeamChange(0);
  }
  
  void CTS_ClientKill (entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
@@@ -1254,7 -1299,7 +1256,7 @@@ void FixClientCvars(entity e
                stuffcmd(e, "cl_cmd settemp cl_movecliptokeyboard 2\n");
        if(autocvar_g_antilag == 3) // client side hitscan
                stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
-       if(sv_gentle)
+       if(autocvar_sv_gentle)
                stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
        /*
         * we no longer need to stuff this. Remove this comment block if you feel
@@@ -1303,7 -1348,6 +1305,6 @@@ ClientConnec
  Called when a client connects to the server
  =============
  */
- string ColoredTeamName(float t);
  void DecodeLevelParms (void);
  //void dom_player_join_team(entity pl);
  void set_dom_state(entity e);
@@@ -1323,7 -1367,7 +1324,7 @@@ void ClientConnect (void
        DecodeLevelParms();
  
  #ifdef WATERMARK
-       sprint(self, strcat("^4SVQC Build information: ^1", WATERMARK, "\n"));
+       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_WATERMARK, WATERMARK);
  #endif
  
        self.classname = "player_joining";
                {
                        switch(autocvar_g_campaign_forceteam)
                        {
-                               case 1: self.team_forced = COLOR_TEAM1; break;
-                               case 2: self.team_forced = COLOR_TEAM2; break;
-                               case 3: self.team_forced = COLOR_TEAM3; break;
-                               case 4: self.team_forced = COLOR_TEAM4; break;
+                               case 1: self.team_forced = NUM_TEAM_1; break;
+                               case 2: self.team_forced = NUM_TEAM_2; break;
+                               case 3: self.team_forced = NUM_TEAM_3; break;
+                               case 4: self.team_forced = NUM_TEAM_4; break;
                                default: self.team_forced = 0;
                        }
                }
        }
        else if(PlayerInIDList(self, autocvar_g_forced_team_red))
-               self.team_forced = COLOR_TEAM1;
+               self.team_forced = NUM_TEAM_1;
        else if(PlayerInIDList(self, autocvar_g_forced_team_blue))
-               self.team_forced = COLOR_TEAM2;
+               self.team_forced = NUM_TEAM_2;
        else if(PlayerInIDList(self, autocvar_g_forced_team_yellow))
-               self.team_forced = COLOR_TEAM3;
+               self.team_forced = NUM_TEAM_3;
        else if(PlayerInIDList(self, autocvar_g_forced_team_pink))
-               self.team_forced = COLOR_TEAM4;
+               self.team_forced = NUM_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "red")
-               self.team_forced = COLOR_TEAM1;
+               self.team_forced = NUM_TEAM_1;
        else if(autocvar_g_forced_team_otherwise == "blue")
-               self.team_forced = COLOR_TEAM2;
+               self.team_forced = NUM_TEAM_2;
        else if(autocvar_g_forced_team_otherwise == "yellow")
-               self.team_forced = COLOR_TEAM3;
+               self.team_forced = NUM_TEAM_3;
        else if(autocvar_g_forced_team_otherwise == "pink")
-               self.team_forced = COLOR_TEAM4;
+               self.team_forced = NUM_TEAM_4;
        else if(autocvar_g_forced_team_otherwise == "spectate")
                self.team_forced = -1;
        else if(autocvar_g_forced_team_otherwise == "spectator")
  
        self.netname_previous = strzone(self.netname);
  
-       bprint("^4", self.netname, "^4 connected");
-       if(self.classname != "observer" && (g_domination || g_ctf))
-               bprint(" and joined the ", ColoredTeamName(self.team));
-       bprint("\n");
+       if((self.classname == STR_PLAYER && teamplay))
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_ENT_4(self, INFO_JOIN_CONNECT_TEAM_), self.netname);
+       else
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_CONNECT, self.netname);
  
        stuffcmd(self, strcat(clientstuff, "\n"));
        stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this?
        else
                stuffcmd(self, "set _teams_available 0\n");
  
 -      if(g_arena || g_ca)
 -      {
 -              self.classname = "observer";
 -              if(g_arena)
 -                      Spawnqueue_Insert(self);
 -      }
 -
        attach_entcs();
  
        bot_relinkplayerlist();
        self.spectatortime = time;
        if(blockSpectators)
        {
-               sprint(self, strcat("^7You have to become a player within the next ", ftos(autocvar_g_maxplayers_spectator_blocktime), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
        }
  
        self.jointime = time;
        CheatInitClient();
  
        if(!autocvar_g_campaign)
-               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
  
        CSQCMODEL_AUTOINIT();
  
        self.model_randomizer = random();
 -    
 -    if(clienttype(self) != CLIENTTYPE_REAL)
 -        return;
 -        
 -    sv_notice_join();
 -    
 -    MUTATOR_CALLHOOK(ClientConnect);
 +
 +      if(clienttype(self) == CLIENTTYPE_REAL)
 +              sv_notice_join();
 +
 +      MUTATOR_CALLHOOK(ClientConnect);
  }
  /*
  =============
@@@ -1583,8 -1634,8 +1582,8 @@@ void ClientDisconnect (void
  
        if(autocvar_sv_eventlog)
                GameLogEcho(strcat(":part:", ftos(self.playerid)));
-       bprint ("^4",self.netname);
-       bprint ("^4 disconnected\n");
+               
+       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_DISCONNECT, self.netname);
  
        DropAllRunes(self);
        MUTATOR_CALLHOOK(ClientDisconnect);
  
        bot_relinkplayerlist();
  
 -      if(g_arena)
 -      {
 -              Spawnqueue_Unmark(self);
 -              Spawnqueue_Remove(self);
 -      }
 -
        accuracy_free(self);
        ClientData_Detach();
        PlayerScore_Detach(self);
@@@ -1749,7 -1806,8 +1748,8 @@@ void player_powerups (void
                                self.alpha = default_player_alpha;
                                self.exteriorweaponentity.alpha = default_weapon_alpha;
                                self.items &~= IT_STRENGTH;
-                               sprint(self, "^3Invisibility has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_INVISIBILITY, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_INVISIBILITY);
                        }
                }
                else
                                self.alpha = g_minstagib_invis_alpha;
                                self.exteriorweaponentity.alpha = g_minstagib_invis_alpha;
                                self.items |= IT_STRENGTH;
-                               sprint(self, "^3You are invisible\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_INVISIBILITY, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_INVISIBILITY);
                        }
                }
  
                        if (time > self.invincible_finished)
                        {
                                self.items = self.items - (self.items & IT_INVINCIBLE);
-                               sprint(self, "^3Speed has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_SPEED, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SPEED);
                        }
                }
                else
                        if (time < self.invincible_finished)
                        {
                                self.items = self.items | IT_INVINCIBLE;
-                               sprint(self, "^3You are on speed\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SPEED, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SPEED);
                        }
                }
        }
                        if (time > self.strength_finished)
                        {
                                self.items = self.items - (self.items & IT_STRENGTH);
-                               sprint(self, "^3Strength has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_STRENGTH, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_STRENGTH);
                        }
                }
                else
                        if (time < self.strength_finished)
                        {
                                self.items = self.items | IT_STRENGTH;
-                               sprint(self, "^3Strength infuses your weapons with devastating power\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_STRENGTH, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_STRENGTH);
                        }
                }
                if (self.items & IT_INVINCIBLE)
                        if (time > self.invincible_finished)
                        {
                                self.items = self.items - (self.items & IT_INVINCIBLE);
-                               sprint(self, "^3Shield has worn off\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERDOWN_SHIELD, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERDOWN_SHIELD);
                        }
                }
                else
                        if (time < self.invincible_finished)
                        {
                                self.items = self.items | IT_INVINCIBLE;
-                               sprint(self, "^3Shield surrounds you\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_POWERUP_SHIELD, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_POWERUP_SHIELD);
                        }
                }
                if (self.items & IT_SUPERWEAPON)
                        {
                                self.superweapons_finished = 0;
                                self.items = self.items - (self.items & IT_SUPERWEAPON);
-                               sprint(self, "^3Superweapons have been lost\n");
+                               //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_LOST, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_LOST);
                        }
                        else if (self.items & IT_UNLIMITED_SUPERWEAPONS)
                        {
                                {
                                        self.items = self.items - (self.items & IT_SUPERWEAPON);
                                        WEPSET_ANDNOT_EA(self, WEPBIT_SUPERWEAPONS);
-                                       sprint(self, "^3Superweapons have broken down\n");
+                                       //Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_BROKEN, self.netname);
+                                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
                                }
                        }
                }
                        if (time < self.superweapons_finished || (self.items & IT_UNLIMITED_SUPERWEAPONS))
                        {
                                self.items = self.items | IT_SUPERWEAPON;
-                               sprint(self, "^3You now have a superweapon\n");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_SUPERWEAPON_PICKUP, self.netname);
+                               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP);
                        }
                        else
                        {
@@@ -1979,7 -2047,7 +1989,7 @@@ void player_regen (void
        limita = limita * limit_mod;
        //limitf = limitf * limit_mod;
  
 -      if(g_lms && g_ca)
 +      if(g_ca)
                rot_mod = 0;
  
        if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
@@@ -2253,46 -2321,34 +2263,37 @@@ void ShowRespawnCountdown(
        }
  }
  
- .float prevent_join_msgtime;
  void LeaveSpectatorMode()
  {
-       if(nJoinAllowed(self)) {
-               if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0) {
 +      if(self.caplayer)
 +              return;
+       if(nJoinAllowed(self))
+       {
+               if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
+               {
                        self.classname = "player";
  
                        if(autocvar_g_campaign || autocvar_g_balance_teams)
-                               JoinBestTeam(self, FALSE, TRUE);
+                               { JoinBestTeam(self, FALSE, TRUE); }
  
                        if(autocvar_g_campaign)
-                               campaign_bots_may_start = 1;
+                               { campaign_bots_may_start = 1; }
+                       else
+                               { Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD); }
  
+                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+                       
                        PutClientInServer();
  
-                       if(self.classname == "player")
-                               bprint ("^4", self.netname, "^4 is playing now\n");
-                       if(!autocvar_g_campaign)
-                       if (time < self.jointime + autocvar_welcome_message_time)
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); // clear MOTD
-                       if (self.prevent_join_msgtime)
-                       {
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_PREVENT_JOIN);
-                               self.prevent_join_msgtime = 0;
-                       }
-               } else {
-                       stuffcmd(self, "menu_showteamselect\n");
+                       if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname); }
                }
 -              else if not(g_ca && self.caplayer) { stuffcmd(self, "menu_showteamselect\n"); }
++              else
++                      stuffcmd(self, "menu_showteamselect\n");
        }
-       else {
-               //player may not join because of g_maxplayers is set
-               if (time - self.prevent_join_msgtime > 2)
-               {
-                       Send_CSQC_Centerprint_Generic(self, CPID_PREVENT_JOIN, PREVENT_JOIN_TEXT, 0, 0);
-                       self.prevent_join_msgtime = time;
-               }
+       else
+       {
+               // Player may not join because g_maxplayers is set
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
        }
  }
  
@@@ -2327,9 -2383,8 +2328,9 @@@ float nJoinAllowed(entity ignore) 
                return maxclients - totalClients;
  
        float currentlyPlaying = 0;
 -      FOR_EACH_REALPLAYER(e)
 -              currentlyPlaying += 1;
 +      FOR_EACH_REALCLIENT(e)
 +              if(e.classname == "player" || e.caplayer == 1)
 +                      currentlyPlaying += 1;
  
        if(currentlyPlaying < autocvar_g_maxplayers)
                return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
  void checkSpectatorBlock() {
        if(self.classname == "spectator" || self.classname == "observer") {
                if( time > (self.spectatortime + autocvar_g_maxplayers_spectator_blocktime) ) {
-                       sprint(self, "^7You were kicked from the server because you are spectator and spectators aren't allowed at the moment.\n");
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
                        dropclient(self);
                }
        }
@@@ -2357,12 -2412,12 +2358,12 @@@ void PrintWelcomeMessage(
                if (autocvar_g_campaign) {
                        if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
                                self.motd_actived_time = time;
-                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, -1, 0);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, campaign_message);
                        }
                } else {
                        if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
                                self.motd_actived_time = time;
-                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), -1, 0);
+                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
                        }
                }
        } else { // showing MOTD or campaign message
                                self.motd_actived_time = time;
                        else if ((time - self.motd_actived_time > 2) && self.classname == "player") { // hide it some seconds after BUTTON_INFO has been released
                                self.motd_actived_time = 0;
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                } else {
                        if ((time - self.jointime) > autocvar_welcome_message_time) {
                                        self.motd_actived_time = time;
                                else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
                                        self.motd_actived_time = 0;
-                                       Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
+                                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                                }
                        }
                }
@@@ -2490,11 -2545,13 +2491,11 @@@ void PlayerPreThink (void
        WarpZone_PlayerPhysics_FixVAngle();
  
        self.stat_game_starttime = game_starttime;
 +      self.stat_round_starttime = round_starttime;
        self.stat_allow_oldnexbeam = autocvar_g_allow_oldnexbeam;
        self.stat_leadlimit = autocvar_leadlimit;
  
 -      if(g_arena || (g_ca && !allowed_to_spawn))
 -              self.stat_respawn_time = 0;
 -      else
 -              self.stat_respawn_time = self.respawn_time;
 +      self.stat_respawn_time = self.respawn_time;
  
        if(frametime)
        {
                                        {
                                                // notify release users if connecting to git
                                                dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
-                                               sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
+                                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, self.cvar_g_xonoticversion);
                                        }
                                        else
                                        {
                                                {
                                                        // give users new version
                                                        dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n");
-                                                       sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n"));
+                                                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, self.cvar_g_xonoticversion);
                                                }
                                                else if(r > 0)
                                                {
                                                        // notify users about old server version
                                                        print("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
-                                                       sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
+                                                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, self.cvar_g_xonoticversion);
                                                }
                                        }
                                }
        // GOD MODE info
        if(!(self.flags & FL_GODMODE)) if(self.max_armorvalue)
        {
-               sprint(self, strcat("godmode saved you ", ftos(self.max_armorvalue), " units of damage, cheater!\n"));
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_GODMODE_OFF, self.max_armorvalue);
                self.max_armorvalue = 0;
        }
  
                                //sprint(self, "distance: ", ftos(self.lms_traveled_distance), "\n");
                                if(self.lms_traveled_distance < autocvar_g_lms_campcheck_distance)
                                {
-                                       centerprint(self, autocvar_g_lms_campcheck_message);
+                                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_CAMPCHECK);
                                        // FIXME KadaverJack: gibbing player here causes playermodel to bounce around, instead of eye.md3
                                        // I wasn't able to find out WHY that happens, so I put a workaround in place that shall prevent players from being gibbed :(
                                        Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
@@@ -2910,11 -2967,7 +2911,7 @@@ void PlayerPostThink (void
        {
                if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10
                {
-                       if(self.idlekick_lasttimeleft)
-                       {
-                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_DISCONNECT_IDLING);
-                               self.idlekick_lasttimeleft = 0;
-                       }
+                       if(self.idlekick_lasttimeleft) { self.idlekick_lasttimeleft = 0; }
                }
                else
                {
                        if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10
                        {
                                if(!self.idlekick_lasttimeleft)
-                                       Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft);
+                                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_DISCONNECT_IDLING, timeleft);
                        }
                        if(timeleft <= 0)
                        {
-                               bprint("^3", self.netname, "^3 was kicked for idling.\n");
-                               AnnounceTo(self, "terminated");
+                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_KICK_IDLING, self.netname);
                                dropclient(self);
                                return;
                        }
index c0ef0459abf759c90dbc727a2b0c4c49a521b94f,cb44da03fe794cada0243885dd44b53f0a974860..23014b857bed9596d4031c1a04deb683f97c9f05
@@@ -338,6 -338,7 +338,6 @@@ void PlayerCorpseDamage (entity inflict
  }
  
  void ClientKill_Now_TeamChange();
 -void freezetag_CheckWinner();
  
  void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
  {
        float valid_damage_for_weaponstats;
        float excess;
  
 -      if((g_arena && numspawned < 2) || (g_ca && allowed_to_spawn) && !inWarmupStage)
 -              return;
 -
        dh = max(self.health, 0);
        da = max(self.armorvalue, 0);
  
                        {
                                self.pain_finished = time + 0.5;        //Supajoe
  
-                               if(sv_gentle < 1) {
+                               if(autocvar_sv_gentle < 1) {
                                        if(self.classname != "body") // pain anim is BORKED on our ZYMs, FIXME remove this once we have good models
                                        {
                                                if (!self.animstate_override)
                if(valid_damage_for_weaponstats)
                        WeaponStats_LogKill(awep, abot, self.weapon, vbot);
  
-               if(sv_gentle < 1) // TODO make a "gentle" version?
+               if(autocvar_sv_gentle < 1) // TODO make a "gentle" version?
                if(sound_allowed(MSG_BROADCAST, attacker))
                {
                        if(deathtype == DEATH_DROWN)
                        }
                }
  
 -              if(!g_freezetag)
 -              {
 -                      // become fully visible
 -                      self.alpha = default_player_alpha;
 -                      // throw a weapon
 -                      SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
 -              }
 -
                // print an obituary message
                Obituary (attacker, inflictor, self, deathtype);
                race_PreDie();
        if(accuracy_isgooddamage(attacker, self))
          attacker.accuracy.(accuracy_frags[w-1]) += 1;
  
 -              if(deathtype == DEATH_HURTTRIGGER && g_freezetag)
 -              {
 -                      PutClientInServer();
 -                      count_alive_players(); // re-count players
 -                      freezetag_CheckWinner();
 -                      return;
 -              }
 -
                frag_attacker = attacker;
                frag_inflictor = inflictor;
                frag_target = self;
 +              frag_deathtype = deathtype;
                MUTATOR_CALLHOOK(PlayerDies);
 +
                weapon_action(self.weapon, WR_PLAYERDEATH);
  
                RemoveGrapplingHook(self);
                        //WriteAngle (MSG_ONE, 80);
                }
  
 -              if(defer_ClientKill_Now_TeamChange) // TODO does this work with FreezeTag?
 -                      ClientKill_Now_TeamChange();
 -
 -              if(g_arena)
 -                      Spawnqueue_Unmark(self);
 +              if(defer_ClientKill_Now_TeamChange)
 +                      ClientKill_Now_TeamChange(); // can turn player into spectator
  
 -              if(g_freezetag)
 +              // player could have been miraculously resuscitated ;)
 +              // e.g. players in freezetag get frozen, they don't really die
 +              if(self.health >= 1 || self.classname != "player")
                        return;
  
                // when we get here, player actually dies
 -              // clear waypoints (do this AFTER FreezeTag)
 +
 +              // clear waypoints
                WaypointSprite_PlayerDead();
 +              // throw a weapon
 +              SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
  
 +              // become fully visible
 +              self.alpha = default_player_alpha;
                // make the corpse upright (not tilted)
                self.angles_x = 0;
                self.angles_z = 0;
                // set up to fade out later
                SUB_SetFade (self, time + 6 + random (), 1);
  
-               if(sv_gentle > 0 || autocvar_ekg) {
+               if(autocvar_sv_gentle > 0 || autocvar_ekg) {
                        // remove corpse
                        PlayerCorpseDamage (inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force);
                }
@@@ -919,17 -933,18 +919,18 @@@ float Say(entity source, float teamsay
                        if(sourcecmsgstr != "" && !privatesay)
                                centerprint(source, sourcecmsgstr);
                }
-               else if(privatesay) // private message, between 2 people only, not sent to server console
+               else if(privatesay) // private message, between 2 people only
                {
                        sprint(source, sourcemsgstr);
                        sprint(privatesay, msgstr);
+                       if not(autocvar_g_chat_tellprivacy) { dedicated_print(msgstr); } // send to server console too if "tellprivacy" is disabled
                        if(cmsgstr != "")
                                centerprint(privatesay, cmsgstr);
                }
                else if(teamsay > 0) // team message, only sent to team mates
                {
                        sprint(source, sourcemsgstr);
-                       //print(msgstr); // send to server console too
+                       dedicated_print(msgstr); // send to server console too
                        if(sourcecmsgstr != "")
                                centerprint(source, sourcecmsgstr);
                        FOR_EACH_REALPLAYER(head) if(head.team == source.team)
                else if(teamsay < 0) // spectator message, only sent to spectators
                {
                        sprint(source, sourcemsgstr);
-                       //print(msgstr); // send to server console too
+                       dedicated_print(msgstr); // send to server console too
                        FOR_EACH_REALCLIENT(head) if(head.classname != "player")
                                if(head != source)
                                        sprint(head, msgstr);
                else if(sourcemsgstr != msgstr) // trimmed/server fixed message, sent to all players
                {
                        sprint(source, sourcemsgstr);
-                       //print(msgstr); // send to server console too
+                       dedicated_print(msgstr); // send to server console too
                        FOR_EACH_REALCLIENT(head)
                                if(head != source)
                                        sprint(head, msgstr);
@@@ -1133,7 -1148,7 +1134,7 @@@ void FakeGlobalSound(string sample, flo
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        msg_entity = self;
                                        animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        msg_entity = self;
                        if (msg_entity.cvar_cl_voice_directional >= 1)
@@@ -1230,7 -1245,7 +1231,7 @@@ void GlobalSound(string sample, float c
                                break;
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        tauntrand = random();
                        FOR_EACH_REALCLIENT(msg_entity)
                                        animdecide_setaction(self, ANIMACTION_TAUNT, TRUE);
                        if(!sv_taunt)
                                break;
-                       if(sv_gentle)
+                       if(autocvar_sv_gentle)
                                break;
                        FOR_EACH_REALCLIENT(msg_entity)
                        {
@@@ -1296,14 -1311,8 +1297,8 @@@ void VoiceMessage(string type, string m
                FakeGlobalSound(self.sample, CH_VOICE, voicetype);
  }
  
- void MoveToTeam(entity client, float team_colour, float type, float show_message)
+ void MoveToTeam(entity client, float team_colour, float type)
  {
- //    show_message
- //    0 (00) automove centerprint, admin message
- //    1 (01) automove centerprint, no admin message
- //    2 (10) no centerprint, admin message
- //    3 (11) no centerprint, no admin message
        float lockteams_backup;
  
        lockteams_backup = lockteams;  // backup any team lock
  
        TeamchangeFrags(client);  // move the players frags
        SetPlayerColors(client, team_colour - 1);  // set the players colour
-       Damage(client, client, client, 100000, ((show_message & 2) ? DEATH_QUIET : DEATH_AUTOTEAMCHANGE), client.origin, '0 0 0');  // kill the player
+       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE, client.origin, '0 0 0');  // kill the player
  
        lockteams = lockteams_backup;  // restore the team lock
  
        LogTeamchange(client.playerid, client.team, type);
-       if not(show_message & 1) // admin message
-               sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: You have been moved to the ", Team_ColorNameLowerCase(team_colour), " team\n"));  // send a chat message
-       bprint(strcat(client.netname, " joined the ", ColoredTeamName(client.team), "\n"));
  }
index 2715d475c8f6b3fa44425d93ac0af5a289b5ad4a,2a1297dc2be398d5a204852f84c880e862c54820..57b1cf4f4d19b08d54563271ba5d6257ae7aaebf
@@@ -158,16 -158,6 +158,6 @@@ float weapon_action(float wpn, float wr
        return (get_weaponinfo(wpn)).weapon_func(wrequest);
  }
  
- string W_Name(float weaponid)
- {
-       return (get_weaponinfo(weaponid)).message;
- }
- float W_AmmoItemCode(float wpn)
- {
-       return (get_weaponinfo(wpn)).items & IT_AMMO;
- }
  .float savenextthink;
  void thrown_wep_think()
  {
@@@ -313,6 -303,8 +303,6 @@@ float W_IsWeaponThrowable(float w
                return 0;
        if (g_lms)
                return 0;
 -      if (g_ca)
 -              return 0;
        if (g_cts)
                return 0;
        if (g_nexball && w == WEP_GRENADE_LAUNCHER)
@@@ -357,27 -349,12 +347,24 @@@ void W_ThrowWeapon(vector velo, vector 
  
        W_SwitchWeapon_Force(self, w_getbestweapon(self));
        a = W_ThrowNewWeapon(self, w, doreduce, self.origin + delta, velo);
-       if not(a)
-               return;
-       if(a == "")
-               sprint(self, strcat("You dropped the ^2", W_Name(w), "\n"));
-       else
-               sprint(self, strcat("You dropped the ^2", W_Name(w), " with ", a, "\n"));
+       
+       if not(a) return;
+       Send_Notification(NOTIF_ONE, self, MSG_MULTI, ITEM_WEAPON_DROP, a, w);
  }
  
 -// Bringed back weapon frame
 +float forbidWeaponUse()
 +{
 +      if(time < game_starttime && !autocvar_sv_ready_restart_after_countdown)
 +              return 1;
 +      if(round_handler_IsActive() && !round_handler_IsRoundStarted())
 +              return 1;
 +      if(self.player_blocked)
 +              return 1;
 +      if(self.freezetag_frozen)
 +              return 1;
 +      return 0;
 +}
 +
  void W_WeaponFrame()
  {
        vector fo, ri, up;
        if (frametime)
                self.weapon_frametime = frametime;
  
 -      if(((arena_roundbased || g_ca || g_freezetag) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
 -              return;
 -
 -      if(self.freezetag_frozen == 1)
 -              return;
 -
        if (!self.weaponentity || self.health < 1)
                return; // Dead player can't use weapons and injure impulse commands
  
 +      if(forbidWeaponUse())
 +      if(self.weaponentity.state != WS_CLEAR)
 +      {
 +              w_ready();
 +              return;
 +      }
 +
        if(!self.switchweapon)
        {
                self.weapon = 0;
index 96f3606021e7e00b9de86939e230f07a5d016f1e,6c1e0ed56f58e79094ed4fcb1ce461bab8533162..4cb66508961208c521710164013dcd8da3aa2961
@@@ -154,17 -154,20 +154,19 @@@ void ClientCommand_join(float request
                                {
                                        if(nJoinAllowed(self)) 
                                        {
 -                                              if(g_ca) { self.caplayer = 1; }
                                                if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
 -                                              
 +
                                                self.classname = "player";
                                                PlayerScore_Clear(self);
-                                               bprint ("^4", self.netname, "^4 is playing now\n");
+                                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
+                                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+                                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname);
                                                PutClientInServer();
                                        }
                                        else 
                                        {
                                                //player may not join because of g_maxplayers is set
-                                               centerprint(self, PREVENT_JOIN_TEXT);
+                                               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
                                        }
                                }
                        }
@@@ -193,8 -196,6 +195,8 @@@ void ClientCommand_ready(float request
                                {
                                        if(!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
                                        {
 +                                              if(time < game_starttime + 1) // game is already restarting
 +                                                      return;
                                                if (self.ready) // toggle
                                                {
                                                        self.ready = FALSE;
@@@ -285,10 -286,10 +287,10 @@@ void ClientCommand_selectteam(float req
                                                                
                                                                switch(argv(1))
                                                                {
-                                                                       case "red": selection = COLOR_TEAM1; break;
-                                                                       case "blue": selection = COLOR_TEAM2; break;
-                                                                       case "yellow": selection = COLOR_TEAM3; break;
-                                                                       case "pink": selection = COLOR_TEAM4; break;
+                                                                       case "red": selection = NUM_TEAM_1; break;
+                                                                       case "blue": selection = NUM_TEAM_2; break;
+                                                                       case "yellow": selection = NUM_TEAM_3; break;
+                                                                       case "pink": selection = NUM_TEAM_4; break;
                                                                        case "auto": selection = (-1); break;
                                                                        
                                                                        default: selection = 0; break;
@@@ -398,6 -399,8 +400,8 @@@ void ClientCommand_spectate(float reque
                                {
                                        if(self.lms_spectate_warning)
                                        {
+                                               // for the forfeit message...
+                                               self.lms_spectate_warning = 2;
                                                // mark player as spectator
                                                PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0));
                                        }
                                
                                if(self.classname == "player" && autocvar_sv_spectate == 1) 
                                        ClientKill_TeamChange(-2); // observe
 -                              
 +
                                // in CA, allow a dead player to move to spectators (without that, caplayer!=0 will be moved back to the player list)
                                // note: if arena game mode is ever done properly, this needs to be removed.
 -                              if(g_ca && self.caplayer && (self.classname == "spectator" || self.classname == "observer"))
 +                              if(self.caplayer && (self.classname == "spectator" || self.classname == "observer"))
                                {
                                        sprint(self, "WARNING: you will spectate in the next round.\n");
                                        self.caplayer = 0;
diff --combined qcsrc/server/defs.qh
index 80bf9a1c4a50a809f4dc7d41b2a008a551ee77b2,5eaafe4f109e4679aad77b9b4af21f331aa9f3f5..3281218ccb00ac50fa4ceff4700022a73c3447c9
@@@ -39,7 -39,6 +39,6 @@@ float g_pickup_respawntimejitter_poweru
  float g_jetpack;
  
  float sv_clones;
- float sv_gentle;
  float sv_foginterval;
  
  entity        activator;
@@@ -58,6 -57,9 +57,9 @@@ float team1_score, team2_score, team3_s
  
  float maxclients;
  
+ // flag set on worldspawn so that the code knows if it is dedicated or not
+ float server_is_dedicated; 
  // Fields
  
  .void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) event_damage;
@@@ -206,8 -208,6 +208,6 @@@ float WS_READY                     = 4; // idle fram
  
  void weapon_defaultspawnfunc(float wpn);
  
- string w_deathtypestring;
  .vector dest1, dest2;
  
  float gameover;
@@@ -253,8 -253,6 +253,6 @@@ float nJoinAllowed(entity ignore)
  
  .entity flagcarried;
  
- .entity lastrocket;
  .float playerid;
  float playerid_last;
  .float noalign;               // if set to 1, the item or spawnpoint won't be dropped to the floor
@@@ -457,10 -455,8 +455,10 @@@ string cvar_changes
  string cvar_purechanges;
  float cvar_purechanges_count;
  
 -float game_starttime; //point in time when the countdown is over
 +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 stat_game_starttime;
 +.float stat_round_starttime;
  
  .float stat_sv_airaccel_qw;
  .float stat_sv_airstrafeaccel_qw;
@@@ -549,7 -545,13 +547,13 @@@ float client_cefc_accumulatortime
  .float clip_load;
  .float old_clip_load;
  .float clip_size;
+ .entity lastrocket;
  .float minelayer_mines;
+ .float nex_charge;
+ .float nex_charge_rottime;
+ .float nex_chargepool_ammo;
+ .float hagar_load;
  
  .float grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
  
@@@ -586,12 -588,8 +590,6 @@@ string deathmessage
  .void (float act_state) setactive;
  .entity realowner;
  
- .float nex_charge;
- .float nex_charge_rottime;
- .float nex_chargepool_ammo;
- .float hagar_load;
 -float allowed_to_spawn; // boolean variable used by the clan arena code to determine if a player can spawn (after the round has ended)
--
  float serverflags;
  
  .float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
  .float player_blocked;
  
  .float freezetag_frozen;
 -.float freezetag_revive_progress;
  
  .entity muzzle_flash;
  .float misc_bulletcounter;    // replaces uzi & hlac bullet counter.
diff --combined qcsrc/server/g_damage.qc
index 2ba82251de5c95823ecdd66fca2073f3ac704e53,e86b148bcb0b170851e4ac934ba1917d6a3353c3..598f964c06de33b487c39e8d356078aeb7845053
@@@ -120,6 -120,10 +120,6 @@@ void GiveFrags (entity attacker, entit
  
        PlayerScore_Add(targ, SP_DEATHS, 1);
  
 -      if(g_arena || g_ca)
 -              if(autocvar_g_arena_roundbased)
 -                      return;
 -
        if(targ != attacker) // not for suicides
        if(g_weaponarena_random)
        {
                UpdateFrags(attacker, f);
  }
  
- string Obituary_ExtraFragInfo(entity player) // Extra fragmessage information
- {
-       string health_output = string_null;
-       string ping_output = string_null;
-       string handicap_output = string_null;
-       string output = string_null;
-       if(autocvar_sv_fraginfo && ((autocvar_sv_fraginfo == 2) || inWarmupStage))
-       {
-               // health/armor of attacker (person who killed you)
-               if(autocvar_sv_fraginfo_stats && (player.health >= 1))
-                       health_output = strcat("^7(Health ^1", ftos(rint(player.health)), "^7 / Armor ^2", ftos(rint(player.armorvalue)), "^7)");
-               
-               // ping display
-               if(autocvar_sv_fraginfo_ping)
-                       ping_output = ((clienttype(player) == CLIENTTYPE_BOT) ? "^2Bot" : strcat("Ping ", ((player.ping >= 150) ? "^1" : "^2"), ftos(rint(player.ping)), "ms"));
-                       
-               // handicap display 
-               if(autocvar_sv_fraginfo_handicap) 
-               {
-                       if(autocvar_sv_fraginfo_handicap == 2)  
-                               handicap_output = strcat(output, strcat("Handicap ^2", ((player.cvar_cl_handicap <= 1) ? "Off" : ftos(rint(player.cvar_cl_handicap)))));
-                       else if(player.cvar_cl_handicap) // with _handicap 1, only show this if there actually is a handicap enabled.   
-                               handicap_output = strcat("Handicap ^2", ftos(rint(player.cvar_cl_handicap)));
-               }
-               
-               // format the string
-               output = strcat(health_output, (health_output ? ((ping_output || handicap_output) ? " ^7(" : "") : ((ping_output || handicap_output) ? "^7(" : "")), 
-                       ping_output, (handicap_output ? "^7 / " : ""), 
-                       handicap_output, ((ping_output || handicap_output) ? "^7)" : ""));
-               
-               // add new line to the beginning if there is a message
-               if(output) { output = strcat("\n", output); }
-       }
-       
-       return output;
- }
  string AppendItemcodes(string s, entity player)
  {
        float w;
@@@ -282,7 -248,7 +244,7 @@@ void LogDeath(string mode, float deatht
        s = strcat(":kill:", mode);
        s = strcat(s, ":", ftos(killer.playerid));
        s = strcat(s, ":", ftos(killed.playerid));
-       s = strcat(s, ":type=", ftos(deathtype));
+       s = strcat(s, ":type=", Deathtype_Name(deathtype));
        s = strcat(s, ":items=");
        s = AppendItemcodes(s, killer);
        if(killed != killer)
        GameLogEcho(s);
  }
  
- void Send_KillNotification (string s1, string s2, string s3, float msg, float type)
+ void Obituary_SpecialDeath(
+       entity notif_target,
+       float murder,
+       float deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2, float f3)
  {
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_KILLNOTIFY);
-       WriteString(MSG_BROADCAST, s1);
-       WriteString(MSG_BROADCAST, s2);
-       WriteString(MSG_BROADCAST, s3);
-       WriteShort(MSG_BROADCAST, msg);
-       WriteByte(MSG_BROADCAST, type);
+       if(DEATH_ISSPECIAL(deathtype))
+       {
+               entity deathent = deathtypes[(deathtype - DT_FIRST) - 1];
+               if not(deathent) { backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n"); return; }
+               if(murder)
+               {
+                       if(deathent.death_msgmurder)
+                       {
+                               Send_Notification_WOVA(
+                                       NOTIF_ONE,
+                                       notif_target,
+                                       MSG_MULTI,
+                                       deathent.death_msgmurder.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                               Send_Notification_WOVA(
+                                       NOTIF_ALL_EXCEPT,
+                                       notif_target,
+                                       MSG_INFO,
+                                       deathent.death_msgmurder.nent_msginfo.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                       }
+               }
+               else
+               {
+                       if(deathent.death_msgself)
+                       {
+                               Send_Notification_WOVA(
+                                       NOTIF_ONE,
+                                       notif_target,
+                                       MSG_MULTI,
+                                       deathent.death_msgself.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                               Send_Notification_WOVA(
+                                       NOTIF_ALL_EXCEPT,
+                                       notif_target,
+                                       MSG_INFO,
+                                       deathent.death_msgself.nent_msginfo.nent_id,
+                                       s1, s2, s3, "",
+                                       f1, f2, f3, 0
+                               );
+                       }
+               }
+       }
+       else { backtrace("Obituary_SpecialDeath called without a special deathtype?\n"); return; }
  }
  
- // Function is used to send a generic centerprint whose content CSQC gets to decide (gentle version or not in the below cases)
- void Send_CSQC_KillCenterprint(entity e, string s1, string s2, float msg, float type)
+ float w_deathtype;
+ float Obituary_WeaponDeath(
+       entity notif_target,
+       float murder,
+       float deathtype,
+       string s1, string s2, string s3,
+       float f1, float f2)
  {
-       if (clienttype(e) == CLIENTTYPE_REAL)
+       float death_weapon = DEATH_WEAPONOF(deathtype);
+       if(death_weapon)
        {
-               msg_entity = e;
-               WRITESPECTATABLE_MSG_ONE({
-                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                       WriteByte(MSG_ONE, TE_CSQC_KILLCENTERPRINT);
-                       WriteString(MSG_ONE, s1);
-                       WriteString(MSG_ONE, s2);
-                       WriteShort(MSG_ONE, msg);
-                       WriteByte(MSG_ONE, type);
-               });
+               w_deathtype = deathtype;
+               float death_message = weapon_action(death_weapon, ((murder) ? WR_KILLMESSAGE : WR_SUICIDEMESSAGE));
+               w_deathtype = FALSE;
+               if(death_message)
+               {
+                       Send_Notification_WOVA(
+                               NOTIF_ONE,
+                               notif_target,
+                               MSG_MULTI,
+                               death_message,
+                               s1, s2, s3, "",
+                               f1, f2, 0, 0
+                       );
+                       Send_Notification_WOVA(
+                               NOTIF_ALL_EXCEPT,
+                               notif_target,
+                               MSG_INFO,
+                               msg_multi_notifs[death_message - 1].nent_msginfo.nent_id,
+                               s1, s2, s3, "",
+                               f1, f2, 0, 0
+                       );
+               }
+               else
+               {
+                       dprint(sprintf(
+                               "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
+                               deathtype,
+                               death_weapon
+                       ));
+               }
+               return TRUE;
        }
+       return FALSE;
  }
  
- void Obituary (entity attacker, entity inflictor, entity targ, float deathtype)
+ void Obituary(entity attacker, entity inflictor, entity targ, float deathtype)
  {
-       string  s, a, msg;
-       float type;
-       if (targ.classname == "player")
+       // Sanity check
+       if not(IS_PLAYER(targ)) { backtrace("Obituary called on non-player?!\n"); return; }
+       // Declarations
+       float notif_firstblood = FALSE;
+       float kill_count_to_attacker, kill_count_to_target;
+       // Set final information for the death
+       targ.death_origin = targ.origin;
+       if(targ != attacker) { targ.killer_origin = attacker.origin; }
+       string deathlocation = (autocvar_notification_server_allows_location ? NearestLocation(targ.death_origin) : "");
+       #ifdef NOTIFICATIONS_DEBUG
+       dprint(
+               sprintf(
+                       "Obituary(%s, %s, %s, %s = %d);\n",
+                       attacker.netname,
+                       inflictor.netname,
+                       targ.netname,
+                       Deathtype_Name(deathtype),
+                       deathtype
+               )
+       );
+       #endif
+       
+       // =======
+       // SUICIDE
+       // =======
+       if(targ == attacker)
        {
-               s = targ.netname;
-               a = attacker.netname;
-               if (targ == attacker) // suicides
+               if(DEATH_ISSPECIAL(deathtype))
                {
-                       if (deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
-                               msg = ColoredTeamName(targ.team); // TODO: check if needed?
-                       else
-                               msg = "";
-             if(!g_cts) // no "killed your own dumb self" message in CTS
-                 Send_CSQC_KillCenterprint(targ, msg, "", deathtype, MSG_SUICIDE);
-                       if(deathtype != DEATH_TEAMCHANGE && deathtype != DEATH_QUIET)
+                       if(deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
                        {
-                               LogDeath("suicide", deathtype, targ, targ);
-                               GiveFrags(attacker, targ, -1, deathtype);
+                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.team, 0, 0);
                        }
-                       if (targ.killcount > 2)
-                               msg = ftos(targ.killcount);
                        else
-                               msg = "";
-                       if(teamplay && deathtype == DEATH_MIRRORDAMAGE)
                        {
-                               if(attacker.team == COLOR_TEAM1)
-                                       deathtype = KILL_TEAM_RED;
-                               else
-                                       deathtype = KILL_TEAM_BLUE;
+                               switch(deathtype)
+                               {
+                                       case DEATH_MIRRORDAMAGE:
+                                       {
+                                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0);
+                                               break;
+                                       }
+                                       
+                                       default:
+                                       {
+                                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0);
+                                               break;
+                                       }
+                               }
                        }
-                       Send_KillNotification(s, msg, "", deathtype, MSG_SUICIDE);
                }
-               else if (attacker.classname == "player")
+               else if not(Obituary_WeaponDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0))
                {
-                       if(!IsDifferentTeam(attacker, targ))
-                       {
-                               if(attacker.team == COLOR_TEAM1)
-                                       type = KILL_TEAM_RED;
-                               else
-                                       type = KILL_TEAM_BLUE;
-                               GiveFrags(attacker, targ, -1, deathtype);
+                       backtrace("SUICIDE: what the hell happened here?\n");
+                       return;
+               }
+               LogDeath("suicide", deathtype, targ, targ);
+               GiveFrags(attacker, targ, -1, deathtype);
+       }
  
-                               Send_CSQC_KillCenterprint(attacker, s, "", type, MSG_KILL);
+       // ======
+       // MURDER
+       // ======
+       else if(IS_PLAYER(attacker))
+       {
+               if(!IsDifferentTeam(attacker, targ))
+               {
+                       LogDeath("tk", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, -1, deathtype);
  
-                               if (targ.killcount > 2)
-                                       msg = ftos(targ.killcount);
-                               else
-                                       msg = "";
+                       attacker.killcount = 0;
+                       
+                       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.netname);
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(targ.team, INFO_DEATH_TEAMKILL_), targ.netname, attacker.netname, targ.killcount);
  
-                               if (attacker.killcount > 2) {
-                                       msg = ftos(attacker.killcount);
-                                       type = KILL_TEAM_SPREE;
+                       // In this case, the death message will ALWAYS be "foo was betrayed by bar"
+                       // No need for specific death/weapon messages...
+               }
+               else
+               {
+                       LogDeath("frag", deathtype, attacker, targ);
+                       GiveFrags(attacker, targ, 1, deathtype);
+                       attacker.taunt_soundtime = time + 1;
+                       attacker.killcount = attacker.killcount + 1;
+                       #define SPREE_ITEM(counta,countb,center,normal,gentle) \
+                               case counta: \
+                               { \
+                                       AnnounceTo(attacker, strcat(#countb, "kills")); \
+                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
+                                       break; \
                                }
-                               Send_KillNotification(a, s, msg, type, MSG_KILL);
-                               attacker.killcount = 0;
+                       switch(attacker.killcount)
+                       {
+                               KILL_SPREE_LIST
+                               default: break;
+                       }
+                       #undef SPREE_ITEM
  
-                               LogDeath("tk", deathtype, attacker, targ);
+                       if(!checkrules_firstblood)
+                       {
+                               checkrules_firstblood = TRUE;
+                               notif_firstblood = TRUE; // modify the current messages so that they too show firstblood information
+                               PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
+                               PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
+                               // tell spree_inf and spree_cen that this is a first-blood and first-victim event
+                               kill_count_to_attacker = -1;
+                               kill_count_to_target = -2;
                        }
                        else
                        {
-                               if (!checkrules_firstblood)
-                               {
-                                       checkrules_firstblood = TRUE;
-                                       Send_KillNotification(a, "", "", KILL_FIRST_BLOOD, MSG_KILL);
-                                       // TODO: make these print a newline if they dont
-                                       Send_CSQC_KillCenterprint(attacker, "", "", KILL_FIRST_BLOOD, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, "", "", KILL_FIRST_VICTIM, MSG_KILL);
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_FIRSTBLOOD, 1);
-                                       PlayerStats_Event(targ, PLAYERSTATS_ACHIEVEMENT_FIRSTVICTIM, 1);
-                               }
-                               if(targ.istypefrag) {
-                                       Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_TYPEFRAG, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_TYPEFRAGGED, MSG_KILL);
-                               } else {
-                                       Send_CSQC_KillCenterprint(attacker, s, Obituary_ExtraFragInfo(targ), KILL_FRAG, MSG_KILL);
-                                       Send_CSQC_KillCenterprint(targ, a, Obituary_ExtraFragInfo(attacker), KILL_FRAGGED, MSG_KILL);
-                               }
-                               attacker.taunt_soundtime = time + 1;
+                               kill_count_to_attacker = attacker.killcount;
+                               kill_count_to_target = 0;
+                       }
  
-                               if (deathtype == DEATH_HURTTRIGGER && inflictor.message2 != "")
-                                       msg = inflictor.message2;
-                               else if (deathtype == DEATH_CUSTOM)
-                                       msg = deathmessage;
+                       float verbose_allowed = (autocvar_notification_server_allows_frag_verbose && ((autocvar_notification_server_allows_frag_verbose == 2) || inWarmupStage));
+                       if(targ.istypefrag)
+                       {
+                               if(attacker.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
                                else
-                                       msg = "";
-                               if(strstrofs(msg, "%", 0) < 0)
-                                       msg = strcat("%s ", msg, " by %s");
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAG, targ.netname, kill_count_to_attacker);
  
-                               Send_KillNotification(a, s, msg, deathtype, MSG_KILL);
+                               if(targ.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                               else
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_TYPEFRAGGED, attacker.netname, kill_count_to_target);
+                       }
+                       else
+                       {
+                               if(attacker.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG_VERBOSE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? NO_MSG : targ.ping));
+                               else
+                                       Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_MURDER_FRAG, targ.netname, kill_count_to_attacker);
  
-                               GiveFrags(attacker, targ, 1, deathtype);
+                               if(targ.FRAG_VERBOSE && verbose_allowed)
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED_VERBOSE, attacker.netname, kill_count_to_target, attacker.health, attacker.armorvalue, (IS_BOT_CLIENT(attacker) ? NO_MSG : attacker.ping));
+                               else
+                                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_MURDER_FRAGGED, attacker.netname, kill_count_to_target);
+                       }
  
-                               if (targ.killcount > 2) {
-                                       Send_KillNotification(s, ftos(targ.killcount), a, KILL_END_SPREE, MSG_SPREE);
-                               }
+                       if not(Obituary_WeaponDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker))
+                               Obituary_SpecialDeath(targ, TRUE, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker, 0);
+               }
+       }
  
-                               attacker.killcount = attacker.killcount + 1;
+       // =============
+       // ACCIDENT/TRAP
+       // =============
+       else
+       {
+               switch(deathtype)
+               {
+                       // For now, we're just forcing HURTTRIGGER to behave as "DEATH_VOID" and giving it no special options...
+                       // Later on you will only be able to make custom messages using DEATH_CUSTOM,
+                       // and there will be a REAL DEATH_VOID implementation which mappers will use.
+                       /*case DEATH_HURTTRIGGER:
+                       {
+                               s1 = targ.netname;
+                               s2 = inflictor.message;
+                               if(strstrofs(s2, "%", 0) < 0) { s2 = strcat("%s ", s2); }
+                               break;
+                       }*/
  
-                               if (attacker.killcount == 3)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_3, MSG_SPREE);
-                                       AnnounceTo(attacker, "03kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_3, 1);
-                               }
-                               else if (attacker.killcount == 5)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_5, MSG_SPREE);
-                                       AnnounceTo(attacker, "05kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_5, 1);
-                               }
-                               else if (attacker.killcount == 10)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_10, MSG_SPREE);
-                                       AnnounceTo(attacker, "10kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_10, 1);
-                               }
-                               else if (attacker.killcount == 15)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_15, MSG_SPREE);
-                                       AnnounceTo(attacker, "15kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_15, 1);
-                               }
-                               else if (attacker.killcount == 20)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_20, MSG_SPREE);
-                                       AnnounceTo(attacker, "20kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_20, 1);
-                               }
-                               else if (attacker.killcount == 25)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_25, MSG_SPREE);
-                                       AnnounceTo(attacker, "25kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_25, 1);
-                               }
-                               else if (attacker.killcount == 30)
-                               {
-                                       Send_KillNotification(a, "", "", KILL_SPREE_30, MSG_SPREE);
-                                       AnnounceTo(attacker, "30kills");
-                                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_30, 1);
-                               }
-                               else if (attacker.killcount > 2) {
-                                       Send_KillNotification(a, ftos(attacker.killcount), "", KILL_SPREE, MSG_SPREE);
-                               }
-                               LogDeath("frag", deathtype, attacker, targ);
+                       case DEATH_CUSTOM:
+                       {
+                               Obituary_SpecialDeath(targ, FALSE, deathtype,
+                                       targ.netname,
+                                       ((strstrofs(deathmessage, "%", 0) < 0) ? strcat("%s ", deathmessage) : deathmessage),
+                                       deathlocation,
+                                       targ.killcount,
+                                       0,
+                                       0);
+                               break;
                        }
-               }
-               else
-               {
-                       Send_CSQC_KillCenterprint(targ, "", "", deathtype, MSG_KILL_ACTION);
-                       if (deathtype == DEATH_HURTTRIGGER && inflictor.message != "")
-                               msg = inflictor.message;
-                       else if (deathtype == DEATH_CUSTOM)
-                               msg = deathmessage;
-                       else
-                               msg = "";
-                       if(strstrofs(msg, "%", 0) < 0)
-                               msg = strcat("%s ", msg);
-                       GiveFrags(targ, targ, -1, deathtype);
-                       if(PlayerScore_Add(targ, SP_SCORE, 0) == -5) {
-                               AnnounceTo(targ, "botlike");
-                               PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+                       
+                       default:
+                       {
+                               Obituary_SpecialDeath(targ, FALSE, deathtype, targ.netname, deathlocation, "", targ.killcount, 0, 0);
+                               break;
                        }
-                       Send_KillNotification(s, msg, "", deathtype, MSG_KILL_ACTION);
-                       if (targ.killcount > 2)
-                               Send_KillNotification(s, ftos(targ.killcount), "", 0, MSG_KILL_ACTION_SPREE);
-                       LogDeath("accident", deathtype, targ, targ);
                }
  
-               targ.death_origin = targ.origin;
-               if(targ != attacker)
-                       targ.killer_origin = attacker.origin;
+               LogDeath("accident", deathtype, targ, targ);
+               GiveFrags(targ, targ, -1, deathtype);
  
-               // FIXME: this should go in PutClientInServer
-               if (targ.killcount)
-                       targ.killcount = 0;
+               if(PlayerScore_Add(targ, SP_SCORE, 0) == -5)
+               {
+                       AnnounceTo(targ, "botlike");
+                       PlayerStats_Event(attacker, PLAYERSTATS_ACHIEVEMENT_BOTLIKE, 1);
+               }
        }
+       // reset target kill count
+       if(targ.killcount) { targ.killcount = 0; }
  }
  
  // these are updated by each Damage call for use in button triggering and such
@@@ -523,7 -581,7 +577,7 @@@ void Damage (entity targ, entity inflic
  {
        float mirrordamage;
        float mirrorforce;
-       float teamdamage0;
+       float complainteamdamage = 0; 
        entity attacker_save;
        mirrordamage = 0;
        mirrorforce = 0;
                        }
        }
  
-       if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE || deathtype == DEATH_QUIET)
+       if(deathtype == DEATH_KILL || deathtype == DEATH_TEAMCHANGE || deathtype == DEATH_AUTOTEAMCHANGE)
        {
                // These are ALWAYS lethal
                // No damage modification here
                                        {
                                                if(targ.classname == "player" && targ.deadflag == DEAD_NO)
                                                {
-                                                       teamdamage0 = max(attacker.dmg_team, autocvar_g_teamdamage_threshold);
                                                        attacker.dmg_team = attacker.dmg_team + damage;
-                                                       if(attacker.dmg_team > teamdamage0 && !g_ca)
-                                                               mirrordamage = autocvar_g_mirrordamage * (attacker.dmg_team - teamdamage0);
+                                                       complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
+                                                       if(complainteamdamage > 0 && !g_ca) // FIXME why is g_ca ruled out here? Why not just g_mirrordamage 0 on CA servers?
+                                                               mirrordamage = autocvar_g_mirrordamage * complainteamdamage;
                                                        mirrorforce = autocvar_g_mirrordamage * vlen(force);
                                                        if(g_minstagib)
                                                        {
                        {
                                damage = 0;
                                mirrordamage = 0;
+                               complainteamdamage = 0;
                                if (targ != attacker)
                                {
                                        if ((targ.health >= 1) && (targ.classname == "player"))
                {
                        damage *= g_weapondamagefactor;
                        mirrordamage *= g_weapondamagefactor;
+                       complainteamdamage *= g_weapondamagefactor;
                        force = force * g_weaponforcefactor;
                        mirrorforce *= g_weaponforcefactor;
                }
                                        {
                                                attacker.typehitsound += 1;
                                        }
-                                       if(mirrordamage > 0)
+                                       if(complainteamdamage > 0)
                                                if(time > attacker.teamkill_complain)
                                                {
                                                        attacker.teamkill_complain = time + 5;
diff --combined qcsrc/server/g_world.qc
index dad5e33b3fdc92c925bab6c648470bce55244c67,894ffd6158b7b347a5ed283d6f334ee3aef57988..9fe531564085436feb1da51434efbfe6f80500d1
@@@ -256,17 -256,16 +256,17 @@@ void cvar_changes_init(
                BADCVAR("g_arena");
                BADCVAR("g_assault");
                BADCVAR("g_ca");
 +              BADCVAR("g_ca_teams");
                BADCVAR("g_ctf");
                BADCVAR("g_cts");
                BADCVAR("g_dm");
                BADCVAR("g_domination");
                BADCVAR("g_domination_default_teams");
                BADCVAR("g_freezetag");
 +              BADCVAR("g_freezetag_teams");
                BADCVAR("g_keepaway");
                BADCVAR("g_keyhunt");
                BADCVAR("g_keyhunt_teams");
 -              BADCVAR("g_keyhunt_teams");
                BADCVAR("g_lms");
                BADCVAR("g_nexball");
                BADCVAR("g_onslaught");
                BADCVAR("g_balance_teams_scorefactor");
                BADCVAR("g_ban_sync_trusted_servers");
                BADCVAR("g_ban_sync_uri");
 +              BADCVAR("g_ca_teams_override");
                BADCVAR("g_ctf_ignore_frags");
                BADCVAR("g_domination_point_limit");
 +              BADCVAR("g_freezetag_teams_override");
                BADCVAR("g_friendlyfire");
                BADCVAR("g_fullbrightitems");
                BADCVAR("g_fullbrightplayers");
@@@ -553,6 -550,8 +553,8 @@@ void spawnfunc___init_dedicated_server(
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
+       CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
+       CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
  
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
@@@ -585,6 -584,8 +587,6 @@@ void spawnfunc_worldspawn (void
  
        compressShortVector_init();
  
 -      allowed_to_spawn = TRUE;
 -
        entity head;
        head = nextent(world);
        maxclients = 0;
                head = nextent(head);
        }
  
+       server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? TRUE : FALSE);
        // needs to be done so early because of the constants they create
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
        CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
+       CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
+       CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
  
        ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
  
        addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
        addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
        addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
 +      addstat(STAT_ROUNDSTARTTIME, AS_FLOAT, stat_round_starttime);
        addstat(STAT_ALLOW_OLDNEXBEAM, AS_INT, stat_allow_oldnexbeam);
        Nagger_Init();
  
  
        addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
  
 -      if(g_ca || g_freezetag)
 -      {
 -              addstat(STAT_REDALIVE, AS_INT, redalive_stat);
 -              addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
 -              addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
 -              addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
 -      }
 -      if(g_freezetag)
 -      {
 -              addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
 -              addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
 -      }
 -
        // g_movementspeed hack
        addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
        addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
        for(i = 0, j = 0; i < MapInfo_count; ++i)
        {
                if(MapInfo_Get_ByID(i))
-                       if not(MapInfo_Map_flags & (MAPINFO_FLAG_HIDDEN | MAPINFO_FLAG_FORBIDDEN))
+                       if not(MapInfo_Map_flags & MapInfo_ForbiddenFlags())
                        {
                                if(mod(i, 2))
                                        col = "^2";
@@@ -1464,7 -1481,7 +1470,7 @@@ void DumpStats(float final
                {
                        s = strcat(":player:see-labels:", GetPlayerScoreString(other, 0), ":");
                        s = strcat(s, ftos(rint(time - other.jointime)), ":");
 -                      if(other.classname == "player" || g_arena || g_ca || g_lms)
 +                      if(other.classname == "player" || g_arena || other.caplayer == 1 || g_lms)
                                s = strcat(s, ftos(other.team), ":");
                        else
                                s = strcat(s, "spectator:");
@@@ -1579,6 -1596,8 +1585,8 @@@ void NextLevel(
        PlayerStats_Shutdown();
        WeaponStats_Shutdown();
  
+       Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now
        if(autocvar_sv_eventlog)
                GameLogEcho(":gameover");
  
@@@ -1661,20 -1680,8 +1669,8 @@@ void InitiateOvertime() // ONLY call th
        tl = autocvar_timelimit;
        tl += autocvar_timelimit_overtime;
        cvar_set("timelimit", ftos(tl));
-       string minutesPlural;
-       if (autocvar_timelimit_overtime == 1)
-               minutesPlural = " ^3minute";
-       else
-               minutesPlural = " ^3minutes";
-       bcenterprint(
-               strcat(
-                       "^3Now playing ^1OVERTIME^3!\n\n^3Added ^1",
-                       ftos(autocvar_timelimit_overtime),
-                       minutesPlural,
-                       " to the game!"
-               )
-       );
+       Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime);
  }
  
  float GetWinningCode(float fraglimitreached, float equality)
@@@ -1742,10 -1749,10 +1738,10 @@@ float WinningCondition_Onslaught(
        {
                if (head.health > 0)
                {
-                       if (head.team == COLOR_TEAM1) t1 = 1;
-                       if (head.team == COLOR_TEAM2) t2 = 1;
-                       if (head.team == COLOR_TEAM3) t3 = 1;
-                       if (head.team == COLOR_TEAM4) t4 = 1;
+                       if (head.team == NUM_TEAM_1) t1 = 1;
+                       if (head.team == NUM_TEAM_2) t2 = 1;
+                       if (head.team == NUM_TEAM_3) t3 = 1;
+                       if (head.team == NUM_TEAM_4) t4 = 1;
                }
                head = find(head, classname, "onslaught_generator");
        }
        {
                // game over, only one team remains (or none)
                ClearWinners();
-               if (t1) SetWinners(team, COLOR_TEAM1);
-               if (t2) SetWinners(team, COLOR_TEAM2);
-               if (t3) SetWinners(team, COLOR_TEAM3);
-               if (t4) SetWinners(team, COLOR_TEAM4);
+               if (t1) SetWinners(team, NUM_TEAM_1);
+               if (t2) SetWinners(team, NUM_TEAM_2);
+               if (t3) SetWinners(team, NUM_TEAM_3);
+               if (t4) SetWinners(team, NUM_TEAM_4);
                dprint("Have a winner, ending game.\n");
                return WINNING_YES;
        }
@@@ -1794,13 -1801,13 +1790,13 @@@ float WinningCondition_Assault(
  
        status = WINNING_NO;
        // as the timelimit has not yet passed just assume the defending team will win
-       if(assault_attacker_team == COLOR_TEAM1)
+       if(assault_attacker_team == NUM_TEAM_1)
        {
-               SetWinners(team, COLOR_TEAM2);
+               SetWinners(team, NUM_TEAM_2);
        }
        else
        {
-               SetWinners(team, COLOR_TEAM1);
+               SetWinners(team, NUM_TEAM_1);
        }
  
        entity ent;
@@@ -1926,10 -1933,10 +1922,10 @@@ float WinningCondition_Scores(float lim
  
        if(teamplay)
        {
-               team1_score = TeamScore_GetCompareValue(COLOR_TEAM1);
-               team2_score = TeamScore_GetCompareValue(COLOR_TEAM2);
-               team3_score = TeamScore_GetCompareValue(COLOR_TEAM3);
-               team4_score = TeamScore_GetCompareValue(COLOR_TEAM4);
+               team1_score = TeamScore_GetCompareValue(NUM_TEAM_1);
+               team2_score = TeamScore_GetCompareValue(NUM_TEAM_2);
+               team3_score = TeamScore_GetCompareValue(NUM_TEAM_3);
+               team4_score = TeamScore_GetCompareValue(NUM_TEAM_4);
        }
  
        ClearWinners();
@@@ -2045,25 -2052,25 +2041,25 @@@ float WinningCondition_RanOutOfSpawns(
  
        FOR_EACH_PLAYER(head) if(head.deadflag == DEAD_NO)
        {
-               if(head.team == COLOR_TEAM1)
+               if(head.team == NUM_TEAM_1)
                        team1_score = 1;
-               else if(head.team == COLOR_TEAM2)
+               else if(head.team == NUM_TEAM_2)
                        team2_score = 1;
-               else if(head.team == COLOR_TEAM3)
+               else if(head.team == NUM_TEAM_3)
                        team3_score = 1;
-               else if(head.team == COLOR_TEAM4)
+               else if(head.team == NUM_TEAM_4)
                        team4_score = 1;
        }
  
        for(head = world; (head = find(head, classname, "info_player_deathmatch")) != world; )
        {
-               if(head.team == COLOR_TEAM1)
+               if(head.team == NUM_TEAM_1)
                        team1_score = 1;
-               else if(head.team == COLOR_TEAM2)
+               else if(head.team == NUM_TEAM_2)
                        team2_score = 1;
-               else if(head.team == COLOR_TEAM3)
+               else if(head.team == NUM_TEAM_3)
                        team3_score = 1;
-               else if(head.team == COLOR_TEAM4)
+               else if(head.team == NUM_TEAM_4)
                        team4_score = 1;
        }
  
        {
                float t, i;
                if(team1_score)
-                       t = COLOR_TEAM1;
+                       t = NUM_TEAM_1;
                else if(team2_score)
-                       t = COLOR_TEAM2;
+                       t = NUM_TEAM_2;
                else if(team3_score)
-                       t = COLOR_TEAM3;
+                       t = NUM_TEAM_3;
                else // if(team4_score)
-                       t = COLOR_TEAM4;
+                       t = NUM_TEAM_4;
                CheckAllowedTeams(world);
                for(i = 0; i < MAX_TEAMSCORE; ++i)
                {
-                       if(t != COLOR_TEAM1) if(c1 >= 0) TeamScore_AddToTeam(COLOR_TEAM1, i, -1000);
-                       if(t != COLOR_TEAM2) if(c2 >= 0) TeamScore_AddToTeam(COLOR_TEAM2, i, -1000);
-                       if(t != COLOR_TEAM3) if(c3 >= 0) TeamScore_AddToTeam(COLOR_TEAM3, i, -1000);
-                       if(t != COLOR_TEAM4) if(c4 >= 0) TeamScore_AddToTeam(COLOR_TEAM4, i, -1000);
+                       if(t != NUM_TEAM_1) if(c1 >= 0) TeamScore_AddToTeam(NUM_TEAM_1, i, -1000);
+                       if(t != NUM_TEAM_2) if(c2 >= 0) TeamScore_AddToTeam(NUM_TEAM_2, i, -1000);
+                       if(t != NUM_TEAM_3) if(c3 >= 0) TeamScore_AddToTeam(NUM_TEAM_3, i, -1000);
+                       if(t != NUM_TEAM_4) if(c4 >= 0) TeamScore_AddToTeam(NUM_TEAM_4, i, -1000);
                }
  
                AddWinners(team, t);
@@@ -2180,9 -2187,9 +2176,9 @@@ void CheckRules_World(
                {
                        checkrules_suddendeathwarning = TRUE;
                        if(g_race && !g_race_qualifying)
-                               bcenterprint("^3Everyone, finish your lap! The race is over!");
+                               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_RACE_FINISHLAP);
                        else
-                               bcenterprint("^3Now playing ^1OVERTIME^3!\n\n^3Keep fragging until we have a ^1winner^3!");
+                               Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_OVERTIME_FRAG);
                }
        }
        else
index b6d4a45b2d923d2a5d9ad562770a1c3a41ba404b,2b73841808bed3223c1eef10bef5c06dd384138c..60868652dde77183d08321576a504cabaeb8812f
@@@ -32,7 -32,6 +32,6 @@@ void WarpZone_crosshair_trace(entity pl
  void() spawnfunc_info_player_deathmatch; // needed for the other spawnpoints
  void() spawnpoint_use;
  string GetMapname();
- string ColoredTeamName(float t);
  
  string admin_name(void)
  {
@@@ -80,26 -79,27 +79,27 @@@ float DistributeEvenly_GetRandomized(fl
  
  #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e)
  
  string STR_PLAYER = "player";
  string STR_SPECTATOR = "spectator";
  string STR_OBSERVER = "observer";
  
- #if 0
- #define FOR_EACH_CLIENT(v) for(v = world; (v = findflags(v, flags, FL_CLIENT)) != world; )
- #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
- #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; )
- #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL)
- #else
+ #define IS_PLAYER(v)                  (v.classname == STR_PLAYER)
+ #define IS_SPEC(v)                            (v.classname == STR_SPECTATOR)
+ #define IS_OBSERVER(v)                        (v.classname == STR_OBSERVER)
+ #define IS_CLIENT(v)                  (v.flags & FL_CLIENT)
+ #define IS_BOT_CLIENT(v)              (clienttype(v) == CLIENTTYPE_BOT)
+ #define IS_REAL_CLIENT(v)             (clienttype(v) == CLIENTTYPE_REAL)
+ #define IS_NOT_A_CLIENT(v)            (clienttype(v) == CLIENTTYPE_NOTACLIENT)
  #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); )
- #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT)
- #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL)
- #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER)
- #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if(v.classname != STR_PLAYER)
- #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER)
- #endif
+ #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(IS_CLIENT(v))
+ #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(IS_REAL_CLIENT(v))
+ #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(IS_PLAYER(v))
+ #define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if not(IS_PLAYER(v)) // Samual: shouldn't this be IS_SPEC(v)? and rather create a separate macro to include observers too
+ #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(IS_PLAYER(v))
  
- #define CENTER_OR_VIEWOFS(ent) (ent.origin + ((ent.classname == STR_PLAYER) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
+ #define CENTER_OR_VIEWOFS(ent) (ent.origin + (IS_PLAYER(ent) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5)))
  
  // copies a string to a tempstring (so one can strunzone it)
  string strcat1(string s) = #115; // FRIK_FILE
  float logfile_open;
  float logfile;
  
- void bcenterprint(string s)
- {
-     // TODO replace by MSG_ALL (would show it to spectators too, though)?
-     entity head;
-     FOR_EACH_PLAYER(head)
-     if (clienttype(head) == CLIENTTYPE_REAL)
-         centerprint(head, s);
- }
  void GameLogEcho(string s)
  {
      string fn;
@@@ -546,7 -537,11 +537,11 @@@ void GetCvars(float f
  
        get_cvars_f = f;
        get_cvars_s = s;
        MUTATOR_CALLHOOK(GetCvars);
+       Notification_GetCvars();
        GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
        GetCvars_handleFloat(s, f, cvar_cl_autoscreenshot, "cl_autoscreenshot");
        GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
        }
  }
  
- void backtrace(string msg)
- {
-     float dev, war;
-     dev = autocvar_developer;
-     war = autocvar_prvm_backtraceforwarnings;
-     cvar_set("developer", "1");
-     cvar_set("prvm_backtraceforwarnings", "1");
-     print("\n");
-     print("--- CUT HERE ---\nWARNING: ");
-     print(msg);
-     print("\n");
-     remove(world); // isn't there any better way to cause a backtrace?
-     print("\n--- CUT UNTIL HERE ---\n");
-     cvar_set("developer", ftos(dev));
-     cvar_set("prvm_backtraceforwarnings", ftos(war));
- }
- string Team_ColorCode(float teamid)
- {
-     if (teamid == COLOR_TEAM1)
-         return "^1";
-     else if (teamid == COLOR_TEAM2)
-         return "^4";
-     else if (teamid == COLOR_TEAM3)
-         return "^3";
-     else if (teamid == COLOR_TEAM4)
-         return "^6";
-     else
-         return "^7";
- }
- string Team_ColorName(float t)
- {
-     // fixme: Search for team entities and get their .netname's!
-     if (t == COLOR_TEAM1)
-         return "Red";
-     if (t == COLOR_TEAM2)
-         return "Blue";
-     if (t == COLOR_TEAM3)
-         return "Yellow";
-     if (t == COLOR_TEAM4)
-         return "Pink";
-     return "Neutral";
- }
- string Team_ColorNameLowerCase(float t)
- {
-     // fixme: Search for team entities and get their .netname's!
-     if (t == COLOR_TEAM1)
-         return "red";
-     if (t == COLOR_TEAM2)
-         return "blue";
-     if (t == COLOR_TEAM3)
-         return "yellow";
-     if (t == COLOR_TEAM4)
-         return "pink";
-     return "neutral";
- }
- float ColourToNumber(string team_colour)
- {
-       if (team_colour == "red")
-               return COLOR_TEAM1;
-       if (team_colour == "blue")
-               return COLOR_TEAM2;
-       if (team_colour == "yellow")
-               return COLOR_TEAM3;
-       if (team_colour == "pink")
-               return COLOR_TEAM4;
-       if (team_colour == "auto")
-               return 0;
-       return -1;
- }
- float NumberToTeamNumber(float number)
- {
-       if (number == 1)
-               return COLOR_TEAM1;
-       if (number == 2)
-               return COLOR_TEAM2;
-       if (number == 3)
-               return COLOR_TEAM3;
-       if (number == 4)
-               return COLOR_TEAM4;
-       return -1;
- }
  // decolorizes and team colors the player name when needed
  string playername(entity p)
  {
@@@ -1161,7 -1060,6 +1060,6 @@@ void readlevelcvars(void
      g_touchexplode_force = cvar("g_touchexplode_force");
  
        sv_clones = cvar("sv_clones");
-       sv_gentle = cvar("sv_gentle");
        sv_foginterval = cvar("sv_foginterval");
        g_cloaked = cvar("g_cloaked");
      if(g_cts)
      if(!g_weapon_stay)
          g_weapon_stay = cvar("g_weapon_stay");
  
 -      if not(inWarmupStage && !g_ca)
 +      if not(inWarmupStage)
                game_starttime = cvar("g_start_delay");
  
        readplayerstartcvars();
@@@ -1640,34 -1538,6 +1538,6 @@@ void precache(
  #endif
  }
  
- // sorry, but using \ in macros breaks line numbers
- #define WRITESPECTATABLE_MSG_ONE_VARNAME(varname,statement) entity varname; varname = msg_entity; FOR_EACH_REALCLIENT(msg_entity) if(msg_entity == varname || (msg_entity.classname == STR_SPECTATOR && msg_entity.enemy == varname)) statement msg_entity = varname
- #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
- #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
- void Send_CSQC_Centerprint_Generic(entity e, float id, string s, float duration, float countdown_num)
- {
-       if ((clienttype(e) == CLIENTTYPE_REAL) && (e.flags & FL_CLIENT))
-       {
-               msg_entity = e;
-               WRITESPECTATABLE_MSG_ONE({
-                       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-                       WriteByte(MSG_ONE, TE_CSQC_CENTERPRINT_GENERIC);
-                       WriteByte(MSG_ONE, id);
-                       WriteString(MSG_ONE, s);
-                       if (id != 0 && s != "")
-                       {
-                               WriteByte(MSG_ONE, duration);
-                               WriteByte(MSG_ONE, countdown_num);
-                       }
-               });
-       }
- }
- void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
- {
-       Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
- }
  // WARNING: this kills the trace globals
  #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
  #define EXACTTRIGGER_INIT  WarpZoneLib_ExactTrigger_Init()
@@@ -2146,22 -2016,6 +2016,6 @@@ string race_readName(string map, float 
        return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
  }
  
- string race_placeName(float pos) {
-       if(floor((mod(pos, 100))/10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
-       {
-               if(mod(pos, 10) == 1)
-                       return strcat(ftos(pos), "st");
-               else if(mod(pos, 10) == 2)
-                       return strcat(ftos(pos), "nd");
-               else if(mod(pos, 10) == 3)
-                       return strcat(ftos(pos), "rd");
-               else
-                       return strcat(ftos(pos), "th");
-       }
-       else
-               return strcat(ftos(pos), "th");
- }
  float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
  {
      float m, i;
index df3ad10a113123f9bc2ad7ccf42fa223d771af83,c43a398754c34b0e513e60f189423e2a12f78406..3853d49f27d96114bb181d9d19f4230d9487f112
 -void freezetag_Initialize()
 +.float freezetag_frozen_time;
 +.float freezetag_frozen_timeout;
 +.float freezetag_revive_progress;
 +.entity freezetag_ice;
 +#define ICE_MAX_ALPHA 1
 +#define ICE_MIN_ALPHA 0.1
 +float freezetag_teams;
 +
 +void freezetag_count_alive_players()
  {
 -      precache_model("models/ice/ice.md3");
 -      warmup = time + autocvar_g_start_delay + autocvar_g_freezetag_warmup;
 -      ScoreRules_freezetag();
 +      entity e;
 +      total_players = redalive = bluealive = yellowalive = pinkalive = 0;
 +      FOR_EACH_PLAYER(e) {
 +              if(e.team == COLOR_TEAM1 && e.health >= 1)
 +              {
 +                      ++total_players;
 +                      if (!e.freezetag_frozen) ++redalive;
 +              }
 +              else if(e.team == COLOR_TEAM2 && e.health >= 1)
 +              {
 +                      ++total_players;
 +                      if (!e.freezetag_frozen) ++bluealive;
 +              }
 +              else if(e.team == COLOR_TEAM3 && e.health >= 1)
 +              {
 +                      ++total_players;
 +                      if (!e.freezetag_frozen) ++yellowalive;
 +              }
 +              else if(e.team == COLOR_TEAM4 && e.health >= 1)
 +              {
 +                      ++total_players;
 +                      if (!e.freezetag_frozen) ++pinkalive;
 +              }
 +      }
 +      FOR_EACH_REALCLIENT(e) {
 +              e.redalive_stat = redalive;
 +              e.bluealive_stat = bluealive;
 +              e.yellowalive_stat = yellowalive;
 +              e.pinkalive_stat = pinkalive;
 +      }
  }
 +#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
 +#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams)
  
 -void freezetag_CheckWinner()
 +float prev_total_players;
 +float freezetag_CheckTeams()
  {
 -      if(time <= game_starttime) // game didn't even start yet! nobody can win in that case.
 -              return;
 -
 -      if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
 -              return; // already waiting for next round to start
 -
 -      if((redalive >= 1 && bluealive >= 1)
 -              || (redalive >= 1 && yellowalive >= 1)
 -              || (redalive >= 1 && pinkalive >= 1)
 -              || (bluealive >= 1 && yellowalive >= 1)
 -              || (bluealive >= 1 && pinkalive >= 1)
 -              || (yellowalive >= 1 && pinkalive >= 1))
 -              return; // we still have active players on two or more teams, nobody won yet
 -
 -      entity e, winner;
 -      winner = world;
 -
 -      FOR_EACH_PLAYER(e)
 +      entity e;
 +      if(FREEZETAG_ALIVE_TEAMS_OK())
        {
 -              if(e.freezetag_frozen == 0 && e.health >= 1) // here's one player from the winning team... good
 +              if(prev_total_players != -1)
                {
 -                      winner = e;
 -                      break; // break, we found the winner
 +                      FOR_EACH_REALCLIENT(e)
 +                              Send_CSQC_Centerprint_Generic_Expire(e, CPID_WAITING_PLAYERS);
                }
 +              prev_total_players = -1;
 +              return 1;
 +      }
 +      if(prev_total_players != total_players)
 +      {
 +              string teams_missing = "";
 +              if(!redalive)   teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM1), ", ");
 +              if(!bluealive)  teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM2), ", ");
 +              if(freezetag_teams >= 3)
 +              if(!yellowalive)        teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM3), ", ");
 +              if(freezetag_teams == 4)
 +              if(!pinkalive)  teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM4), ", ");
 +              teams_missing = substring(teams_missing, 0, strlen(teams_missing)-2);
 +
 +              FOR_EACH_REALCLIENT(e)
 +                      Send_CSQC_Centerprint_Generic(e, CPID_WAITING_PLAYERS, strcat("Waiting for players to join...\n\nNeed active players for: ", teams_missing), -1, 0);
 +              prev_total_players = total_players;
 +      }
 +      return 0;
 +}
 +
 +float freezetag_getWinnerTeam()
 +{
 +      float winner_team = 0;
 +      if(redalive >= 1)
 +              winner_team = COLOR_TEAM1;
 +      if(bluealive >= 1)
 +      {
 +              if(winner_team) return 0;
 +              winner_team = COLOR_TEAM2;
 +      }
 +      if(yellowalive >= 1)
 +      {
 +              if(winner_team) return 0;
 +              winner_team = COLOR_TEAM3;
 +      }
 +      if(pinkalive >= 1)
 +      {
 +              if(winner_team) return 0;
 +              winner_team = COLOR_TEAM4;
 +      }
 +      if(winner_team)
 +              return winner_team;
 +      return -1; // no player left
 +}
 +
 +float freezetag_CheckWinner()
 +{
 +      entity e;
 +      if(round_handler_GetTimeLeft() <= 0)
 +      {
 +              FOR_EACH_REALCLIENT(e)
 +                      centerprint(e, "Round over, there's no winner");
 +              bprint("Round over, there's no winner.\n");
 +              FOR_EACH_PLAYER(e)
 +                      e.freezetag_frozen_timeout = 0;
 +              round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
 +              return 1;
        }
  
 -      if(winner != world) // just in case a winner wasn't found
 +      if(FREEZETAG_ALIVE_TEAMS() > 1)
 +              return 0;
 +
 +      float winner_team;
 +      string teamname;
 +      winner_team = freezetag_getWinnerTeam();
 +      if(winner_team > 0)
        {
-               teamname = ColoredTeamName(winner_team);
-               FOR_EACH_REALCLIENT(e)
-                       centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen."));
-               bprint(teamname, "^5 wins the round since all the other teams were frozen.\n");
+               Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner.team, CENTER_FREEZETAG_ROUND_WIN_));
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner.team, INFO_FREEZETAG_ROUND_WIN_));
 -              TeamScore_AddToTeam(winner.team, ST_SCORE, +1);
 +              TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
 +      }
 +      else if(winner_team == -1)
 +      {
 +              FOR_EACH_REALCLIENT(e)
 +                      centerprint(e, "^5Round tied! All teams were frozen.");
 +              bprint("^5Round tied! All teams were frozen.\n");
        }
  
 -      next_round = time + 5;
 +      FOR_EACH_PLAYER(e)
 +              e.freezetag_frozen_timeout = 0;
 +      round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
 +      return 1;
  }
  
  // this is needed to allow the player to turn his view around (fixangle can't
@@@ -149,36 -52,13 +147,36 @@@ void freezetag_Ice_Think(
        self.nextthink = time;
  }
  
 +void freezetag_Add_Score(entity attacker)
 +{
 +      if(attacker == self)
 +      {
 +              // you froze your own dumb self
 +              // counted as "suicide" already
 +              PlayerScore_Add(self, SP_SCORE, -1);
 +      }
 +      else if(attacker.classname == "player")
 +      {
 +              // got frozen by an enemy
 +              // counted as "kill" and "death" already
 +              PlayerScore_Add(self, SP_SCORE, -1);
 +              PlayerScore_Add(attacker, SP_SCORE, +1);
 +      }
 +      // else nothing - got frozen by the game type rules themselves
 +}
 +
  void freezetag_Freeze(entity attacker)
  {
        if(self.freezetag_frozen)
                return;
        self.freezetag_frozen = 1;
 +      self.freezetag_frozen_time = time;
        self.freezetag_revive_progress = 0;
        self.health = 1;
 +      if(autocvar_g_freezetag_frozen_maxtime > 0)
 +              self.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
 +
 +      freezetag_count_alive_players();
  
        entity ice;
        ice = spawn();
        ice.think = freezetag_Ice_Think;
        ice.nextthink = time;
        ice.frame = floor(random() * 21); // ice model has 20 different looking frames
 +      ice.alpha = ICE_MAX_ALPHA;
 +      ice.colormod = TeamColor(self.team);
 +      ice.glowmod = ice.colormod;
        setmodel(ice, "models/ice/ice.md3");
  
 -      entity oldself;
 -      oldself = self;
 -      self = ice;
 -      freezetag_Ice_Think();
 -      self = oldself;
 +      self.freezetag_ice = ice;
  
        RemoveGrapplingHook(self);
  
        // add waypoint
        WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1');
  
 -      if(attacker == self)
 -      {
 -              // you froze your own dumb self
 -              // counted as "suicide" already
 -              PlayerScore_Add(self, SP_SCORE, -1);
 -      }
 -      else if(attacker.classname == "player")
 -      {
 -              // got frozen by an enemy
 -              // counted as "kill" and "death" already
 -              PlayerScore_Add(self, SP_SCORE, -1);
 -              PlayerScore_Add(attacker, SP_SCORE, +1);
 -      }
 -      else
 -      {
 -              // nothing - got frozen by the game type rules themselves
 -      }
 +      freezetag_Add_Score(attacker);
  }
  
  void freezetag_Unfreeze(entity attacker)
  {
        self.freezetag_frozen = 0;
 +      self.freezetag_frozen_time = 0;
 +      self.freezetag_frozen_timeout = 0;
        self.freezetag_revive_progress = 0;
 -      self.health = autocvar_g_balance_health_start;
  
 -      // remove the ice block
 -      entity ice;
 -      for(ice = world; (ice = find(ice, classname, "freezetag_ice")); ) if(ice.owner == self)
 -      {
 -              remove(ice);
 -              break;
 -      }
 +      remove(self.freezetag_ice);
 +      self.freezetag_ice = world;
  
 -      // remove waypoint
        if(self.waypointsprite_attached)
                WaypointSprite_Kill(self.waypointsprite_attached);
  }
@@@ -327,151 -229,112 +325,151 @@@ void havocbot_role_ft_freeing(
  
  MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer)
  {
 -      if(self.freezetag_frozen == 0 && self.health >= 1)
 -      {
 -              if(self.team == NUM_TEAM_1)
 -                      --redalive;
 -              else if(self.team == NUM_TEAM_2)
 -                      --bluealive;
 -              else if(self.team == NUM_TEAM_3)
 -                      --yellowalive;
 -              else if(self.team == NUM_TEAM_4)
 -                      --pinkalive;
 -              --totalalive;
 -      }
 -
 -      if(total_players > 2) // only check for winners if we had more than two players (one of them left, don't let the other player win just because of that)
 -              freezetag_CheckWinner();
 -
 +      self.health = 0; // neccessary to update correctly alive stats
        freezetag_Unfreeze(world);
 -
 +      freezetag_count_alive_players();
        return 1;
  }
  
  MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
  {
 -      if(self.freezetag_frozen == 0)
 +      if(round_handler_IsActive())
 +      if(round_handler_CountdownRunning())
        {
 -              if(self.team == NUM_TEAM_1)
 -                      --redalive;
 -              else if(self.team == NUM_TEAM_2)
 -                      --bluealive;
 -              else if(self.team == NUM_TEAM_3)
 -                      --yellowalive;
 -              else if(self.team == NUM_TEAM_4)
 -                      --pinkalive;
 -              --totalalive;
 +              if(self.freezetag_frozen)
 +                      freezetag_Unfreeze(world);
 +              freezetag_count_alive_players();
 +              return 1; // let the player die so that he can respawn whenever he wants
 +      }
  
 -              freezetag_Freeze(frag_attacker);
 +      // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
 +      // you succeed changing team through the menu: you both really die (gibbing) and get frozen
 +      if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
 +              || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE)
 +      {
 +              // let the player die, he will be automatically frozen when he respawns
 +              if(!self.freezetag_frozen)
 +              {
 +                      freezetag_Add_Score(frag_attacker);
 +                      freezetag_count_alive_players();
 +              }
 +              else
 +                      freezetag_Unfreeze(world); // remove ice
 +              self.freezetag_frozen_timeout = -2; // freeze on respawn
 +              return 1;
        }
  
 +      if(self.freezetag_frozen)
 +              return 1;
 +
 +      freezetag_Freeze(frag_attacker);
 +
        if(frag_attacker == frag_target || frag_attacker == world)
        {
                if(frag_target.classname == STR_PLAYER)
-                       centerprint(frag_target, "^1You froze yourself.\n");
-               bprint("^7", frag_target.netname, "^1 froze himself.\n");
+                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
        }
        else
        {
                if(frag_target.classname == STR_PLAYER)
-                       centerprint(frag_target, strcat("^1You were frozen by ^7", frag_attacker.netname, ".\n"));
+                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_FROZEN, frag_attacker.netname);
                if(frag_attacker.classname == STR_PLAYER)
-                       centerprint(frag_attacker, strcat("^2You froze ^7", frag_target.netname, ".\n"));
-               bprint("^7", frag_target.netname, "^1 was frozen by ^7", frag_attacker.netname, ".\n");
+                       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_FREEZETAG_FREEZE, frag_target.netname);
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
        }
  
        frag_target.health = 1; // "respawn" the player :P
  
 -      freezetag_CheckWinner();
 -
        return 1;
  }
  
  MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
  {
 -      freezetag_Unfreeze(world); // start by making sure that all ice blocks are removed
 +      if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
 +              return 1; // do nothing, round is starting right now
  
 -      if(total_players == 1 && time > game_starttime) // only one player active on server, start a new match immediately
 -      if(!next_round && warmup && (time < warmup - autocvar_g_freezetag_warmup || time > warmup)) // not awaiting next round
 +      if(self.freezetag_frozen_timeout == -2) // player was dead
        {
 -              next_round = time;
 +              freezetag_Freeze(world);
                return 1;
        }
 -      if(warmup && time > warmup) // spawn too late, freeze player
 +
 +      freezetag_count_alive_players();
 +
 +      if(round_handler_IsActive())
 +      if(round_handler_IsRoundStarted())
        {
-               centerprint(self, "^1Round already started, you spawn as frozen.");
+               Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
                freezetag_Freeze(world);
        }
  
        return 1;
  }
  
 +MUTATOR_HOOKFUNCTION(freezetag_reset_map_players)
 +{
 +      FOR_EACH_PLAYER(self)
 +      {
 +              if (self.freezetag_frozen)
 +                      freezetag_Unfreeze(world);
 +              self.freezetag_frozen_timeout = -1;
 +              PutClientInServer();
 +              self.freezetag_frozen_timeout = 0;
 +      }
 +      freezetag_count_alive_players();
 +      return 1;
 +}
 +
  MUTATOR_HOOKFUNCTION(freezetag_GiveFragsForKill)
  {
        frag_score = 0; // no frags counted in Freeze Tag
        return 1;
  }
  
 +.float reviving; // temp var
  MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
  {
        float n;
 -      vector revive_extra_size;
  
 -      revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
 +      if(gameover)
 +              return 1;
 +
 +      if(self.freezetag_frozen)
 +      {
 +              // keep health = 1
 +              self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
 +      }
 +
 +      if(round_handler_IsActive())
 +      if(!round_handler_IsRoundStarted())
 +              return 1;
  
        entity o;
        o = world;
 -      n = 0;
 -      FOR_EACH_PLAYER(other) if(self != other)
 +      if(self.freezetag_frozen_timeout > 0 && time < self.freezetag_frozen_timeout)
 +              self.freezetag_ice.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time);
 +
 +      if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
 +              n = -1;
 +      else
        {
 -              if(other.freezetag_frozen == 0)
 +              vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
 +              n = 0;
 +              FOR_EACH_PLAYER(other) if(self != other)
                {
 -                      if(other.team == self.team)
 +                      if(other.freezetag_frozen == 0)
                        {
 -                              if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
 +                              if(other.team == self.team)
                                {
 -                                      if(!o)
 -                                              o = other;
 -                                      ++n;
 +                                      if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
 +                                      {
 +                                              if(!o)
 +                                                      o = other;
 +                                              if(self.freezetag_frozen)
 +                                                      other.reviving = TRUE;
 +                                              ++n;
 +                                      }
                                }
                        }
                }
                if(self.freezetag_revive_progress >= 1)
                {
                        freezetag_Unfreeze(self);
 +                      freezetag_count_alive_players();
 +
 +                      if(n == -1)
 +                      {
 +                              string s = ftos(autocvar_g_freezetag_frozen_maxtime);
 +                              centerprint(self, strcat("^5You were automatically revived after ", s, " seconds^5.\n"));
 +                              bprint("^7", self.netname, "^5 were automatically revived after ", s, " seconds^5.\n");
 +                              return 1;
 +                      }
  
                        // EVERY team mate nearby gets a point (even if multiple!)
 -                      FOR_EACH_PLAYER(other) if(self != other)
 +                      FOR_EACH_PLAYER(other)
                        {
 -                              if(other.freezetag_frozen == 0)
 +                              if(other.reviving)
                                {
 -                                      if(other.team == self.team)
 -                                      {
 -                                              if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
 -                                              {
 -                                                      PlayerScore_Add(other, SP_FREEZETAG_REVIVALS, +1);
 -                                                      PlayerScore_Add(other, SP_SCORE, +1);
 -                                              }
 -                                      }
 +                                      PlayerScore_Add(other, SP_FREEZETAG_REVIVALS, +1);
 +                                      PlayerScore_Add(other, SP_SCORE, +1);
                                }
                        }
  
-                       if(n > 1)
-                               centerprint(self, strcat("^5You were revived by ^7", o.netname, "^5 et al.\n"));
-                       else
-                               centerprint(self, strcat("^5You were revived by ^7", o.netname, "^5.\n"));
-                       centerprint(o, strcat("^5You revived ^7", self.netname, "^5.\n"));
-                       if(n > 1)
-                               bprint("^7", o.netname, "^5 et al revived ^7", self.netname, "^5.\n");
-                       else
-                               bprint("^7", o.netname, "^5 revived ^7", self.netname, "^5.\n");
+                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
+                       Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
+                       Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVE, self.netname, o.netname);
                }
  
 -              // now find EVERY teammate within reviving radius, set their revive_progress values correct
 -              FOR_EACH_PLAYER(other) if(self != other)
 +              FOR_EACH_PLAYER(other)
                {
 -                      if(other.freezetag_frozen == 0)
 +                      if(other.reviving)
                        {
 -                              if(other.team == self.team)
 -                              {
 -                                      if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, other.absmin, other.absmax))
 -                                              other.freezetag_revive_progress = self.freezetag_revive_progress;
 -                              }
 +                              other.freezetag_revive_progress = self.freezetag_revive_progress;
 +                              other.reviving = FALSE;
                        }
                }
        }
@@@ -550,12 -408,15 +542,12 @@@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPh
  
  MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate)
  {
 -    if(g_freezetag)
 -    {
 -        if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
 -        {
 -            frag_damage = 0;
 -            frag_force = frag_force * autocvar_g_freezetag_frozen_force;
 -        }
 -    }
 -    return 1;
 +      if(frag_target.freezetag_frozen && frag_deathtype != DEATH_HURTTRIGGER)
 +      {
 +              frag_damage = 0;
 +              frag_force = frag_force * autocvar_g_freezetag_frozen_force;
 +      }
 +      return 1;
  }
  
  MUTATOR_HOOKFUNCTION(freezetag_ForbidThrowCurrentWeapon)
@@@ -574,59 -435,22 +566,59 @@@ MUTATOR_HOOKFUNCTION(freezetag_BotRoles
                else
                        self.havocbot_role = havocbot_role_ft_offense;
        }
 -      
 +
        return TRUE;
  }
  
 +MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy)
 +{
 +      self.freezetag_frozen = other.freezetag_frozen;
 +      self.freezetag_revive_progress = other.freezetag_revive_progress;
 +      return 0;
 +}
 +
 +MUTATOR_HOOKFUNCTION(freezetag_GetTeamCount)
 +{
 +      freezetag_teams = autocvar_g_freezetag_teams_override;
 +      if(freezetag_teams < 2)
 +              freezetag_teams = autocvar_g_freezetag_teams;
 +      freezetag_teams = bound(2, freezetag_teams, 4);
 +      ret_float = freezetag_teams;
 +      return 0;
 +}
 +
 +void freezetag_Initialize()
 +{
 +      precache_model("models/ice/ice.md3");
 +      ScoreRules_freezetag();
 +
 +      round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
 +      round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
 +
 +      addstat(STAT_REDALIVE, AS_INT, redalive_stat);
 +      addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
 +      addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
 +      addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
 +
 +      addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
 +      addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
 +}
 +
  MUTATOR_DEFINITION(gamemode_freezetag)
  {
        MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY);
        MUTATOR_HOOK(ClientDisconnect, freezetag_RemovePlayer, CBC_ORDER_ANY);
        MUTATOR_HOOK(PlayerDies, freezetag_PlayerDies, CBC_ORDER_ANY);
        MUTATOR_HOOK(PlayerSpawn, freezetag_PlayerSpawn, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY);
        MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY);
 -      MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_FIRST); //first, last or any? dunno.
 +      MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
        MUTATOR_HOOK(HavocBot_ChooseRule, freezetag_BotRoles, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(SpectateCopy, freezetag_SpectateCopy, CBC_ORDER_ANY);
 +      MUTATOR_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE);
  
        MUTATOR_ONADD
        {
index 55614ff8effba562ed5f9fa21120caed6fc9188a,bda701f96a015dafd8440f35df82b22ae032e147..611f7f065e10be5eda8f984c10166c76ea99fdf6
@@@ -6,6 -6,7 +6,6 @@@ float kh_tracking_enabled
  .entity kh_next;
  float kh_Key_AllOwnedByWhichTeam();
  
 -// used by arena.qc ready-restart:
  typedef void(void) kh_Think_t;
  void kh_StartRound();
- void kh_Controller_SetThink_NoMsg(float t, kh_Think_t func);
+ void kh_Controller_SetThink(float t, kh_Think_t func);
index 708db15b631d6b993ad259f4da482708256f45d6,a351f937c7c73df9d078bcf2fe0c4febb137cd79..5a050356de617f251898f27648ca1736a91065f8
@@@ -392,9 -392,9 +392,9 @@@ MUTATOR_HOOKFUNCTION(superspec_SV_Parse
                if(cmd_argc == 2)
                {
                        if(argv(1) == "red")
-                               _team = COLOR_TEAM1;
+                               _team = NUM_TEAM_1;
                        else
-                               _team = COLOR_TEAM2;
+                               _team = NUM_TEAM_2;
                }
  
                FOR_EACH_PLAYER(_player)
@@@ -443,9 -443,6 +443,9 @@@ void superspec_hello(
  
  MUTATOR_HOOKFUNCTION(superspec_ClientConnect)
  {
 +      if(clienttype(self) != CLIENTTYPE_REAL)
 +              return FALSE;
 +
        string fn = "superspec-local.options";
        float fh;
  
diff --combined qcsrc/server/progs.src
index fcc82ed08557e6b0008acd229f2b482a46a515f0,a00fd32c5e6f0e47a4865434dadee0ce79556034..03326da8436610985d732af71a64ceb08a1500c8
@@@ -13,7 -13,9 +13,9 @@@ sys-post.q
  ../warpzonelib/server.qh
  
  ../common/constants.qh
+ ../common/teams.qh
  ../common/util.qh
+ ../common/counting.qh
  ../common/items.qh
  ../common/explosion_equation.qh
  ../common/urllib.qh
@@@ -28,10 -30,11 +30,13 @@@ autocvars.q
  constants.qh
  defs.qh               // Should rename this, it has fields and globals
  
+ ../common/notifications.qh // must be after autocvars
+ ../common/deathtypes.qh // must be after notifications
  mutators/base.qh
  mutators/mutators.qh
 +mutators/gamemode_arena.qh
 +mutators/gamemode_ca.qh
  mutators/gamemode_ctf.qh
  mutators/gamemode_domination.qh
  mutators/gamemode_keyhunt.qh // TODO fix this
@@@ -82,8 -85,6 +87,8 @@@ antilag.q
  
  playerdemo.qh
  
 +round_handler.qh
 +
  // singleplayer stuff
  item_key.qh
  secret.qh
@@@ -101,6 -102,7 +106,6 @@@ g_subs.q
  g_tetris.qc
  
  runematch.qc
 -arena.qc
  
  g_violence.qc
  g_damage.qc
@@@ -209,13 -211,9 +214,13 @@@ anticheat.q
  cheats.qc
  playerstats.qc
  
 +round_handler.qc
 +
  ../common/explosion_equation.qc
  
  mutators/base.qc
 +mutators/gamemode_arena.qc
 +mutators/gamemode_ca.qc
  mutators/gamemode_ctf.qc
  mutators/gamemode_domination.qc
  mutators/gamemode_freezetag.qc
@@@ -242,5 -240,6 +247,6 @@@ mutators/mutator_superspec.q
  
  ../common/animdecide.qc
  ../common/util.qc
+ ../common/notifications.qc
  
  ../common/if-this-file-errors-scroll-up-and-fix-the-warnings.fteqccfail
diff --combined qcsrc/server/scores.qc
index 7d9ffd8ca3c3ae6b7488ed0d08da958ff676365c,eb305e72203d48462e505a7a9261622660a5f2f1..ef2551fa6495961a58457b1a718aa2da192fb63d
@@@ -204,13 -204,13 +204,13 @@@ void ScoreInfo_Init(float teams
                Net_LinkEntity(scores_initialized, FALSE, 0, ScoreInfo_SendEntity);
        }
        if(teams >= 1)
-               TeamScore_Spawn(COLOR_TEAM1, "Red");
+               TeamScore_Spawn(NUM_TEAM_1, "Red");
        if(teams >= 2)
-               TeamScore_Spawn(COLOR_TEAM2, "Blue");
+               TeamScore_Spawn(NUM_TEAM_2, "Blue");
        if(teams >= 3)
-               TeamScore_Spawn(COLOR_TEAM3, "Yellow");
+               TeamScore_Spawn(NUM_TEAM_3, "Yellow");
        if(teams >= 4)
-               TeamScore_Spawn(COLOR_TEAM4, "Pink");
+               TeamScore_Spawn(NUM_TEAM_4, "Pink");
  }
  
  /*
@@@ -256,8 -256,8 +256,8 @@@ float PlayerScore_Clear(entity player
        if(teamscores_entities_count)
                return 0;
  
 +      if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return 0;
        if(g_lms) return 0;
 -      if(g_arena || g_ca) return 0;
        if(g_cts) return 0; // in CTS, you don't lose score by observing
        if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
  
@@@ -527,12 -527,12 +527,12 @@@ void WinningConditionHelper(
                                s = strcat(s, ":human");
                        else
                                s = strcat(s, ":bot");
 -                      if(p.classname != "player" && !g_arena && !g_ca && !g_lms)
 +                      if(p.classname != "player" && !g_arena && p.caplayer != 1 && !g_lms)
                                s = strcat(s, ":spectator");
                }
                else
                {
 -                      if(p.classname == "player" || g_arena || g_ca || g_lms)
 +                      if(p.classname == "player" || g_arena || p.caplayer == 1 || g_lms)
                                s = GetPlayerScoreString(p, 2);
                        else
                                s = "-666";
@@@ -795,7 -795,7 +795,7 @@@ void Score_NicePrint_Team(entity to, fl
        sk = teamscorekeepers[t - 1];
        if(sk)
        {
-               s = strcat(s, ColoredTeamName(t));
+               s = strcat(s, Team_ColoredFullName(t));
                for(i = 0; i < MAX_TEAMSCORE; ++i)
                        if(teamscores_label[i] != "")
                        {
diff --combined qcsrc/server/teamplay.qc
index 98a524bca3cee0c628b94f9e6c52abde0d774ad2,a96726c5643f175174783c563ec77751deb70190..4e8febc409d4d7c657df483244a83218df571b0d
@@@ -13,45 -13,6 +13,6 @@@ void TeamchangeFrags(entity e
        PlayerScore_Clear(e);
  }
  
- vector TeamColor(float teem)
- {
-       switch(teem)
-       {
-               case COLOR_TEAM1:
-                       return '1 0.0625 0.0625';
-               case COLOR_TEAM2:
-                       return '0.0625 0.0625 1';
-               case COLOR_TEAM3:
-                       return '1 1 0.0625';
-               case COLOR_TEAM4:
-                       return '1 0.0625 1';
-               default:
-                       return '1 1 1';
-       }
- }
- string TeamName(float t)
- {
-       return strcat(Team_ColorName(t), " Team");
- }
- string ColoredTeamName(float t)
- {
-       return strcat(Team_ColorCode(t), Team_ColorName(t), " Team^7");
- }
- string TeamNoName(float t)
- {
-       // fixme: Search for team entities and get their .netname's!
-       if(t == 1)
-               return "Red Team";
-       if(t == 2)
-               return "Blue Team";
-       if(t == 3)
-               return "Yellow Team";
-       if(t == 4)
-               return "Pink Team";
-       return "Neutral Team";
- }
  void runematch_init();
  void tdm_init();
  void entcs_init();
@@@ -169,7 -130,10 +130,7 @@@ void InitGameplayMode(
        {
                fraglimit_override = autocvar_g_arena_point_limit;
                leadlimit_override = autocvar_g_arena_point_leadlimit;
 -              maxspawned = autocvar_g_arena_maxspawned;
 -              if(maxspawned < 2)
 -                      maxspawned = 2;
 -              arena_roundbased = autocvar_g_arena_roundbased;
 +              MUTATOR_ADD(gamemode_arena);
        }
  
        if(g_ca)
                ActivateTeamplay();
                fraglimit_override = autocvar_g_ca_point_limit;
                leadlimit_override = autocvar_g_ca_point_leadlimit;
 -              precache_sound("ctf/red_capture.wav");
 -              precache_sound("ctf/blue_capture.wav");
 +              MUTATOR_ADD(gamemode_ca);
        }
 +
        if(g_keyhunt)
        {
                ActivateTeamplay();
@@@ -413,13 -377,13 +374,13 @@@ void SetPlayerTeam(entity pl, float t, 
        float _color;
  
        if(t == 4)
-               _color = COLOR_TEAM4 - 1;
+               _color = NUM_TEAM_4 - 1;
        else if(t == 3)
-               _color = COLOR_TEAM3 - 1;
+               _color = NUM_TEAM_3 - 1;
        else if(t == 2)
-               _color = COLOR_TEAM2 - 1;
+               _color = NUM_TEAM_2 - 1;
        else
-               _color = COLOR_TEAM1 - 1;
+               _color = NUM_TEAM_1 - 1;
  
        SetPlayerColors(pl,_color);
  
                LogTeamchange(pl.playerid, pl.team, 3);  // log manual team join
  
                if(!noprint)
-               bprint(pl.netname, "^7 has changed from ", TeamNoName(s), " to ", TeamNoName(t), "\n");
+               bprint(pl.netname, "^7 has changed from ", Team_NumberToColoredFullName(s), "^7 to ", Team_NumberToColoredFullName(t), "\n");
        }
  
  }
@@@ -449,10 -413,10 +410,10 @@@ void CheckAllowedTeams (entity for_whom
                head = findchain(classname, "onslaught_generator");
                while (head)
                {
-                       if (head.team == COLOR_TEAM1) c1 = 0;
-                       if (head.team == COLOR_TEAM2) c2 = 0;
-                       if (head.team == COLOR_TEAM3) c3 = 0;
-                       if (head.team == COLOR_TEAM4) c4 = 0;
+                       if (head.team == NUM_TEAM_1) c1 = 0;
+                       if (head.team == NUM_TEAM_2) c2 = 0;
+                       if (head.team == NUM_TEAM_3) c3 = 0;
+                       if (head.team == NUM_TEAM_4) c4 = 0;
                        head = head.chain;
                }
        }
                {
                        if(!(g_domination && head.netname == ""))
                        {
-                               if(head.team == COLOR_TEAM1)
+                               if(head.team == NUM_TEAM_1)
                                        c1 = 0;
-                               else if(head.team == COLOR_TEAM2)
+                               else if(head.team == NUM_TEAM_2)
                                        c2 = 0;
-                               else if(head.team == COLOR_TEAM3)
+                               else if(head.team == NUM_TEAM_3)
                                        c3 = 0;
-                               else if(head.team == COLOR_TEAM4)
+                               else if(head.team == NUM_TEAM_4)
                                        c4 = 0;
                        }
                        head = find(head, classname, teament_name);
        }
  
        // if player has a forced team, ONLY allow that one
-       if(self.team_forced == COLOR_TEAM1 && c1 >= 0)
+       if(self.team_forced == NUM_TEAM_1 && c1 >= 0)
                c2 = c3 = c4 = -1;
-       else if(self.team_forced == COLOR_TEAM2 && c2 >= 0)
+       else if(self.team_forced == NUM_TEAM_2 && c2 >= 0)
                c1 = c3 = c4 = -1;
-       else if(self.team_forced == COLOR_TEAM3 && c3 >= 0)
+       else if(self.team_forced == NUM_TEAM_3 && c3 >= 0)
                c1 = c2 = c4 = -1;
-       else if(self.team_forced == COLOR_TEAM4 && c4 >= 0)
+       else if(self.team_forced == NUM_TEAM_4 && c4 >= 0)
                c1 = c2 = c3 = -1;
  }
  
@@@ -573,7 -537,7 +534,7 @@@ void GetTeamCounts(entity ignore
                                bvalue = value;
                        else
                                bvalue = 0;
-                       if(t == COLOR_TEAM1)
+                       if(t == NUM_TEAM_1)
                        {
                                if(c1 >= 0)
                                {
                                        cb1 = cb1 + bvalue;
                                }
                        }
-                       if(t == COLOR_TEAM2)
+                       if(t == NUM_TEAM_2)
                        {
                                if(c2 >= 0)
                                {
                                        cb2 = cb2 + bvalue;
                                }
                        }
-                       if(t == COLOR_TEAM3)
+                       if(t == NUM_TEAM_3)
                        {
                                if(c3 >= 0)
                                {
                                        cb3 = cb3 + bvalue;
                                }
                        }
-                       if(t == COLOR_TEAM4)
+                       if(t == NUM_TEAM_4)
                        {
                                if(c4 >= 0)
                                {
@@@ -766,13 -730,13 +727,13 @@@ float JoinBestTeam(entity pl, float onl
        // if he's not on a valid team, then let other code put him on the smallest team
        if(!forcebestteam)
        {
-               if(     c1 >= 0 && pl.team == COLOR_TEAM1)
+               if(     c1 >= 0 && pl.team == NUM_TEAM_1)
                        selectedteam = pl.team;
-               else if(c2 >= 0 && pl.team == COLOR_TEAM2)
+               else if(c2 >= 0 && pl.team == NUM_TEAM_2)
                        selectedteam = pl.team;
-               else if(c3 >= 0 && pl.team == COLOR_TEAM3)
+               else if(c3 >= 0 && pl.team == NUM_TEAM_3)
                        selectedteam = pl.team;
-               else if(c4 >= 0 && pl.team == COLOR_TEAM4)
+               else if(c4 >= 0 && pl.team == NUM_TEAM_4)
                        selectedteam = pl.team;
                else
                        selectedteam = -1;
                TeamchangeFrags(self);
                if(smallest == 1)
                {
-                       SetPlayerColors(pl, COLOR_TEAM1 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_1 - 1);
                }
                else if(smallest == 2)
                {
-                       SetPlayerColors(pl, COLOR_TEAM2 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_2 - 1);
                }
                else if(smallest == 3)
                {
-                       SetPlayerColors(pl, COLOR_TEAM3 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_3 - 1);
                }
                else if(smallest == 4)
                {
-                       SetPlayerColors(pl, COLOR_TEAM4 - 1);
+                       SetPlayerColors(pl, NUM_TEAM_4 - 1);
                }
                else
                {
@@@ -841,21 -805,21 +802,21 @@@ void SV_ChangeTeam(float _color
        scolor = self.clientcolors & 0x0F;
        dcolor = _color & 0x0F;
  
-       if(scolor == COLOR_TEAM1 - 1)
+       if(scolor == NUM_TEAM_1 - 1)
                steam = 1;
-       else if(scolor == COLOR_TEAM2 - 1)
+       else if(scolor == NUM_TEAM_2 - 1)
                steam = 2;
-       else if(scolor == COLOR_TEAM3 - 1)
+       else if(scolor == NUM_TEAM_3 - 1)
                steam = 3;
-       else // if(scolor == COLOR_TEAM4 - 1)
+       else // if(scolor == NUM_TEAM_4 - 1)
                steam = 4;
-       if(dcolor == COLOR_TEAM1 - 1)
+       if(dcolor == NUM_TEAM_1 - 1)
                dteam = 1;
-       else if(dcolor == COLOR_TEAM2 - 1)
+       else if(dcolor == NUM_TEAM_2 - 1)
                dteam = 2;
-       else if(dcolor == COLOR_TEAM3 - 1)
+       else if(dcolor == NUM_TEAM_3 - 1)
                dteam = 3;
-       else // if(dcolor == COLOR_TEAM4 - 1)
+       else // if(dcolor == NUM_TEAM_4 - 1)
                dteam = 4;
  
        CheckAllowedTeams(self);
@@@ -944,13 -908,13 +905,13 @@@ void ShufflePlayerOutOfTeam (float sour
        }
  
        if(source_team == 1)
-               steam = COLOR_TEAM1;
+               steam = NUM_TEAM_1;
        else if(source_team == 2)
-               steam = COLOR_TEAM2;
+               steam = NUM_TEAM_2;
        else if(source_team == 3)
-               steam = COLOR_TEAM3;
+               steam = NUM_TEAM_3;
        else // if(source_team == 4)
-               steam = COLOR_TEAM4;
+               steam = NUM_TEAM_4;
  
        lowest_bot = world;
        lowest_bot_score = 999999999;
  
        if(selected.deadflag == DEAD_NO)
                Damage(selected, selected, selected, 100000, DEATH_AUTOTEAMCHANGE, selected.origin, '0 0 0');
-       centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", ColoredTeamName(selected.team)));
+       centerprint(selected, strcat("You have been moved into a different team to improve team balance\nYou are now on: ", Team_ColoredFullName(selected.team)));
  }
  
  // code from here on is just to support maps that don't have team entities
@@@ -1069,12 -1033,12 +1030,12 @@@ void tdm_spawnteams(
                numteams = autocvar_g_tdm_teams;
        numteams = bound(2, numteams, 4);
  
-       tdm_spawnteam("Red", COLOR_TEAM1-1);
-       tdm_spawnteam("Blue", COLOR_TEAM2-1);
+       tdm_spawnteam("Red", NUM_TEAM_1-1);
+       tdm_spawnteam("Blue", NUM_TEAM_2-1);
        if(numteams >= 3)
-               tdm_spawnteam("Yellow", COLOR_TEAM3-1);
+               tdm_spawnteam("Yellow", NUM_TEAM_3-1);
        if(numteams >= 4)
-               tdm_spawnteam("Pink", COLOR_TEAM4-1);
+               tdm_spawnteam("Pink", NUM_TEAM_4-1);
  }
  
  void tdm_delayedinit()
index b241774acf7456b66003f5e09e81cc3e99a38c6b,c464af93a27c07e05ad5493efe0cfcd4b3cb60f8..bd39e9fb65abffd811d7792bea3c251dcef545ea
@@@ -43,25 -43,25 +43,25 @@@ void W_MinstaNex_Attack (void
        {
            switch(self.team)
            {
-             case COLOR_TEAM1:   // Red
+             case NUM_TEAM_1:   // Red
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED_HIT"), w_shotorg, v);
                  else
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3RED"), w_shotorg, v);
                  break;
-             case COLOR_TEAM2:   // Blue
+             case NUM_TEAM_2:   // Blue
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE_HIT"), w_shotorg, v);
                  else
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3BLUE"), w_shotorg, v);
                  break;
-             case COLOR_TEAM3:   // Yellow
+             case NUM_TEAM_3:   // Yellow
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW_HIT"), w_shotorg, v);
                  else
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3YELLOW"), w_shotorg, v);
                  break;
-             case COLOR_TEAM4:   // Pink
+             case NUM_TEAM_4:   // Pink
                  if(damage_goodhits)
                      WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3PINK_HIT"), w_shotorg, v);
                  else
@@@ -85,7 -85,7 +85,7 @@@ void minstagib_stop_countdown(entity e
  {
        if (!e.minstagib_needammo)
                return;
-       Send_CSQC_Centerprint_Generic_Expire(e, CPID_MINSTA_FINDAMMO);
+       Kill_Notification(NOTIF_ONE_ONLY, e, MSG_CENTER_CPID, CPID_MINSTA_FINDAMMO);
        e.minstagib_needammo = FALSE;
  }
  void minstagib_ammocheck(void)
@@@ -97,9 -97,8 +97,9 @@@
                minstagib_stop_countdown(self);
        else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO))
        {
 +              if (self.minstagib_needammo)
 +                      self.health = 100;
                minstagib_stop_countdown(self);
 -              self.health = 100;
        }
        else
        {
                }
                else if (self.health == 90)
                {
-                       Send_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "^1%d^7 seconds left to find some ammo", 1, 9);
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MINSTA_FINDAMMO);
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "9");
                }
                else if (self.health == 100)
                {
-                       Send_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "get some ammo or\nyou'll be dead in ^3%d^7 seconds...", 1, 10);
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MINSTA_FINDAMMO_FIRST);
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        if not(self.flags & FL_GODMODE)
                                AnnounceTo(self, "10");
@@@ -272,6 -271,14 +272,14 @@@ float w_minstanex(float req
  
                W_Reload(used_ammo, autocvar_g_balance_minstanex_reload_ammo, autocvar_g_balance_minstanex_reload_time, "weapons/reload.wav");
        }
+       else if (req == WR_SUICIDEMESSAGE)
+       {
+               return WEAPON_THINKING_WITH_PORTALS;
+       }
+       else if (req == WR_KILLMESSAGE)
+       {
+               return WEAPON_MINSTANEX_MURDER;
+       }
        return TRUE;
  }
  #endif
@@@ -290,10 -297,6 +298,6 @@@ float w_minstanex(float req
        {
                precache_sound("weapons/neximpact.wav");
        }
-       else if (req == WR_SUICIDEMESSAGE)
-               w_deathtypestring = _("%s is now thinking with portals");
-       else if (req == WR_KILLMESSAGE)
-               w_deathtypestring = _("%s has been vaporized by %s's minstanex");
        return TRUE;
  }
  #endif