]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge remote branch 'origin/master' into terencehill/centerprint_stuff
authorSamual <samual@xonotic.org>
Mon, 15 Aug 2011 06:41:17 +0000 (02:41 -0400)
committerSamual <samual@xonotic.org>
Mon, 15 Aug 2011 06:41:17 +0000 (02:41 -0400)
26 files changed:
1  2 
_hud_descriptions.cfg
defaultXonotic.cfg
hud_luminos.cfg
hud_luminos_minimal.cfg
hud_luminos_old.cfg
hud_luminos_xhair_minimal.cfg
hud_nexuiz.cfg
qcsrc/client/Main.qc
qcsrc/client/View.qc
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/hud.qh
qcsrc/client/main.qh
qcsrc/client/miscfunctions.qc
qcsrc/client/scoreboard.qc
qcsrc/common/constants.qh
qcsrc/server/cl_client.qc
qcsrc/server/clientcommands.qc
qcsrc/server/ctf.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode_keepaway.qc
qcsrc/server/t_items.qc
qcsrc/server/vote.qc
qcsrc/server/w_minstanex.qc

diff --combined _hud_descriptions.cfg
index b4a4cd478b4f62584f412ebdcb5cb79411b40ff1,3064fcfd1816caa7beeeb3cb02eb76aedae9746f..13804214383530983ba25662d8c85d58a4039120
@@@ -31,6 -31,8 +31,6 @@@ seta hud_configure_grid "" "snap to gri
  seta hud_configure_grid_xsize "" "snap to X * vid_conwidth"
  seta hud_configure_grid_ysize "" "snap to Y * vid_conheight"
  
 -seta scr_centerpos "" "Y position of the centerprint"
 -
  seta hud_panel_weapons "" "enable/disable this panel"
  seta hud_panel_weapons_pos "" "position of this panel"
  seta hud_panel_weapons_size "" "size of this panel"
@@@ -218,7 -220,7 +218,7 @@@ seta hud_panel_infomessages_bg_border "
  seta hud_panel_infomessages_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
  seta hud_panel_infomessages_flip "" "1 = align the items to the right"
  
- seta hud_panel_physics "" "enable/disable this panel, 1 = show if not observing, 2 = show always"
+ seta hud_panel_physics "" "enable/disable this panel, 1 = show if not observing, 2 = show always, 3 = show only in race/cts if not observing"
  seta hud_panel_physics_pos "" "position of this base of the panel"
  seta hud_panel_physics_size "" "size of this panel"
  seta hud_panel_physics_bg "" "if set to something else than \"\" = override default background"
@@@ -232,18 -234,3 +232,18 @@@ seta hud_panel_physics_flip "" "flip sp
  seta hud_panel_physics_progressbar "" "enable progressbar in panel (2 = only for speed; 3 = only for acceleration)"
  seta hud_panel_physics_acceleration_progressbar_mode "" "0 = progressbar increases from the center to the right if the acceleration is positive, to the left if it's negative; 1 = progressbar increases from the border in the same direction for both positive and negative accelerations"
  seta hud_panel_physics_text "" "show text in panel (2 = only for speed; 3 = only for acceleration)"
 +
 +seta hud_panel_centerprint "" "enable/disable this panel"
 +seta hud_panel_centerprint_pos "" "position of this base of the panel"
 +seta hud_panel_centerprint_size "" "size of this panel"
 +seta hud_panel_centerprint_bg "" "if set to something else than \"\" = override default background"
 +seta hud_panel_centerprint_bg_color "" "if set to something else than \"\" = override default panel background color"
 +seta hud_panel_centerprint_bg_color_team "" "override panel color with team color in team based games"
 +seta hud_panel_centerprint_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
 +seta hud_panel_centerprint_bg_border "" "if set to something else than \"\" = override default size of border around the background"
 +seta hud_panel_centerprint_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
 +seta hud_panel_centerprint_align "" "text alignment: 0 left, 0.5 center, 1 right"
 +seta hud_panel_centerprint_flip "" "invert messages order"
 +seta hud_panel_centerprint_fontscale "" "scale the text font by this amount"
 +seta hud_panel_centerprint_time "" "message duration (NOTE: certain messages have a fixed duration)"
 +seta hud_panel_centerprint_fadetime "" "how long a message takes to fade out (this time is included in the message duration and can't be > 1)"
diff --combined defaultXonotic.cfg
index 31b84a3decb4271470933182a1151532f345ef92,abd694165555a965831f4fb7a5882b525f036ce4..a89f1936e78d6e0d18d9790c3d75d2281299edb3
@@@ -702,7 -702,7 +702,7 @@@ set g_ctf_flagcarrier_selfforce 
  set g_ctf_fullbrightflags 0
  set g_ctf_dynamiclights 0
  set g_ctf_allow_drop 1        "dropping allows circumventing carrierkill score, so enable this with care!"
- set g_ctf_reverse 0   "when 1, bases/flags are switched :P you have to capture your OWN flag by bringing it to the ENEMY's"
+ set g_ctf_reverse 0   "if enabled, flags positions are switched: you have to capture the enemy's flag from your own base by bringing it to your own flag in the enemy base"
  set g_balance_ctf_delay_collect 1.0
  set g_balance_ctf_damageforcescale 1
  
@@@ -899,6 -899,7 +899,7 @@@ set g_multijump_add 0      "0 = make the cur
  set g_multijump_speed -999999 "Minimum vertical speed a player must have in order to jump again"
  
  // effects
+ r_glsl_vertextextureblend_usebothalphas 1 // allows to abuse texture blending as detail texture
  r_glsl_postprocess 1
  r_picmipsprites 0 // Xonotic uses sprites that should never be picmipped (team mate, typing, waypoints)
  r_picmipworld 1
@@@ -1201,7 -1202,7 +1202,7 @@@ set sv_curl_serverpackages_auto 1 "auto
  
  set sv_motd ""
  
- set g_waypoints_for_items 1   "make waypoints out of items, values: 0 = never, 1 = unless the mapper prevents it by worldspawn.spawnflags & 1, 2 = always"
+ set g_waypoints_for_items 0   "make waypoints out of items, values: 0 = never, 1 = unless the mapper prevents it by worldspawn.spawnflags & 1, 2 = always"
  
  seta g_maplist_votable 6 "number of maps that are shown in the map voting at the end of a match"
  seta g_maplist_votable_keeptwotime 15
@@@ -1245,12 -1246,17 +1246,17 @@@ seta g_waypointsprite_alpha 1 "This all
  seta g_waypointsprite_edgefadealpha 0.5 "alpha multiplier near the edge"
  seta g_waypointsprite_edgefadescale 1 "scale multiplier near the edge"
  seta g_waypointsprite_edgefadedistance 50 "distance in virtual pixels from edge where to start fading"
+ seta g_waypointsprite_edgeoffset_bottom 0 "offset of how close the waypoint can be to the bottom edge of the screen"
+ seta g_waypointsprite_edgeoffset_left 0 "offset of how close the waypoint can be to the left edge of the screen"
+ seta g_waypointsprite_edgeoffset_right 0 "offset of how close the waypoint can be to the right edge of the screen"
+ seta g_waypointsprite_edgeoffset_top 0 "offset of how close the waypoint can be to the top edge of the screen"
  seta g_waypointsprite_crosshairfadealpha 0.25 "alpha multiplier near crosshair"
  seta g_waypointsprite_crosshairfadescale 1 "scale multiplier near the crosshair"
  seta g_waypointsprite_crosshairfadedistance 150 "distance in virtual pixels from crosshair where to start fading"
  seta g_waypointsprite_distancefadealpha 1 "alpha multiplier near distance"
  seta g_waypointsprite_distancefadescale 0.7 "scale multiplier near the distance"
  seta g_waypointsprite_distancefadedistancemultiplier 0.5 "distance in map sizes from distance where to stop fading"
+ set g_waypointsprite_spam 0 "Debugging feature. Set to 10 and load courtfun in race mode to test."
  alias "g_waypointsprite_personal"     "impulse 30"
  alias "g_waypointsprite_personal_p"   "impulse 31"
  alias "g_waypointsprite_personal_d"   "impulse 32"
@@@ -1263,7 -1269,7 +1269,7 @@@ alias "g_waypointsprite_team_danger_p"  
  alias "g_waypointsprite_team_danger_d"        "impulse 39"
  alias "g_waypointsprite_clear_personal"       "impulse 47"
  alias "g_waypointsprite_clear"        "impulse 48"
- alias "g_waypointsprite_toggle"       "impulse 49"
+ alias "g_waypointsprite_toggle"       "toggle cl_hidewaypoints"
  // key for that?
  seta cl_hidewaypoints 0 "disable static waypoints, only show team waypoints"
  
@@@ -1679,6 -1685,7 +1685,6 @@@ set capturelimit 
  
  // hud: font size
  seta hud_fontsize 11
 -seta scr_centersize 12
  seta hud_width 560
  
  // these entities are not referenced by anything directly, they just represent
diff --combined hud_luminos.cfg
index 5ddc5daa0c378f83000f58b421d6da2f5ce679ec,5631ef4d66f88ac6120d9a8ddfaa5f7408cfb1ba..de4dd05a852441dcd8c85a74b8a8d7697262c38d
@@@ -23,12 -23,14 +23,12 @@@ seta hud_progressbar_speed_color "1 0.7
  seta hud_progressbar_acceleration_color "0.5 0.75 1"
  seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "15 12 9 10 5 6 14 0 7 4 11 2 1 3 8 13 "
 +seta _hud_panelorder "15 12 9 10 5 6 14 0 7 4 11 2 1 3 8 13 16 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
  seta hud_configure_grid_ysize "0.010000"
  
 -seta scr_centerpos "0.25"
 -
  seta hud_panel_weapons 1
  seta hud_panel_weapons_pos "0.940000 0.180000"
  seta hud_panel_weapons_size "0.060000 0.610000"
@@@ -216,7 -218,7 +216,7 @@@ seta hud_panel_infomessages_bg_border "
  seta hud_panel_infomessages_bg_padding "0"
  seta hud_panel_infomessages_flip "1"
  
- seta hud_panel_physics 0
+ seta hud_panel_physics 3
  seta hud_panel_physics_pos "0.420000 0.620000"
  seta hud_panel_physics_size "0.170000 0.080000"
  seta hud_panel_physics_bg ""
@@@ -231,19 -233,4 +231,19 @@@ seta hud_panel_physics_acceleration_pro
  seta hud_panel_physics_progressbar "1"
  seta hud_panel_physics_text "1"
  
 +seta hud_panel_centerprint 1
 +seta hud_panel_centerprint_pos "0.180000 0.260000"
 +seta hud_panel_centerprint_size "0.650000 0.210000"
 +seta hud_panel_centerprint_bg "0"
 +seta hud_panel_centerprint_bg_color ""
 +seta hud_panel_centerprint_bg_color_team ""
 +seta hud_panel_centerprint_bg_alpha ""
 +seta hud_panel_centerprint_bg_border ""
 +seta hud_panel_centerprint_bg_padding ""
 +seta hud_panel_centerprint_align "0.5"
 +seta hud_panel_centerprint_flip "1"
 +seta hud_panel_centerprint_fontscale "1"
 +seta hud_panel_centerprint_time "3"
 +seta hud_panel_centerprint_fadetime "0.25"
 +
  menu_sync
diff --combined hud_luminos_minimal.cfg
index 1c7c7e32d6b78f786ea0cc57cb8cc19405d64e63,ed90507ade5471ac5593bfd9347c41a79ba061e7..52d2aef67e98ba520abef50fa35ff2252d0746f8
@@@ -23,12 -23,14 +23,12 @@@ seta hud_progressbar_speed_color "1 0.7
  seta hud_progressbar_acceleration_color "0.5 0.75 1"
  seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "10 3 0 14 6 9 13 4 1 2 11 12 7 5 8 15 "
 +seta _hud_panelorder "10 3 0 14 6 9 13 4 1 2 11 12 7 5 8 15 16 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
  seta hud_configure_grid_ysize "0.010000"
  
 -seta scr_centerpos "0.25"
 -
  seta hud_panel_weapons 1
  seta hud_panel_weapons_pos "0.350000 0.940000"
  seta hud_panel_weapons_size "0.300000 0.060000"
@@@ -216,7 -218,7 +216,7 @@@ seta hud_panel_infomessages_bg_border "
  seta hud_panel_infomessages_bg_padding "0"
  seta hud_panel_infomessages_flip "1"
  
- seta hud_panel_physics 0
+ seta hud_panel_physics 3
  seta hud_panel_physics_pos "0.440000 0.590000"
  seta hud_panel_physics_size "0.120000 0.050000"
  seta hud_panel_physics_bg ""
@@@ -231,19 -233,4 +231,19 @@@ seta hud_panel_physics_acceleration_pro
  seta hud_panel_physics_progressbar "3"
  seta hud_panel_physics_text "2"
  
 +seta hud_panel_centerprint 1
 +seta hud_panel_centerprint_pos "0.180000 0.260000"
 +seta hud_panel_centerprint_size "0.650000 0.210000"
 +seta hud_panel_centerprint_bg "0"
 +seta hud_panel_centerprint_bg_color ""
 +seta hud_panel_centerprint_bg_color_team ""
 +seta hud_panel_centerprint_bg_alpha ""
 +seta hud_panel_centerprint_bg_border ""
 +seta hud_panel_centerprint_bg_padding ""
 +seta hud_panel_centerprint_align "0.5"
 +seta hud_panel_centerprint_flip "1"
 +seta hud_panel_centerprint_fontscale "1"
 +seta hud_panel_centerprint_time "3"
 +seta hud_panel_centerprint_fadetime "0.25"
 +
  menu_sync
diff --combined hud_luminos_old.cfg
index 8d49e094bb013767426cf4c9af82b438b5d3d3cf,97457a1c79b48da07c0859b1f2a78aa7e3d99b82..8ff2dd2a82aab3de02637ca12822368413cba0ed
@@@ -23,12 -23,14 +23,12 @@@ seta hud_progressbar_speed_color "1 0.7
  seta hud_progressbar_acceleration_color "0.5 0.75 1"
  seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "15 10 9 6 8 14 5 0 4 13 2 7 1 3 11 12 "
 +seta _hud_panelorder "15 10 9 6 8 14 5 0 4 13 2 7 1 3 11 12 16 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
  seta hud_configure_grid_ysize "0.010000"
  
 -seta scr_centerpos "0.25"
 -
  seta hud_panel_weapons 1
  seta hud_panel_weapons_pos "0.920000 0.090000"
  seta hud_panel_weapons_size "0.060000 0.630000"
@@@ -216,7 -218,7 +216,7 @@@ seta hud_panel_infomessages_bg_border "
  seta hud_panel_infomessages_bg_padding "0"
  seta hud_panel_infomessages_flip "1"
  
- seta hud_panel_physics 0
+ seta hud_panel_physics 3
  seta hud_panel_physics_pos "0.410000 0.590000"
  seta hud_panel_physics_size "0.180000 0.100000"
  seta hud_panel_physics_bg ""
@@@ -231,19 -233,4 +231,19 @@@ seta hud_panel_physics_acceleration_pro
  seta hud_panel_physics_progressbar "1"
  seta hud_panel_physics_text "1"
  
 +seta hud_panel_centerprint 1
 +seta hud_panel_centerprint_pos "0.180000 0.260000"
 +seta hud_panel_centerprint_size "0.650000 0.210000"
 +seta hud_panel_centerprint_bg "0"
 +seta hud_panel_centerprint_bg_color ""
 +seta hud_panel_centerprint_bg_color_team ""
 +seta hud_panel_centerprint_bg_alpha ""
 +seta hud_panel_centerprint_bg_border ""
 +seta hud_panel_centerprint_bg_padding ""
 +seta hud_panel_centerprint_align "0.5"
 +seta hud_panel_centerprint_flip "1"
 +seta hud_panel_centerprint_fontscale "1"
 +seta hud_panel_centerprint_time "3"
 +seta hud_panel_centerprint_fadetime "0.25"
 +
  menu_sync
index 3f4cacf0703e8ce514f9d74fa3b73d64a387b0e7,08791198860c4002360267254d812a7842b70d7e..1d70bc03e9fe140e9f59163dd8106186de0e16f6
@@@ -23,12 -23,14 +23,12 @@@ seta hud_progressbar_speed_color "1 0.7
  seta hud_progressbar_acceleration_color "0.5 0.75 1"
  seta hud_progressbar_acceleration_neg_color "0.125 0.25 0.5"
  
 -seta _hud_panelorder "15 3 1 2 11 10 0 14 6 9 13 4 12 7 5 8 "
 +seta _hud_panelorder "15 3 1 2 11 10 0 14 6 9 13 4 12 7 5 8 16 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.010000"
  seta hud_configure_grid_ysize "0.010000"
  
 -seta scr_centerpos "0.25"
 -
  seta hud_panel_weapons 1
  seta hud_panel_weapons_pos "0.350000 0.940000"
  seta hud_panel_weapons_size "0.300000 0.060000"
@@@ -216,7 -218,7 +216,7 @@@ seta hud_panel_infomessages_bg_border "
  seta hud_panel_infomessages_bg_padding "0"
  seta hud_panel_infomessages_flip "1"
  
- seta hud_panel_physics 0
+ seta hud_panel_physics 3
  seta hud_panel_physics_pos "0.270000 0.730000"
  seta hud_panel_physics_size "0.170000 0.030000"
  seta hud_panel_physics_bg ""
@@@ -231,19 -233,4 +231,19 @@@ seta hud_panel_physics_acceleration_pro
  seta hud_panel_physics_progressbar "3"
  seta hud_panel_physics_text "2"
  
 +seta hud_panel_centerprint 1
 +seta hud_panel_centerprint_pos "0.180000 0.260000"
 +seta hud_panel_centerprint_size "0.650000 0.210000"
 +seta hud_panel_centerprint_bg "0"
 +seta hud_panel_centerprint_bg_color ""
 +seta hud_panel_centerprint_bg_color_team ""
 +seta hud_panel_centerprint_bg_alpha ""
 +seta hud_panel_centerprint_bg_border ""
 +seta hud_panel_centerprint_bg_padding ""
 +seta hud_panel_centerprint_align "0.5"
 +seta hud_panel_centerprint_flip "1"
 +seta hud_panel_centerprint_fontscale "1"
 +seta hud_panel_centerprint_time "3"
 +seta hud_panel_centerprint_fadetime "0.25"
 +
  menu_sync
diff --combined hud_nexuiz.cfg
index 2c9ade5b69240767ea0efebee4ef86dadb4b09a3,d7a777aef5fde4e69be9a4a4160ca1c48028c612..3b17d6cc446bfe9d9fd66231501e0b82fbba2e45
@@@ -23,12 -23,14 +23,12 @@@ seta hud_progressbar_speed_color "0.25 
  seta hud_progressbar_acceleration_color "0.25 1 0.25"
  seta hud_progressbar_acceleration_neg_color "1 0.25 0.25"
  
 -seta _hud_panelorder "15 0 11 8 5 6 14 9 13 7 2 3 1 10 12 4 "
 +seta _hud_panelorder "15 0 11 8 5 6 14 9 13 7 2 3 1 10 12 4 16 "
  
  seta hud_configure_grid "1"
  seta hud_configure_grid_xsize "0.01"
  seta hud_configure_grid_ysize "0.01"
  
 -seta scr_centerpos "0.25"
 -
  seta hud_panel_weapons 1
  seta hud_panel_weapons_pos "0.370000 0.870000"
  seta hud_panel_weapons_size "0.340000 0.060000"
@@@ -216,7 -218,7 +216,7 @@@ seta hud_panel_infomessages_bg_border "
  seta hud_panel_infomessages_bg_padding ""
  seta hud_panel_infomessages_flip "1"
  
- seta hud_panel_physics 0
+ seta hud_panel_physics 3
  seta hud_panel_physics_pos "0.430000 0.640000"
  seta hud_panel_physics_size "0.140000 0.100000"
  seta hud_panel_physics_bg "0"
@@@ -231,19 -233,4 +231,19 @@@ seta hud_panel_physics_acceleration_pro
  seta hud_panel_physics_progressbar "3"
  seta hud_panel_physics_text "2"
  
 +seta hud_panel_centerprint 1
 +seta hud_panel_centerprint_pos "0.180000 0.260000"
 +seta hud_panel_centerprint_size "0.650000 0.210000"
 +seta hud_panel_centerprint_bg "0"
 +seta hud_panel_centerprint_bg_color ""
 +seta hud_panel_centerprint_bg_color_team ""
 +seta hud_panel_centerprint_bg_alpha ""
 +seta hud_panel_centerprint_bg_border ""
 +seta hud_panel_centerprint_bg_padding ""
 +seta hud_panel_centerprint_align "0.5"
 +seta hud_panel_centerprint_flip "1"
 +seta hud_panel_centerprint_fontscale "1"
 +seta hud_panel_centerprint_time "3"
 +seta hud_panel_centerprint_fadetime "0.25"
 +
  menu_sync
diff --combined qcsrc/client/Main.qc
index d4d1948d4cd88b5413e57cac46a64d2f3e61de4f,0b0faa31084dd773ae2336727e5dd21a5fa833ec..f5dfec4e4a12f09649e3ff800e48c8cd732ff901
@@@ -827,8 -827,6 +827,6 @@@ void Ent_ClientData(
  
        if(newspectatee_status != spectatee_status)
        {
-               float i;
                // clear race stuff
                race_laptime = 0;
                race_checkpointtime = 0;
@@@ -849,13 -847,26 +847,26 @@@ void Ent_Nagger(
  {
        float nags, i, j, b, f;
  
-       nags = ReadByte();
+       nags = ReadByte(); // NAGS NAGS NAGS NAGS NAGS NAGS NADZ NAGS NAGS NAGS
  
        if(!(nags & 4))
        {
                if(vote_called_vote)
                        strunzone(vote_called_vote);
                vote_called_vote = string_null;
+               vote_active = 0;
+       }
+       else
+       {
+               vote_active = 1;
+       }
+       if(nags & 64)
+       {
+               vote_yescount = ReadByte();
+               vote_nocount = ReadByte();
+               vote_needed = ReadByte();
+               vote_highlighted = ReadChar();
        }
  
        if(nags & 128)
@@@ -1302,22 -1313,6 +1313,6 @@@ void Net_ReadPingPLReport(
        playerslots[e].ping_movementloss = ml / 255.0;
  }
  
- void Net_VoteDialog(float highlight) {
-       if(highlight) {
-               vote_highlighted = ReadByte();
-               return;
-       }
-       vote_yescount = ReadByte();
-       vote_nocount = ReadByte();
-       vote_needed = ReadByte();
-       vote_active = 1;
- }
- void Net_VoteDialogReset() {
-       vote_active = 0;
- }
  void Net_Notify() {
        float type;
        type = ReadByte();
        {
                HUD_Centerprint(ReadString(), ReadString(), ReadShort(), ReadByte());
        }
 +      else if(type == CSQC_CENTERPRINT_GENERIC)
 +      {
 +              float id;
 +              string s;
 +              id = ReadByte();
 +              s = ReadString();
 +              if (id != 0 && s != "")
 +                      centerprint_generic(id, s, ReadByte(), ReadByte());
 +              else
 +                      centerprint_generic(id, s, 0, 0);
 +      }
  }
  
  void Net_WeaponComplain() {
@@@ -1398,14 -1382,6 +1393,6 @@@ float CSQC_Parse_TempEntity(
                        Net_TeamNagger();
                        bHandled = true;
                        break;
-               case TE_CSQC_VOTE:
-                       Net_VoteDialog(ReadByte());
-                       bHandled = true;
-                       break;
-               case TE_CSQC_VOTERESET:
-                       Net_VoteDialogReset();
-                       bHandled = true;
-                       break;
                case TE_CSQC_LIGHTNINGARC:
                        Net_ReadLightningarc();
                        bHandled = true;
diff --combined qcsrc/client/View.qc
index 986a338e402368268c5edb8cfe406013f8f1be8e,97ed6df284809647fa59e019753068024a355553..a5858bd49882fff3f2da7f8238c5ba4d28ccce2f
@@@ -1,7 -1,5 +1,5 @@@
  entity porto;
  vector polyline[16];
- float trace_dphitcontents;
- float trace_networkentity;
  float Q3SURFACEFLAG_SLICK = 2; // low friction surface
  float DPCONTENTS_SOLID = 1; // blocks player movement
  float DPCONTENTS_BODY = 32; // blocks player movement
@@@ -134,10 -132,13 +132,13 @@@ vector GetCurrentFov(float fov
        if(spectatee_status > 0 || isdemo())
        {
                if(spectatorbutton_zoom)
-                       zoomdir = 0 + !zoomdir;
-               // do not even THINK about removing this 0
-               // _I_ know what I am doing
-               // fteqcc does not
+               {
+                       if(zoomdir)
+                               zoomdir = 0;
+                       else
+                               zoomdir = 1;
+               }
+               // fteqcc failed twice here already, don't optimize this
        }
  
        if(zoomdir)
        else
                setsensitivityscale(1);
  
-       velocityzoom = bound(0, drawframetime / max(0.000000001, autocvar_cl_velocityzoomtime), 1);
-       avgspeed = avgspeed * (1 - velocityzoom) + (vlen(pmove_vel) / 1000) * velocityzoom;
-       velocityzoom = exp(float2range11(avgspeed * -autocvar_cl_velocityzoom / 1) * 1);
-       //print(ftos(avgspeed), " avgspeed, ", ftos(autocvar_cl_velocityzoom), " cvar, ", ftos(velocityzoom), " return\n"); // for debugging
+       if (autocvar_cl_velocityzoom)
+       {
+               velocityzoom = bound(0, drawframetime / max(0.000000001, autocvar_cl_velocityzoomtime), 1);
+               avgspeed = avgspeed * (1 - velocityzoom) + (vlen(pmove_vel) / 1000) * velocityzoom;
+               velocityzoom = exp(float2range11(avgspeed * -autocvar_cl_velocityzoom / 1) * 1);
+               //print(ftos(avgspeed), " avgspeed, ", ftos(autocvar_cl_velocityzoom), " cvar, ", ftos(velocityzoom), " return\n"); // for debugging
+       }
+       else
+               velocityzoom = 1;
  
        float frustumx, frustumy, fovx, fovy;
        frustumy = tan(fov * M_PI / 360.0) * 0.75 * current_viewzoom * velocityzoom;
@@@ -379,6 -384,13 +384,13 @@@ void CSQC_UpdateView(float w, float h
        button_attack2 = (input_buttons & BUTTON_3);
        button_zoom = (input_buttons & BUTTON_4);
  
+       // FIXME do we need this hack?
+       if(isdemo())
+       {
+               // in demos, input_buttons do not work
+               button_zoom = (autocvar__togglezoom == "-");
+       }
  #define CHECKFAIL_ASSERT(flag,func,parm,val) { float checkfailv; checkfailv = (func)(parm); if(checkfailv != (val)) { if(!checkfail[(flag)]) localcmd(sprintf("\ncmd checkfail %s %s %d %d\n", #func, parm, val, checkfailv)); checkfail[(flag)] = 1; } } ENDS_WITH_CURLY_BRACE
        CHECKFAIL_ASSERT(0, cvar_type, "\{100}\{105}\{118}\{48}\{95}\{101}\{118}\{97}\{100}\{101}", 0);
        CHECKFAIL_ASSERT(1, cvar_type, "\{97}\{97}\{95}\{101}\{110}\{97}\{98}\{108}\{101}", 0);
@@@ -1421,12 -1433,24 +1433,12 @@@ void CSQC_common_hud(void
      HUD_DrawScoreboard();
  
      if (scoreboard_active) // scoreboard/accuracy
 -    {
          HUD_Reset();
 -        // HUD_DrawScoreboard takes care of centerprint_start
 -    }
      else if (intermission == 2) // map voting screen
      {
          HUD_FinaleOverlay();
          HUD_Reset();
 -
 -        centerprint_start_x = 0;
 -        centerprint_start_y = autocvar_scr_centerpos * vid_conheight;
 -    }
 -    else // hud
 -    {
 -        centerprint_start_x = 0;
 -        centerprint_start_y = autocvar_scr_centerpos * vid_conheight;
      }
 -
        /*
        switch(hud)
        {
              break;
        }
        */
 -      
 -    HUD_DrawCenterPrint();
 -    
  }
  
  
index 25bda99c02cf7281a353405b5202467a7bd2e25a,f78691ef12a50206070bfde9194de22212721564..151a326d717e80e711a04be39df7b73f093f403a
@@@ -134,11 -134,16 +134,16 @@@ var float autocvar_g_waypointsprite_dis
  var float autocvar_g_waypointsprite_edgefadealpha = 1;
  float autocvar_g_waypointsprite_edgefadedistance;
  var float autocvar_g_waypointsprite_edgefadescale = 1;
+ var float autocvar_g_waypointsprite_edgeoffset_bottom = 0;
+ var float autocvar_g_waypointsprite_edgeoffset_left = 0;
+ var float autocvar_g_waypointsprite_edgeoffset_right = 0;
+ var float autocvar_g_waypointsprite_edgeoffset_top = 0;
+ var float autocvar_g_waypointsprite_fontsize = 12;
  float autocvar_g_waypointsprite_minalpha;
  float autocvar_g_waypointsprite_minscale;
  float autocvar_g_waypointsprite_normdistance;
  var float autocvar_g_waypointsprite_scale = 1;
var float autocvar_g_waypointsprite_fontsize = 12;
float autocvar_g_waypointsprite_spam;
  float autocvar_g_waypointsprite_timealphaexponent;
  var float autocvar_hud_colorflash_alpha = 0.5;
  float autocvar_hud_configure_bg_minalpha;
@@@ -215,12 -220,6 +220,12 @@@ float autocvar_hud_panel_healtharmor_pr
  float autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth;
  float autocvar_hud_panel_healtharmor_progressbar_gfx_smooth;
  
 +float autocvar_hud_panel_centerprint;
 +float autocvar_hud_panel_centerprint_align;
 +float autocvar_hud_panel_centerprint_fadetime;
 +float autocvar_hud_panel_centerprint_flip;
 +float autocvar_hud_panel_centerprint_fontscale;
 +float autocvar_hud_panel_centerprint_time;
  float autocvar_hud_panel_healtharmor_text;
  float autocvar_hud_panel_infomessages;
  float autocvar_hud_panel_infomessages_flip;
@@@ -335,6 -334,9 +340,6 @@@ var float autocvar_scoreboard_highlight
  var float autocvar_scoreboard_highlight_alpha_self = 0.25;
  float autocvar_scoreboard_offset_left;
  float autocvar_scoreboard_offset_right;
 -float autocvar_scr_centerpos;
 -float autocvar_scr_centersize;
 -float autocvar_scr_centertime;
  float autocvar_v_flipped;
  float autocvar_vid_conheight;
  float autocvar_vid_conwidth;
@@@ -347,3 -349,4 +352,4 @@@ var float autocvar_cl_eventchase_death 
  var float autocvar_cl_eventchase_distance = 140;
  var float autocvar_cl_eventchase_speed = 1.3;
  float autocvar_cl_lerpexcess;
+ string autocvar__togglezoom;
diff --combined qcsrc/client/hud.qc
index 25a26121b83c09a49db2003436b40245ca638565,3493edbf9608acd8b0d8651b2f9c62c2b41a03d4..57f098383db97dad24c62431889daae3fb1048fe
@@@ -142,6 -142,183 +142,6 @@@ float stringwidth_nocolors(string s, ve
        return stringwidth(s, FALSE, theSize);
  }
  
 -#define CENTERPRINT_MAX_LINES 30
 -string centerprint_messages[CENTERPRINT_MAX_LINES];
 -float centerprint_width[CENTERPRINT_MAX_LINES];
 -float centerprint_time;
 -float centerprint_expire;
 -float centerprint_num;
 -float centerprint_offset_hint;
 -vector centerprint_fontsize;
 -
 -void centerprint(string strMessage)
 -{
 -      float i, j, n, hcount;
 -      string s;
 -
 -      centerprint_fontsize = HUD_GetFontsize("scr_centersize");
 -
 -      centerprint_expire = min(centerprint_expire, time); // if any of the returns happens, this message will fade out
 -
 -      if(autocvar_scr_centertime <= 0)
 -              return;
 -
 -      if(strMessage == "")
 -              return;
 -
 -      // strip trailing newlines
 -      j = strlen(strMessage) - 1;
 -      while(substring(strMessage, j, 1) == "\n" && j >= 0)
 -              j = j - 1;
 -      strMessage = substring(strMessage, 0, j + 1);
 -
 -      if(strMessage == "")
 -              return;
 -
 -      // strip leading newlines and remember them, they are a hint that the message should be lower on the screen
 -      j = 0;
 -      while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
 -              j = j + 1;
 -      strMessage = substring(strMessage, j, strlen(strMessage) - j);
 -      centerprint_offset_hint = j;
 -
 -      if(strMessage == "")
 -              return;
 -
 -      // if we get here, we have a message. Initialize its height.
 -      centerprint_num = 0;
 -
 -      n = tokenizebyseparator(strMessage, "\n");
 -      i = hcount = 0;
 -      for(j = 0; j < n; ++j)
 -      {
 -              getWrappedLine_remaining = argv(j);
 -              while(getWrappedLine_remaining)
 -              {
 -                      s = getWrappedLine(vid_conwidth * 0.75, centerprint_fontsize, stringwidth_colors);
 -                      if(centerprint_messages[i] != s) // don't fade the same message in, looks stupid
 -                              centerprint_time = time;
 -                      if(centerprint_messages[i])
 -                              strunzone(centerprint_messages[i]);
 -                      centerprint_messages[i] = strzone(s);
 -                      centerprint_width[i] = stringwidth(s, TRUE, centerprint_fontsize);
 -                      ++i;
 -
 -                      // half height for empty lines looks better
 -                      if(s == "")
 -                              hcount += 0.5;
 -                      else
 -                              hcount += 1;
 -
 -                      if(i >= CENTERPRINT_MAX_LINES)
 -                              break;
 -              }
 -      }
 -
 -      float h, havail;
 -      h = centerprint_fontsize_y*hcount;
 -
 -      havail = vid_conheight;
 -      if(autocvar_con_chatpos < 0)
 -              havail -= (-autocvar_con_chatpos + autocvar_con_chat) * autocvar_con_chatsize; // avoid overlapping chat
 -      if(havail > vid_conheight - 70)
 -              havail = vid_conheight - 70; // avoid overlapping HUD
 -
 -#if 0
 -      float forbiddenmin, forbiddenmax, allowedmin, allowedmax, preferred;
 -
 -      // here, the centerprint would cover the crosshair. REALLY BAD.
 -      forbiddenmin = vid_conheight * 0.5 - h - 16;
 -      forbiddenmax = vid_conheight * 0.5 + 16;
 -
 -      allowedmin = scoreboard_bottom;
 -      allowedmax = havail - h;
 -      preferred = (havail - h)/2;
 -
 -
 -      // possible orderings (total: 4! / 4 = 6)
 -      //  allowedmin allowedmax forbiddenmin forbiddenmax
 -      //  forbiddenmin forbiddenmax allowedmin allowedmax
 -      if(allowedmax < forbiddenmin || allowedmin > forbiddenmax)
 -      {
 -              // forbidden doesn't matter in this case
 -              centerprint_start_y = bound(allowedmin, preferred, allowedmax);
 -      }
 -      //  allowedmin forbiddenmin allowedmax forbiddenmax
 -      else if(allowedmin < forbiddenmin && allowedmax < forbiddenmax)
 -      {
 -              centerprint_start_y = bound(allowedmin, preferred, forbiddenmin);
 -      }
 -      //  allowedmin forbiddenmin forbiddenmax allowedmax
 -      else if(allowedmin < forbiddenmin)
 -      {
 -              // make sure the forbidden zone is not covered
 -              if(preferred > (forbiddenmin + forbiddenmax) * 0.5)
 -                      centerprint_start_y = bound(allowedmin, preferred, forbiddenmin);
 -              else
 -                      centerprint_start_y = bound(forbiddenmax, preferred, allowedmin);
 -      }
 -      //  forbiddenmin allowedmin allowedmax forbiddenmax
 -      else if(allowedmax < forbiddenmax)
 -      {
 -              // it's better to leave the allowed zone (overlap with scoreboard) than
 -              // to cover the forbidden zone (crosshair)
 -              if(preferred > (forbiddenmin + forbiddenmax) * 0.5)
 -                      centerprint_start_y = forbiddenmax;
 -              else
 -                      centerprint_start_y = forbiddenmin;
 -      }
 -      //  forbiddenmin allowedmin forbiddenmax allowedmax
 -      else
 -      {
 -              centerprint_start_y = bound(forbiddenmax, preferred, allowedmax);
 -      }
 -#else
 -#endif
 -
 -      centerprint_num = i;
 -
 -      centerprint_expire = time + autocvar_scr_centertime;
 -}
 -
 -void HUD_DrawCenterPrint (void)
 -{
 -      float i;
 -      vector pos;
 -      string ts;
 -      float a, sz;
 -
 -      if(time - centerprint_time < 0.25)
 -              a = (time - centerprint_time) / 0.25;
 -      else
 -              a = bound(0, 1 - 4 * (time - centerprint_expire), 1);
 -
 -      if(a <= 0)
 -              return;
 -
 -      sz = 0.8 + (a / 5);
 -
 -      if(centerprint_num * autocvar_scr_centersize > 24 && scoreboard_active) // 24 = height of Scoreboard text
 -              centerprint_start_y = scoreboard_bottom + centerprint_fontsize_y;
 -
 -      pos = centerprint_start;
 -      for (i=0; i<centerprint_num; i = i + 1)
 -      {
 -              ts = centerprint_messages[i];
 -              drawfontscale = sz * '1 1 0';
 -              pos_x = (vid_conwidth - stringwidth(ts, TRUE, centerprint_fontsize)) * 0.5;
 -              if (ts != "")
 -              {
 -                      drawcolorcodedstring(pos + '0 1 0' * (1 - sz) * 0.5 *centerprint_fontsize_y, ts, centerprint_fontsize, a, DRAWFLAG_NORMAL);
 -                      pos_y = pos_y + centerprint_fontsize_y;
 -              }
 -              else
 -                      // half height for empty lines looks better
 -                      pos_y = pos_y + sz * centerprint_fontsize_y * 0.5;
 -              drawfontscale = '1 1 0';
 -      }
 -}
 -
  void drawstringright(vector position, string text, vector scale, vector rgb, float alpha, float flag)
  {
        position_x -= 2 / 3 * strlen(text) * scale_x;
@@@ -466,7 -643,6 +466,7 @@@ void HUD_Weapons(void
        }
  
        HUD_Panel_UpdateCvars(weapons);
 +      HUD_Panel_ApplyFadeAlpha();
  
        if (timeout && time >= weapontime + timeout && !autocvar__hud_configure)
        {
@@@ -853,7 -1029,6 +853,7 @@@ void HUD_Ammo(void
                hud_configure_active_panel = HUD_PANEL_AMMO;
  
        HUD_Panel_UpdateCvars(ammo);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -1039,7 -1214,6 +1039,7 @@@ void HUD_Powerups(void
        }
  
        HUD_Panel_UpdateCvars(powerups);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -1194,7 -1368,6 +1194,7 @@@ void HUD_HealthArmor(void
        }
  
        HUD_Panel_UpdateCvars(healtharmor);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -1833,90 -2006,92 +1833,90 @@@ void HUD_KillNotify(string s1, string s
        }
  }
  
 -#define DAMAGE_CENTERPRINT_SPACER NEWLINES
 -
  void HUD_Centerprint(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(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("You are now on: %s"), s1)));
 +                      centerprint(sprintf(_("You are now on: %s"), s1));
                } else if (type == DEATH_AUTOTEAMCHANGE) {
 -                      centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("You have been moved into a different team to improve team balance\nYou are now on: %s"), s1)));
 +                      centerprint(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(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Reconsider your tactics, camper!")));
 +                              centerprint(_("^1Reconsider your tactics, camper!"));
                        else
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Die camper!")));
 +                              centerprint(_("^1Die camper!"));
                } else if (type == DEATH_NOAMMO) {
                        if(gentle)
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You are reinserted into the game for running out of ammo...")));
 +                              centerprint(_("^1You are reinserted into the game for running out of ammo..."));
                        else
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You were killed for running out of ammo...")));
 +                              centerprint(_("^1You were killed for running out of ammo..."));
                } else if (type == DEATH_ROT) {
                        if(gentle)
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You need to preserve your health")));
 +                              centerprint(_("^1You need to preserve your health"));
                        else
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You grew too old without taking your medicine")));
 +                              centerprint(_("^1You grew too old without taking your medicine"));
                } else if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) {
                        if(gentle)
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Don't go against team mates!")));
 +                              centerprint(_("^1Don't go against team mates!"));
                        else
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Don't shoot your team mates!")));
 +                              centerprint(_("^1Don't shoot your team mates!"));
                } else if (type == DEATH_QUIET) {
                        // do nothing
                } else { // generic message
                        if(gentle)
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You need to be more careful!")));
 +                              centerprint(_("^1You need to be more careful!"));
                        else
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You killed your own dumb self!")));
 +                              centerprint(_("^1You killed your own dumb self!"));
                }
        } else if(msg == MSG_KILL) {
                if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) {
                        if(gentle) {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1Moron! You went against ^7%s^1, a team mate!"), s1)));
 +                              centerprint(sprintf(_("^1Moron! You went against ^7%s^1, a team mate!"), s1));
                        } else {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1Moron! You fragged ^7%s^1, a team mate!"), s1)));
 +                              centerprint(sprintf(_("^1Moron! You fragged ^7%s^1, a team mate!"), s1));
                        }
                } else if (type == KILL_FIRST_BLOOD) {
                        if(gentle) {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First score")));
 +                              centerprint(_("^1First score"));
                        } else {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First blood")));
 +                              centerprint(_("^1First blood"));
                        }
                } else if (type == KILL_FIRST_VICTIM) {
                        if(gentle) {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First casualty")));
 +                              centerprint(_("^1First casualty"));
                        } else {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First victim")));
 +                              centerprint(_("^1First victim"));
                        }
                } else if (type == KILL_TYPEFRAG) { // s2 contains "advanced kill messages" such as ping, handicap...
                        if(gentle) {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You scored against ^7%s^1 who was typing!"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^1You scored against ^7%s^1 who was typing!"), s1), s2));
                        } else {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You typefragged ^7%s"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^1You typefragged ^7%s"), s1), s2));
                        }
                } else if (type == KILL_TYPEFRAGGED) {
                        if(gentle) {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were scored against by ^7%s^1 while you were typing!"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^1You were scored against by ^7%s^1 while you were typing!"), s1), s2));
                        } else {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were typefragged by ^7%s"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^1You were typefragged by ^7%s"), s1), s2));
                        }
                } else if (type == KILL_FRAG) {
                        if(gentle) {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^4You scored against ^7%s"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^4You scored against ^7%s"), s1), s2));
                        } else {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^4You fragged ^7%s"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^4You fragged ^7%s"), s1), s2));
                        }
                } else { // generic message
                        if(gentle) {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were scored against by ^7%s"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^1You were scored against by ^7%s"), s1), s2));
                        } else {
 -                              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were fragged by ^7%s"), s1), s2));
 +                              centerprint(strcat(sprintf(_("^1You were fragged by ^7%s"), s1), s2));
                        }
                }
        } else if(msg == MSG_KILL_ACTION) {
                // TODO: invent more centerprints here?
 -              centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Watch your step!")));
 +              centerprint(_("^1Watch your step!"));
        }
  }
  
@@@ -1930,7 -2105,6 +1930,7 @@@ void HUD_Notify (void
                hud_configure_active_panel = HUD_PANEL_NOTIFY;
  
        HUD_Panel_UpdateCvars(notify);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2244,7 -2418,6 +2244,7 @@@ void HUD_Timer(void
                hud_configure_active_panel = HUD_PANEL_TIMER;
  
        HUD_Panel_UpdateCvars(timer);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2302,7 -2475,6 +2302,7 @@@ void HUD_Radar(void
                hud_configure_active_panel = HUD_PANEL_RADAR;
  
        HUD_Panel_UpdateCvars(radar);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2554,7 -2726,6 +2554,7 @@@ void HUD_Score(void
                hud_configure_active_panel = HUD_PANEL_SCORE;
  
        HUD_Panel_UpdateCvars(score);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2739,7 -2910,6 +2739,7 @@@ void HUD_RaceTimer (void
                hud_configure_active_panel = HUD_PANEL_RACETIMER;
  
        HUD_Panel_UpdateCvars(racetimer);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2935,7 -3105,6 +2935,7 @@@ void HUD_VoteWindow(void
                return;
  
        HUD_Panel_UpdateCvars(vote);
 +      HUD_Panel_ApplyFadeAlpha();
  
        if(uid2name_dialog)
        {
        pos = panel_pos;
        mySize = panel_size;
  
-       a = vote_alpha * bound(autocvar_hud_panel_vote_alreadyvoted_alpha, 1 - vote_highlighted, 1);
+       a = vote_alpha * (vote_highlighted ? autocvar_hud_panel_vote_alreadyvoted_alpha : 1);
        HUD_Panel_DrawBg(a);
        a = panel_fg_alpha * a;
  
                drawsetcliparea(pos_x, pos_y, mySize_x * 0.5, mySize_y);
                drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
        }
-       else if(vote_highlighted == 2) {
+       else if(vote_highlighted == -1) {
                drawsetcliparea(pos_x + 0.5 * mySize_x, pos_y, mySize_x * 0.5, mySize_y);
                drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
        }
        }
  
        drawresetcliparea();
-       if(!vote_active) {
-               vote_highlighted = 0;
-       }
  }
  
  // Mod icons panel (#10)
@@@ -3691,7 -3856,6 +3687,7 @@@ void HUD_ModIcons(void
                hud_configure_active_panel = HUD_PANEL_MODICONS;
  
        HUD_Panel_UpdateCvars(modicons);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -3746,7 -3910,6 +3742,7 @@@ void HUD_DrawPressedKeys(void
  
  
        HUD_Panel_UpdateCvars(pressedkeys);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -3811,7 -3974,6 +3807,7 @@@ void HUD_Chat(void
                hud_configure_active_panel = HUD_PANEL_CHAT;
  
        HUD_Panel_UpdateCvars(chat);
 +      HUD_Panel_ApplyFadeAlpha();
  
        if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
        {
@@@ -3887,7 -4049,6 +3883,7 @@@ void HUD_EngineInfo(void
                hud_configure_active_panel = HUD_PANEL_ENGINEINFO;
  
        HUD_Panel_UpdateCvars(engineinfo);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -3950,7 -4111,6 +3946,7 @@@ void HUD_InfoMessages(void
                hud_configure_active_panel = HUD_PANEL_INFOMESSAGES;
  
        HUD_Panel_UpdateCvars(infomessages);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -4130,13 -4290,13 +4126,14 @@@ void HUD_Physics(void
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_physics) return;
-               if(spectatee_status == -1 && autocvar_hud_panel_physics < 2) return;
+               if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
+               if(autocvar_hud_panel_physics == 3 && !(gametype == GAME_RACE || gametype == GAME_CTS)) return;
        }
        else
                hud_configure_active_panel = HUD_PANEL_PHYSICS;
  
        HUD_Panel_UpdateCvars(physics);
 +      HUD_Panel_ApplyFadeAlpha();
  
        HUD_Panel_DrawBg(1);
        if(panel_bg_padding)
                drawstring_aspect(panel_pos + acceleration_offset, strcat(ftos_decimals(acceleration, 2), "g"), panel_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
  }
  
 +// CenterPrint (#16)
 +//
 +#define CENTERPRINT_MAX_MSGS 10
 +#define CENTERPRINT_MAX_ENTRIES 50
 +#define CENTERPRINT_SPACING 0.7
 +float cpm_index;
 +string centerprint_messages[CENTERPRINT_MAX_MSGS];
 +float centerprint_msgID[CENTERPRINT_MAX_MSGS];
 +float centerprint_time[CENTERPRINT_MAX_MSGS];
 +float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
 +float centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
 +float centerprint_fadetime;
 +float centerprint_showing;
 +
 +void centerprint_generic(float new_id, string strMessage, float duration, float countdown_num)
 +{
 +      float i, j;
 +
 +      if(strMessage == "" && new_id == 0)
 +              return;
 +
 +      // strip trailing newlines
 +      j = strlen(strMessage) - 1;
 +      while(substring(strMessage, j, 1) == "\n" && j >= 0)
 +              --j;
 +      if (j < strlen(strMessage) - 1)
 +              strMessage = substring(strMessage, 0, j + 1);
 +
 +      if(strMessage == "" && new_id == 0)
 +              return;
 +
 +      // strip leading newlines
 +      j = 0;
 +      while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
 +              ++j;
 +      if (j > 0)
 +              strMessage = substring(strMessage, j, strlen(strMessage) - j);
 +
 +      if(strMessage == "" && new_id == 0)
 +              return;
 +
 +      if (!centerprint_showing)
 +              centerprint_showing = TRUE;
 +
 +      centerprint_fadetime = bound(0, autocvar_hud_panel_centerprint_fadetime, 1);
 +
 +      for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
 +      {
 +              if (j == CENTERPRINT_MAX_MSGS)
 +                      j = 0;
 +              if (new_id && new_id == centerprint_msgID[j])
 +              {
 +                      if (strMessage == "" && centerprint_messages[j] != "" && centerprint_countdown_num[j] == 0)
 +                      {
 +                              // fade out the current msg (duration and countdown_num are ignored)
 +                              centerprint_time[j] = centerprint_fadetime;
 +                              if (centerprint_expire_time[j] > time + centerprint_fadetime || centerprint_expire_time[j] < time)
 +                                      centerprint_expire_time[j] = time + centerprint_fadetime;
 +                              return;
 +                      }
 +                      break; // found a msg with the same id, at position j
 +              }
 +      }
 +
 +      if (i == CENTERPRINT_MAX_MSGS)
 +      {
 +              // a msg with the same id was not found, add the msg at the next position
 +              --cpm_index;
 +              if (cpm_index == -1)
 +                      cpm_index = CENTERPRINT_MAX_MSGS - 1;
 +              j = cpm_index;
 +      }
 +      if(centerprint_messages[j])
 +              strunzone(centerprint_messages[j]);
 +      centerprint_messages[j] = strzone(strMessage);
 +      centerprint_msgID[j] = new_id;
 +      if (duration < 0)
 +              centerprint_time[j] = -1;
 +      else
 +      {
 +              if(duration == 0)
 +                      duration = max(1, autocvar_hud_panel_centerprint_time);
 +              centerprint_time[j] = duration;
 +              centerprint_expire_time[j] = time + duration;
 +      }
 +      centerprint_countdown_num[j] = countdown_num;
 +}
 +
 +void centerprint(string strMessage)
 +{
 +      centerprint_generic(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
 +}
 +
 +void reset_centerprint_messages(void)
 +{
 +      float i;
 +      for (i=0; i<CENTERPRINT_MAX_MSGS; ++i)
 +      {
 +              centerprint_expire_time[i] = 0;
 +              centerprint_time[i] = 1;
 +              centerprint_msgID[i] = 0;
 +              if(centerprint_messages[i])
 +                      strunzone(centerprint_messages[i]);
 +              centerprint_messages[i] = string_null;
 +      }
 +}
 +float hud_configure_cp_generation_time;
 +void HUD_CenterPrint (void)
 +{
 +      if(!autocvar__hud_configure)
 +      {
 +              if(!autocvar_hud_panel_centerprint) return;
 +
 +              if (hud_configure_prev && hud_configure_prev != -1)
 +                      reset_centerprint_messages();
 +      }
 +      else
 +      {
 +              hud_configure_active_panel = HUD_PANEL_CENTERPRINT;
 +
 +              if (!hud_configure_prev)
 +                      reset_centerprint_messages();
 +              if (time > hud_configure_cp_generation_time)
 +              {
 +                      float r;
 +                      r = random();
 +                      if (r > 0.9)
 +                              centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: %d"), 1, 10);
 +                      else if (r > 0.8)
 +                              centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
 +                      else
 +                              centerprint(sprintf("Message at time %s", seconds_tostring(time)));
 +                      hud_configure_cp_generation_time = time + 1 + random()*4;
 +              }
 +      }
 +
 +      HUD_Panel_UpdateCvars(centerprint);
 +
 +      // this panel doesn't fade when showing the scoreboard
 +      if(autocvar__menu_alpha)
 +              HUD_Panel_ApplyFadeAlpha();
 +
 +      if(scoreboard_fade_alpha)
 +      {
 +              // move the panel below the scoreboard
 +              if (scoreboard_bottom >= 0.96 * vid_conheight)
 +                      return;
 +              vector target_pos;
 +              target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
 +              panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
 +              panel_size_y = min(panel_size_y, vid_conheight - scoreboard_bottom);
 +      }
 +
 +      HUD_Panel_DrawBg(1);
 +
 +      if (!centerprint_showing)
 +              return;
 +
 +      if(panel_bg_padding)
 +      {
 +              panel_pos += '1 1 0' * panel_bg_padding;
 +              panel_size -= '2 2 0' * panel_bg_padding;
 +      }
 +
 +      float entries, height;
 +      vector fontsize;
 +      // entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
 +      // height = panel_size_y/entries;
 +      // fontsize = '1 1 0' * height;
 +      height = vid_conheight/40 * autocvar_hud_panel_centerprint_fontscale;
 +      fontsize = '1 1 0' * height;
 +      entries = bound(1, floor(panel_size_y/height), CENTERPRINT_MAX_ENTRIES);
 +
 +      float i, j, k, n;
 +      float a, sz, align, current_msg_pos_y, msg_size;
 +      vector pos;
 +      string ts;
 +
 +      n = -1; // if no msg will be displayed, n stays -1
 +
 +      pos = panel_pos;
 +      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)
 +      {
 +              if (j == CENTERPRINT_MAX_MSGS)
 +                      j = 0;
 +              if (centerprint_expire_time[j] < time)
 +              {
 +                      if (centerprint_countdown_num[j] && centerprint_time[j] > 0)
 +                      {
 +                              centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
 +                              if (centerprint_countdown_num[j] == 0)
 +                                      continue;
 +                              centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
 +                      }
 +                      else
 +                              continue;
 +              }
 +              if (centerprint_time[j] < 0 || centerprint_expire_time[j] - centerprint_fadetime > time)
 +              {
 +                      a = 1;
 +                      sz = 1;
 +              }
 +              else if (centerprint_expire_time[j] > time)
 +              {
 +                      a = (centerprint_expire_time[j] - time) / centerprint_fadetime;
 +                      sz = 0.8 + a * (1 - 0.8);
 +              }
 +
 +              drawfontscale = sz * '1 1 0';
 +              if (centerprint_countdown_num[j])
 +                      n = tokenizebyseparator(sprintf(centerprint_messages[j], centerprint_countdown_num[j]), "\n");
 +              else
 +                      n = tokenizebyseparator(centerprint_messages[j], "\n");
 +              if (autocvar_hud_panel_centerprint_flip)
 +              {
 +                      // check if the message can be entirely shown
 +                      for(k = 0; k < n; ++k)
 +                      {
 +                              getWrappedLine_remaining = argv(k);
 +                              while(getWrappedLine_remaining)
 +                              {
 +                                      ts = getWrappedLine(panel_size_x * sz, fontsize, stringwidth_colors);
 +                                      if (ts != "")
 +                                              pos_y -= fontsize_y;
 +                                      else
 +                                              pos_y -= fontsize_y * CENTERPRINT_SPACING/2;
 +                                      if (pos_y < panel_pos_y) // check if the next line can be shown
 +                                      {
 +                                              drawfontscale = '1 1 0';
 +                                              return;
 +                                      }
 +                              }
 +                      }
 +                      current_msg_pos_y = pos_y; // save starting pos (first line) of the current message
 +              }
 +
 +              msg_size = pos_y;
 +              for(k = 0; k < n; ++k)
 +              {
 +                      getWrappedLine_remaining = argv(k);
 +                      while(getWrappedLine_remaining)
 +                      {
 +                              ts = getWrappedLine(panel_size_x * sz, fontsize, stringwidth_colors);
 +                              if (ts != "")
 +                              {
 +                                      if (align)
 +                                              pos_x = panel_pos_x + (panel_size_x - stringwidth(ts, TRUE, fontsize)) * align;
 +                                      drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize_y, ts, fontsize, a * panel_fg_alpha, DRAWFLAG_NORMAL);
 +                                      pos_y += fontsize_y;
 +                              }
 +                              else
 +                                      pos_y += fontsize_y * CENTERPRINT_SPACING/2;
 +                              if (!autocvar_hud_panel_centerprint_flip && pos_y > panel_pos_y + panel_size_y - fontsize_y) // check if the next line can be shown
 +                              {
 +                                      drawfontscale = '1 1 0';
 +                                      return;
 +                              }
 +                      }
 +              }
 +              msg_size = pos_y - msg_size;
 +              if (autocvar_hud_panel_centerprint_flip)
 +              {
 +                      pos_y = current_msg_pos_y - CENTERPRINT_SPACING * fontsize_y;
 +                      if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
 +                              pos_y += (msg_size + CENTERPRINT_SPACING * fontsize_y) * (1 - sqrt(a));
 +              }
 +              else
 +              {
 +                      pos_y += CENTERPRINT_SPACING * fontsize_y;
 +                      if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
 +                              pos_y -= (msg_size + CENTERPRINT_SPACING * fontsize_y) * (1 - sqrt(a));
 +              }
 +      }
 +      drawfontscale = '1 1 0';
 +      if (n == -1)
 +      {
 +              centerprint_showing = FALSE;
 +              reset_centerprint_messages();
 +      }
 +}
 +
  /*
  ==================
  Main HUD system
@@@ -4680,8 -4556,6 +4677,8 @@@ switch (id) {
                 HUD_InfoMessages(); break;\
        case (HUD_PANEL_PHYSICS):\
                 HUD_Physics(); break;\
 +      case (HUD_PANEL_CENTERPRINT):\
 +               HUD_CenterPrint(); break;\
  } ENDS_WITH_CURLY_BRACE
  
  void HUD_Main (void)
        else if(autocvar__menu_alpha == 0 && scoreboard_fade_alpha == 0)
                hud_fade_alpha = 1;
  
 +      // panels that we want to be active together with the scoreboard
 +      // they must call HUD_Panel_ApplyFadeAlpha(); only when showing the menu
 +      if(scoreboard_fade_alpha == 1)
 +      {
 +              HUD_CenterPrint();
 +              return;
 +      }
 +
        if(!autocvar__hud_configure && !hud_fade_alpha)
                return;
  
        if(autocvar__con_chat_maximized)
                HUD_Chat(); // HUD_DrawPanel(HUD_PANEL_CHAT);
  
 -      if (autocvar__hud_configure && spectatee_status && hud_configure_prev == -1) // try to join if we are in hud_configure mode, but still spectating, and in the first frame (in order to get rid of motd when launching a server via the menu "HUD Setup" button)
 -              localcmd("cmd selectteam auto; cmd join\n");
 -
        if(autocvar__hud_configure && tab_panel != -1)
        {
                HUD_Panel_UpdatePosSizeForId(tab_panel)
diff --combined qcsrc/client/hud.qh
index 53b920ede596caa81fb98121a6cbb879e365a9f4,fc3dd7422183fddc9aa1dc283bed76ff59529893..ca9296799e8ecb6134645387c1e66fcaf1267859
@@@ -1,5 -1,7 +1,5 @@@
  float log(float f);
  
 -vector centerprint_start;
 -
  float panel_order[HUD_PANEL_NUM];
  string hud_panelorder_prev;
  
@@@ -154,14 -156,6 +154,14 @@@ if(panel_bg_color_team_str == "") {
        panel_bg_color_team = stof(panel_bg_color_team_str);\
  }
  
 +// the check doesn't allow to fade this panel when showing the panel-specific menu dialog
 +#define HUD_Panel_ApplyFadeAlpha()\
 +if(!(menu_enabled == 2 && highlightedPanel == hud_configure_active_panel))\
 +{\
 +      panel_bg_alpha *= hud_fade_alpha;\
 +      panel_fg_alpha *= hud_fade_alpha;\
 +} ENDS_WITH_CURLY_BRACE
 +
  // Get value for panel_bg_alpha: if "" fetch default, else use panel_bg_alpha. Also do various menu dialog fadeout/in checks, and minalpha checks
  // comment on line 3 of macro: // do not set a minalpha cap when showing the config dialog for this panel
  #define HUD_Panel_GetBgAlpha()\
@@@ -176,14 -170,19 +176,14 @@@ if(autocvar__hud_configure) {
                panel_bg_alpha = (1 - autocvar__menu_alpha) * max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha) + autocvar__menu_alpha * panel_bg_alpha;\
        else\
                panel_bg_alpha = max(cvar("hud_configure_bg_minalpha"), panel_bg_alpha);\
 -} if(!(menu_enabled == 2 && highlightedPanel == hud_configure_active_panel)) {\
 -      panel_bg_alpha *= hud_fade_alpha;\
  }
  
  // Get value for panel_fg_alpha. Also do various minalpha checks
  // comment on line 2 of macro: // ALWAYS show disabled panels at 0.25 alpha when in config mode
 -// comment on line 4 of macro: // don't fade this panel when showing the panel-specific menu dialog
  #define HUD_Panel_GetFgAlpha()\
  panel_fg_alpha = autocvar_hud_panel_fg_alpha;\
  if(autocvar__hud_configure && !panel_enabled)\
        panel_fg_alpha = 0.25;\
 -if(!(menu_enabled == 2 && highlightedPanel == hud_configure_active_panel))\
 -      panel_fg_alpha *= hud_fade_alpha;
  
  // Get border. See comments above, it's similar.
  #define HUD_Panel_GetBorder()\
@@@ -233,7 -232,7 +233,7 @@@ else
  panel_pos = (1 - autocvar__menu_alpha) * panel_pos + (autocvar__menu_alpha) * menu_enable_panelpos;
  
  // return smoothly faded size of given panel when a dialog is active
- //var vector menu_enable_maxsize; FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(menu_enable_maxsize);
+ //var vector menu_enable_maxsize;
  var float menu_enable_maxsize_x;
  var float menu_enable_maxsize_y;
  var vector menu_enable_size;
@@@ -284,7 -283,6 +284,7 @@@ if(menu_enabled == 2 && hud_configure_a
  switch(id) { \
        case HUD_PANEL_INFOMESSAGES: HUD_Panel_UpdateCvars(infomessages) break; \
        case HUD_PANEL_PHYSICS: HUD_Panel_UpdateCvars(physics); break;\
 +      case HUD_PANEL_CENTERPRINT: HUD_Panel_UpdateCvars(centerprint); break;\
  }
  
  #define HUD_Panel_UpdateCvarsForId(id) \
@@@ -322,7 -320,6 +322,7 @@@ HUD_Panel_GetBorder(
  switch(id) { \
        case HUD_PANEL_INFOMESSAGES: HUD_Panel_UpdatePosSize(infomessages) break;\
        case HUD_PANEL_PHYSICS: HUD_Panel_UpdatePosSize(physics); break;\
 +      case HUD_PANEL_CENTERPRINT: HUD_Panel_UpdatePosSize(centerprint); break;\
  }
  
  #define HUD_Panel_UpdatePosSizeForId(id) \
diff --combined qcsrc/client/main.qh
index 62475f9fb1f6bd33b8c01bd1fe7880344bd229a1,a0634d42c981244604f5a913051fe74e46af9e3c..64399b20a3e035e6ad899978225cdfadb44a581d
@@@ -86,8 -86,8 +86,8 @@@ string scores_label[MAX_SCORE]
  float scores_flags[MAX_SCORE];
  string teamscores_label[MAX_SCORE];
  float teamscores_flags[MAX_SCORE];
- .float scores[MAX_SCORE]; FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(scores);
- .float teamscores[MAX_TEAMSCORE]; FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(teamscores);
+ .float scores[MAX_SCORE];
+ .float teamscores[MAX_TEAMSCORE];
  
  #define IS_INCREASING(x) ( (x)&SFL_LOWER_IS_BETTER )
  #define IS_DECREASING(x) ( !((x)&SFL_LOWER_IS_BETTER) )
@@@ -144,7 -144,6 +144,7 @@@ float camera_roll
  vector camera_direction;
  
  void centerprint(string strMessage);
 +void centerprint_generic(float new_id, string strMessage, float duration, float countdown_num);
  
  #define ALPHA_MIN_VISIBLE 0.003
  
index 77f40992590ba0d6a780ac31f3734165755e21c4,0ba6097701ebe85295efa9179652aa92f42bf0aa..7301fbf0bbf2922fa30b14f83c487e770239da5e
@@@ -20,7 -20,7 +20,7 @@@ void restartAnnouncer_Think() 
        countdown_rounded = floor(0.5 + countdown);
        if(countdown <= 0) {
                if (!spectatee_status) //do cprint only for players
 -                      centerprint(_("^1Begin!"));
 +                      centerprint_generic(CPID_GAME_STARTING, _("^1Begin!"), 1, 0);
  
                sound(world, CH_INFO, strcat("announcer/", autocvar_cl_announcer, "/begin.wav"), VOL_BASEVOICE, ATTN_NONE);
                //reset maptime announcers now as well
@@@ -31,7 -31,7 +31,7 @@@
        }
        else {
                if (!spectatee_status) //do cprint only for players
 -                      centerprint(sprintf(_("^1Game starts in %d seconds"), countdown_rounded));
 +                      centerprint_generic(CPID_GAME_STARTING, _("^1Game starts in %d seconds"), 1, countdown_rounded);
  
                if(countdown_rounded <= 3 && countdown_rounded >= 1) {
                        sound(world, CH_INFO, strcat("announcer/", autocvar_cl_announcer, "/", ftos(countdown_rounded), ".wav"), VOL_BASEVOICE, ATTN_NONE);
@@@ -319,9 -319,6 +319,6 @@@ vector HUD_GetFontsize(string cvarname
  
  float PreviewExists(string name)
  {
-       float f;
-       string file;
        if(autocvar_cl_readpicture_force)
                return false;
  
index 2d32083d311f51e49cbe635e35ffb0787311b889,67b7f746c8d43f0b2711ff6f655d1ca22d5a88c9..93f851876da157a0a229127cfdf8cac4111272b9
@@@ -981,7 -981,7 +981,7 @@@ vector HUD_DrawScoreboardAccuracyStats(
        if(getstati(STAT_SWITCHWEAPON) == WEP_MINSTANEX)
                g_minstagib = 1; // TODO: real detection for minstagib?
  
-       float weapon_stats, weapon_number;
+       float weapon_stats;
  
        if (!acc_levels)
                rgb = '1 1 1';
@@@ -1168,6 -1168,9 +1168,6 @@@ void HUD_DrawScoreboard(
        vector sb_heading_fontsize;
        sb_heading_fontsize = hud_fontsize * 2;
        drawstring(pos, _("Scoreboard"), sb_heading_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
 -      
 -      centerprint_start_x = vid_conwidth - 0.5 * (pos_x + stringwidth(_("Scoreboard"), FALSE, sb_heading_fontsize));
 -      centerprint_start_y = pos_y;
  
        pos_y += sb_heading_fontsize_y + hud_fontsize_y * 0.25;
  
index fe368caa0ac9b7361943828ab7227a01f458956d,939f6f9700352a4ec402e2e8b68b1b25598d3c47..82b306506fe41387d843ab072babd34635a5e183
@@@ -55,8 -55,6 +55,6 @@@ 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_VOTE = 108;
- const float TE_CSQC_VOTERESET = 109;
  const float TE_CSQC_ANNOUNCE = 110;
  const float TE_CSQC_TARGET_MUSIC = 111;
  const float TE_CSQC_NOTIFY = 112;
@@@ -83,7 -81,6 +81,7 @@@ const float RANKINGS_CNT = 15
  
  const float CSQC_KILLNOTIFY = 0;
  const float CSQC_CENTERPRINT = 1;
 +const float CSQC_CENTERPRINT_GENERIC = 2;
  
  const float ENT_CLIENT = 0;
  const float ENT_CLIENT_DEAD = 1;
@@@ -434,11 -431,12 +432,12 @@@ const float STAT_DOM_PPS_YELLOW = 104
  float CH_INFO = 0; // only on world and csqc
  float CH_TRIGGER = 0; // only on players; compat: FALSELY CONTROLLED BY "Info"
  float CH_WEAPON_A = 1; // only on players and entities
- float CH_WEAPON_SINGLE = 1; // only on players and entities
+ float CH_WEAPON_SINGLE = 5; // only on players and entities
  float CH_VOICE = 2; // only on players
  float CH_BGM_SINGLE = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice"
  float CH_AMBIENT = 2; // only on csqc; compat: FALSELY CONTROLLED BY "Voice"
  float CH_TRIGGER_SINGLE = 3; // only on players, entities, csqc
+ float CH_SHOTS = 4; // only on players, entities, csqc
  float CH_SHOTS_SINGLE = 4; // only on players, entities, csqc
  float CH_WEAPON_B = 5; // only on players and entities
  float CH_PAIN = 6; // only on players and csqc
@@@ -453,6 -451,7 +452,7 @@@ float CH_VOICE = -2
  float CH_BGM_SINGLE = 8;
  float CH_AMBIENT = -9;
  float CH_TRIGGER_SINGLE = 3;
+ float CH_SHOTS = -4;
  float CH_SHOTS_SINGLE = 4;
  float CH_WEAPON_B = -1;
  float CH_PAIN = -6;
@@@ -592,6 -591,9 +592,6 @@@ float HITTYPE_RESERVED = 0x1000; // unu
  #define FRAGS_PLAYER_NONSOLID -616
  // we can use this frags value for both
  
 -//misc. stuff
 -#define NEWLINES "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
 -
  // water levels
  float WATERLEVEL_NONE = 0;
  float WATERLEVEL_WETFEET = 1;
@@@ -600,18 -602,6 +600,18 @@@ 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_ROUND_STARTING = 6;
 +float CPID_GAME_STARTING = 7;
 +float CPID_TIMEOUT_COUNTDOWN = 8;
 +float CPID_MOTD = 9;
 +float CPID_KH_MSG = 10;
 +
  // CSQC centerprint/notify message types
  float MSG_SUICIDE = 0;
  float MSG_KILL = 1;
@@@ -686,8 -676,7 +686,8 @@@ float HUD_PANEL_CHAT               = 12
  float HUD_PANEL_ENGINEINFO    = 13;
  float HUD_PANEL_INFOMESSAGES  = 14;
  float HUD_PANEL_PHYSICS       = 15;
 -float HUD_PANEL_NUM           = 16; // always last panel id + 1, please increment when adding a new panel
 +float HUD_PANEL_CENTERPRINT   = 16;
 +float HUD_PANEL_NUM           = 17; // always last panel id + 1, please increment when adding a new panel
  
  string HUD_PANELNAME_WEAPONS          = "weapons";
  string HUD_PANELNAME_AMMO             = "ammo";
@@@ -705,7 -694,6 +705,7 @@@ string HUD_PANELNAME_CHAT          = "chat"
  string HUD_PANELNAME_ENGINEINFO               = "engineinfo";
  string HUD_PANELNAME_INFOMESSAGES     = "infomessages";
  string HUD_PANELNAME_PHYSICS  = "physics";
 +string HUD_PANELNAME_CENTERPRINT      = "centerprint";
  
  float HUD_MENU_ENABLE         = 0;
  
index 3ccd515fc297505496965905a877bfdbcd665d92,a497f8c34e336a4508296ebafb80e769ab401c52..c3adfe781d80a403b2c21465c1fd8919ca589511
@@@ -614,9 -614,6 +614,9 @@@ void PutObserverInServer (void
        DropAllRunes(self);
        MUTATOR_CALLHOOK(MakePlayerObserver);
  
 +      if (g_minstagib)
 +              minstagib_stop_countdown();
 +
        Portal_ClearAll(self);
  
        if(self.alivetime)
@@@ -1018,6 -1015,7 +1018,7 @@@ void PutClientInServer (void
                self.oldorigin = self.origin;
                self.prevorigin = self.origin;
                self.lastrocket = world; // stop rocket guiding, no revenge from the grave!
+               self.lastteleporttime = time; // prevent insane speeds due to changing origin
  
                if(g_arena)
                {
@@@ -1279,10 -1277,10 +1280,10 @@@ void ClientKill_Now(
              Damage(self, self, self, 1 , DEATH_KILL, self.origin, '0 0 0');           
            }
        }
-       
        if(self.killindicator && !wasfreed(self.killindicator))
-         remove(self.killindicator);
-       
+               remove(self.killindicator);
        self.killindicator = world;
  
        if(self.killindicator_teamchange)
  }
  void KillIndicator_Think()
  {
+       if (gameover)
+       {
+               self.owner.killindicator = world;
+               remove(self);
+               return;
+       }
        if (!self.owner.modelindex)
        {
                self.owner.killindicator = world;
                {
                        if(self.cnt <= 10)
                                AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
 -                      if(self.owner.killindicator_teamchange)
 -                      {
 -                              if(self.owner.killindicator_teamchange == -1)
 -                                      centerprint(self.owner, strcat("Changing team in ", ftos(self.cnt), " seconds"));
 -                              else if(self.owner.killindicator_teamchange == -2)
 -                                      centerprint(self.owner, strcat("Spectating in ", ftos(self.cnt), " seconds"));
 -                              else
 -                                      centerprint(self.owner, strcat("Changing to ", ColoredTeamName(self.owner.killindicator_teamchange), " in ", ftos(self.cnt), " seconds"));
 -                      }
 -                      else
 -                              centerprint(self.owner, strcat("^1Suicide in ", ftos(self.cnt), " seconds"));
                }
                self.nextthink = time + 1;
                self.cnt -= 1;
@@@ -1331,6 -1347,10 +1339,10 @@@ void ClientKill_TeamChange (float targe
  {
        float killtime;
        entity e;
+       if (gameover)
+               return;
        killtime = autocvar_g_balance_kill_delay;
  
        if(g_race_qualifying || g_cts)
        if(self.killindicator)
        {
                if(targetteam == 0) // just die
 +              {
                        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);
 +              }
                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);
 +              }
                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);
 +              }
                else
 +              {
                        self.killindicator.colormod = TeamColor(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);
 +              }
        }
 +
  }
  
  void ClientKill (void)
  {
+       if (gameover)
+               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
@@@ -1447,55 -1449,6 +1462,6 @@@ void CTS_ClientKill (entity e) // silen
      e.lip = 0;
  }
  
- void DoTeamChange(float destteam)
- {
-       float t, c0;
-       if(!teamplay)
-       {
-               if(destteam >= 0)
-                       SetPlayerColors(self, destteam);
-               return;
-       }
-       if(self.classname == "player")
-       if(destteam == -1)
-       {
-               CheckAllowedTeams(self);
-               t = FindSmallestTeam(self, TRUE);
-               switch(self.team)
-               {
-                       case COLOR_TEAM1: c0 = c1; break;
-                       case COLOR_TEAM2: c0 = c2; break;
-                       case COLOR_TEAM3: c0 = c3; break;
-                       case COLOR_TEAM4: c0 = c4; break;
-                       default:          c0 = 999;
-               }
-               switch(t)
-               {
-                       case 1:
-                               if(c0 > c1)
-                                       destteam = COLOR_TEAM1;
-                               break;
-                       case 2:
-                               if(c0 > c2)
-                                       destteam = COLOR_TEAM2;
-                               break;
-                       case 3:
-                               if(c0 > c3)
-                                       destteam = COLOR_TEAM3;
-                               break;
-                       case 4:
-                               if(c0 > c4)
-                                       destteam = COLOR_TEAM4;
-                               break;
-               }
-               if(destteam == -1)
-                       return;
-       }
-       if(destteam == self.team && destteam >= 0 && !self.killindicator)
-               return;
-       ClientKill_TeamChange(destteam);
- }
  void FixClientCvars(entity e)
  {
        // send prediction settings to the client
@@@ -1690,6 -1643,8 +1656,6 @@@ void ClientConnect (void
  
        bprint("\n");
  
 -      self.welcomemessage_time = 0;
 -
        stuffcmd(self, strcat(clientstuff, "\n"));
        stuffcmd(self, strcat("exec maps/", mapname, ".cfg\n"));
        stuffcmd(self, "cl_particles_reloadeffects\n");
                set_dom_state(self);
  
        CheatInitClient();
 +
 +      if(!autocvar_g_campaign)
 +              Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
  }
  
  /*
@@@ -2004,6 -1956,47 +1970,6 @@@ void play_countdown(float finished, str
                                sound (self, CH_INFO, samp, VOL_BASE, ATTN_NORM);
  }
  
 -/**
 - * When sv_timeout is used this function returs strings like
 - * "Timeout begins in 2 seconds!\n" or "Timeout ends in 23 seconds!\n".
 - * Called by centerprint functions
 - * @param addOneSecond boolean, set to 1 if the welcome-message centerprint asks for the text
 - */
 -string getTimeoutText(float addOneSecond) {
 -      if (!autocvar_sv_timeout || !timeoutStatus)
 -              return "";
 -
 -      local string retStr;
 -      if (timeoutStatus == 1) {
 -              if (addOneSecond == 1) {
 -                      retStr = strcat("Timeout begins in ", ftos(remainingLeadTime + 1), " seconds!\n");
 -              }
 -              else {
 -                      retStr = strcat("Timeout begins in ", ftos(remainingLeadTime), " seconds!\n");
 -              }
 -              return retStr;
 -      }
 -      else if (timeoutStatus == 2) {
 -              if (addOneSecond) {
 -                      retStr = strcat("Timeout ends in ", ftos(remainingTimeoutTime + 1), " seconds!\n");
 -                      //don't show messages like "Timeout ends in 0 seconds"...
 -                      if ((remainingTimeoutTime + 1) > 0)
 -                              return retStr;
 -                      else
 -                              return "";
 -              }
 -              else {
 -                      retStr = strcat("Timeout ends in ", ftos(remainingTimeoutTime), " seconds!\n");
 -                      //don't show messages like "Timeout ends in 0 seconds"...
 -                      if (remainingTimeoutTime > 0)
 -                              return retStr;
 -                      else
 -                              return "";
 -              }
 -      }
 -      else return "";
 -}
 -
  void player_powerups (void)
  {
        // add a way to see what the items were BEFORE all of these checks for the mutator hook
@@@ -2472,8 -2465,7 +2438,8 @@@ void LeaveSpectatorMode(
                                bprint ("^4", self.netname, "^4 is playing now\n");
  
                        if(!autocvar_g_campaign)
 -                              centerprint(self,""); // clear MOTD
 +                      if (time < self.jointime + autocvar_welcome_message_time)
 +                              Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); // clear MOTD
  
                        return;
                } else {
        }
        else {
                //player may not join because of g_maxplayers is set
 -              centerprint_atprio(self, CENTERPRIO_MAPVOTE, PREVENT_JOIN_TEXT);
 +              centerprint(self, PREVENT_JOIN_TEXT);
        }
  }
  
@@@ -2537,9 -2529,11 +2503,9 @@@ void ObserverThink(
  {
        if (self.flags & FL_JUMPRELEASED) {
                if (self.BUTTON_JUMP && !self.version_mismatch) {
 -                      self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        self.flags |= FL_SPAWNING;
                } else if(self.BUTTON_ATCK && !self.version_mismatch) {
 -                      self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        if(SpectateNext() == 1) {
                                self.classname = "spectator";
                        }
                }
        }
 -      PrintWelcomeMessage(self);
  }
  
  void SpectatorThink()
  {
        if (self.flags & FL_JUMPRELEASED) {
                if (self.BUTTON_JUMP && !self.version_mismatch) {
 -                      self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        self.flags |= FL_SPAWNING;
                } else if(self.BUTTON_ATCK) {
 -                      self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        if(SpectateNext() == 1) {
                                self.classname = "spectator";
                                PutClientInServer();
                        }
                } else if (self.BUTTON_ATCK2) {
 -                      self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        self.classname = "observer";
                        PutClientInServer();
                        PutObserverInServer();
        }
  
 -      PrintWelcomeMessage(self);
        self.flags |= FL_CLIENT | FL_NOTARGET;
  }
  
@@@ -2629,7 -2628,6 +2595,7 @@@ Called every frame for each client befo
  void() ctf_setstatus;
  void() nexball_setstatus;
  .float items_added;
 +.float motd_actived_time; // used for both motd and campaign_message
  void PlayerPreThink (void)
  {
        WarpZone_PlayerPhysics_FixVAngle();
                PlayerUseKey();
        self.usekeypressed = self.BUTTON_USE;
  
 +      if (self.motd_actived_time == 0) {
 +              if (autocvar_g_campaign) {
 +                      if (self.classname == "player" && self.BUTTON_INFO) {
 +                              self.motd_actived_time = time;
 +                              Send_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, -1, 0);
 +                      }
 +              } else {
 +                      if ((self.classname == "player" || 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);
 +                      }
 +              }
 +      } else { // showing MOTD or campaign message
 +              if (autocvar_g_campaign) {
 +                      if (self.classname == "player") {
 +                              if (self.BUTTON_INFO)
 +                                      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);
 +                              }
 +                      }
 +              } else {
 +                      if (self.classname == "player" || (time - self.jointime) > autocvar_welcome_message_time) {
 +                              if (self.BUTTON_INFO)
 +                                      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);
 +                              }
 +                      }
 +              }
 +      }
 +
        if(self.classname == "player") {
  //            if(self.netname == "Wazat")
  //                    bprint(self.classname, "\n");
  
                CheckRules_Player();
  
 -              PrintWelcomeMessage(self);
 -
                if (intermission_running)
                {
                        IntermissionThink ();   // otherwise a button could be missed between
                        player_powerups();
                }
  
 +              if (g_minstagib)
 +                      minstagib_ammocheck();
 +
                if (self.deadflag != DEAD_NO)
                {
                        float button_pressed, force_respawn;
                        }
                        return;
                }
 +              // FIXME from now on self.deadflag is always 0 (and self.health is never < 1)
 +              // so (self.deadflag == DEAD_NO) is always true in the code below
  
                if(g_touchexplode)
                if(time > self.touchexplode_time)
                if(frametime)
                        player_anim();
  
 -              if (g_minstagib)
 -                      minstagib_ammocheck();
 -
                if(g_ctf)
                        ctf_setstatus();
  
@@@ -3092,21 -3056,7 +3058,21 @@@ void PlayerPostThink (void
        {
                // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
                float timeleft;
 +              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;
 +                      }
 +                      return;
 +              }
                timeleft = ceil(sv_maxidle - (time - self.parm_idlesince));
 +              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);
 +              }
                if(timeleft <= 0)
                {
                        bprint("^3", self.netname, "^3 was kicked for idling.\n");
                else if(timeleft <= 10)
                {
                        if(timeleft != self.idlekick_lasttimeleft)
 -                      {
 -                              centerprint_atprio(self, CENTERPRIO_IDLEKICK, strcat("^3Stop idling!\n^3Disconnecting in ", ftos(timeleft), "..."));
 -                              AnnounceTo(self, strcat(ftos(timeleft), ""));
 -                      }
 -              }
 -              else
 -              {
 -                      centerprint_expire(self, CENTERPRIO_IDLEKICK);
 +                              AnnounceTo(self, ftos(timeleft));
 +                      self.idlekick_lasttimeleft = timeleft;
                }
 -              self.idlekick_lasttimeleft = timeleft;
        }
  
  #ifdef TETRIS
index 0b6a956db913554ab688da06de9a7b615ac1c7e1,bace1dd7ea26f67dfa2e377c937eebca5e5aee1f..13cddc0d22cf87a7734b7d8ec77dbd07ba92d792
@@@ -1,11 -1,22 +1,22 @@@
  entity nagger;
  float readycount;
  float Nagger_SendEntity(entity to, float sendflags)
  {
        float nags, i, f, b;
        entity e;
        WriteByte(MSG_ENTITY, ENT_CLIENT_NAGGER);
  
+       // bits:
+       //   1 = ready
+       //   2 = player needs to ready up
+       //   4 = vote
+       //   8 = player needs to vote
+       //  16 = warmup
+       // sendflags:
+       //  64 = vote counts
+       // 128 = vote string
        nags = 0;
        if(readycount)
        {
        if(inWarmupStage)
                nags |= 16;
  
+       if(sendflags & 64)
+               nags |= 64;
        if(sendflags & 128)
                nags |= 128;
  
        if(!(nags & 4)) // no vote called? send no string
-               nags &~= 128;
+               nags &~= (64 | 128);
  
        WriteByte(MSG_ENTITY, nags);
  
-       if(nags & 128)
+       if(nags & 64)
        {
-               WriteString(MSG_ENTITY, votecalledvote_display);
+               WriteByte(MSG_ENTITY, vote_yescount);
+               WriteByte(MSG_ENTITY, vote_nocount);
+               WriteByte(MSG_ENTITY, vote_needed_absolute);
+               WriteChar(MSG_ENTITY, to.vote_vote);
        }
  
+       if(nags & 128)
+               WriteString(MSG_ENTITY, votecalledvote_display);
        if(nags & 1)
        {
                for(i = 1; i <= maxclients; i += 8)
@@@ -60,7 -80,7 +80,7 @@@ void Nagger_VoteChanged(
  void Nagger_VoteCountChanged()
  {
        if(nagger)
-               nagger.SendFlags |= 1;
+               nagger.SendFlags |= 64;
  }
  void Nagger_ReadyCounted()
  {
@@@ -219,6 -239,11 +239,11 @@@ void SV_ParseClientCommand(string s) 
                if(self.classname == "player" && autocvar_sv_spectate == 1) {
                        ClientKill_TeamChange(-2); // observe
                }
+               if(g_ca && self.caplayer && (self.classname == "spectator" || self.classname == "observer")) {
+                       // in CA, allow a dead player to move to spectatators (without that, caplayer!=0 will be moved back to the player list)
+                       sprint(self, "WARNING: you will spectate in the next round.\n");
+                       self.caplayer = 0;
+               }
        } else if(cmd == "join") {
                if not(self.flags & FL_CLIENT)
                        return;
                        }
                        else {
                                //player may not join because of g_maxplayers is set
 -                              centerprint_atprio(self, CENTERPRIO_MAPVOTE, PREVENT_JOIN_TEXT);
 +                              centerprint(self, PREVENT_JOIN_TEXT);
                        }
                }
        } else if( cmd == "selectteam" ) {
diff --combined qcsrc/server/ctf.qc
index 8e93ab44a1aa13a6b7a5c994b409142277b27b34,93446ed5ba811bd430c8d0eb30b8dfe0f7b3e3ee..7b78958451dc79f6ae5d5ae80eac1d16343b858c
@@@ -66,12 -66,12 +66,12 @@@ void ctf_captureshield_update(entity p
                {
                        if(should)
                        {
 -                              centerprint_atprio(p, CENTERPRIO_SHIELDING, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.");
 +                              Send_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.", 5, 0);
                                // TODO csqc notifier for this
                        }
                        else
                        {
 -                              centerprint_atprio(p, CENTERPRIO_SHIELDING, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.");
 +                              Send_CSQC_Centerprint_Generic(p, CPID_CTF_CAPTURESHIELD, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.", 5, 0);
                                // TODO csqc notifier for this
                        }
                        p.ctf_captureshielded = should;
@@@ -88,7 -88,6 +88,7 @@@ float ctf_captureshield_customize(
        return TRUE;
  }
  
 +.float ctf_captureshield_touch_msgtime;
  void ctf_captureshield_touch()
  {
        if not(other.ctf_captureshielded)
        mymid = (self.absmin + self.absmax) * 0.5;
        othermid = (other.absmin + other.absmax) * 0.5;
        Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * captureshield_force);
 -      centerprint_atprio(other, CENTERPRIO_SHIELDING, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.");
 +      if (time - other.ctf_captureshield_touch_msgtime > 2)
 +              Send_CSQC_Centerprint_Generic(other, CPID_CTF_CAPTURESHIELD, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.", 5, 0);
 +      other.ctf_captureshield_touch_msgtime = time;
  }
  
  void ctf_flag_spawnstuff()
@@@ -361,7 -358,7 +361,7 @@@ void FlagThink(
                {
                        bprint("The ", self.netname, " became impatient after ", ftos_decimals(flagcaptimerecord, 2), " seconds and returned itself\n");
  
-                       sound (self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NONE);
+                       sound (self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
                        self.owner.impulse = 141; // returning!
  
                        e = self;
                if (time > self.pain_finished)
                {
                        bprint("The ", self.netname, " has returned to base\n");
-                       sound (self, CH_TRIGGER_SINGLE, self.noise3, VOL_BASE, ATTN_NONE);
+                       sound (self, CH_TRIGGER, self.noise3, VOL_BASE, ATTN_NONE);
                        LogCTF("returned", self.team, world);
                        ReturnFlag(self);
                }
@@@ -768,6 -765,7 +768,7 @@@ Keys
   (default ctf/respawn.wav)
  */
  
+ void spawnfunc_item_flag_team2();
  void spawnfunc_item_flag_team1()
  {
        if (!g_ctf)
                return;
        }
  
+       if (g_ctf_reverse)
+       {
+               float old_g_ctf_reverse = g_ctf_reverse;
+               g_ctf_reverse = 0; // avoid an endless loop
+               spawnfunc_item_flag_team2();
+               g_ctf_reverse = old_g_ctf_reverse;
+               return;
+       }
        // link flag into ctf_worldflaglist
        self.ctf_worldflagnext = ctf_worldflaglist;
        ctf_worldflaglist = self;
  
        self.classname = "item_flag_team";
-       if(g_ctf_reverse)
-       {
-               self.team = COLOR_TEAM2; // color 13 team (blue)
-               self.items = IT_KEY1; // silver key (bluish enough)
-       }
-       else
-       {
-               self.team = COLOR_TEAM1; // color 4 team (red)
-               self.items = IT_KEY2; // gold key (redish enough)
-       }
+       self.team = COLOR_TEAM1; // color 4 team (red)
+       self.items = IT_KEY2; // gold key (redish enough)
        self.netname = "^1RED^7 flag";
        self.target = "###item###";
        self.skin = autocvar_g_ctf_flag_red_skin;
@@@ -874,21 -873,22 +876,22 @@@ void spawnfunc_item_flag_team2(
                return;
        }
  
+       if (g_ctf_reverse)
+       {
+               float old_g_ctf_reverse = g_ctf_reverse;
+               g_ctf_reverse = 0; // avoid an endless loop
+               spawnfunc_item_flag_team1();
+               g_ctf_reverse = old_g_ctf_reverse;
+               return;
+       }
        // link flag into ctf_worldflaglist
        self.ctf_worldflagnext = ctf_worldflaglist;
        ctf_worldflaglist = self;
  
        self.classname = "item_flag_team";
-       if(g_ctf_reverse)
-       {
-               self.team = COLOR_TEAM1; // color 4 team (red)
-               self.items = IT_KEY2; // gold key (redish enough)
-       }
-       else
-       {
-               self.team = COLOR_TEAM2; // color 13 team (blue)
-               self.items = IT_KEY1; // silver key (bluish enough)
-       }
+       self.team = COLOR_TEAM2; // color 13 team (blue)
+       self.items = IT_KEY1; // silver key (bluish enough)
        self.netname = "^4BLUE^7 flag";
        self.target = "###item###";
        self.skin = autocvar_g_ctf_flag_blue_skin;
diff --combined qcsrc/server/defs.qh
index 87ff757a9e42434669043f42c92511bf2d60cb78,2e8ba3d698064524db892edbc3145e981e3fc889..9e6a73b5e3642fe9e9ae952a9b6a318120e32ad7
@@@ -231,6 -231,7 +231,6 @@@ void weapon_defaultspawnfunc(float wpn)
  
  string w_deathtypestring;
  
 -void(entity client, string s) centerprint_builtin = #73;
  .vector dest1, dest2;
  
  float gameover;
@@@ -242,6 -243,7 +242,6 @@@ float alreadychangedlevel
  .float runes;
  
  
 -.float welcomemessage_time;
  .float version;
  
  // minstagib vars
@@@ -284,6 -286,7 +284,6 @@@ entity timeoutHandler; //responsible fo
  void timeoutHandler_Think();
  void evaluateTimeout();
  void evaluateTimein();
 -string getTimeoutText(float addOneSecond);
  
  .float spawnshieldtime;
  
@@@ -309,6 -312,7 +309,6 @@@ float default_weapon_alpha
  .float() customizeentityforclient;
  .float cvar_cl_handicap;
  .float cvar_cl_playerdetailreduction;
 -.float cvar_scr_centertime;
  .string cvar_g_xonoticversion;
  .string cvar_cl_weaponpriority;
  .string cvar_cl_weaponpriorities[10];
@@@ -364,6 -368,10 +364,6 @@@ void FixClientCvars(entity e)
  
  float weaponsInMap;
  
 -void centerprint_atprio(entity e, float prio, string s);
 -void centerprint_expire(entity e, float prio);
 -void centerprint(entity e, string s);
 -
  .float respawn_countdown; // next number to count
  
  float bot_waypoints_for_items;
@@@ -597,7 -605,7 +597,7 @@@ float client_cefc_accumulatortime
  
  ..float current_ammo;
  
- .float weapon_load[WEP_MAXCOUNT]; FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(weapon_load);
+ .float weapon_load[WEP_MAXCOUNT];
  .float ammo_none; // used by the reloading system, must always be 0
  .float clip_load;
  .float old_clip_load;
diff --combined qcsrc/server/g_world.qc
index 82290cf540bf399fd7c8c7c10dbc0ba14a031902,047d2c0be61a8d1bc26e8161fa2ebaf0be0409cd..58f53c05d1e0a4ad4a3d27d21fa1011acf46c322
@@@ -101,13 -101,15 +101,13 @@@ void fteqcc_testbugs(
   * players. Also plays reminder sounds.
   */
  void timeoutHandler_Think() {
 -      local string timeStr;
        local entity plr;
        if (timeoutStatus == 1) {
                if (remainingLeadTime > 0) {
                        //centerprint the information to every player
 -                      timeStr = getTimeoutText(0);
                        FOR_EACH_REALCLIENT(plr) {
                                if(plr.classname == "player") {
 -                                      centerprint_atprio(plr, CENTERPRIO_SPAM, timeStr);
 +                                      Send_CSQC_Centerprint_Generic(plr, CPID_TIMEOUT_COUNTDOWN, "Timeout begins in %d seconds!", 1, remainingLeadTime);
                                }
                        }
                        remainingLeadTime -= 1;
        }
        else if (timeoutStatus == 2) {
                if (remainingTimeoutTime > 0) {
 -                      timeStr = getTimeoutText(0);
                        FOR_EACH_REALCLIENT(plr) {
                                if(plr.classname == "player") {
 -                                      centerprint_atprio(plr, CENTERPRIO_SPAM, timeStr);
 +                                      Send_CSQC_Centerprint_Generic(plr, CPID_TIMEOUT_COUNTDOWN, "Timeout ends in %d seconds!", 1, remainingTimeoutTime);
                                }
                        }
                        if(remainingTimeoutTime == autocvar_sv_timeout_resumetime) { //play a warning sound when only <sv_timeout_resumetime> seconds are left
                        //get rid of the countdown message
                        FOR_EACH_REALCLIENT(plr) {
                                if(plr.classname == "player") {
 -                                      centerprint_atprio(plr, CENTERPRIO_SPAM, "");
 +                                      Send_CSQC_Centerprint_Generic_Expire(plr, CPID_TIMEOUT_COUNTDOWN);
                                }
                        }
                        remove(self);
        else if (timeoutStatus == 0) { //if a player called the resumegame command (which set timeoutStatus to 0 already)
                FOR_EACH_REALCLIENT(plr) {
                        if(plr.classname == "player") {
 -                              centerprint_atprio(plr, CENTERPRIO_SPAM, "");
 +                              Send_CSQC_Centerprint_Generic_Expire(plr, CPID_TIMEOUT_COUNTDOWN);
                        }
                }
                remove(self);
@@@ -1191,7 -1194,7 +1191,7 @@@ void Maplist_Init(
        if(Map_Count == 0)
        {
                bprint( "Maplist is empty!  Resetting it to default map list.\n" );
-               cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
+               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
                if(autocvar_g_maplist_shuffle)
                        ShuffleMaplist();
                localcmd("\nmenu_cmd sync\n");
@@@ -1311,7 -1314,7 +1311,7 @@@ void GotoNextMap(
                        if(allowReset)
                        {
                                bprint( "Maplist contains no single playable map!  Resetting it to default map list.\n" );
-                               cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
+                               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
                                if(autocvar_g_maplist_shuffle)
                                        ShuffleMaplist();
                                localcmd("\nmenu_cmd sync\n");
@@@ -2296,7 -2299,6 +2296,6 @@@ string mapvote_maps_pakfile[MAPVOTE_COU
  float mapvote_maps_suggested[MAPVOTE_COUNT];
  string mapvote_suggestions[MAPVOTE_COUNT];
  float mapvote_suggestion_ptr;
- float mapvote_maxlen;
  float mapvote_voters;
  float mapvote_votes[MAPVOTE_COUNT];
  float mapvote_run;
@@@ -2358,8 -2360,10 +2357,10 @@@ void MapVote_AddVotable(string nextMap
        for(j = 0; j < mapvote_count; ++j)
                if(mapvote_maps[j] == nextMap)
                        return;
-       if(strlen(nextMap) > mapvote_maxlen)
-               mapvote_maxlen = strlen(nextMap);
+       // suggestions might be no longer valid/allowed after gametype switch!
+       if(isSuggestion)
+               if(!MapInfo_CheckMap(nextMap))
+                       return;
        mapvote_maps[mapvote_count] = strzone(nextMap);
        mapvote_maps_suggested[mapvote_count] = isSuggestion;
  
@@@ -2421,7 -2425,7 +2422,7 @@@ void MapVote_Init(
        if(mapvote_count == 0)
        {
                bprint( "Maplist contains no single playable map!  Resetting it to default map list.\n" );
-               cvar_set("g_maplist", MapInfo_ListAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
+               cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags()));
                if(autocvar_g_maplist_shuffle)
                        ShuffleMaplist();
                localcmd("\nmenu_cmd sync\n");
index b94238036bfab813cd349ccac93b9fe8972339e4,9d671fc50b77e2d49cd0c4f865d3cd0f04aa581e..5797effcd333bf2cc581a542606140c4b32cfb99
@@@ -579,6 -579,7 +579,6 @@@ void GetCvars(float f
        MUTATOR_CALLHOOK(GetCvars);
        GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
        GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
 -      GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
        GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
        GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
        GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
@@@ -717,6 -718,46 +717,6 @@@ float NumberToTeamNumber(float number
        return -1;
  }
  
 -#define CENTERPRIO_POINT 1
 -#define CENTERPRIO_SPAM 2
 -#define CENTERPRIO_VOTE 4
 -#define CENTERPRIO_NORMAL 5
 -#define CENTERPRIO_SHIELDING 7
 -#define CENTERPRIO_MAPVOTE 9
 -#define CENTERPRIO_IDLEKICK 50
 -#define CENTERPRIO_ADMIN 99
 -.float centerprint_priority;
 -.float centerprint_expires;
 -void centerprint_atprio(entity e, float prio, string s)
 -{
 -    if (intermission_running)
 -        if (prio < CENTERPRIO_MAPVOTE)
 -            return;
 -    if (time > e.centerprint_expires)
 -        e.centerprint_priority = 0;
 -    if (prio >= e.centerprint_priority)
 -    {
 -        e.centerprint_priority = prio;
 -        if (timeoutStatus == 2)
 -            e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
 -        else
 -            e.centerprint_expires = time + e.cvar_scr_centertime;
 -        centerprint_builtin(e, s);
 -    }
 -}
 -void centerprint_expire(entity e, float prio)
 -{
 -    if (prio == e.centerprint_priority)
 -    {
 -        e.centerprint_priority = 0;
 -        centerprint_builtin(e, "");
 -    }
 -}
 -void centerprint(entity e, string s)
 -{
 -    centerprint_atprio(e, CENTERPRIO_NORMAL, s);
 -}
 -
  // decolorizes and team colors the player name when needed
  string playername(entity p)
  {
@@@ -1659,30 -1700,6 +1659,30 @@@ void precache(
  #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)
 +      {
 +              msg_entity = e;
 +              WRITESPECTATABLE_MSG_ONE({
 +                      WriteByte(MSG_ONE, SVC_TEMPENTITY);
 +                      WriteByte(MSG_ONE, TE_CSQC_NOTIFY);
 +                      WriteByte(MSG_ONE, 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()
@@@ -2022,7 -2039,7 +2022,7 @@@ float WarpZone_Projectile_Touch_ImpactF
                return TRUE;
        }
        if(trace_ent && trace_ent.solid > SOLID_TRIGGER)
-               UpdateCSQCProjectileNextFrame(self);
+               UpdateCSQCProjectile(self);
        return FALSE;
  }
  #define PROJECTILE_TOUCH if(WarpZone_Projectile_Touch()) return
index 4b937dba2fe189594e4521ea9b28b802cbcc8192,e71c2d7ef6ecd20f04faa06627c041f7673ed225..8d3511eceda0750e74266d5649133b69f9c15e84
@@@ -78,7 -78,7 +78,7 @@@ void ka_RespawnBall() // runs whenever 
                WaypointSprite_Spawn("ka-ball", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAGCARRIER, '0 1 1');
                WaypointSprite_Ping(self.waypointsprite_attachedforcarrier);    
  
-               sound(self, CH_TRIGGER_SINGLE, "keepaway/respawn.wav", VOL_BASE, ATTN_NONE); // ATTN_NONE (it's a sound intended to be heard anywhere) 
+               sound(self, CH_TRIGGER, "keepaway/respawn.wav", VOL_BASE, ATTN_NONE); // ATTN_NONE (it's a sound intended to be heard anywhere) 
        }
        else
        {
@@@ -99,7 -99,7 +99,7 @@@ void ka_TouchEvent() // runs any time t
        if(other.classname != "player") 
        {  // The ball just touched an object, most likely the world
                pointparticles(particleeffectnum("kaball_sparks"), self.origin, '0 0 0', 1);
-               sound(self, CH_TRIGGER_SINGLE, "keepaway/touch.wav", VOL_BASE, ATTN_NORM);
+               sound(self, CH_TRIGGER, "keepaway/touch.wav", VOL_BASE, ATTN_NORM);
                return; 
        }
        else if(self.wait > time) { return; }
        // messages and sounds
        Send_KillNotification(other.netname, "", "", KA_PICKUPBALL, MSG_KA);
        WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
 -      WriteString(MSG_BROADCAST, strcat("\n\n", other.netname, "^7 has picked up the ball!\n"));
 +      WriteString(MSG_BROADCAST, strcat(other.netname, "^7 has picked up the ball!"));
        sound(self.owner, CH_TRIGGER, "keepaway/pickedup.wav", VOL_BASE, ATTN_NONE); // ATTN_NONE (it's a sound intended to be heard anywhere) 
        
        // scoring
@@@ -169,8 -169,8 +169,8 @@@ void ka_DropEvent(entity plyr) // runs 
        // messages and sounds
        Send_KillNotification(plyr.netname, "", "", KA_DROPBALL, MSG_KA);
        WriteByte(MSG_BROADCAST, SVC_CENTERPRINT);
 -      WriteString(MSG_BROADCAST, strcat("\n\n", plyr.netname, "^7 has dropped the ball!\n"));
 -      sound(plyr, CH_TRIGGER, "keepaway/dropped.wav", VOL_BASE, ATTN_NONE);   // ATTN_NONE (it's a sound intended to be heard anywhere) 
 +      WriteString(MSG_BROADCAST, strcat(plyr.netname, "^7 has dropped the ball!"));
 +      sound(other, CH_TRIGGER, "keepaway/dropped.wav", VOL_BASE, ATTN_NONE);  // ATTN_NONE (it's a sound intended to be heard anywhere) 
        
        // scoring
        // PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
@@@ -216,7 -216,7 +216,7 @@@ MUTATOR_HOOKFUNCTION(ka_Scoring
                }
                else if(!frag_attacker.ballcarried)
                        if(autocvar_g_keepaway_noncarrier_warn)
 -                              centerprint_atprio(frag_attacker, (CENTERPRIO_SPAM + 5), "Killing people while you don't have the ball gives no points!");
 +                              centerprint(frag_attacker, "Killing people while you don't have the ball gives no points!");
  
                if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier
                        PlayerScore_Add(frag_attacker, SP_SCORE, autocvar_g_keepaway_score_killac);
diff --combined qcsrc/server/t_items.qc
index ec39afcc8c9ccd5c89ead9c8363def8fbea16dc7,99ddc018b95a08352eabb2df2a3ac8fc14b276fc..b502cac3312d051d46c4f044516f78c1d4ff80eb
@@@ -146,11 -146,11 +146,11 @@@ void Item_Respawn (void
  {
        Item_Show(self, 1);
        if(!g_minstagib && self.items == IT_STRENGTH)
-               sound (self, CH_TRIGGER_SINGLE, "misc/strength_respawn.wav", VOL_BASE, ATTN_NORM);      // play respawn sound
+               sound (self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTN_NORM);     // play respawn sound
        else if(!g_minstagib && self.items == IT_INVINCIBLE)
-               sound (self, CH_TRIGGER_SINGLE, "misc/shield_respawn.wav", VOL_BASE, ATTN_NORM);        // play respawn sound
+               sound (self, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTN_NORM);       // play respawn sound
        else
-               sound (self, CH_TRIGGER_SINGLE, "misc/itemrespawn.wav", VOL_BASE, ATTN_NORM);   // play respawn sound
+               sound (self, CH_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTN_NORM);  // play respawn sound
        setorigin (self, self.origin);
  
        //pointparticles(particleeffectnum("item_respawn"), self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
@@@ -203,7 -203,7 +203,7 @@@ void Item_RespawnCountdown (void
                                        WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
                        }
                }
-               sound (self, CH_TRIGGER_SINGLE, "misc/itemrespawncountdown.wav", VOL_BASE, ATTN_NORM);  // play respawn sound
+               sound (self, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTN_NORM); // play respawn sound
                if(self.waypointsprite_attached)
                {
                        WaypointSprite_Ping(self.waypointsprite_attached);
@@@ -279,6 -279,7 +279,6 @@@ float Item_GiveTo(entity item, entity p
                        {
                                pickedup = TRUE;
                                // play some cool sounds ;)
 -                              centerprint(player, "\n");
                                if (clienttype(player) == CLIENTTYPE_REAL)
                                {
                                        if(player.health <= 5)
diff --combined qcsrc/server/vote.qc
index ebb11a64d62d7696d764e3cd935dc52d9fa91914,1690cf437b828c9f91538af05a4b982ab0827caf..65468a3b6204c750a5ff0fac0473b97778131c18
@@@ -116,18 -116,6 +116,6 @@@ float RemapVote(string vote, string cmd
        return TRUE;
  }
  
- void VoteDialog_UpdateHighlight(float selected) {
-       WriteByte(MSG_ONE, SVC_TEMPENTITY);
-       WriteByte(MSG_ONE, TE_CSQC_VOTE);
-       WriteByte(MSG_ONE, 1);
-       WriteByte(MSG_ONE, selected);
- }
- void VoteDialog_Reset() {
-       WriteByte(MSG_ALL, SVC_TEMPENTITY);
-       WriteByte(MSG_ALL, TE_CSQC_VOTERESET);
- }
  float GameCommand_Vote(string s, entity e) {
        local float playercount;
        float argc;
                                                bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2 calls a vote for ", votecalledvote_display, "\n");
                                                if(autocvar_sv_eventlog)
                                                        GameLogEcho(strcat(":vote:vcall:", ftos(votecaller.playerid), ":", votecalledvote_display));
-                                               VoteCount(); // needed if you are the only one
                                                Nagger_VoteChanged();
+                                               VoteCount(); // needed if you are the only one
                                                msg_entity = e;
-                                               VoteDialog_UpdateHighlight(1);
  
                                                local entity player;
                                                FOR_EACH_REALCLIENT(player)
                        if(!votecalled) {
                                print_to(e, "^1No vote called.");
                        } else if(e == votecaller) { // the votecaller can stop a vote
-                               VoteDialog_Reset();
                                VoteStop(e);
                        } else if(!e) { // server admin / console can too
-                               VoteDialog_Reset();
                                VoteStop(e);
                        } else if(e.vote_master) { // masters can too
-                               VoteDialog_Reset();
                                VoteStop(e);
                        } else {
                                print_to(e, "^1You are not allowed to stop that Vote.");
                                        bprint("\{1}^2* ^3", VoteNetname(votecaller), "^2 calls a vote to become ^3master^2.\n");
                                        if(autocvar_sv_eventlog)
                                                GameLogEcho(strcat(":vote:vcall:", ftos(votecaller.playerid), ":", votecalledvote_display));
-                                       VoteCount(); // needed if you are the only one
                                        Nagger_VoteChanged();
+                                       VoteCount(); // needed if you are the only one
                                }
                        } else {
                                print_to(e, "^1Vote to become master is NOT allowed.");
                        } else if(e.vote_vote == 0
                                  || autocvar_sv_vote_change) {
                                msg_entity = e;
-                               VoteDialog_UpdateHighlight(1);
                                print_to(e, "^1You accepted the vote.");
                                e.vote_vote = 1;
 -                              centerprint_expire(e, CENTERPRIO_VOTE);
                                if(!autocvar_sv_vote_singlecount) {
                                        VoteCount();
                                }
                        } else if(e.vote_vote == 0
                                  || autocvar_sv_vote_change) {
                                msg_entity = e;
-                               VoteDialog_UpdateHighlight(2);
                                print_to(e, "^1You rejected the vote.");
                                e.vote_vote = -1;
 -                              centerprint_expire(e, CENTERPRIO_VOTE);
                                if(!autocvar_sv_vote_singlecount) {
                                        VoteCount();
                                }
                        } else if(e.vote_vote == 0
                                  || autocvar_sv_vote_change) {
                                msg_entity = e;
-                               VoteDialog_UpdateHighlight(3);
                                print_to(e, "^1You abstained from your vote.");
                                e.vote_vote = -2;
 -                              centerprint_expire(e, CENTERPRIO_VOTE);
                                if(!autocvar_sv_vote_singlecount) {
                                        VoteCount();
                                }
@@@ -463,6 -447,7 +444,6 @@@ void VoteReset() 
        FOR_EACH_CLIENT(player)
        {
                player.vote_vote = 0;
 -              centerprint_expire(player, CENTERPRIO_VOTE);
        }
  
        if(votecalled)
@@@ -521,54 -506,42 +502,42 @@@ void VoteStop(entity stopper) 
        VoteReset();
  }
  
- void VoteSpam(float yescount, float nocount, float abstaincount, float notvoters, float mincount, string result)
+ void VoteSpam(float notvoters, float mincount, string result)
  {
        string s;
        if(mincount >= 0)
        {
-               s = strcat("\{1}^2* vote results: ^1", ftos(yescount), "^2:^1");
-               s = strcat(s, ftos(nocount), "^2 (^1");
+               s = strcat("\{1}^2* vote results: ^1", ftos(vote_yescount), "^2:^1");
+               s = strcat(s, ftos(vote_nocount), "^2 (^1");
                s = strcat(s, ftos(mincount), "^2 needed), ^1");
-               s = strcat(s, ftos(abstaincount), "^2 didn't care, ^1");
+               s = strcat(s, ftos(vote_abstaincount), "^2 didn't care, ^1");
                s = strcat(s, ftos(notvoters), "^2 didn't vote\n");
        }
        else
        {
-               s = strcat("\{1}^2* vote results: ^1", ftos(yescount), "^2:^1");
-               s = strcat(s, ftos(nocount), "^2, ^1");
-               s = strcat(s, ftos(abstaincount), "^2 didn't care, ^1");
+               s = strcat("\{1}^2* vote results: ^1", ftos(vote_yescount), "^2:^1");
+               s = strcat(s, ftos(vote_nocount), "^2, ^1");
+               s = strcat(s, ftos(vote_abstaincount), "^2 didn't care, ^1");
                s = strcat(s, ftos(notvoters), "^2 didn't have to vote\n");
        }
        bprint(s);
        if(autocvar_sv_eventlog)
        {
-               s = strcat(":vote:v", result, ":", ftos(yescount));
-               s = strcat(s, ":", ftos(nocount));
-               s = strcat(s, ":", ftos(abstaincount));
+               s = strcat(":vote:v", result, ":", ftos(vote_yescount));
+               s = strcat(s, ":", ftos(vote_nocount));
+               s = strcat(s, ":", ftos(vote_abstaincount));
                s = strcat(s, ":", ftos(notvoters));
                s = strcat(s, ":", ftos(mincount));
                GameLogEcho(s);
        }
  }
  
- void VoteDialog_Update(float msg, float vyes, float vno, float needed) {
-       WriteByte(msg, SVC_TEMPENTITY);
-       WriteByte(msg, TE_CSQC_VOTE);
-       WriteByte(msg, 0);
-       WriteByte(msg, vyes);
-       WriteByte(msg, vno);
-       WriteByte(msg, needed);
- }
  void VoteCount() {
        local float playercount;
        playercount = 0;
-       local float yescount;
-       yescount = 0;
-       local float nocount;
-       nocount = 0;
-       local float abstaincount;
-       abstaincount = 0;
+       vote_yescount = 0;
+       vote_nocount = 0;
+       vote_abstaincount = 0;
        local entity player;
        //same for real players
        local float realplayercount;
        local float realplayerabstaincount;
        realplayercount = realplayernocount = realplayerabstaincount = realplayeryescount = 0;
  
+       Nagger_VoteCountChanged();
        FOR_EACH_REALCLIENT(player)
        {
                if(player.vote_vote == -1) {
-                       ++nocount;
+                       ++vote_nocount;
                } else if(player.vote_vote == 1) {
-                       ++yescount;
+                       ++vote_yescount;
                } else if(player.vote_vote == -2) {
-                       ++abstaincount;
+                       ++vote_abstaincount;
                }
                ++playercount;
                //do the same for real players
        //in tournament mode, if we have at least one player then don't make the vote dependent on spectators (so specs don't have to press F1)
        if(autocvar_sv_vote_nospectators)
        if(realplayercount > 0) {
-               yescount = realplayeryescount;
-               nocount = realplayernocount;
-               abstaincount = realplayerabstaincount;
+               vote_yescount = realplayeryescount;
+               vote_nocount = realplayernocount;
+               vote_abstaincount = realplayerabstaincount;
                playercount = realplayercount;
        }
  
        float votefactor, simplevotefactor;
        votefactor = bound(0.5, autocvar_sv_vote_majority_factor, 0.999);
        simplevotefactor = autocvar_sv_vote_simple_majority_factor;
-       float needed;
-       needed = floor((playercount - abstaincount) * max(votefactor, simplevotefactor)) + 1;
-       VoteDialog_Update(MSG_ALL, yescount, nocount, needed);
+       // FIXME this number is a guess
+       vote_needed_absolute = floor((playercount - vote_abstaincount) * votefactor) + 1;
+       if(simplevotefactor)
+       {
+               simplevotefactor = bound(votefactor, simplevotefactor, 0.999);
+               vote_needed_simple = floor((vote_yescount + vote_nocount) * simplevotefactor) + 1;
+       }
+       else
+               vote_needed_simple = 0;
  
        if(votecalledmaster
           && playercount == 1) {
                }
                VoteReset();
        } else {
-               if(yescount > (playercount - abstaincount) * votefactor)
+               if(vote_yescount >= vote_needed_absolute)
                {
-                       VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, -1, "yes");
+                       VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, -1, "yes");
                        VoteAccept();
-                       VoteDialog_Reset();
                }
-               else if(nocount >= (playercount - abstaincount) * (1 - votefactor)) // that means, yescount cannot reach minyes any more
+               else if(vote_nocount > playercount - vote_abstaincount - vote_needed_absolute) // that means, vote_yescount cannot reach vote_needed_absolute any more
                {
-                       VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, -1, "no");
+                       VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, -1, "no");
                        VoteReject();
-                       VoteDialog_Reset();
                }
                else if(time > votefinished)
                {
                        if(simplevotefactor)
                        {
                                string result;
-                               simplevotefactor = bound(votefactor, simplevotefactor, 0.999);
-                               if(yescount > (yescount + nocount) * simplevotefactor)
+                               if(vote_yescount >= vote_needed_simple)
                                        result = "yes";
-                               else if(yescount + nocount > 0)
+                               else if(vote_yescount + vote_nocount > 0)
                                        result = "no";
                                else
                                        result = "timeout";
-                               VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, floor(min((playercount - abstaincount) * votefactor, (yescount + nocount) * simplevotefactor)) + 1, result);
+                               VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, min(vote_needed_absolute, vote_needed_simple), result);
                                if(result == "yes")
                                        VoteAccept();
                                else if(result == "no")
                        }
                        else
                        {
-                               VoteSpam(yescount, nocount, abstaincount, playercount - yescount - nocount - abstaincount, floor((playercount - abstaincount) * votefactor) + 1, "timeout");
+                               VoteSpam(playercount - vote_yescount - vote_nocount - vote_abstaincount, vote_needed_absolute, "timeout");
                                VoteTimeout();
                        }
-               VoteDialog_Reset();
                }
        }
  }
index 51153a15f92f2a8d2ae3804cdc533ec488aeb061,54dd5a6ce8281c2c852f04dd52a7aa91d204142d..16cbdcded3778eb1bb7988991ecbeb39a11c54ec
@@@ -88,80 -88,77 +88,80 @@@ void W_MinstaNex_Attack (void
  
  
  .float minstagib_nextthink;
 -void minstagib_ammocheck (void)
 +.float minstagib_needammo;
 +void minstagib_stop_countdown(void)
  {
 -      if (time < self.minstagib_nextthink || self.deadflag || gameover)
 +      if (self.minstagib_needammo)
 +      {
 +              self.health = 100;
 +              Send_CSQC_Centerprint_Generic_Expire(self, CPID_MINSTA_FINDAMMO);
 +      }
 +      self.minstagib_needammo = FALSE;
 +}
 +void minstagib_ammocheck(void)
 +{
 +      if (time < self.minstagib_nextthink)
                return;
  
 -      if (self.ammo_cells <= 0)
 -      if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
 +      if (self.deadflag || gameover || self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO))
 +              minstagib_stop_countdown();
 +      else
        {
 +              self.minstagib_needammo = TRUE;
                if (self.health == 5)
                {
 -                      centerprint(self, "you're dead now...\n");
                        Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "terminated");
                }
                else if (self.health == 10)
                {
 -                      centerprint(self, "^11^7 second left to find some ammo\n");
                        Damage(self, self, self, 5, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "1");
                }
                else if (self.health == 20)
                {
 -                      centerprint(self, "^12^7 seconds left to find some ammo\n");
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "2");
                }
                else if (self.health == 30)
                {
 -                      centerprint(self, "^13^7 seconds left to find some ammo\n");
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "3");
                }
                else if (self.health == 40)
                {
 -                      centerprint(self, "^14^7 seconds left to find some ammo\n");
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "4");
                }
                else if (self.health == 50)
                {
 -                      centerprint(self, "^15^7 seconds left to find some ammo\n");
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "5");
                }
                else if (self.health == 60)
                {
 -                      centerprint(self, "^36^7 seconds left to find some ammo\n");
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "6");
                }
                else if (self.health == 70)
                {
 -                      centerprint(self, "^37^7 seconds left to find some ammo\n");
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "7");
                }
                else if (self.health == 80)
                {
 -                      centerprint(self, "^38^7 seconds left to find some ammo\n");
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "8");
                }
                else if (self.health == 90)
                {
 -                      centerprint(self, "^39^7 seconds left to find some ammo\n");
 +                      Send_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "^1%d^7 seconds left to find some ammo", 1, 9);
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        AnnounceTo(self, "9");
                }
                else if (self.health == 100)
                {
 -                      centerprint(self, "get some ammo or\nyou'll be dead in ^310^7 seconds...");
 +                      Send_CSQC_Centerprint_Generic(self, CPID_MINSTA_FINDAMMO, "get some ammo or\nyou'll be dead in ^3%d^7 seconds...", 1, 10);
                        Damage(self, self, self, 10, DEATH_NOAMMO, self.origin, '0 0 0');
                        if not(self.flags & FL_GODMODE)
                                AnnounceTo(self, "10");
@@@ -283,7 -280,7 +283,7 @@@ float w_minstanex(float req
                org2 = w_org + w_backoff * 6;
                pointparticles(particleeffectnum("nex_impact"), org2, '0 0 0', 1);
                if(!w_issilent)
-                       sound(self, CH_SHOTS_SINGLE, "weapons/neximpact.wav", VOL_BASE, ATTN_NORM);
+                       sound(self, CH_SHOTS, "weapons/neximpact.wav", VOL_BASE, ATTN_NORM);
        }
        else if(req == WR_PRECACHE)
        {