]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/ons_updates
authorMario <zacjardine@y7mail.com>
Tue, 18 Aug 2015 23:18:14 +0000 (09:18 +1000)
committerMario <zacjardine@y7mail.com>
Tue, 18 Aug 2015 23:18:14 +0000 (09:18 +1000)
# Conflicts:
# qcsrc/client/waypointsprites.qc
# qcsrc/common/constants.qh
# qcsrc/common/stats.qh

22 files changed:
1  2 
defaultXonotic.cfg
gamemodes.cfg
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/hud.qh
qcsrc/client/hud_config.qc
qcsrc/client/main.qc
qcsrc/client/mapvoting.qc
qcsrc/client/progs.src
qcsrc/client/scoreboard.qc
qcsrc/client/view.qc
qcsrc/client/waypointsprites.qc
qcsrc/common/constants.qh
qcsrc/common/mapinfo.qh
qcsrc/common/notifications.qh
qcsrc/common/stats.qh
qcsrc/server/autocvars.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_world.qc
qcsrc/server/progs.src
qcsrc/server/teamplay.qc
qcsrc/server/waypointsprites.qc

diff --combined defaultXonotic.cfg
index 470bfee2352d0767f208ea0a031089f6cc823a7a,45c920195ede5f95c6f1e68fd9bdf2063d00a5d6..294d8bd04f2f2731243e77202f4761e2861f693d
@@@ -72,7 -72,7 +72,7 @@@ seta cl_velocityzoom_time 0.2 "time val
  seta cl_spawnzoom 1 "zoom effect immediately when a player spawns"
  seta cl_spawnzoom_speed 1 "speed at which zooming occurs while spawning"
  seta cl_spawnzoom_factor 2 "factor of zoom while spawning"
- seta cl_zoomfactor 5  "how much +zoom will zoom (1-16)"
+ seta cl_zoomfactor 5  "how much +zoom will zoom (1-30)"
  seta cl_zoomspeed 8   "how fast it will zoom (0.5-16), negative values mean instant zoom"
  seta cl_zoomsensitivity 0     "how zoom changes sensitivity (0 = weakest, 1 = strongest)"
  
@@@ -234,12 -234,10 +234,12 @@@ seta cl_hitsound_nom_damage 25 "damage 
  seta cl_eventchase_death 1 "camera goes into 3rd person mode when the player is dead; set to 2 to active the effect only when the corpse doesn't move anymore"
  seta cl_eventchase_nexball 1 "camera goes into 3rd person mode when in nexball game-mode"
  seta cl_eventchase_distance 140 "final camera distance"
 +seta cl_eventchase_distance 400 "final camera distance while viewing generator explosion"
  seta cl_eventchase_speed 1.3 "how fast the camera slides back, 0 is instant"
  seta cl_eventchase_maxs "12 12 8" "max size of eventchase camera bbox"
  seta cl_eventchase_mins "-12 -12 -8" "min size of eventchase camera bbox"
  seta cl_eventchase_viewoffset "0 0 20" "viewoffset of eventchase camera"
 +seta cl_eventchase_generator_viewoffset "0 0 80" "viewoffset of eventchase camera while viewing generator explosion"
  
  //nifreks lockonrestart feature, used in team-based game modes, if set to 1 and all players readied up no other player can then join the game anymore, useful to block spectators from joining
  set teamplay_lockonrestart 0 "it set to 1 in a team-based game, the teams are locked once all players readied up and the game restarted (no new players can join after restart unless using the server-command unlockteams)"
@@@ -760,6 -758,7 +760,7 @@@ seta g_waypointsprite_crosshairfadedist
  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"
+ seta g_waypointsprite_itemstime 2 "show waypoints to indicate that some important items (mega health, large armor) are about to respawn: 1 when spectating, 2 even playing in warmup stage"
  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"
@@@ -781,6 -780,8 +782,8 @@@ seta g_waypointsprite_turrets 1 "disabl
  seta g_waypointsprite_turrets_maxdist 5000 "max distace for turret sprites"
  seta g_waypointsprite_tactical 1 "tactical overlay on turrets when in a vehicle"
  
+ set sv_itemstime 1 "enable networking of left time until respawn for items such as mega health and large armor"
  // so it can be stuffcmd-ed still
  set cl_gravity 800    "but ignored anyway"
  
@@@ -1134,11 -1135,6 +1137,6 @@@ set g_mapinfo_settemp_acl "+*" "ACL fo
  
  seta cl_casings_maxcount 100 "maximum amount of shell casings (must be at least 1)"
  seta cl_gibs_maxcount 100 "maximum amount of gibs (must be at least 1)"
- seta cl_vehicle_spiderbot_cross_alpha 0.6
- seta cl_vehicle_spiderbot_cross_size 1
- seta cl_vehicles_hudscale 0.5
- seta cl_vehicles_hudalpha 0.75
- seta cl_vehicles_hud_tactical 1
  
  //cl_gunalign calculator
  seta menu_cl_gunalign 3 "Gun alignment; 1 = center (if allowed by g_shootfromclient) or right, 2 = center (if allowed by g_shootfromclient) or left, 3 = right only, 4 = left only"
diff --combined gamemodes.cfg
index 547e7cbd1a905d2ebc16aa5126f90dabfa0ffbad,7f444e4448815763de060f518280d4ee50cdd237..340d01b9dcec368814affe8aaa70103b82945983
@@@ -254,6 -254,10 +254,10 @@@ set g_ca_teams 
  //  capture the flag
  // ==================
  set g_ctf 0 "Capture The Flag: take the enemy flag and bring it to yours at your base to score"
+ set g_ctf_oneflag 1 "Allow oneflag CTF mode on maps that support it"
+ set g_ctf_oneflag_reverse 0 "apply reverse mode to oneflag CTF (take flag to enemy bases to cap), overrides g_ctf_reverse only in oneflag, g_ctf_reverse still affects oneflag"
+ set g_ctf_flag_return 1 "auto return the flag to base when touched by a teammate"
+ set g_ctf_flag_return_carried_radius 100 "allow flags to be returned by carrier if base is within this radius"
  set g_ctf_flag_return_time 15
  set g_ctf_flag_return_dropped 100
  set g_ctf_flag_return_damage 0
@@@ -311,6 -315,12 +315,12 @@@ set g_ctf_flag_red_model "models/ctf/fl
  set g_ctf_flag_red_skin 0
  set g_ctf_flag_blue_model "models/ctf/flags.md3"
  set g_ctf_flag_blue_skin 1
+ set g_ctf_flag_yellow_model "models/ctf/flags.md3"
+ set g_ctf_flag_yellow_skin 2
+ set g_ctf_flag_pink_model "models/ctf/flags.md3"
+ set g_ctf_flag_pink_skin 3
+ set g_ctf_flag_neutral_model "models/ctf/flags.md3"
+ set g_ctf_flag_neutral_skin 4
  set g_ctf_flag_glowtrails 1
  set g_ctf_fullbrightflags 0
  set g_ctf_dynamiclights 0
@@@ -491,17 -501,7 +501,17 @@@ seta g_nexball_tackling 1 "Allow ball t
  //  onslaught
  // ===========
  set g_onslaught 0 "Onslaught: take control points towards the enemy generator and then destroy it"
 +set g_onslaught_point_limit 1 "Onslaught point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
 +set g_onslaught_warmup 5
 +set g_onslaught_round_timelimit 280
 +set g_onslaught_debug 0 "show debug prints in onslaught"
 +set g_onslaught_teleport_radius 200 "Allows teleporting from a control point to another"
 +set g_onslaught_teleport_wait 5 "Time before player can teleport again"
 +set g_onslaught_spawn_choose 1 "Allow players to choose the control point to be spawned at"
 +set g_onslaught_click_radius 500 "When choosing from the map, this level of precision is required"
 +
  set g_onslaught_gen_health 2500
 +set g_onslaught_allow_vehicle_touch 0
  set g_onslaught_cp_health 1000
  set g_onslaught_cp_buildhealth 100
  set g_onslaught_cp_buildtime 5
@@@ -509,13 -509,8 +519,13 @@@ set g_onslaught_cp_regen 2
  set g_onslaught_cp_proxydecap 0 "de-capture controlpoints by standing close to them"
  set g_onslaught_cp_proxydecap_distance 512
  set g_onslaught_cp_proxydecap_dps 100
 +set g_onslaught_shield_force 100
  set g_onslaught_spawn_at_controlpoints 0
 +set g_onslaught_spawn_at_controlpoints_chance 0.5
 +set g_onslaught_spawn_at_controlpoints_random 0
  set g_onslaught_spawn_at_generator 0
 +set g_onslaught_spawn_at_generator_chance 0
 +set g_onslaught_spawn_at_generator_random 0
  
  
  // ======
index 18e58e522a4e301503eea2129f2ebe2bbaadb537,1e6d7444afef449449215d9796152eee68e00180..848c5ffd0384515b3d0564469d982297ba36e729
@@@ -77,9 -77,9 +77,9 @@@ bool autocvar_cl_spawnzoom = 1
  float autocvar_cl_spawnzoom_speed = 1;
  float autocvar_cl_spawnzoom_factor = 2;
  bool autocvar_cl_stripcolorcodes;
- float autocvar_cl_vehicle_spiderbot_cross_alpha = 0.6;
- float autocvar_cl_vehicle_spiderbot_cross_size = 1;
  bool autocvar_cl_vehicles_hud_tactical = 1;
+ float autocvar_cl_vehicles_hudscale = 0.5;
+ float autocvar_cl_vehicles_crosshair_size = 0.5;
  bool autocvar_cl_velocityzoom_enabled;
  float autocvar_cl_velocityzoom_factor;
  int autocvar_cl_velocityzoom_type = 3;
@@@ -94,7 -94,6 +94,6 @@@ bool autocvar_cl_unpress_zoom_on_death 
  bool autocvar_cl_unpress_zoom_on_weapon_switch = 1;
  bool autocvar_cl_unpress_attack_on_weapon_switch = 1;
  bool autocvar_con_chat;
- float autocvar_con_chatpos;
  bool autocvar_con_chatrect;
  float autocvar_con_chatsize;
  float autocvar_con_chattime;
@@@ -173,6 -172,7 +172,7 @@@ float autocvar_g_waypointsprite_edgeoff
  float autocvar_g_waypointsprite_edgeoffset_right;
  float autocvar_g_waypointsprite_edgeoffset_top;
  float autocvar_g_waypointsprite_fontsize;
+ int autocvar_g_waypointsprite_itemstime;
  float autocvar_g_waypointsprite_minalpha;
  float autocvar_g_waypointsprite_minscale;
  float autocvar_g_waypointsprite_normdistance;
@@@ -269,6 -269,16 +269,16 @@@ float autocvar_hud_panel_healtharmor_pr
  float autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth;
  float autocvar_hud_panel_healtharmor_progressbar_gfx_smooth;
  int autocvar_hud_panel_healtharmor_text;
+ int autocvar_hud_panel_itemstime = 2;
+ float autocvar_hud_panel_itemstime_dynamicsize = 1;
+ float autocvar_hud_panel_itemstime_ratio = 2;
+ int autocvar_hud_panel_itemstime_iconalign;
+ bool autocvar_hud_panel_itemstime_progressbar = 0;
+ float autocvar_hud_panel_itemstime_progressbar_maxtime = 30;
+ string autocvar_hud_panel_itemstime_progressbar_name = "progressbar";
+ float autocvar_hud_panel_itemstime_progressbar_reduced;
+ bool autocvar_hud_panel_itemstime_hidespawned = 1;
+ int autocvar_hud_panel_itemstime_text = 1;
  bool autocvar_hud_panel_infomessages;
  bool autocvar_hud_panel_infomessages_flip;
  bool autocvar_hud_panel_modicons;
@@@ -302,14 -312,8 +312,8 @@@ bool autocvar_hud_panel_physics_topspee
  float autocvar_hud_panel_physics_topspeed_time;
  bool autocvar_hud_panel_powerups;
  int autocvar_hud_panel_powerups_baralign;
- bool autocvar_hud_panel_powerups_flip;
  int autocvar_hud_panel_powerups_iconalign;
  bool autocvar_hud_panel_powerups_progressbar;
- bool autocvar_hud_panel_buffs;
- //float autocvar_hud_panel_buffs_iconalign;
- string autocvar_hud_panel_powerups_progressbar_shield;
- string autocvar_hud_panel_powerups_progressbar_strength;
- string autocvar_hud_panel_powerups_progressbar_superweapons;
  bool autocvar_hud_panel_powerups_text;
  int autocvar_hud_panel_pressedkeys;
  float autocvar_hud_panel_pressedkeys_aspect;
@@@ -354,6 -358,8 +358,8 @@@ float autocvar_hud_panel_weapons_compla
  int autocvar_hud_panel_weapons_label;
  float autocvar_hud_panel_weapons_label_scale = 0.5;
  bool autocvar_hud_panel_weapons_onlyowned;
+ float autocvar_hud_panel_weapons_noncurrent_alpha = 1;
+ float autocvar_hud_panel_weapons_noncurrent_scale = 1;
  float autocvar_hud_panel_weapons_timeout;
  int autocvar_hud_panel_weapons_timeout_effect;
  float autocvar_hud_panel_weapons_timeout_fadebgmin;
@@@ -371,6 -377,8 +377,8 @@@ vector autocvar_hud_progressbar_shield_
  vector autocvar_hud_progressbar_speed_color;
  vector autocvar_hud_progressbar_strength_color;
  vector autocvar_hud_progressbar_superweapons_color;
+ vector autocvar_hud_progressbar_vehicles_ammo1_color;
+ vector autocvar_hud_progressbar_vehicles_ammo2_color;
  bool autocvar_hud_showbinds;
  bool autocvar_hud_showbinds_limit;
  bool autocvar__hud_showbinds_reload;
@@@ -433,8 -441,6 +441,8 @@@ float autocvar_cl_hitsound_nom_damage 
  float autocvar_cl_hitsound_antispam_time;
  int autocvar_cl_eventchase_death = 1;
  int autocvar_cl_eventchase_nexball = 1;
 +vector autocvar_cl_eventchase_generator_viewoffset = '0 0 80';
 +float autocvar_cl_eventchase_generator_distance = 400;
  float autocvar_cl_eventchase_distance = 140;
  float autocvar_cl_eventchase_speed = 1.3;
  vector autocvar_cl_eventchase_maxs = '12 12 8';
diff --combined qcsrc/client/hud.qc
index 06cf453346e5c3f531cbda5e67c28c511496d43e,8ea4155ae939242d66e672238c16905ba1272439..4146412280d173781f542e24662c3b6b18d66232
@@@ -2,20 -2,20 +2,23 @@@
  #include "_all.qh"
  
  #include "hud_config.qh"
 +#include "mapvoting.qh"
  #include "scoreboard.qh"
  #include "sortlist.qh"
  #include "teamradar.qh"
  #include "t_items.qh"
  
 +#include "../dpdefs/keycodes.qh"
 +
  #include "../common/buffs.qh"
  #include "../common/constants.qh"
  #include "../common/counting.qh"
  #include "../common/deathtypes.qh"
  #include "../common/mapinfo.qh"
  #include "../common/nades.qh"
+ #include "../server/mutators/gamemode_ctf.qh"
  #include "../common/stats.qh"
  
  #include "../csqcmodellib/cl_player.qh"
@@@ -162,7 -162,7 +165,7 @@@ float HUD_GetRowCount(int item_count, v
        return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
  }
  
- vector HUD_GetTableSize(int item_count, vector psize, float item_aspect)
+ vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect)
  {
        float columns, rows;
        float ratio, best_ratio = 0;
@@@ -507,7 -507,8 +510,8 @@@ void HUD_Weapons(void
        vector color;
  
        // check to see if we want to continue
-       if(hud != HUD_NORMAL) { return; }
+       if(intermission == 2) return;
+       if(hud != HUD_NORMAL) return;
  
        if(!autocvar__hud_configure)
        {
                vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
  
                // get the all-weapons layout
-               vector table_size = HUD_GetTableSize(WEP_COUNT, padded_panel_size, aspect);
+               vector table_size = HUD_GetTableSize_BestItemAR(WEP_COUNT, padded_panel_size, aspect);
                columns = table_size.x;
                rows = table_size.y;
                weapon_size.x = padded_panel_size.x / columns;
  
        if(!rows) // if rows is > 0 onlyowned code has already updated these vars
        {
-               vector table_size = HUD_GetTableSize(WEP_COUNT, panel_size, aspect);
+               vector table_size = HUD_GetTableSize_BestItemAR(WEP_COUNT, panel_size, aspect);
                columns = table_size.x;
                rows = table_size.y;
                weapon_size.x = panel_size.x / columns;
        // draw items
        row = column = 0;
        vector label_size = '1 1 0' * min(weapon_size.x, weapon_size.y) * bound(0, autocvar_hud_panel_weapons_label_scale, 1);
+       vector noncurrent_pos = '0 0 0';
+       vector noncurrent_size = weapon_size * bound(0, autocvar_hud_panel_weapons_noncurrent_scale, 1);
+       float noncurrent_alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_weapons_noncurrent_alpha, 1);
+       bool isCurrent;
        for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
        {
                // retrieve information about the current weapon to be drawn
                self = weaponorder[i];
                weapon_id = self.impulse;
+               isCurrent = (self.weapon == switchweapon);
  
                // skip if this weapon doesn't exist
                if(!self || weapon_id < 0) { continue; }
                        continue;
  
                // figure out the drawing position of weapon
-               weapon_pos = (panel_pos
-                       + eX * column * weapon_size.x
-                       + eY * row * weapon_size.y);
+               weapon_pos = (panel_pos + eX * column * weapon_size.x + eY * row * weapon_size.y);
+               noncurrent_pos.x = weapon_pos.x + (weapon_size.x - noncurrent_size.x) / 2;
+               noncurrent_pos.y = weapon_pos.y + (weapon_size.y - noncurrent_size.y) / 2;
  
                // draw background behind currently selected weapon
-               if(self.weapon == switchweapon)
+               if(isCurrent)
                        drawpic_aspect_skin(weapon_pos, "weapon_current_bg", weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
  
                // draw the weapon accuracy
                if(weapons_stat & WepSet_FromWeapon(self.weapon))
                {
                        // draw the weapon image
-                       drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                       if(isCurrent)
+                               drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                       else
+                               drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '1 1 1', noncurrent_alpha, DRAWFLAG_NORMAL);
  
                        // draw weapon label string
                        switch(autocvar_hud_panel_weapons_label)
                }
                else // draw a "ghost weapon icon" if you don't have the weapon
                {
-                       drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '0 0 0', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+                       drawpic_aspect_skin(noncurrent_pos, self.model2, noncurrent_size, '0.2 0.2 0.2', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
                }
  
                // draw the complain message
@@@ -968,8 -978,8 +981,8 @@@ void DrawAmmoNades(vector myPos, vecto
        float bonusNades    = getstatf(STAT_NADE_BONUS);
        float bonusProgress = getstatf(STAT_NADE_BONUS_SCORE);
        float bonusType     = getstati(STAT_NADE_BONUS_TYPE);
-       vector nadeColor    = Nade_Color(bonusType);
-       string nadeIcon     = Nade_Icon(bonusType);
+       vector nadeColor    = NADES[bonusType].m_color;
+       string nadeIcon     = NADES[bonusType].m_icon;
  
        vector iconPos, textPos;
  
@@@ -1075,6 -1085,7 +1088,7 @@@ int nade_prevframe
  float nade_statuschange_time;
  void HUD_Ammo(void)
  {
+       if(intermission == 2) return;
        if(hud != HUD_NORMAL) return;
        if(!autocvar__hud_configure)
        {
@@@ -1292,196 -1303,218 +1306,218 @@@ void DrawNumIcon(vector myPos, vector m
  
  // Powerups (#2)
  //
+ // Powerup item fields (reusing existing fields)
+ .string message;  // Human readable name
+ .string netname;  // Icon name
+ .vector colormod; // Color
+ .float count;     // Time left
+ .float lifetime;  // Maximum time
+ entity powerupItems;
+ int powerupItemsCount;
+ void resetPowerupItems()
+ {
+       entity item;
+       for(item = powerupItems; item; item = item.chain)
+               item.count = 0;
+       powerupItemsCount = 0;
+ }
+ void addPowerupItem(string name, string icon, vector color, float currentTime, float lifeTime)
+ {
+       if(!powerupItems)
+               powerupItems = spawn();
+       entity item;
+       for(item = powerupItems; item.count; item = item.chain)
+               if(!item.chain)
+                       item.chain = spawn();
+       item.message  = name;
+       item.netname  = icon;
+       item.colormod = color;
+       item.count    = currentTime;
+       item.lifetime = lifeTime;
+       ++powerupItemsCount;
+ }
+ int getPowerupItemAlign(int align, int column, int row, int columns, int rows, bool isVertical)
+ {
+       if(align < 2)
+               return align;
+       bool isTop    =  isVertical && rows > 1 && row == 0;
+       bool isBottom =  isVertical && rows > 1 && row == rows-1;
+       bool isLeft   = !isVertical && columns > 1 && column == 0;
+       bool isRight  = !isVertical && columns > 1 && column == columns-1;
+       if(isTop    || isLeft)  return (align == 2) ? 1 : 0;
+       if(isBottom || isRight) return (align == 2) ? 0 : 1;
+       return 2;
+ }
  void HUD_Powerups(void)
  {
-       float strength_time, shield_time, superweapons_time;
+       if(intermission == 2) return;
+       int allItems = getstati(STAT_ITEMS, 0, 24);
+       int allBuffs = getstati(STAT_BUFFS, 0, 24);
+       int strengthTime, shieldTime, superTime;
+       // Initialize items
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_powerups) return;
                if(spectatee_status == -1) return;
-               if(!(getstati(STAT_ITEMS, 0, 24) & (IT_STRENGTH | IT_INVINCIBLE | IT_SUPERWEAPON))) return;
-               if (getstati(STAT_HEALTH) <= 0) return;
+               if(getstati(STAT_HEALTH) <= 0) return;
+               if(!(allItems & (IT_STRENGTH | IT_INVINCIBLE | IT_SUPERWEAPON)) && !allBuffs) return;
  
-               strength_time = bound(0, getstatf(STAT_STRENGTH_FINISHED) - time, 99);
-               shield_time = bound(0, getstatf(STAT_INVINCIBLE_FINISHED) - time, 99);
-               superweapons_time = bound(0, getstatf(STAT_SUPERWEAPONS_FINISHED) - time, 99);
+               strengthTime = bound(0, getstatf(STAT_STRENGTH_FINISHED) - time, 99);
+               shieldTime = bound(0, getstatf(STAT_INVINCIBLE_FINISHED) - time, 99);
+               superTime = bound(0, getstatf(STAT_SUPERWEAPONS_FINISHED) - time, 99);
  
-               if (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_SUPERWEAPONS)
-                       superweapons_time = 99; // force max
+               if(allItems & IT_UNLIMITED_SUPERWEAPONS)
+                       superTime = 99;
  
-               // prevent stuff to show up on mismatch that will be fixed next frame
-               if (!(getstati(STAT_ITEMS, 0, 24) & IT_SUPERWEAPON))
-                       superweapons_time = 0;
+               // Prevent stuff to show up on mismatch that will be fixed next frame
+               if(!(allItems & IT_SUPERWEAPON))
+                       superTime = 0;
        }
        else
        {
-               strength_time = 15;
-               shield_time = 27;
-               superweapons_time = 13;
+               strengthTime = 15;
+               shieldTime = 27;
+               superTime = 13;
+               allBuffs = 0;
        }
  
-       HUD_Panel_UpdateCvars();
+       // Add items to linked list
+       resetPowerupItems();
  
-       draw_beginBoldFont();
+       if(strengthTime)
+               addPowerupItem("Strength", "strength", autocvar_hud_progressbar_strength_color, strengthTime, 30);
+       if(shieldTime)
+               addPowerupItem("Shield", "shield", autocvar_hud_progressbar_shield_color, shieldTime, 30);
+       if(superTime)
+               addPowerupItem("Superweapons", "superweapons", autocvar_hud_progressbar_superweapons_color, superTime, 30);
  
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
+       FOREACH(BUFFS, it.m_itemid & allBuffs, LAMBDA(
+               addPowerupItem(it.m_prettyName, strcat("buff_", it.m_name), it.m_color, bound(0, getstatf(STAT_BUFF_TIME) - time, 99), 60);
+       ));
+       if(!powerupItemsCount)
+               return;
+       // Draw panel background
+       HUD_Panel_UpdateCvars();
+       HUD_Panel_DrawBg(1);
+       // Set drawing area
+       vector pos = panel_pos;
+       vector size = panel_size;
+       bool isVertical = size.y > size.x;
  
-       HUD_Panel_DrawBg(bound(0, max(strength_time, shield_time, superweapons_time), 1));
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
+               size -= '2 2 0' * panel_bg_padding;
        }
  
-       float panel_ar = mySize.x/mySize.y;
-       bool is_vertical = (panel_ar < 1);
-       vector shield_offset = '0 0 0', strength_offset = '0 0 0', superweapons_offset = '0 0 0';
-       int superweapons_is = -1;
+       // Find best partitioning of the drawing area
+       const float DESIRED_ASPECT = 6;
+       float aspect = 0, a;
+       int columns = 0, c;
+       int rows = 0, r;
+       int i = 1;
  
-       if(superweapons_time)
+       do
        {
-               if(strength_time)
-               {
-                       if(shield_time)
-                               superweapons_is = 0;
-                       else
-                               superweapons_is = 2;
-               }
-               else
-               {
-                       if(shield_time)
-                               superweapons_is = 1;
-                       else
-                               superweapons_is = 2;
-               }
-       }
+               c = floor(powerupItemsCount / i);
+               r = ceil(powerupItemsCount / c);
+               a = isVertical ? (size.y/r) / (size.x/c) : (size.x/c) / (size.y/r);
  
-       // FIXME handle superweapons here
-       if(superweapons_is == 0)
-       {
-               if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
-               {
-                       mySize.x *= (1.0 / 3.0);
-                       superweapons_offset.x = mySize.x;
-                       if (autocvar_hud_panel_powerups_flip)
-                               shield_offset.x = 2*mySize.x;
-                       else
-                               strength_offset.x = 2*mySize.x;
-               }
-               else
+               if(i == 1 || fabs(DESIRED_ASPECT - a) < fabs(DESIRED_ASPECT - aspect))
                {
-                       mySize.y *= (1.0 / 3.0);
-                       superweapons_offset.y = mySize.y;
-                       if (autocvar_hud_panel_powerups_flip)
-                               shield_offset.y = 2*mySize.y;
-                       else
-                               strength_offset.y = 2*mySize.y;
+                       aspect = a;
+                       columns = c;
+                       rows = r;
                }
        }
-       else
+       while(++i <= powerupItemsCount);
+       // Prevent single items from getting too wide
+       if(powerupItemsCount == 1 && aspect > DESIRED_ASPECT)
        {
-               if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
+               if(isVertical)
                {
-                       mySize.x *= 0.5;
-                       if (autocvar_hud_panel_powerups_flip)
-                               shield_offset.x = mySize.x;
-                       else
-                               strength_offset.x = mySize.x;
+                       size.y *= 0.5;
+                       pos.y += size.y * 0.5;
                }
                else
                {
-                       mySize.y *= 0.5;
-                       if (autocvar_hud_panel_powerups_flip)
-                               shield_offset.y = mySize.y;
-                       else
-                               strength_offset.y = mySize.y;
+                       size.x *= 0.5;
+                       pos.x += size.x * 0.5;
                }
        }
  
-       bool shield_baralign, strength_baralign, superweapons_baralign;
-       bool shield_iconalign, strength_iconalign, superweapons_iconalign;
+       // Draw items from linked list
+       vector itemPos = pos;
+       vector itemSize = eX * (size.x / columns) + eY * (size.y / rows);
+       vector textColor = '1 1 1';
  
-       if (autocvar_hud_panel_powerups_flip)
-       {
-               strength_baralign = (autocvar_hud_panel_powerups_baralign == 2 || autocvar_hud_panel_powerups_baralign == 1);
-               shield_baralign = (autocvar_hud_panel_powerups_baralign == 3 || autocvar_hud_panel_powerups_baralign == 1);
-               strength_iconalign = (autocvar_hud_panel_powerups_iconalign == 2 || autocvar_hud_panel_powerups_iconalign == 1);
-               shield_iconalign = (autocvar_hud_panel_powerups_iconalign == 3 || autocvar_hud_panel_powerups_iconalign == 1);
-       }
-       else
-       {
-               shield_baralign = (autocvar_hud_panel_powerups_baralign == 2 || autocvar_hud_panel_powerups_baralign == 1);
-               strength_baralign = (autocvar_hud_panel_powerups_baralign == 3 || autocvar_hud_panel_powerups_baralign == 1);
-               shield_iconalign = (autocvar_hud_panel_powerups_iconalign == 2 || autocvar_hud_panel_powerups_iconalign == 1);
-               strength_iconalign = (autocvar_hud_panel_powerups_iconalign == 3 || autocvar_hud_panel_powerups_iconalign == 1);
-       }
+       int fullSeconds = 0;
+       int align = 0;
+       int column = 0;
+       int row = 0;
  
-       if(superweapons_is == 0)
-       {
-               superweapons_iconalign = strength_iconalign;
-               superweapons_baralign = 2;
-       }
-       else if(superweapons_is == 1)
-       {
-               superweapons_offset = strength_offset;
-               superweapons_iconalign = strength_iconalign;
-               superweapons_baralign = strength_baralign;
-       }
-       else // if(superweapons_is == 2)
+       draw_beginBoldFont();
+       for(entity item = powerupItems; item.count; item = item.chain)
        {
-               superweapons_offset = shield_offset;
-               superweapons_iconalign = shield_iconalign;
-               superweapons_baralign = shield_baralign;
-       }
+               itemPos = eX * (pos.x + column * itemSize.x) + eY * (pos.y + row * itemSize.y);
  
-       if(shield_time)
-       {
-               const float maxshield = 30;
-               float shield = ceil(shield_time);
+               // Draw progressbar
                if(autocvar_hud_panel_powerups_progressbar)
-                       HUD_Panel_DrawProgressBar(pos + shield_offset, mySize, autocvar_hud_panel_powerups_progressbar_shield, shield/maxshield, is_vertical, shield_baralign, autocvar_hud_progressbar_shield_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               if(autocvar_hud_panel_powerups_text)
                {
-                       if(shield > 1)
-                               DrawNumIcon(pos + shield_offset, mySize, shield, "shield", is_vertical, shield_iconalign, '1 1 1', 1);
-                       if(shield <= 5)
-                               DrawNumIcon_expanding(pos + shield_offset, mySize, shield, "shield", is_vertical, shield_iconalign, '1 1 1', 1, bound(0, (shield - shield_time) / 0.5, 1));
+                       align = getPowerupItemAlign(autocvar_hud_panel_powerups_baralign, column, row, columns, rows, isVertical);
+                       HUD_Panel_DrawProgressBar(itemPos, itemSize, "progressbar", item.count / item.lifetime, isVertical, align, item.colormod, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                }
-       }
  
-       if(strength_time)
-       {
-               const float maxstrength = 30;
-               float strength = ceil(strength_time);
-               if(autocvar_hud_panel_powerups_progressbar)
-                       HUD_Panel_DrawProgressBar(pos + strength_offset, mySize, autocvar_hud_panel_powerups_progressbar_strength, strength/maxstrength, is_vertical, strength_baralign, autocvar_hud_progressbar_strength_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+               // Draw icon and text
                if(autocvar_hud_panel_powerups_text)
                {
-                       if(strength > 1)
-                               DrawNumIcon(pos + strength_offset, mySize, strength, "strength", is_vertical, strength_iconalign, '1 1 1', 1);
-                       if(strength <= 5)
-                               DrawNumIcon_expanding(pos + strength_offset, mySize, strength, "strength", is_vertical, strength_iconalign, '1 1 1', 1, bound(0, (strength - strength_time) / 0.5, 1));
+                       align = getPowerupItemAlign(autocvar_hud_panel_powerups_iconalign, column, row, columns, rows, isVertical);
+                       fullSeconds = ceil(item.count);
+                       textColor = '0.6 0.6 0.6' + (item.colormod * 0.4);
+                       if(item.count > 1)
+                               DrawNumIcon(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha);
+                       if(item.count <= 5)
+                               DrawNumIcon_expanding(itemPos, itemSize, fullSeconds, item.netname, isVertical, align, textColor, panel_fg_alpha, bound(0, (fullSeconds - item.count) / 0.5, 1));
                }
-       }
  
-       if(superweapons_time)
-       {
-               const float maxsuperweapons = 30;
-               float superweapons = ceil(superweapons_time);
-               if(autocvar_hud_panel_powerups_progressbar)
-                       HUD_Panel_DrawProgressBar(pos + superweapons_offset, mySize, autocvar_hud_panel_powerups_progressbar_superweapons, superweapons/maxsuperweapons, is_vertical, superweapons_baralign, autocvar_hud_progressbar_superweapons_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               if(autocvar_hud_panel_powerups_text)
+               // Determine next section
+               if(isVertical)
+               {
+                       if(++column >= columns)
+                       {
+                               column = 0;
+                               ++row;
+                       }
+               }
+               else
                {
-                       if(superweapons > 1)
-                               DrawNumIcon(pos + superweapons_offset, mySize, superweapons, "superweapons", is_vertical, superweapons_iconalign, '1 1 1', 1);
-                       if(superweapons <= 5)
-                               DrawNumIcon_expanding(pos + superweapons_offset, mySize, superweapons, "superweapons", is_vertical, superweapons_iconalign, '1 1 1', 1, bound(0, (superweapons - superweapons_time) / 0.5, 1));
+                       if(++row >= rows)
+                       {
+                               row = 0;
+                               ++column;
+                       }
                }
        }
        draw_endBoldFont();
  }
  
  void HUD_HealthArmor(void)
  {
        int armor, health, fuel;
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_healtharmor) return;
@@@ -1798,6 -1832,7 +1835,7 @@@ void HUD_Notify_Push(string icon, strin
  
  void HUD_Notify(void)
  {
+       if(intermission == 2) return;
        if (!autocvar__hud_configure)
                if (!autocvar_hud_panel_notify)
                        return;
@@@ -1923,6 -1958,7 +1961,7 @@@ string seconds_tostring(float sec
  
  void HUD_Timer(void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_timer) return;
  
  // Radar (#6)
  //
- void HUD_Radar_Show_Maximized(float show,float clickable)
 +
 +float HUD_Radar_Clickable()
 +{
 +      return hud_panel_radar_mouse && !hud_panel_radar_temp_hidden;
 +}
 +
-       hud_panel_radar_maximized = show;
++void HUD_Radar_Show_Maximized(bool doshow,float clickable)
 +{
-       if ( show )
++      hud_panel_radar_maximized = doshow;
 +      hud_panel_radar_temp_hidden = 0;
 +      
++      if ( doshow )
 +      {
 +              if (clickable)
 +              {
 +                      if(autocvar_hud_cursormode)
 +                              setcursormode(1);
 +                      hud_panel_radar_mouse = 1; 
 +              }
 +      }
 +      else if ( hud_panel_radar_mouse )
 +      {
 +              hud_panel_radar_mouse = 0;
 +              mouseClicked = 0;
 +              if(autocvar_hud_cursormode)
 +              if(!mv_active)
 +                      setcursormode(0);
 +      }
 +}
 +void HUD_Radar_Hide_Maximized()
 +{
 +      HUD_Radar_Show_Maximized(false,false);
 +}
 +
 +
 +float HUD_Radar_InputEvent(float bInputType, float nPrimary, float nSecondary)
 +{
 +      if(!hud_panel_radar_maximized || !hud_panel_radar_mouse || 
 +              autocvar__hud_configure || mv_active)
 +              return false;
 +
 +      if(bInputType == 3)
 +      {
 +              mousepos_x = nPrimary;
 +              mousepos_y = nSecondary;
 +              return true;
 +      }
 +
 +      if(nPrimary == K_MOUSE1)
 +      {
 +              if(bInputType == 0) // key pressed
 +                      mouseClicked |= S_MOUSE1;
 +              else if(bInputType == 1) // key released
 +                      mouseClicked -= (mouseClicked & S_MOUSE1);
 +      }
 +      else if(nPrimary == K_MOUSE2)
 +      {
 +              if(bInputType == 0) // key pressed
 +                      mouseClicked |= S_MOUSE2;
 +              else if(bInputType == 1) // key released
 +                      mouseClicked -= (mouseClicked & S_MOUSE2);
 +      }
 +      else if ( nPrimary == K_ESCAPE && bInputType == 0 )
 +      {
 +              HUD_Radar_Hide_Maximized();
 +      }
 +      else
 +      {
 +              // allow console/use binds to work without hiding the map
 +              string con_keys;
 +              float keys;
 +              float i;
 +              con_keys = strcat(findkeysforcommand("toggleconsole", 0)," ",findkeysforcommand("+use", 0)) ;
 +              keys = tokenize(con_keys); // findkeysforcommand returns data for this
 +              for (i = 0; i < keys; ++i)
 +              {
 +                      if(nPrimary == stof(argv(i)))
 +                              return false;
 +              }
 +              
 +              if ( getstati(STAT_HEALTH) <= 0 )
 +              {
 +                      // Show scoreboard
 +                      if ( bInputType < 2 )
 +                      {
 +                              con_keys = findkeysforcommand("+showscores", 0);
 +                              keys = tokenize(con_keys);
 +                              for (i = 0; i < keys; ++i)
 +                              {
 +                                      if ( nPrimary == stof(argv(i)) )
 +                                      {
 +                                              hud_panel_radar_temp_hidden = bInputType == 0;
 +                                              return false;
 +                                      }
 +                              }
 +                      }
 +              }
 +              else if ( bInputType == 0 )
 +                      HUD_Radar_Hide_Maximized();
 +              
 +              return false;
 +      }
 +
 +      return true;
 +}
 +
 +void HUD_Radar_Mouse()
 +{
 +      if ( !hud_panel_radar_mouse ) return;
 +      if(mv_active) return;
 +      
 +      if ( intermission )
 +      {
 +              HUD_Radar_Hide_Maximized();
 +              return;
 +      }
 +      
 +      if(mouseClicked & S_MOUSE2)
 +      {
 +              HUD_Radar_Hide_Maximized();
 +              return;
 +      }
 +      
 +      if(!autocvar_hud_cursormode)
 +      {
 +              mousepos = mousepos + getmousepos() * autocvar_menu_mouse_speed;
 +
 +              mousepos_x = bound(0, mousepos_x, vid_conwidth);
 +              mousepos_y = bound(0, mousepos_y, vid_conheight);
 +      }
 +
 +      HUD_Panel_UpdateCvars();
 +      
 +      
 +      panel_size = autocvar_hud_panel_radar_maximized_size;
 +      panel_size_x = bound(0.2, panel_size_x, 1) * vid_conwidth;
 +      panel_size_y = bound(0.2, panel_size_y, 1) * vid_conheight;
 +      panel_pos_x = (vid_conwidth - panel_size_x) / 2;
 +      panel_pos_y = (vid_conheight - panel_size_y) / 2;
 +              
 +      if(mouseClicked & S_MOUSE1)
 +      {
 +              // click outside
 +              if ( mousepos_x < panel_pos_x || mousepos_x > panel_pos_x + panel_size_x ||
 +                       mousepos_y < panel_pos_y || mousepos_y > panel_pos_y + panel_size_y )
 +              {
 +                      HUD_Radar_Hide_Maximized();
 +                      return;
 +              }
 +              vector pos = teamradar_texcoord_to_3dcoord(teamradar_2dcoord_to_texcoord(mousepos),view_origin_z);
 +              localcmd(sprintf("cmd ons_spawn %f %f %f",pos_x,pos_y,pos_z));
 +              
 +              HUD_Radar_Hide_Maximized();
 +              return;
 +      }
 +      
 +
 +      const vector cursor_size = '32 32 0';
 +      drawpic(mousepos-'8 4 0', strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), cursor_size, '1 1 1', 0.8, DRAWFLAG_NORMAL);
 +}
 +
  void HUD_Radar(void)
  {
+       if(intermission == 2) return;
        if (!autocvar__hud_configure)
        {
                if (hud_panel_radar_maximized)
                }
        }
  
 +      if ( hud_panel_radar_temp_hidden )
 +              return;
 +
        HUD_Panel_UpdateCvars();
  
        float f = 0;
  
        for(tm = world; (tm = find(tm, classname, "radarlink")); )
                draw_teamradar_link(tm.origin, tm.velocity, tm.team);
 +
 +      vector coord;
 +      vector brightcolor;
        for(tm = world; (tm = findflags(tm, teamradar_icon, 0xFFFFFF)); )
 +      {
 +              if ( hud_panel_radar_mouse )
 +              if ( tm.health > 0 )
 +              if ( tm.team == myteam+1 )
 +              {
 +                      coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(tm.origin));
 +                      if ( vlen(mousepos-coord) < 8 )
 +                      {
 +                              brightcolor_x = min(1,tm.teamradar_color_x*1.5);
 +                              brightcolor_y = min(1,tm.teamradar_color_y*1.5);
 +                              brightcolor_z = min(1,tm.teamradar_color_z*1.5);
 +                              drawpic(coord - '8 8 0', "gfx/teamradar_icon_glow", '16 16 0', brightcolor, panel_fg_alpha, 0);
 +                      }
 +              }
 +
                draw_teamradar_icon(tm.origin, tm.teamradar_icon, tm, tm.teamradar_color, panel_fg_alpha);
 +      }
        for(tm = world; (tm = find(tm, classname, "entcs_receiver")); )
        {
                color2 = GetPlayerColor(tm.sv_entnum);
        draw_teamradar_player(view_origin, view_angles, '1 1 1');
  
        drawresetcliparea();
 +
 +      if ( hud_panel_radar_mouse )
 +      {                       
 +              string message = "Click to select teleport destination";
 +
 +              if ( getstati(STAT_HEALTH) <= 0 )
 +              {
 +                      message = "Click to select spawn location";
 +              }
 +
 +              drawcolorcodedstring(pos + '0.5 0 0' * (mySize_x - stringwidth(message, true, hud_fontsize)) - '0 1 0' * hud_fontsize_y * 2,
 +                                                       message, hud_fontsize, hud_panel_radar_foreground_alpha, DRAWFLAG_NORMAL);
 +
 +              hud_panel_radar_bottom = pos_y + mySize_y + hud_fontsize_y;
 +      }
  }
  
  // Score (#7)
@@@ -2491,6 -2330,7 +2531,7 @@@ void HUD_Score_Rankings(vector pos, vec
  
  void HUD_Score(void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_score) return;
  //
  void HUD_RaceTimer (void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_racetimer) return;
  
  void HUD_Vote(void)
  {
+       if(intermission == 2) return;
        if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
        {
                vote_active = 1;
@@@ -3052,154 -2894,184 +3095,184 @@@ void HUD_Mod_CA(vector myPos, vector my
  }
  
  // CTF HUD modicon section
float redflag_prevframe, blueflag_prevframe; // status during previous frame
- int redflag_prevstatus, blueflag_prevstatus; // last remembered status
- float redflag_statuschange_time, blueflag_statuschange_time; // time when the status changed
int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
+ int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
+ float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
  
  void HUD_Mod_CTF_Reset(void)
  {
-       redflag_prevstatus = blueflag_prevstatus = redflag_prevframe = blueflag_prevframe = redflag_statuschange_time = blueflag_statuschange_time = 0;
+       redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
+       redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
+       redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
  }
  
  void HUD_Mod_CTF(vector pos, vector mySize)
  {
-       vector redflag_pos, blueflag_pos;
+       vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
        vector flag_size;
        float f; // every function should have that
  
-       int redflag, blueflag; // current status
-       float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime; // time since the status changed
-       int stat_items;
+       int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
+       float redflag_statuschange_elapsedtime, blueflag_statuschange_elapsedtime, yellowflag_statuschange_elapsedtime, pinkflag_statuschange_elapsedtime, neutralflag_statuschange_elapsedtime; // time since the status changed
+       bool ctf_oneflag; // one-flag CTF mode enabled/disabled
+       int stat_items = getstati(STAT_CTF_FLAGSTATUS, 0, 24);
+       float fs, fs2, fs3, size1, size2;
+       vector e1, e2;
  
-       stat_items = getstati(STAT_ITEMS, 0, 24);
-       redflag = (stat_items/IT_RED_FLAG_TAKEN) & 3;
-       blueflag = (stat_items/IT_BLUE_FLAG_TAKEN) & 3;
+       redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
+       blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
+       yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
+       pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
+       neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
  
-       if(redflag || blueflag)
-               mod_active = 1;
-       else
-               mod_active = 0;
+       ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
  
-       if(autocvar__hud_configure)
-       {
+       mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag);
+       if (autocvar__hud_configure) {
                redflag = 1;
                blueflag = 2;
+               if (team_count >= 3)
+                       yellowflag = 2;
+               if (team_count >= 4)
+                       pinkflag = 3;
+               ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
        }
  
        // when status CHANGES, set old status into prevstatus and current status into status
-       if (redflag != redflag_prevframe)
-       {
-               redflag_statuschange_time = time;
-               redflag_prevstatus = redflag_prevframe;
-               redflag_prevframe = redflag;
-       }
-       if (blueflag != blueflag_prevframe)
-       {
-               blueflag_statuschange_time = time;
-               blueflag_prevstatus = blueflag_prevframe;
-               blueflag_prevframe = blueflag;
-       }
-       redflag_statuschange_elapsedtime = time - redflag_statuschange_time;
-       blueflag_statuschange_elapsedtime = time - blueflag_statuschange_time;
-       float BLINK_FACTOR = 0.15;
-       float BLINK_BASE = 0.85;
+       #define X(team) do {                                                                                                                    \
+               if (team##flag != team##flag_prevframe) {                                                                       \
+               team##flag_statuschange_time = time;                                                                    \
+               team##flag_prevstatus = team##flag_prevframe;                                                   \
+               team##flag_prevframe = team##flag;                                                                              \
+       }                                                                                                                                                       \
+       team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time;      \
+     } while (0)
+       X(red);
+       X(blue);
+       X(yellow);
+       X(pink);
+       X(neutral);
+       #undef X
+       const float BLINK_FACTOR = 0.15;
+       const float BLINK_BASE = 0.85;
        // note:
        //   RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
        // thus
        //   BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
        // ensure RMS == 1
-       float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
-       string red_icon, red_icon_prevstatus;
-       float red_alpha, red_alpha_prevstatus;
-       red_alpha = red_alpha_prevstatus = 1;
-       switch(redflag) {
-               case 1: red_icon = "flag_red_taken"; break;
-               case 2: red_icon = "flag_red_lost"; break;
-               case 3: red_icon = "flag_red_carrying"; red_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
+       const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
+       #define X(team, cond) \
+       string team##_icon, team##_icon_prevstatus; \
+       int team##_alpha, team##_alpha_prevstatus; \
+       team##_alpha = team##_alpha_prevstatus = 1; \
+       do { \
+               switch (team##flag) { \
+                       case 1: team##_icon = "flag_" #team "_taken"; break; \
+                       case 2: team##_icon = "flag_" #team "_lost"; break; \
+                       case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+                       default: \
+                               if ((stat_items & CTF_SHIELDED) && (cond)) { \
+                                       team##_icon = "flag_" #team "_shielded"; \
+                               } else { \
+                                       team##_icon = string_null; \
+                               } \
+                               break; \
+               } \
+               switch (team##flag_prevstatus) { \
+                       case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
+                       case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
+                       case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+                       default: \
+                               if (team##flag == 3) { \
+                                       team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
+                               } else if((stat_items & CTF_SHIELDED) && (cond)) { \
+                                       team##_icon_prevstatus = "flag_" #team "_shielded"; \
+                               } else { \
+                                       team##_icon_prevstatus = string_null; \
+                               } \
+                               break; \
+               } \
+       } while (0)
+       X(red, myteam != NUM_TEAM_1);
+       X(blue, myteam != NUM_TEAM_2);
+       X(yellow, myteam != NUM_TEAM_3);
+       X(pink, myteam != NUM_TEAM_4);
+       X(neutral, true);
+       #undef X
+       if (ctf_oneflag) {
+               // hacky, but these aren't needed
+               red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
+               fs = fs2 = fs3 = 1;
+       } else switch (team_count) {
                default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2))
-                               red_icon = "flag_red_shielded";
-                       else
-                               red_icon = string_null;
-                       break;
-       }
-       switch(redflag_prevstatus) {
-               case 1: red_icon_prevstatus = "flag_red_taken"; break;
-               case 2: red_icon_prevstatus = "flag_red_lost"; break;
-               case 3: red_icon_prevstatus = "flag_red_carrying"; red_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
-               default:
-                       if(redflag == 3)
-                               red_icon_prevstatus = "flag_red_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_2))
-                               red_icon_prevstatus = "flag_red_shielded";
-                       else
-                               red_icon_prevstatus = string_null;
-                       break;
+               case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
+               case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
+               case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
        }
  
-       string blue_icon, blue_icon_prevstatus;
-       float blue_alpha, blue_alpha_prevstatus;
-       blue_alpha = blue_alpha_prevstatus = 1;
-       switch(blueflag) {
-               case 1: blue_icon = "flag_blue_taken"; break;
-               case 2: blue_icon = "flag_blue_lost"; break;
-               case 3: blue_icon = "flag_blue_carrying"; blue_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
-               default:
-                       if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1))
-                               blue_icon = "flag_blue_shielded";
-                       else
-                               blue_icon = string_null;
-                       break;
-       }
-       switch(blueflag_prevstatus) {
-               case 1: blue_icon_prevstatus = "flag_blue_taken"; break;
-               case 2: blue_icon_prevstatus = "flag_blue_lost"; break;
-               case 3: blue_icon_prevstatus = "flag_blue_carrying"; blue_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break;
-               default:
-                       if(blueflag == 3)
-                               blue_icon_prevstatus = "flag_blue_carrying"; // make it more visible
-                       else if((stat_items & IT_CTF_SHIELDED) && (myteam == NUM_TEAM_1))
-                               blue_icon_prevstatus = "flag_blue_shielded";
-                       else
-                               blue_icon_prevstatus = string_null;
-                       break;
+       if (mySize_x > mySize_y) {
+               size1 = mySize_x;
+               size2 = mySize_y;
+               e1 = eX;
+               e2 = eY;
+       } else {
+               size1 = mySize_y;
+               size2 = mySize_x;
+               e1 = eY;
+               e2 = eX;
        }
  
-       if(mySize.x > mySize.y) {
-               if (myteam == NUM_TEAM_1) { // always draw own flag on left
+       switch (myteam) {
+               default:
+               case NUM_TEAM_1: {
                        redflag_pos = pos;
-                       blueflag_pos = pos + eX * 0.5 * mySize.x;
-               } else {
-                       blueflag_pos = pos;
-                       redflag_pos = pos + eX * 0.5 * mySize.x;
+                       blueflag_pos = pos + eX * fs2 * size1;
+                       yellowflag_pos = pos - eX * fs2 * size1;
+                       pinkflag_pos = pos + eX * fs3 * size1;
+                       break;
                }
-               flag_size = eX * 0.5 * mySize.x + eY * mySize.y;
-       } else {
-               if (myteam == NUM_TEAM_1) { // always draw own flag on left
-                       redflag_pos = pos;
-                       blueflag_pos = pos + eY * 0.5 * mySize.y;
-               } else {
+               case NUM_TEAM_2: {
+                       redflag_pos = pos + eX * fs2 * size1;
                        blueflag_pos = pos;
-                       redflag_pos = pos + eY * 0.5 * mySize.y;
+                       yellowflag_pos = pos - eX * fs2 * size1;
+                       pinkflag_pos = pos + eX * fs3 * size1;
+                       break;
+               }
+               case NUM_TEAM_3: {
+                       redflag_pos = pos + eX * fs3 * size1;
+                       blueflag_pos = pos - eX * fs2 * size1;
+                       yellowflag_pos = pos;
+                       pinkflag_pos = pos + eX * fs2 * size1;
+                       break;
+               }
+               case NUM_TEAM_4: {
+                       redflag_pos = pos - eX * fs2 * size1;
+                       blueflag_pos = pos + eX * fs3 * size1;
+                       yellowflag_pos = pos + eX * fs2 * size1;
+                       pinkflag_pos = pos;
+                       break;
                }
-               flag_size = eY * 0.5 * mySize.y + eX * mySize.x;
        }
-       f = bound(0, redflag_statuschange_elapsedtime*2, 1);
-       if(red_icon_prevstatus && f < 1)
-               drawpic_aspect_skin_expanding(redflag_pos, red_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * red_alpha_prevstatus, DRAWFLAG_NORMAL, f);
-       if(red_icon)
-               drawpic_aspect_skin(redflag_pos, red_icon, flag_size, '1 1 1', panel_fg_alpha * red_alpha * f, DRAWFLAG_NORMAL);
-       f = bound(0, blueflag_statuschange_elapsedtime*2, 1);
-       if(blue_icon_prevstatus && f < 1)
-               drawpic_aspect_skin_expanding(blueflag_pos, blue_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * blue_alpha_prevstatus, DRAWFLAG_NORMAL, f);
-       if(blue_icon)
-               drawpic_aspect_skin(blueflag_pos, blue_icon, flag_size, '1 1 1', panel_fg_alpha * blue_alpha * f, DRAWFLAG_NORMAL);
+       neutralflag_pos = pos;
+       flag_size = e1 * fs * size1 + e2 * size2;
+       #define X(team) do { \
+               f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
+               if (team##_icon_prevstatus && f < 1) \
+                       drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
+               if (team##_icon) \
+                       drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
+       } while (0)
+       X(red);
+       X(blue);
+       X(yellow);
+       X(pink);
+       X(neutral);
+       #undef X
  }
  
  // Keyhunt HUD modicon section
@@@ -3670,6 -3542,7 +3743,7 @@@ float mod_change; // "time" when mod_ac
  
  void HUD_ModIcons(void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_modicons) return;
  //
  void HUD_PressedKeys(void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_pressedkeys) return;
@@@ -3797,6 -3671,15 +3872,15 @@@ void HUD_Chat(void
  
        HUD_Panel_UpdateCvars();
  
+       if(intermission == 2)
+       {
+               // reserve some more space to the mapvote panel
+               // by resizing and moving chat panel to the bottom
+               panel_size.y = min(panel_size.y, vid_conheight * 0.2);
+               panel_pos.y = vid_conheight - panel_size.y - panel_bg_border * 2;
+               chat_posy = panel_pos.y;
+               chat_sizey = panel_size.y;
+       }
        if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
        {
                panel_pos.y = panel_bg_border;
@@@ -3865,6 -3748,7 +3949,7 @@@ float frametimeavg1; // 1 frame ag
  float frametimeavg2; // 2 frames ago
  void HUD_EngineInfo(void)
  {
+       //if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_engineinfo) return;
  } while(0)
  void HUD_InfoMessages(void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_infomessages) return;
@@@ -4107,6 -3992,7 +4193,7 @@@ float acc_prevtime, acc_avg, top_speed
  float physics_update_time, discrete_speed, discrete_acceleration;
  void HUD_Physics(void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_physics) return;
@@@ -4498,6 -4384,7 +4585,7 @@@ void reset_centerprint_messages(void
  float hud_configure_cp_generation_time;
  void HUD_CenterPrint (void)
  {
+       if(intermission == 2) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_centerprint) return;
        }
        HUD_Panel_UpdateCvars();
  
 -      if(scoreboard_fade_alpha)
 +      if ( HUD_Radar_Clickable() )
 +      {
 +              if (hud_panel_radar_bottom >= 0.96 * vid_conheight)
 +                      return;
 +
 +              panel_pos = eY * hud_panel_radar_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
 +              panel_size_y = min(panel_size_y, vid_conheight - hud_panel_radar_bottom);
 +      }
 +      else if(scoreboard_fade_alpha)
        {
                hud_fade_alpha = hud_fade_alpha_save;
  
        }
  }
  
- // Buffs (#18)
+ // ItemsTime (#XX)
  //
- void HUD_Buffs(void)
+ const float ITEMSTIME_MAXITEMS = 10;
+ float ItemsTime_time[ITEMSTIME_MAXITEMS];
+ float ItemsTime_availableTime[ITEMSTIME_MAXITEMS];
+ string GetItemsTimePicture(float i)
  {
-       int buffs = getstati(STAT_BUFFS, 0, 24);
-       if(!autocvar__hud_configure)
+       switch(i)
        {
-               if(!autocvar_hud_panel_buffs) return;
-               if(spectatee_status == -1) return;
-               if(getstati(STAT_HEALTH) <= 0) return;
-               if(!buffs) return;
+               case 0: return "item_large_armor";
+               case 1: return "item_mega_health";
+               case 2: return "strength";
+               case 3: return "shield";
+               case 4: return "item_mega_health";
+               case 5: return "strength";
+               case 6: return "shield";
+               case 7: return "fuelregen";
+               case 8: return "jetpack";
+               case 9: return "superweapons";
+               default: return "";
+       }
+ }
+ void DrawItemsTimeItem(vector myPos, vector mySize, float ar, float itemcode, float item_time, bool item_available, float item_availableTime)
+ {
+       float t = 0;
+       vector color = '0 0 0';
+       float picalpha;
+       if(autocvar_hud_panel_itemstime_hidespawned == 2)
+               picalpha = 1;
+       else if(item_available)
+       {
+               float BLINK_FACTOR = 0.15;
+               float BLINK_BASE = 0.85;
+               float BLINK_FREQ = 5;
+               picalpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
+       }
+       else
+               picalpha = 0.5;
+       t = floor(item_time - time + 0.999);
+       if(t < 5)
+               color = '0.7 0 0';
+       else if(t < 10)
+               color = '0.7 0.7 0';
+       else
+               color = '1 1 1';
+       vector picpos, numpos;
+       if(autocvar_hud_panel_itemstime_iconalign)
+       {
+               numpos = myPos;
+               picpos = myPos + eX * (ar - 1) * mySize_y;
        }
        else
        {
-               buffs = Buff_Type_first.items; // force first buff
+               numpos = myPos + eX * mySize_y;
+               picpos = myPos;
        }
  
-       int b = 0; // counter to tell other functions that we have buffs
-       entity e;
-       string s = "";
-       for(e = Buff_Type_first; e; e = e.enemy) if(buffs & e.items)
+       if(t > 0 && autocvar_hud_panel_itemstime_progressbar)
        {
-               ++b;
-               string o = strcat(rgb_to_hexcolor(Buff_Color(e.items)), Buff_PrettyName(e.items));
-               if(s == "")
-                       s = o;
+               vector p_pos, p_size;
+               if(autocvar_hud_panel_itemstime_progressbar_reduced)
+               {
+                       p_pos = numpos;
+                       p_size = eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y;
+               }
                else
-                       s = strcat(s, " ", o);
+               {
+                       p_pos = myPos;
+                       p_size = mySize;
+               }
+               HUD_Panel_DrawProgressBar(p_pos, p_size, autocvar_hud_panel_itemstime_progressbar_name, t/autocvar_hud_panel_itemstime_progressbar_maxtime, 0, autocvar_hud_panel_itemstime_iconalign, color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
        }
  
-       HUD_Panel_UpdateCvars();
+       if(t > 0 && autocvar_hud_panel_itemstime_text)
+               drawstring_aspect(numpos, ftos(t), eX * ((ar - 1)/ar) * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+       else
+               picpos.x = myPos.x + mySize.x / 2 - mySize.y / 2;
+       if(item_availableTime)
+               drawpic_aspect_skin_expanding(picpos, GetItemsTimePicture(itemcode), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL, item_availableTime);
+       drawpic_aspect_skin(picpos, GetItemsTimePicture(itemcode), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * picalpha, DRAWFLAG_NORMAL);
+ }
  
-       draw_beginBoldFont();
+ void HUD_ItemsTime(void)
+ {
+       if(!autocvar__hud_configure)
+       {
+               if(!(
+                       (autocvar_hud_panel_itemstime == 1 && spectatee_status != 0)
+               ||      (autocvar_hud_panel_itemstime == 2 && (spectatee_status != 0 || warmup_stage))
+                       )) { return; }
+               ItemsTime_time[0] = getstatf(STAT_ARMOR_LARGE_TIME);
+               ItemsTime_time[1] = getstatf(STAT_HEALTH_MEGA_TIME);
+               ItemsTime_time[2] = getstatf(STAT_INVISIBLE_TIME);
+               ItemsTime_time[3] = getstatf(STAT_SPEED_TIME);
+               ItemsTime_time[4] = getstatf(STAT_EXTRALIFE_TIME);
+               ItemsTime_time[5] = getstatf(STAT_STRENGTH_TIME);
+               ItemsTime_time[6] = getstatf(STAT_SHIELD_TIME);
+               ItemsTime_time[7] = getstatf(STAT_FUELREGEN_TIME);
+               ItemsTime_time[8] = getstatf(STAT_JETPACK_TIME);
+               ItemsTime_time[9] = getstatf(STAT_SUPERWEAPONS_TIME);
+       }
+       else
+       {
+               // do not show here mutator-dependent items
+               ItemsTime_time[0] = time + 0;
+               ItemsTime_time[1] = time + 8;
+               ItemsTime_time[2] = -1; // mutator-dependent
+               ItemsTime_time[3] = -1; // mutator-dependent
+               ItemsTime_time[4] = -1; // mutator-dependent
+               ItemsTime_time[5] = time + 0;
+               ItemsTime_time[6] = time + 4;
+               ItemsTime_time[7] = time + 49;
+               ItemsTime_time[8] = -1;
+               ItemsTime_time[9] = time + 28;
+       }
+       float i;
+       float count = 0;
+       if(autocvar_hud_panel_itemstime_hidespawned == 1)
+               for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
+                       count += (ItemsTime_time[i] > time || -ItemsTime_time[i] > time);
+       else if(autocvar_hud_panel_itemstime_hidespawned == 2)
+               for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
+                       count += (ItemsTime_time[i] > time);
+       else
+               for (i = 0; i < ITEMSTIME_MAXITEMS; ++i)
+                       count += (ItemsTime_time[i] != -1);
+       if (count == 0)
+               return;
+       HUD_Panel_UpdateCvars();
  
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
  
-       HUD_Panel_DrawBg(bound(0, b, 1));
        if(panel_bg_padding)
        {
                pos += '1 1 0' * panel_bg_padding;
                mySize -= '2 2 0' * panel_bg_padding;
        }
  
-       //float panel_ar = mySize_x/mySize_y;
-       //bool is_vertical = (panel_ar < 1);
-       //float buff_iconalign = autocvar_hud_panel_buffs_iconalign;
-       vector buff_offset = '0 0 0';
+       float rows, columns;
+       float ar = max(2, autocvar_hud_panel_itemstime_ratio) + 1;
+       rows = HUD_GetRowCount(count, mySize, ar);
+       columns = ceil(count/rows);
+       vector itemstime_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
  
-       for(e = Buff_Type_first; e; e = e.enemy) if(buffs & e.items)
+       vector offset = '0 0 0';
+       float newSize;
+       if(autocvar_hud_panel_itemstime_dynamicsize)
        {
-               //DrawNumIcon(pos + buff_offset, mySize, shield, "shield", is_vertical, buff_iconalign, '1 1 1', 1);
-               drawcolorcodedstring_aspect(pos + buff_offset, s, mySize, panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+               if(autocvar__hud_configure)
+               if(menu_enabled != 2)
+                       HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
+               // reduce panel to avoid spacing items
+               if(itemstime_size.x / itemstime_size.y < ar)
+               {
+                       newSize = rows * itemstime_size.x / ar;
+                       pos.y += (mySize.y - newSize) / 2;
+                       mySize.y = newSize;
+                       itemstime_size.y = mySize.y / rows;
+               }
+               else
+               {
+                       newSize = columns * itemstime_size.y * ar;
+                       pos.x += (mySize.x - newSize) / 2;
+                       mySize.x = newSize;
+                       itemstime_size.x = mySize.x / columns;
+               }
+               panel_pos = pos - '1 1 0' * panel_bg_padding;
+               panel_size = mySize + '2 2 0' * panel_bg_padding;
+       }
+       else
+       {
+               if(itemstime_size.x/itemstime_size.y > ar)
+               {
+                       newSize = ar * itemstime_size.y;
+                       offset.x = itemstime_size.x - newSize;
+                       pos.x += offset.x/2;
+                       itemstime_size.x = newSize;
+               }
+               else
+               {
+                       newSize = 1/ar * itemstime_size.x;
+                       offset.y = itemstime_size.y - newSize;
+                       pos.y += offset.y/2;
+                       itemstime_size.y = newSize;
+               }
        }
  
-       draw_endBoldFont();
+       HUD_Panel_DrawBg(1);
+       float row = 0, column = 0;
+       bool item_available;
+       for (i = 0; i < ITEMSTIME_MAXITEMS; ++i) {
+               if (ItemsTime_time[i] == -1)
+                       continue;
+               float item_time = ItemsTime_time[i];
+               if(item_time < -1)
+               {
+                       item_available = true;
+                       item_time = -item_time;
+               }
+               else
+                       item_available = (item_time <= time);
+               if(ItemsTime_time[i] >= 0)
+               {
+                       if(time <= ItemsTime_time[i])
+                               ItemsTime_availableTime[i] = 0;
+                       else if(ItemsTime_availableTime[i] == 0)
+                               ItemsTime_availableTime[i] = time;
+               }
+               else if(ItemsTime_availableTime[i] == 0)
+                       ItemsTime_availableTime[i] = time;
+               float f = (time - ItemsTime_availableTime[i]) * 2;
+               f = (f > 1) ? 0 : bound(0, f, 1);
+               if(autocvar_hud_panel_itemstime_hidespawned == 1)
+                       if(!(ItemsTime_time[i] > time || -ItemsTime_time[i] > time))
+                               continue;
+               if(autocvar_hud_panel_itemstime_hidespawned == 2)
+                       if(!(ItemsTime_time[i] > time))
+                               continue;
+               DrawItemsTimeItem(pos + eX * column * (itemstime_size.x + offset.x) + eY * row * (itemstime_size.y + offset.y), itemstime_size, ar, i, item_time, item_available, f);
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       column = column + 1;
+               }
+       }
  }
  
  
@@@ -4811,9 -4876,6 +5085,6 @@@ void HUD_Main (void
  
        HUD_Configure_Frame();
  
-       if(intermission == 2) // no hud during mapvote
-               hud_fade_alpha = 0;
        // panels that we want to be active together with the scoreboard
        // they must fade only when the menu does
        if(scoreboard_fade_alpha == 1)
        }
  
        hud_draw_maximized = 0;
-       // draw panels in order specified by panel_order array
+       // draw panels in the order specified by panel_order array
        for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
                (panel = hud_panel[panel_order[i]]).panel_draw();
  
diff --combined qcsrc/client/hud.qh
index 74701acffb99198904263b303ec4ced903a49a25,72e3326429eb7662feca88680ec696d5287494d4..8a2f76ded479e0cc2427e32d690b844235f8d1a7
@@@ -12,16 -12,6 +12,16 @@@ int HUD_PANEL_LAST
  int panel_order[HUD_PANEL_MAX];
  string hud_panelorder_prev;
  
 +bool hud_draw_maximized;
 +bool hud_panel_radar_maximized;
 +bool hud_panel_radar_mouse;
 +float hud_panel_radar_bottom;
 +bool hud_panel_radar_temp_hidden;
 +bool chat_panel_modified;
 +bool radar_panel_modified;
 +
 +void HUD_Radar_Hide_Maximized();
 +
  void HUD_Reset (void);
  void HUD_Main (void);
  
@@@ -35,6 -25,11 +35,6 @@@ int vote_prev; // previous state of vot
  float vote_alpha;
  float vote_change; // "time" when vote_active changed
  
 -float hud_draw_maximized;
 -float hud_panel_radar_maximized;
 -float chat_panel_modified;
 -float radar_panel_modified;
 -
  vector mousepos;
  vector panel_click_distance; // mouse cursor distance from the top left corner of the panel (saved only upon a click)
  vector panel_click_resizeorigin; // coordinates for opposite point when resizing
@@@ -118,6 -113,11 +118,11 @@@ string panel_bg_padding_str
  
  class(HUDPanel) .void() panel_draw;
  
+ // chat panel can be reduced / moved while the mapvote is active
+ // let know the mapvote panel about chat pos and size
+ float chat_posy;
+ float chat_sizey;
  float current_player;
  
  float GetPlayerColorForce(int i);
@@@ -142,25 -142,27 +147,27 @@@ float old_p_healthtime, old_p_armortime
  int prev_p_health, prev_p_armor;
  
  
- #define HUD_PANELS(HUD_PANEL)                                                                                                                                                                                 \
-       HUD_PANEL(WEAPONS      , HUD_Weapons      , weapons)                                                                                                                    \
-       HUD_PANEL(AMMO         , HUD_Ammo         , ammo)                                                                                                                               \
-       HUD_PANEL(POWERUPS     , HUD_Powerups     , powerups)                                                                                                                   \
-       HUD_PANEL(HEALTHARMOR  , HUD_HealthArmor  , healtharmor)                                                                                                                \
-       HUD_PANEL(NOTIFY       , HUD_Notify       , notify)                                                                                                                     \
-       HUD_PANEL(TIMER        , HUD_Timer        , timer)                                                                                                                              \
-       HUD_PANEL(RADAR        , HUD_Radar        , radar)                                                                                                                              \
-       HUD_PANEL(SCORE        , HUD_Score        , score)                                                                                                                              \
-       HUD_PANEL(RACETIMER    , HUD_RaceTimer    , racetimer)                                                                                                                  \
-       HUD_PANEL(VOTE         , HUD_Vote         , vote)                                                                                                                               \
-       HUD_PANEL(MODICONS     , HUD_ModIcons     , modicons)                                                                                                                   \
-       HUD_PANEL(PRESSEDKEYS  , HUD_PressedKeys  , pressedkeys)                                                                                                                \
-       HUD_PANEL(CHAT         , HUD_Chat         , chat)                                                                                                                               \
-       HUD_PANEL(ENGINEINFO   , HUD_EngineInfo   , engineinfo)                                                                                                                 \
-       HUD_PANEL(INFOMESSAGES , HUD_InfoMessages , infomessages)                                                                                                               \
-       HUD_PANEL(PHYSICS      , HUD_Physics      , physics)                                                                                                                    \
-       HUD_PANEL(CENTERPRINT  , HUD_CenterPrint  , centerprint)                                                                                                                \
-       HUD_PANEL(BUFFS        , HUD_Buffs        , buffs)
+ #define HUD_PANELS(HUD_PANEL) \
+       HUD_PANEL(WEAPONS      , HUD_Weapons      , weapons) \
+       HUD_PANEL(AMMO         , HUD_Ammo         , ammo) \
+       HUD_PANEL(POWERUPS     , HUD_Powerups     , powerups) \
+       HUD_PANEL(HEALTHARMOR  , HUD_HealthArmor  , healtharmor) \
+       HUD_PANEL(NOTIFY       , HUD_Notify       , notify) \
+       HUD_PANEL(TIMER        , HUD_Timer        , timer) \
+       HUD_PANEL(RADAR        , HUD_Radar        , radar) \
+       HUD_PANEL(SCORE        , HUD_Score        , score) \
+       HUD_PANEL(RACETIMER    , HUD_RaceTimer    , racetimer) \
+       HUD_PANEL(VOTE         , HUD_Vote         , vote) \
+       HUD_PANEL(MODICONS     , HUD_ModIcons     , modicons) \
+       HUD_PANEL(PRESSEDKEYS  , HUD_PressedKeys  , pressedkeys) \
+       HUD_PANEL(CHAT         , HUD_Chat         , chat) \
+       HUD_PANEL(ENGINEINFO   , HUD_EngineInfo   , engineinfo) \
+       HUD_PANEL(INFOMESSAGES , HUD_InfoMessages , infomessages) \
+       HUD_PANEL(PHYSICS      , HUD_Physics      , physics) \
+       HUD_PANEL(CENTERPRINT  , HUD_CenterPrint  , centerprint) \
+       HUD_PANEL(MAPVOTE      , MapVote_Draw     , mapvote) \
+       HUD_PANEL(ITEMSTIME    , HUD_ItemsTime    , itemstime) \
+       // always add new panels to the end of list
  
  #define HUD_PANEL(NAME, draw_func, name)                                                                                                                                                      \
        int HUD_PANEL_##NAME;                                                                                                                                                                                   \
index abe6740223420baa08570bfb060c6fdacc986dd3,485b82b2c3ed2fc3a5689f859df502a944d8d789..ca7fde9e049436e99d1d8f2acd0f2b1e1f116973
@@@ -96,6 -96,8 +96,8 @@@ void HUD_Panel_ExportCfg(string cfgname
                                        HUD_Write_PanelCvar_q("_timeout_speed_in");
                                        HUD_Write_PanelCvar_q("_timeout_speed_out");
                                        HUD_Write_PanelCvar_q("_onlyowned");
+                                       HUD_Write_PanelCvar_q("_noncurrent_alpha");
+                                       HUD_Write_PanelCvar_q("_noncurrent_scale");
                                        break;
                                case HUD_PANEL_AMMO:
                                        HUD_Write_PanelCvar_q("_onlycurrent");
                                        HUD_Write_PanelCvar_q("_text");
                                        break;
                                case HUD_PANEL_POWERUPS:
-                                       HUD_Write_PanelCvar_q("_flip");
                                        HUD_Write_PanelCvar_q("_iconalign");
                                        HUD_Write_PanelCvar_q("_baralign");
                                        HUD_Write_PanelCvar_q("_progressbar");
-                                       HUD_Write_PanelCvar_q("_progressbar_strength");
-                                       HUD_Write_PanelCvar_q("_progressbar_shield");
                                        HUD_Write_PanelCvar_q("_text");
                                        break;
                                case HUD_PANEL_HEALTHARMOR:
                                        HUD_Write_PanelCvar_q("_fade_subsequent_minfontsize");
                                        HUD_Write_PanelCvar_q("_fade_minfontsize");
                                        break;
+                               case HUD_PANEL_ITEMSTIME:
+                                       HUD_Write_PanelCvar_q("_iconalign");
+                                       HUD_Write_PanelCvar_q("_progressbar");
+                                       HUD_Write_PanelCvar_q("_progressbar_name");
+                                       HUD_Write_PanelCvar_q("_progressbar_reduced");
+                                       HUD_Write_PanelCvar_q("_text");
+                                       HUD_Write_PanelCvar_q("_ratio");
+                                       HUD_Write_PanelCvar_q("_dynamicsize");
+                                       break;
                        }
                        HUD_Write("\n");
                }
@@@ -232,6 -240,7 +240,7 @@@ vector HUD_Panel_CheckMove(vector myPos
        int i;
        for (i = 0; i < HUD_PANEL_NUM; ++i) {
                panel = hud_panel[i];
+               if(panel == HUD_PANEL(MAPVOTE)) continue;
                if(panel == highlightedPanel) continue;
                HUD_Panel_UpdatePosSize();
                if(!panel_enabled) continue;
@@@ -328,6 -337,7 +337,7 @@@ vector HUD_Panel_CheckResize(vector myS
        int i;
        for (i = 0; i < HUD_PANEL_NUM; ++i) {
                panel = hud_panel[i];
+               if(panel == HUD_PANEL(MAPVOTE)) continue;
                if(panel == highlightedPanel) continue;
                HUD_Panel_UpdatePosSize();
                if(!panel_enabled) continue;
@@@ -626,6 -636,14 +636,6 @@@ void HUD_Panel_Arrow_Action(float nPrim
        }
  }
  
 -const int S_MOUSE1 = 1;
 -const int S_MOUSE2 = 2;
 -const int S_MOUSE3 = 4;
 -int mouseClicked;
 -int prevMouseClicked; // previous state
 -float prevMouseClickedTime; // time during previous left mouse click, to check for doubleclicks
 -vector prevMouseClickedPos; // pos during previous left mouse click, to check for doubleclicks
 -
  void HUD_Panel_EnableMenu();
  entity tab_panels[HUD_PANEL_MAX];
  entity tab_panel;
@@@ -779,6 -797,8 +789,8 @@@ float HUD_Panel_InputEvent(float bInput
                        for(i = 0; i < HUD_PANEL_NUM; ++i)
                        {
                                panel = hud_panel[i];
+                               if(panel == HUD_PANEL(MAPVOTE))
+                                       continue;
                                if (panel == tab_panels[i] || panel == starting_panel)
                                        continue;
                                HUD_Panel_UpdatePosSize();
@@@ -926,6 -946,7 +938,7 @@@ float HUD_Panel_Check_Mouse_Pos(float a
                j += 1;
  
                panel = hud_panel[i];
+               if(panel == HUD_PANEL(MAPVOTE)) continue;
                HUD_Panel_UpdatePosSize();
  
                float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
@@@ -1007,6 -1028,8 +1020,8 @@@ void HUD_Panel_Highlight(float allow_mo
                j += 1;
  
                panel = hud_panel[i];
+               if(panel == HUD_PANEL(MAPVOTE))
+                       continue;
                HUD_Panel_UpdatePosSize();
  
                float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
diff --combined qcsrc/client/main.qc
index 5068a6a4e716eef294bf8528bbd88ef31c85629f,b56887878d392b9651ed518a19d3f4f2f8f65135..7f9b544dab0cd47141f53dcf54b859f6bb4a257f
@@@ -2,11 -2,9 +2,11 @@@
  #include "_all.qh"
  
  #include "casings.qh"
 +#include "controlpoint.qh"
  #include "csqcmodel_hooks.qh"
  #include "damage.qh"
  #include "effects.qh"
 +#include "generator.qh"
  #include "gibs.qh"
  #include "hook.qh"
  #include "hud.qh"
@@@ -121,6 -119,9 +121,9 @@@ void CSQC_Init(void
        registercvar("cl_nade_type", "3");
        registercvar("cl_pokenade_type", "zombie");
  
+       registercvar("cl_jumpspeedcap_min", "");
+       registercvar("cl_jumpspeedcap_max", "");
        gametype = 0;
  
        // hud_fields uses strunzone on the titles!
        GetTeam(NUM_SPECTATOR, true); // add specs first
  
        // needs to be done so early because of the constants they create
+       static_init();
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
-       CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
-       CALL_ACCUMULATED_FUNCTION(RegisterItems);
-       CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
        CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
        CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
        CALL_ACCUMULATED_FUNCTION(RegisterHUD_Panels);
-       CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
  
        WaypointSprite_Load();
  
        precache_sound("misc/hit.wav");
        precache_sound("misc/typehit.wav");
  
 +      generator_precache();
        Projectile_Precache();
        Hook_Precache();
        GibSplash_Precache();
@@@ -367,9 -364,6 +367,9 @@@ float CSQC_InputEvent(float bInputType
        if (HUD_Panel_InputEvent(bInputType, nPrimary, nSecondary))
                return true;
  
 +      if ( HUD_Radar_InputEvent(bInputType, nPrimary, nSecondary) )
 +              return true;
 +
        if (MapVote_InputEvent(bInputType, nPrimary, nSecondary))
                return true;
  
@@@ -785,7 -779,7 +785,7 @@@ void Ent_ReadSpawnEvent(float is_new
                        button_zoom = false;
                }
        }
 -
 +      HUD_Radar_Hide_Maximized();
        //printf("Ent_ReadSpawnEvent(is_new = %d); origin = %s, entnum = %d, localentnum = %d\n", is_new, vtos(self.origin), entnum, player_localentnum);
  }
  
@@@ -872,8 -866,6 +872,8 @@@ void CSQC_Ent_Update(float bIsNewEntity
                case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
                case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
                case ENT_CLIENT_TURRET: ent_turret(); break;
 +              case ENT_CLIENT_GENERATOR: ent_generator(); break;
 +              case ENT_CLIENT_CONTROLPOINT_ICON: ent_cpicon(); break;
                case ENT_CLIENT_MODEL: CSQCModel_Read(bIsNewEntity); break;
                case ENT_CLIENT_ITEM: ItemRead(bIsNewEntity); break;
                case ENT_CLIENT_BUMBLE_RAYGUN: bumble_raygun_read(bIsNewEntity); break;
                case ENT_CLIENT_SPAWNEVENT: Ent_ReadSpawnEvent(bIsNewEntity); break;
                case ENT_CLIENT_NOTIFICATION: Read_Notification(bIsNewEntity); break;
                case ENT_CLIENT_HEALING_ORB: ent_healer(); break;
+               case ENT_CLIENT_VIEWLOC: ent_viewloc(); break;
+               case ENT_CLIENT_VIEWLOC_TRIGGER: ent_viewloc_trigger(); break;
                case ENT_CLIENT_LADDER: ent_func_ladder(); break;
                case ENT_CLIENT_TRIGGER_PUSH: ent_trigger_push(); break;
                case ENT_CLIENT_TARGET_PUSH: ent_target_push(); break;
index e75214a4edfeead37ef838789679090067f46e5e,6610f80362b3d8b3241dff339cf409fec5a51288..037d906fbe09c1ec9f3a2b0f91a77be42c609e4a
@@@ -12,6 -12,7 +12,6 @@@
  
  int mv_num_maps;
  
 -float mv_active;
  string mv_maps[MAPVOTE_COUNT];
  string mv_pics[MAPVOTE_COUNT];
  string mv_pk3[MAPVOTE_COUNT]; // map pk3 name or gametype human readable name
@@@ -88,6 -89,12 +88,12 @@@ void GameTypeVote_DrawGameTypeItem(vect
  
        // Bounding box details
        float rect_margin = hud_fontsize.y / 2;
+       pos.x += rect_margin + autocvar_scoreboard_border_thickness;
+       pos.y += rect_margin + autocvar_scoreboard_border_thickness;
+       maxh -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
+       tsize -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
        vector rect_pos = pos - '0.5 0.5 0' * rect_margin;
        vector rect_size = '1 1 0';
        rect_size.x = tsize + rect_margin;
  void MapVote_DrawMapItem(vector pos, float isize, float tsize, string map, string pic, float _count, int id)
  {
        vector img_size = '0 0 0';
-       vector rgb;
        string label;
        float text_size;
  
-       isize -= hud_fontsize.y; // respect the text when calculating the image size
+       float rect_margin = hud_fontsize.y / 2;
  
-       rgb = MapVote_RGB(id);
+       pos.x += rect_margin + autocvar_scoreboard_border_thickness;
+       pos.y += rect_margin + autocvar_scoreboard_border_thickness;
+       isize -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
+       tsize -= 2 * (rect_margin + autocvar_scoreboard_border_thickness);
  
-       img_size.y = isize;
-       img_size.x = isize / 0.75; // 4:3 x can be stretched easily, height is defined in isize
+       vector rect_pos = pos - '0.5 0.5 0' * rect_margin;
+       vector rect_size = '1 1 0';
+       rect_size.x = tsize + rect_margin;
+       rect_size.y = isize + rect_margin;
+       float img_ar = 4/3;
+       img_size.x = min(tsize, isize * img_ar);
+       img_size.y = img_size.x / img_ar;
+       img_size.y -= hud_fontsize.y;
+       img_size.x = img_size.y * img_ar;
  
-       pos.y = pos.y + img_size.y;
+       pos.y += (isize - img_size.y - hud_fontsize.y) / 2;
  
        label = MapVote_FormatMapItem(id, map, _count, tsize, hud_fontsize);
  
        text_size = stringwidth(label, false, hud_fontsize);
  
+       float save_rect_sizex = rect_size.x;
+       rect_size.x = max(img_size.x, text_size) + rect_margin;
+       rect_pos.x += (save_rect_sizex - rect_size.x) / 2;
+       vector text_pos = '0 0 0';
+       text_pos.x = pos.x + (tsize - text_size) / 2;
+       text_pos.y = pos.y + img_size.y;
+       pos.x += (tsize - img_size.x) / 2;
        float theAlpha;
        if (!(mv_flags[id] & GTV_AVAILABLE) && mv_top2_alpha)
                theAlpha = mv_top2_alpha;
        else
                theAlpha = 1;
  
-       pos.x -= text_size*0.5;
-       drawstring(pos, label, hud_fontsize, rgb, theAlpha, DRAWFLAG_NORMAL);
+       // Highlight selected item
+       if(id == mv_selection && (mv_flags[id] & GTV_AVAILABLE))
+               drawfill(rect_pos, rect_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
  
-       pos.x = pos.x + text_size*0.5 - img_size.x*0.5;
-       pos.y = pos.y - img_size.y;
+       // Highlight current vote
+       vector rgb = MapVote_RGB(id);
+       if(id == mv_ownvote)
+       {
+               drawfill(rect_pos, rect_size, rgb, 0.1*theAlpha, DRAWFLAG_NORMAL);
+               drawborderlines(autocvar_scoreboard_border_thickness, rect_pos, rect_size, rgb, theAlpha, DRAWFLAG_NORMAL);
+       }
+       drawstring(text_pos, label, hud_fontsize, rgb, theAlpha, DRAWFLAG_NORMAL);
  
-       pos += autocvar_scoreboard_border_thickness * '1 1 0';
-       img_size -= (autocvar_scoreboard_border_thickness * 2) * '1 1 0';
        if(pic == "")
        {
                drawfill(pos, img_size, '.5 .5 .5', .7 * theAlpha, DRAWFLAG_NORMAL);
                else
                        drawpic(pos, pic, img_size, '1 1 1', theAlpha, DRAWFLAG_NORMAL);
        }
-       if(id == mv_ownvote)
-               drawborderlines(autocvar_scoreboard_border_thickness, pos, img_size, rgb, theAlpha, DRAWFLAG_NORMAL);
-       else
-               drawborderlines(autocvar_scoreboard_border_thickness, pos, img_size, '0 0 0', theAlpha, DRAWFLAG_NORMAL);
-       if(id == mv_selection && (mv_flags[id] & GTV_AVAILABLE))
-               drawfill(pos, img_size, '1 1 1', 0.1, DRAWFLAG_NORMAL);
  }
  
  void MapVote_DrawAbstain(vector pos, float isize, float tsize, float _count, int id)
  
        rgb = MapVote_RGB(id);
  
-       pos.y = pos.y + hud_fontsize.y;
        label = MapVote_FormatMapItem(id, _("Don't care"), _count, tsize, hud_fontsize);
  
        text_size = stringwidth(label, false, hud_fontsize);
@@@ -293,18 -316,18 +315,18 @@@ float MapVote_Selection(vector topleft
        return mv_mouse_selection;
  }
  
+ vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect);
  void MapVote_Draw()
  {
        string map;
        int i;
        float tmp;
        vector pos;
-       float isize;
        float center;
        float rows;
-       float tsize;
        vector dist = '0 0 0';
  
+       //if(intermission != 2) return;
        if(!mv_active)
                return;
  
        }
  
        center = (vid_conwidth - 1)/2;
-       xmin = vid_conwidth*0.05; // 5% border must suffice
+       xmin = vid_conwidth * 0.08;
        xmax = vid_conwidth - xmin;
        ymin = 20;
-       i = autocvar_con_chatpos; //*autocvar_con_chatsize;
-       if(i < 0)
-               ymax = vid_conheight + (i - autocvar_con_chat) * autocvar_con_chatsize;
-       if(i >= 0 || ymax < (vid_conheight*0.5))
-               ymax = vid_conheight - ymin;
+       ymax = vid_conheight - ymin;
+       if(chat_posy + chat_sizey / 2 < vid_conheight / 2)
+               ymin += chat_sizey;
+       else
+               ymax -= chat_sizey;
  
        hud_fontsize = HUD_GetFontsize("hud_fontsize");
  
        pos.z = 0;
  
        draw_beginBoldFont();
        map = ((gametypevote) ? _("Decide the gametype") : _("Vote for a map"));
-       pos.x = center - stringwidth(map, false, '12 0 0');
-       drawstring(pos, map, '24 24 0', '1 1 1', 1, DRAWFLAG_NORMAL);
-       pos.y += 26;
+       pos.x = center - stringwidth(map, false, hud_fontsize * 2) * 0.5;
+       drawstring(pos, map, hud_fontsize * 2, '1 1 1', 1, DRAWFLAG_NORMAL);
+       pos.y += hud_fontsize.y * 2;
  
        if( mapvote_chosenmap != "" )
        {
-               pos.x = center - stringwidth(mapvote_chosenmap, false, hud_fontsize*1.5/2);
-               drawstring(pos, mapvote_chosenmap, hud_fontsize*1.5, '1 1 1', 1, DRAWFLAG_NORMAL);
-               pos.y += hud_fontsize.y*2;
+               pos.y += hud_fontsize.y * 0.25;
+               pos.x = center - stringwidth(mapvote_chosenmap, false, hud_fontsize * 1.5) * 0.5;
+               drawstring(pos, mapvote_chosenmap, hud_fontsize * 1.5, '1 1 1', 1, DRAWFLAG_NORMAL);
+               pos.y += hud_fontsize.y * 1.5;
+               pos.y += hud_fontsize.y * 0.5;
        }
+       else
+               pos.y += hud_fontsize.y * 0.5;
+       draw_endBoldFont();
  
        i = ceil(max(0, mv_timeout - time));
        map = sprintf(_("%d seconds left"), i);
-       pos.x = center - stringwidth(map, false, '8 0 0');
-       drawstring(pos, map, '16 16 0', '0 1 0', 1, DRAWFLAG_NORMAL);
-       pos.y += 22;
-       pos.x = xmin;
-       draw_endBoldFont();
+       pos.x = center - stringwidth(map, false, hud_fontsize * 1.5) * 0.5;
+       drawstring(pos, map, hud_fontsize * 1.5, '0 1 0', 1, DRAWFLAG_NORMAL);
+       pos.y += hud_fontsize.y * 1.5;
+       pos.y += hud_fontsize.y * 0.5;
+       HUD_Panel_UpdateCvars();
  
        // base for multi-column stuff...
+       pos.y += hud_fontsize.y;
+       pos.x = xmin;
        ymin = pos.y;
+       float abstain_spacing = panel_bg_border + hud_fontsize.y;
        if(mv_abstain)
+       {
                mv_num_maps -= 1;
+               ymax -= abstain_spacing;
+       }
  
-       rows = ceil(mv_num_maps / mv_columns);
+       // higher than the image itself ratio for mapvote items to reserve space for long map names
+       int item_aspect = (gametypevote) ? 3/1 : 5/3;
+       vector table_size = HUD_GetTableSize_BestItemAR(mv_num_maps, eX * (xmax - xmin) + eY * (ymax - ymin), item_aspect);
+       mv_columns = table_size.x;
+       rows = table_size.y;
  
        dist.x = (xmax - xmin) / mv_columns;
        dist.y = (ymax - pos.y) / rows;
  
-       if ( gametypevote )
+       // reduce size of too wide items
+       tmp = vid_conwidth / 3; // max width
+       if(dist.x > tmp)
        {
-               tsize = dist.x - hud_fontsize.y;
-               isize = dist.y;
-               float maxheight = (ymax - pos.y) / 3;
-               if ( isize > maxheight )
-               {
-                       pos.x += (isize - maxheight)/2;
-                       isize = maxheight;
-               }
-               else
-                       dist.y += hud_fontsize.y;
-               pos.x = ( vid_conwidth - dist.x * mv_columns ) / 2;
+               dist.x = tmp;
+               dist.y = min(dist.y, dist.x / item_aspect);
        }
+       tmp = vid_conheight / 3; // max height
+       if(dist.y > tmp)
+       {
+               dist.y = tmp;
+               dist.x = min(dist.x, dist.y * item_aspect);
+       }
+       // reduce size to fix aspect ratio
+       if(dist.x / dist.y > item_aspect)
+               dist.x = dist.y * item_aspect;
        else
+               dist.y = dist.x / item_aspect;
+       // adjust table pos and size according to the new size
+       float offset;
+       offset = ((xmax - pos.x) - dist.x * mv_columns) / 2;
+       xmin = pos.x += offset;
+       xmax -= offset;
+       offset = ((ymax - pos.y) - dist.y * rows) / 2;
+       ymax -= 2 * offset;
+       // override panel_pos and panel_size
+       panel_pos.x = pos.x;
+       panel_pos.y = pos.y;
+       panel_size.x = xmax - xmin;
+       panel_size.y = ymax - ymin;
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
        {
-               tsize = dist.x - 10;
-               isize = min(dist.y - 10, 0.75 * tsize);
+               // FIXME item AR gets slightly changed here...
+               // it's rather hard to avoid it at this point
+               dist.x -= 2 * panel_bg_padding / mv_columns;
+               dist.y -= 2 * panel_bg_padding / rows;
+               xmin = pos.x += panel_bg_padding;
+               ymin = pos.y += panel_bg_padding;
+               xmax -= 2 * panel_bg_padding;
+               ymax -= 2 * panel_bg_padding;
        }
  
        mv_selection = MapVote_Selection(pos, dist, rows, mv_columns);
  
-       if ( !gametypevote )
-               pos.x += dist.x / 2;
-       pos.y += (dist.y - isize) / 2;
-       ymax -= isize;
        if (mv_top2_time)
                mv_top2_alpha = max(0.2, 1 - (time - mv_top2_time)*(time - mv_top2_time));
  
                tmp = mv_votes[i]; // FTEQCC bug: too many array accesses in the function call screw it up
                map = mv_maps[i];
                if(mv_preview[i])
-                       DrawItem(pos + MapVote_GridVec(dist, i, mv_columns), isize, tsize, map, mv_pics[i], tmp, i);
+                       DrawItem(pos + MapVote_GridVec(dist, i, mv_columns), dist.y, dist.x, map, mv_pics[i], tmp, i);
                else
-                       DrawItem(pos + MapVote_GridVec(dist, i, mv_columns), isize, tsize, map, "", tmp, i);
+                       DrawItem(pos + MapVote_GridVec(dist, i, mv_columns), dist.y, dist.x, map, "", tmp, i);
        }
  
        if(mv_abstain)
  
        if(mv_abstain && i < mv_num_maps) {
                tmp = mv_votes[i];
-               pos.y = ymax + isize - hud_fontsize.y;
+               pos.y = ymax + abstain_spacing;
                pos.x = (xmax+xmin)*0.5;
-               MapVote_DrawAbstain(pos, isize, xmax - xmin, tmp, i);
+               MapVote_DrawAbstain(pos, dist.x, xmax - xmin, tmp, i);
        }
  
        drawpic(mv_mousepos, strcat("gfx/menu/", autocvar_menu_skin, "/cursor.tga"), '32 32 0', '1 1 1', 1 - autocvar__menu_alpha, DRAWFLAG_NORMAL);
@@@ -597,8 -661,6 +660,6 @@@ void MapVote_Init(
  
        gametypevote = ReadByte();
  
-       float mv_real_num_maps = mv_num_maps - mv_abstain;
        if(gametypevote)
        {
                mapvote_chosenmap = strzone(ReadString());
  
                gtv_text_size = hud_fontsize*1.4;
                gtv_text_size_small = hud_fontsize*1.1;
-               if (mv_real_num_maps > 8 )
-                       mv_columns = 3;
-               else
-                       mv_columns = min(2, mv_real_num_maps);
-     }
-     else
-       {
-               if (mv_real_num_maps > 16)
-                       mv_columns = 5;
-               else if (mv_real_num_maps > 9)
-                       mv_columns = 4;
-               else if(mv_real_num_maps > 3)
-                       mv_columns = 3;
-               else
-                       mv_columns = mv_real_num_maps;
        }
  
        MapVote_ReadMask();
diff --combined qcsrc/client/progs.src
index 60cb996755d6e68ceb2f9fe14deeecc563d2b993,d161c6dfc60b09ff502b2cfa4bb24c313ade789d..70bf4f44607eb2c0ad706774bf560cf3139e56c9
@@@ -2,15 -2,14 +2,16 @@@
  
  ../common/util-pre.qh
  ../dpdefs/csprogsdefs.qh
+ ../common/util-post.qh
  
  announcer.qc
  bgmscript.qc
  casings.qc
 +controlpoint.qc
  csqcmodel_hooks.qc
  damage.qc
  effects.qc
 +generator.qc
  gibs.qc
  hook.qc
  hud.qc
@@@ -52,10 -51,13 +53,13 @@@ weapons/projectile.qc // TOD
  ../common/notifications.qc
  ../common/physics.qc
  ../common/playerstats.qc
+ ../common/p2mathlib.qc
  ../common/test.qc
  ../common/urllib.qc
  ../common/util.qc
  
+ ../common/viewloc.qc
  ../common/items/all.qc
  
  ../common/monsters/all.qc
index ec27b404e0d2d2842659abcfb8dfd02b2fe81974,b6d2db25c2e90086e9ba9dedf7f410f52382d629..126cc904d02aab36c43c7f903e3a769f6b53d375
@@@ -302,7 -302,7 +302,7 @@@ void Cmd_HUD_Help(
  #define HUD_DefaultColumnLayout() \
  "ping pl name | " \
  "-teams,race,lms/kills +ft,tdm/kills -teams,lms/deaths +ft,tdm/deaths -teams,lms,race,ka/suicides +ft,tdm/suicides -race,dm,tdm,ka,ft/frags " /* tdm already has this in "score" */ \
 -"+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns " \
 +"+ctf/caps +ctf/pickups +ctf/fckills +ctf/returns +ons/caps +ons/takes " \
  "+lms/lives +lms/rank " \
  "+kh/caps +kh/pushes +kh/destroyed " \
  "?+race/laps ?+race/time ?+race/fastest " \
@@@ -960,8 -960,6 +960,8 @@@ vector HUD_Scoreboard_MakeTable(vector 
  float HUD_WouldDrawScoreboard() {
        if (autocvar__hud_configure)
                return 0;
 +      else if (HUD_Radar_Clickable())
 +              return 0;
        else if (scoreboard_showscores)
                return 1;
        else if (intermission == 1)
  float average_accuracy;
  vector HUD_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size)
  {
+       WepSet weapons_stat = WepSet_GetFromStat();
+       WepSet weapons_inmap = WepSet_GetFromStat_InMap();
+       float initial_posx = pos.x;
        int i;
-       int weapon_cnt = WEP_COUNT - 3; // either vaporizer/vortex are hidden, no port-o-launch, no tuba
-       float rows;
-       if(autocvar_scoreboard_accuracy_doublerows)
+       float weapon_stats;
+       int disownedcnt = 0;
+       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+       {
+               self = get_weaponinfo(i);
+               if(!self.weapon)
+                       continue;
+               weapon_stats = weapon_accuracy[i-WEP_FIRST];
+               if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+                       ++disownedcnt;
+       }
+       int weapon_cnt = WEP_COUNT - disownedcnt;
+       if(weapon_cnt <= 0)
+               return pos;
+       int rows;
+       if(autocvar_scoreboard_accuracy_doublerows && weapon_cnt >= floor(WEP_COUNT * 0.5))
                rows = 2;
        else
                rows = 1;
+       int columnns = ceil(weapon_cnt / rows);
        float height = 40;
        float fontsize = height * 1/3;
        float weapon_height = height * 2/3;
-       float weapon_width = sbwidth / weapon_cnt;
-       float g_instagib = 0;
+       float weapon_width = sbwidth / columnns / rows;
  
        drawstring(pos, sprintf(_("Accuracy stats (average %d%%)"), average_accuracy), hud_fontsize, '1 1 1', scoreboard_alpha_fg, DRAWFLAG_NORMAL);
        pos.y += 1.25 * hud_fontsize.y + autocvar_scoreboard_border_thickness;
        drawborderlines(autocvar_scoreboard_border_thickness, pos, tmp, '0 0 0', scoreboard_alpha_bg * 0.75, DRAWFLAG_NORMAL);
  
        // column highlighting
-       for(i = 0; i < weapon_cnt/rows; ++i)
+       for(i = 0; i < columnns; ++i)
        {
                if(!(i % 2))
                        drawfill(pos + '1 0 0' * weapon_width * rows * i, '0 1 0' * height * rows + '1 0 0' * weapon_width * rows, '0 0 0', scoreboard_alpha_bg * 0.2, DRAWFLAG_NORMAL);
        }
  
        average_accuracy = 0;
-       float weapons_with_stats;
-       weapons_with_stats = 0;
+       int weapons_with_stats = 0;
        if(rows == 2)
                pos.x += weapon_width / 2;
  
-       if(switchweapon == WEP_VAPORIZER)
-               g_instagib = 1; // TODO: real detection for instagib?
-       float weapon_stats;
        if(autocvar_scoreboard_accuracy_nocolors)
                rgb = '1 1 1';
        else
                Accuracy_LoadColors();
  
-       for(i = WEP_FIRST; i <= WEP_LAST; ++i)
+       float oldposx = pos.x;
+       vector tmpos = pos;
+       int column;
+       for(i = WEP_FIRST, column = 0; i <= WEP_LAST; ++i)
        {
                self = get_weaponinfo(i);
                if (!self.weapon)
                        continue;
-               if ((i == WEP_VORTEX && g_instagib) || i == WEP_PORTO || (i == WEP_VAPORIZER && !g_instagib) || i == WEP_TUBA) // skip port-o-launch, vortex || vaporizer and tuba
-                       continue;
                weapon_stats = weapon_accuracy[i-WEP_FIRST];
  
+               if(weapon_stats < 0 && !(weapons_stat & WepSet_FromWeapon(i) || weapons_inmap & WepSet_FromWeapon(i)))
+                       continue;
                float weapon_alpha;
                if(weapon_stats >= 0)
                        weapon_alpha = scoreboard_alpha_fg;
                        weapon_alpha = 0.2 * scoreboard_alpha_fg;
  
                // weapon icon
-               drawpic_aspect_skin(pos, self.model2, '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(tmpos, self.model2, '1 0 0' * weapon_width + '0 1 0' * weapon_height, '1 1 1', weapon_alpha, DRAWFLAG_NORMAL);
                // the accuracy
                if(weapon_stats >= 0) {
                        weapons_with_stats += 1;
                        if(!autocvar_scoreboard_accuracy_nocolors)
                                rgb = Accuracy_GetColor(weapon_stats);
  
-                       drawstring(pos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
+                       drawstring(tmpos + '1 0 0' * padding + '0 1 0' * weapon_height, s, '1 1 0' * fontsize, rgb, scoreboard_alpha_fg, DRAWFLAG_NORMAL);
                }
+               tmpos.x += weapon_width * rows;
                pos.x += weapon_width * rows;
-               if(rows == 2 && i == 6) {
-                       pos.x -= sbwidth;
+               if(rows == 2 && column == columnns - 1) {
+                       tmpos.x = oldposx;
+                       tmpos.y += height;
                        pos.y += height;
                }
+               ++column;
        }
  
        if(weapons_with_stats)
                average_accuracy = floor((average_accuracy * 100 / weapons_with_stats) + 0.5);
  
-       if(rows == 2)
-               pos.x -= weapon_width / 2;
-       pos.x -= sbwidth;
        pos.y += height;
-       pos.y +=  1.25 * hud_fontsize.y;
+       pos.y += 1.25 * hud_fontsize.y;
+       pos.x = initial_posx;
        return pos;
  }
  
diff --combined qcsrc/client/view.qc
index 177261d3f8e959b6eea500797704a383c6669b5a,df8113b412c6f93aaeec1108cd12c4f96e477219..0a4f53ca28388154a59ce40653763523e9ec7dc9
@@@ -124,7 -124,7 +124,7 @@@ vector GetCurrentFov(float fov
  
        zoomsensitivity = autocvar_cl_zoomsensitivity;
        zoomfactor = autocvar_cl_zoomfactor;
-       if(zoomfactor < 1 || zoomfactor > 16)
+       if(zoomfactor < 1 || zoomfactor > 30)
                zoomfactor = 2.5;
        zoomspeed = autocvar_cl_zoomspeed;
        if(zoomspeed >= 0)
        }
        else if(autocvar_cl_spawnzoom && zoomin_effect)
        {
-               float spawnzoomfactor = bound(1, autocvar_cl_spawnzoom_factor, 16);
+               float spawnzoomfactor = bound(1, autocvar_cl_spawnzoom_factor, 30);
  
                current_viewzoom += (autocvar_cl_spawnzoom_speed * (spawnzoomfactor - current_viewzoom) * drawframetime);
                current_viewzoom = bound(1 / spawnzoomfactor, current_viewzoom, 1);
        return '1 0 0' * fovx + '0 1 0' * fovy;
  }
  
+ vector GetViewLocationFOV(float fov)
+ {
+       float frustumy = tan(fov * M_PI / 360.0) * 0.75;
+       float frustumx = frustumy * vid_width / vid_height / vid_pixelheight;
+       float fovx = atan2(frustumx, 1) / M_PI * 360.0;
+       float fovy = atan2(frustumy, 1) / M_PI * 360.0;
+       return '1 0 0' * fovx + '0 1 0' * fovy;
+ }
  vector GetOrthoviewFOV(vector ov_worldmin, vector ov_worldmax, vector ov_mid, vector ov_org)
  {
        float fovx, fovy;
@@@ -420,12 -429,14 +429,14 @@@ vector liquidcolor_prev
  
  float eventchase_current_distance;
  float eventchase_running;
float WantEventchase()
bool WantEventchase()
  {
        if(autocvar_cl_orthoview)
                return false;
        if(intermission)
                return true;
+       if(self.viewloc)
+               return true;
        if(spectatee_status >= 0)
        {
                if(autocvar_cl_eventchase_nexball && gametype == MAPINFO_TYPE_NEXBALL && !(WepSet_GetFromStat() & WepSet_FromWeapon(WEP_PORTO)))
@@@ -532,7 -543,7 +543,7 @@@ void UpdateCrosshair(
        if(getstati(STAT_FROZEN))
                drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, ((getstatf(STAT_REVIVE_PROGRESS)) ? ('0.25 0.90 1' + ('1 0 0' * getstatf(STAT_REVIVE_PROGRESS)) + ('0 1 1' * getstatf(STAT_REVIVE_PROGRESS) * -1)) : '0.25 0.90 1'), autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
        else if (getstatf(STAT_HEALING_ORB)>time)
-               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, Nade_Color(NADE_TYPE_HEAL), autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
+               drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, NADE_TYPE_HEAL.m_color, autocvar_hud_colorflash_alpha*getstatf(STAT_HEALING_ORB_ALPHA), DRAWFLAG_ADDITIVE);
        if(!intermission)
        if(getstatf(STAT_NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
        {
                        CSQC_common_hud();
  
        // crosshair goes VERY LAST
-       if(!scoreboard_active && !camera_active && intermission != 2 && spectatee_status != -1 && hud == HUD_NORMAL)
+       if(!scoreboard_active && !camera_active && intermission != 2 && spectatee_status != -1 && hud == HUD_NORMAL && !csqcplayer.viewloc)
        {
                if (!autocvar_crosshair_enabled) // main toggle for crosshair rendering
                        return;
@@@ -1091,39 -1102,18 +1102,39 @@@ void CSQC_UpdateView(float w, float h
        // event chase camera
        if(autocvar_chase_active <= 0) // greater than 0 means it's enabled manually, and this code is skipped
        {
 -              if(WantEventchase())
 +              float ons_roundlost = (gametype == MAPINFO_TYPE_ONSLAUGHT && getstati(STAT_ROUNDLOST));
 +              entity gen = world;
 +              
 +              if(ons_roundlost)
 +              {
 +                      entity e;
 +                      for(e = world; (e = find(e, classname, "onslaught_generator")); )
 +                      {
 +                              if(e.health <= 0)
 +                              {
 +                                      gen = e;
 +                                      break;
 +                              }
 +                      }
 +                      if(!gen)
 +                              ons_roundlost = FALSE; // don't enforce the 3rd person camera if there is no dead generator to show
 +              }
 +              if(WantEventchase() || (!autocvar_cl_orthoview && ons_roundlost))
                {
                        eventchase_running = true;
  
                        // make special vector since we can't use view_origin (It is one frame old as of this code, it gets set later with the results this code makes.)
                        vector current_view_origin = (csqcplayer ? csqcplayer.origin : pmove_org);
 +                      if(ons_roundlost) { current_view_origin = gen.origin; }
  
                        // detect maximum viewoffset and use it
 -                      if(autocvar_cl_eventchase_viewoffset)
 +                      vector view_offset = autocvar_cl_eventchase_viewoffset;
 +                      if(ons_roundlost) { view_offset = autocvar_cl_eventchase_generator_viewoffset; }
 +
 +                      if(view_offset)
                        {
 -                              WarpZone_TraceLine(current_view_origin, current_view_origin + autocvar_cl_eventchase_viewoffset + ('0 0 1' * autocvar_cl_eventchase_maxs.z), MOVE_WORLDONLY, self);
 -                              if(trace_fraction == 1) { current_view_origin += autocvar_cl_eventchase_viewoffset; }
 +                              WarpZone_TraceLine(current_view_origin, current_view_origin + view_offset + ('0 0 1' * autocvar_cl_eventchase_maxs.z), MOVE_WORLDONLY, self);
 +                              if(trace_fraction == 1) { current_view_origin += view_offset; }
                                else { current_view_origin.z += max(0, (trace_endpos.z - current_view_origin.z) - autocvar_cl_eventchase_maxs.z); }
                        }
  
                        if(!autocvar_chase_active) { cvar_set("chase_active", "-1"); }
  
                        // make the camera smooth back
 -                      if(autocvar_cl_eventchase_speed && eventchase_current_distance < autocvar_cl_eventchase_distance)
 -                              eventchase_current_distance += autocvar_cl_eventchase_speed * (autocvar_cl_eventchase_distance - eventchase_current_distance) * frametime; // slow down the further we get
 -                      else if(eventchase_current_distance != autocvar_cl_eventchase_distance)
 -                              eventchase_current_distance = autocvar_cl_eventchase_distance;
 +                      float chase_distance = autocvar_cl_eventchase_distance;
 +                      if(ons_roundlost) { chase_distance = autocvar_cl_eventchase_generator_distance; }
 +
 +                      if(autocvar_cl_eventchase_speed && eventchase_current_distance < chase_distance)
 +                              eventchase_current_distance += autocvar_cl_eventchase_speed * (chase_distance - eventchase_current_distance) * frametime; // slow down the further we get
 +                      else if(eventchase_current_distance != chase_distance)
 +                              eventchase_current_distance = chase_distance;
  
                        makevectors(view_angles);
  
                        WarpZone_TraceBox(current_view_origin, autocvar_cl_eventchase_mins, autocvar_cl_eventchase_maxs, eventchase_target_origin, MOVE_WORLDONLY, self);
  
                        // If the boxtrace fails, revert back to line tracing.
+                       if(!self.viewloc)
                        if(trace_startsolid)
                        {
                                eventchase_target_origin = (current_view_origin - (v_forward * eventchase_current_distance));
                        }
                        else { setproperty(VF_ORIGIN, trace_endpos); }
  
-                       setproperty(VF_ANGLES, WarpZone_TransformVAngles(WarpZone_trace_transform, view_angles));
+                       if(!self.viewloc)
+                               setproperty(VF_ANGLES, WarpZone_TransformVAngles(WarpZone_trace_transform, view_angles));
                }
                else if(autocvar_chase_active < 0) // time to disable chase_active if it was set by this code
                {
        vid_pixelheight = autocvar_vid_pixelheight;
  
        if(autocvar_cl_orthoview) { setproperty(VF_FOV, GetOrthoviewFOV(ov_worldmin, ov_worldmax, ov_mid, ov_org)); }
+       else if(csqcplayer.viewloc) { setproperty(VF_FOV, GetViewLocationFOV(110)); } // enforce 110 fov, so things dont look odd
        else { setproperty(VF_FOV, GetCurrentFov(fov)); }
  
        // Camera for demo playback
  
        if(autocvar__hud_configure)
                HUD_Panel_Mouse();
 +      else 
 +              HUD_Radar_Mouse();
  
      if(hud && !intermission)
      {
@@@ -1841,13 -1829,9 +1855,9 @@@ void CSQC_common_hud(void
        HUD_Main(); // always run these functions for alpha checks
        HUD_DrawScoreboard();
  
-       if (scoreboard_active) // scoreboard/accuracy
-               HUD_Reset();
-       else if (intermission == 2) // map voting screen
-       {
-               MapVote_Draw();
+       // scoreboard/accuracy, map/gametype voting screen
+       if (scoreboard_active || intermission == 2)
                HUD_Reset();
-       }
  }
  
  
index 671f0593722e5041d62a62055d35672e3916316a,4a1ba2a1fae972e3306892711066b42de67365e4..f0c2d5215b3995c7c2610eaffb511cc3542ba308
@@@ -166,10 -166,19 +166,16 @@@ vector drawspritetext(vector o, float a
  
  float spritelookupblinkvalue(string s)
  {
+       if(substring(s, 0, 4) == "wpn-")
+       if(get_weaponinfo(stof(substring(s, 4, strlen(s)))).spawnflags & WEP_FLAG_SUPERWEAPON)
+               return 2;
        switch(s)
        {
 -              case "ons-cp-atck-neut": return 2;
 -              case "ons-cp-atck-red":  return 2;
 -              case "ons-cp-atck-blue": return 2;
 -              case "ons-cp-dfnd-red":  return 0.5;
 -              case "ons-cp-dfnd-blue": return 0.5;
 +              case "ons-cp-atck":      return 2;
 +              case "ons-cp-dfnd":      return 0.5;
+               case "item_health_mega": return 2;
+               case "item_armor_large": return 2;
                case "item-invis":       return 2;
                case "item-extralife":   return 2;
                case "item-speed":       return 2;
@@@ -195,7 -204,15 +201,15 @@@ vector spritelookupcolor(string s, vect
  string spritelookuptext(string s)
  {
        if(substring(s, 0, 4) == "wpn-") { return (get_weaponinfo(stof(substring(s, 4, strlen(s)))).message); }
-       if(substring(s, 0, 5) == "buff-") { return Buff_PrettyName(Buff_Type_FromSprite(s)); }
+       if (substring(s, 0, 5) == "buff-")
+       {
+               entity buff = BUFF_NULL;
+               FOREACH(BUFFS, it.m_sprite == s, LAMBDA(
+                       buff = it;
+                       break;
+               ));
+               return buff.m_prettyName;
+       }
  
        switch(s)
        {
                case "keycarrier-red": return _("Key carrier");
                case "keycarrier-yellow": return _("Key carrier");
                case "redbase": return _("Red base");
+               case "yellowbase": return _("Yellow base");
+               case "neutralbase": return _("White base");
+               case "pinkbase": return _("Pink base");
                case "waypoint": return _("Waypoint");
 -              case "ons-gen-red": return _("Generator");
 -              case "ons-gen-blue": return _("Generator");
 +              case "ons-gen": return _("Generator");
                case "ons-gen-shielded": return _("Generator");
 -              case "ons-cp-neut": return _("Control point");
 -              case "ons-cp-red": return _("Control point");
 -              case "ons-cp-blue": return _("Control point");
 -              case "ons-cp-atck-neut": return _("Control point");
 -              case "ons-cp-atck-red": return _("Control point");
 -              case "ons-cp-atck-blue": return _("Control point");
 -              case "ons-cp-dfnd-red": return _("Control point");
 -              case "ons-cp-dfnd-blue": return _("Control point");
 +              case "ons-cp": return _("Control point");
 +              case "ons-cp-atck": return _("Control point");
 +              case "ons-cp-dfnd": return _("Control point");
                case "race-checkpoint": return _("Checkpoint");
                case "race-finish": return _("Finish");
                case "race-start": return _("Start");
                case "dom-blue": return _("Control point");
                case "dom-yellow": return _("Control point");
                case "dom-pink": return _("Control point");
+               case "item_health_mega": return _("Mega health");
+               case "item_armor_large": return _("Large armor");
                case "item-invis": return _("Invisibility");
                case "item-extralife": return _("Extra life");
                case "item-speed": return _("Speed");
@@@ -337,6 -365,14 +356,14 @@@ void Draw_WaypointSprite(
        // choose the sprite
        switch(self.rule)
        {
+               case SPRITERULE_SPECTATOR:
+                       if(!(
+                               (autocvar_g_waypointsprite_itemstime == 1 && t == NUM_SPECTATOR + 1)
+                       ||      (autocvar_g_waypointsprite_itemstime == 2 && (t == NUM_SPECTATOR + 1 || warmup_stage))
+                               ))
+                               return;
+                       spriteimage = self.netname;
+                       break;
                case SPRITERULE_DEFAULT:
                        if(self.team)
                        {
        {
                if(self.helpme && time < self.helpme)
                        a *= SPRITE_HELPME_BLINK;
-               else
+               else if(!self.lifetime) // fading out waypoints don't blink
                        a *= spritelookupblinkvalue(spriteimage);
        }
  
                a = 1;
        }
  
-       if(a <= 0)
+       if(a <= 0.003)
                return;
  
        rgb = fixrgbexcess(rgb);
index 4fb15af865c6de0c3180c54dc26c1881d3504030,61c08bf86f3c1b1f201a986739f57db4fc6ba2a1..2d32ebf3fe089352d8fac05762d1815f4bcb3b06
@@@ -115,13 -115,14 +115,16 @@@ const int ENT_CLIENT_TRIGGER_IMPULSE = 
  const int ENT_CLIENT_SWAMP = 69;
  const int ENT_CLIENT_CORNER = 70;
  const int ENT_CLIENT_KEYLOCK = 71;
 +const int ENT_CLIENT_GENERATOR = 72;
 +const int ENT_CLIENT_CONTROLPOINT_ICON = 73;
+ const int ENT_CLIENT_VIEWLOC = 78;
+ const int ENT_CLIENT_VIEWLOC_TRIGGER = 79;
  
  const int ENT_CLIENT_HEALING_ORB = 80;
  
  const int SPRITERULE_DEFAULT = 0;
  const int SPRITERULE_TEAMPLAY = 1;
+ const int SPRITERULE_SPECTATOR = 2;
  
  const int RADARICON_NONE = 0;
  const int RADARICON_FLAG = 1;
diff --combined qcsrc/common/mapinfo.qh
index 1dccb2fbd699a0edba8977cd2a3d47166a70e85a,22b17d900de78e4e4fb451363d27fd29360e00c8..1d21c74def90e99c80803840667a3327144fc7d9
@@@ -3,44 -3,54 +3,54 @@@
  
  #include "util.qh"
  
+ CLASS(Gametype, Object)
+     ATTRIB(Gametype, m_id, int, 0)
+     /** game type ID */
+     ATTRIB(Gametype, items, int, 0)
+     /** game type name as in cvar (with g_ prefix) */
+     ATTRIB(Gametype, netname, string, string_null)
+     /** game type short name */
+     ATTRIB(Gametype, mdl, string, string_null)
+     /** human readable name */
+     ATTRIB(Gametype, message, string, string_null)
+     /** does this gametype support teamplay? */
+     ATTRIB(Gametype, team, bool, false)
+     /** game type defaults */
+     ATTRIB(Gametype, model2, string, string_null)
+     /** game type description */
+     ATTRIB(Gametype, gametype_description, string, string_null)
+     CONSTRUCTOR(Gametype, string hname, string sname, string g_name, bool gteamplay, string defaults, string gdescription)
+     {
+         CONSTRUCT(Gametype);
+         this.netname = g_name;
+         this.mdl = sname;
+         this.message = hname;
+         this.team = gteamplay;
+         this.model2 = defaults;
+         this.gametype_description = gdescription;
+         return this;
+     }
+ ENDCLASS(Gametype)
+ void RegisterGametypes();
+ const int MAX_MAPINFO_TYPES = 24;
+ entity MAPINFO_TYPES[MAX_MAPINFO_TYPES], MAPINFO_TYPES_first, MAPINFO_TYPES_last;
+ int MAPINFO_TYPE_COUNT;
  int MAPINFO_TYPE_ALL;
- entity MapInfo_Type_first;
- entity MapInfo_Type_last;
- .entity enemy; // internal next pointer
- .int items; // game type ID
- .string netname; // game type name as in cvar (with g_ prefix)
- .string mdl; // game type short name
- .string message; // human readable name
- .int team; // does this gametype support teamplay?
- .string model2; // game type defaults
- .string gametype_description; // game type description
- #define REGISTER_GAMETYPE(hname,sname,g_name,NAME,gteamplay,defaults,gdescription) \
-       int MAPINFO_TYPE_##NAME; \
-       entity MapInfo_Type##g_name; \
-       void RegisterGametypes_##g_name() \
-       { \
-               MAPINFO_TYPE_##NAME = MAPINFO_TYPE_ALL + 1; \
-               MAPINFO_TYPE_ALL |= MAPINFO_TYPE_##NAME; \
-               MapInfo_Type##g_name = spawn(); \
-               MapInfo_Type##g_name.items = MAPINFO_TYPE_##NAME; \
-               MapInfo_Type##g_name.netname = #g_name; \
-               MapInfo_Type##g_name.mdl = #sname; \
-               MapInfo_Type##g_name.message = hname; \
-               MapInfo_Type##g_name.team = gteamplay; \
-               MapInfo_Type##g_name.model2 = defaults; \
-               MapInfo_Type##g_name.gametype_description = gdescription; \
-               if(!MapInfo_Type_first) \
-                       MapInfo_Type_first = MapInfo_Type##g_name; \
-               if(MapInfo_Type_last) \
-                       MapInfo_Type_last.enemy = MapInfo_Type##g_name; \
-               MapInfo_Type_last = MapInfo_Type##g_name; \
-       } \
-       ACCUMULATE_FUNCTION(RegisterGametypes, RegisterGametypes_##g_name)
+ #define REGISTER_GAMETYPE(hname, sname, g_name, NAME, gteamplay, defaults, gdescription)                    \
+     int MAPINFO_TYPE_##NAME;                                                                                \
+     REGISTER(RegisterGametypes, MAPINFO_TYPE, MAPINFO_TYPES, MAPINFO_TYPE_COUNT, g_name, m_id,              \
+         NEW(Gametype, hname, #sname, #g_name, gteamplay, defaults, gdescription)                            \
+     ) {                                                                                                     \
+         /* same as `1 << m_id` */                                                                           \
+         MAPINFO_TYPE_##NAME = MAPINFO_TYPE_ALL + 1; MAPINFO_TYPE_ALL |= MAPINFO_TYPE_##NAME;                \
+         this.items = MAPINFO_TYPE_##NAME;                                                                   \
+     }
+ REGISTER_REGISTRY(RegisterGametypes)
  
  #define IS_GAMETYPE(NAME) \
-       (MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME)
+     (MapInfo_LoadedGametype == MAPINFO_TYPE_##NAME)
  
  REGISTER_GAMETYPE(_("Deathmatch"),dm,g_dm,DEATHMATCH,false,"timelimit=20 pointlimit=30 leadlimit=0",_("Kill all enemies"));
  #define g_dm IS_GAMETYPE(DEATHMATCH)
@@@ -72,7 -82,7 +82,7 @@@ REGISTER_GAMETYPE(_("Key Hunt"),kh,g_ke
  REGISTER_GAMETYPE(_("Assault"),as,g_assault,ASSAULT,true,"timelimit=20",_("Destroy obstacles to find and destroy the enemy power core before time runs out"));
  #define g_assault IS_GAMETYPE(ASSAULT)
  
 -REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,true,"timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
 +REGISTER_GAMETYPE(_("Onslaught"),ons,g_onslaught,ONSLAUGHT,true,"pointlimit=1 timelimit=20",_("Capture control points to reach and destroy the enemy generator"));
  #define g_onslaught IS_GAMETYPE(ONSLAUGHT)
  
  REGISTER_GAMETYPE(_("Nexball"),nb,g_nexball,NEXBALL,true,"timelimit=20 pointlimit=5 leadlimit=0",_("XonSports"));
@@@ -120,6 -130,7 +130,7 @@@ void MapInfo_Enumerate()
  // filter the info by game type mask (updates MapInfo_count)
  float MapInfo_progress;
  float MapInfo_FilterGametype(float gametype, float features, float pFlagsRequired, float pFlagsForbidden, float pAbortOnGenerate); // 1 on success, 0 on temporary failure (call it again next frame then; use MapInfo_progress as progress indicator)
+ void MapInfo_FilterString(string sf); // filter _MapInfo_filtered (created by MapInfo_FilterGametype) with keyword
  int MapInfo_CurrentFeatures(); // retrieves currently required features from cvars
  int MapInfo_CurrentGametype(); // retrieves current gametype from cvars
  int MapInfo_ForbiddenFlags(); // retrieves current flags from cvars
index 0fd753453a5e85c7d8206223631d657dcfb1f848,f7afcc60fe5b30389c9b22d19e194593dbad3c6b..e9795a6f5f02609f9fa341b817818978b9bcc4c0
@@@ -347,25 -347,35 +347,35 @@@ void Send_Notification_WOCOVA
  
  #define MSG_INFO_NOTIFICATIONS \
      MSG_INFO_NOTIF(2, INFO_CHAT_NOSPECTATORS,              0, 0, "", "",                            "",                     _("^F4NOTE: ^BGSpectator chat is not sent to players during the match"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_, 4,                1, 0, "s1", "s1",                        "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_BROKEN_, 4,         2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG%s^BG's previous record of ^F2%s^BG seconds"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_CAPTURE_NEUTRAL,            1, 0, "s1", "s1",                        "notify_%s_captured",   _("^BG%s^BG captured the flag"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_TIME_, 4,           1, 1, "s1 f1p2dec", "s1",                "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_UNBROKEN_, 4,       2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break ^BG%s^BG's previous record of ^F1%s^BG seconds"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_ABORTRUN_, 4,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was returned to base by its owner"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_ABORTRUN_NEUTRAL,0, 0, "", "",                            "",                     _("^BGThe flag was returned by its owner"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DAMAGED_, 4,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was destroyed and returned to base"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_DAMAGED_NEUTRAL, 0, 0, "", "",                            "",                     _("^BGThe flag was destroyed and returned to base"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DROPPED_, 4,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_DROPPED_NEUTRAL, 0, 0, "", "",                            "",                     _("^BGThe flag was dropped in the base and returned itself"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_NEEDKILL_, 4,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_NEEDKILL_NEUTRAL,0, 0, "", "",                            "",                     _("^BGThe flag fell somewhere it couldn't be reached and returned to base"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_SPEEDRUN_, 4,    0, 1, "f1p2dec", "",                     "",                     _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_SPEEDRUN_NEUTRAL,0, 1, "f1p2dec", "",                     "",                     _("^BGThe flag became impatient after ^F1%.2f^BG seconds and returned itself"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_TIMEOUT_, 4,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag has returned to the base"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_FLAGRETURN_TIMEOUT_NEUTRAL, 0, 0, "", "",                            "",                     _("^BGThe flag has returned to the base"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_LOST_, 4,                   1, 0, "s1", "s1",                        "notify_%s_lost",       _("^BG%s^BG lost the ^TC^TT^BG flag"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_LOST_NEUTRAL,               1, 0, "s1", "s1",                        "notify_%s_lost",       _("^BG%s^BG lost the flag"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_PICKUP_, 4,                 1, 0, "s1", "s1",                        "notify_%s_taken",      _("^BG%s^BG got the ^TC^TT^BG flag"), "") \
+     MSG_INFO_NOTIF(1, INFO_CTF_PICKUP_NEUTRAL,             1, 0, "s1", "s1",                        "notify_%s_taken",      _("^BG%s^BG got the flag"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_RETURN_, 4,                 1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
+     MULTITEAM_INFO(1, INFO_CTF_RETURN_MONSTER_, 4,         1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
      MSG_INFO_NOTIF(2, INFO_COINTOSS,                       1, 0, "s1", "",                          "",                     _("^F2Throwing coin... Result: %s^F2!"), "") \
      MSG_INFO_NOTIF(1, INFO_JETPACK_NOFUEL,                 0, 0, "", "",                            "",                     _("^BGYou don't have any fuel for the ^F1Jetpack"), "") \
      MSG_INFO_NOTIF(2, INFO_SUPERSPEC_MISSING_UID,          0, 0, "", "",                            "",                     _("^F2You lack a UID, superspec options will not be saved/restored"), "") \
      MSG_INFO_NOTIF(1, INFO_CA_JOIN_LATE,                   0, 0, "", "",                            "",                     _("^F1Round already started, you will join the game in the next round"), "") \
      MSG_INFO_NOTIF(1, INFO_CA_LEAVE,                       0, 0, "", "",                            "",                     _("^F2You will spectate in the next round"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_, 2,                1, 0, "s1", "s1",                        "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_BROKEN_, 2,         2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG%s^BG's previous record of ^F2%s^BG seconds"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_TIME_, 2,           1, 1, "s1 f1p2dec", "s1",                "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_CAPTURE_UNBROKEN_, 2,       2, 2, "s1 f1p2dec s2 f2p2dec", "s1",     "notify_%s_captured",   _("^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break ^BG%s^BG's previous record of ^F1%s^BG seconds"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_ABORTRUN_, 2,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was returned to base by its owner"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DAMAGED_, 2,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was destroyed and returned to base"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_DROPPED_, 2,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_NEEDKILL_, 2,    0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_SPEEDRUN_, 2,    0, 1, "f1p2dec", "",                     "",                     _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_FLAGRETURN_TIMEOUT_, 2,     0, 0, "", "",                            "",                     _("^BGThe ^TC^TT^BG flag has returned to the base"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_LOST_, 2,                   1, 0, "s1", "s1",                        "notify_%s_lost",       _("^BG%s^BG lost the ^TC^TT^BG flag"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_PICKUP_, 2,                 1, 0, "s1", "s1",                        "notify_%s_taken",      _("^BG%s^BG got the ^TC^TT^BG flag"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_RETURN_, 2,                 1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
-     MULTITEAM_INFO(1, INFO_CTF_RETURN_MONSTER_, 2,         1, 0, "s1", "s1",                        "notify_%s_returned",   _("^BG%s^BG returned the ^TC^TT^BG flag"), "") \
+     MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_BUFF,              3, 3, "spree_inf s1 s2 f3buffname s3loc spree_end", "s2 s1",  "notify_death", _("^BG%s%s^K1 was killed by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"), _("^BG%s%s^K1 was scored against by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s")) \
      MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_CHEAT,             3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_death",         _("^BG%s%s^K1 was unfairly eliminated by ^BG%s^K1%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_DROWN,             3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_water",         _("^BG%s%s^K1 was drowned by ^BG%s^K1%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_FALL,              3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_fall",          _("^BG%s%s^K1 was grounded by ^BG%s^K1%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_DEATH,     3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_death",         _("^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_GUN,       3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_death",         _("^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VH_WAKI_ROCKET,    3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_death",         _("^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s"), "") \
-     MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VENGEANCE,         3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_death",         _("^BG%s%s^K1 was destroyed by the vengeful ^BG%s^K1%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_MURDER_VOID,              3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",  "notify_void",          _("^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_SELF_AUTOTEAMCHANGE,      2, 1, "s1 s2loc death_team", "",         "",                     _("^BG%s^K1 was moved into the %s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_DEATH_SELF_BETRAYAL,            2, 1, "s1 s2loc spree_lost", "s1",       "notify_teamkill_red",  _("^BG%s^K1 became enemies with the Lord of Teamplay%s%s"), "") \
      MSG_INFO_NOTIF(1, INFO_LMS_FORFEIT,                    1, 0, "s1", "",                          "",                     _("^BG%s^F3 forfeited"), "") \
      MSG_INFO_NOTIF(1, INFO_LMS_NOLIVES,                    1, 0, "s1", "",                          "",                     _("^BG%s^F3 has no more lives left"), "") \
      MSG_INFO_NOTIF(1, INFO_MONSTERS_DISABLED,              0, 0, "", "",                            "",                     _("^BGMonsters are currently disabled"), "") \
 +    MSG_INFO_NOTIF(1, INFO_ONSLAUGHT_CAPTURE,              2, 0, "s1 s2", "",                       "",                     _("^BG%s^BG captured %s^BG control point"), "") \
 +    MULTITEAM_INFO(1, INFO_ONSLAUGHT_CPDESTROYED_, 4,      2, 0, "s1 s2", "",                       "",                     _("^TC^TT^BG team %s^BG control point has been destroyed by %s"), "") \
 +    MULTITEAM_INFO(1, INFO_ONSLAUGHT_GENDESTROYED_, 4,     0, 0, "", "",                            "",                     _("^TC^TT^BG generator has been destroyed"), "") \
 +    MULTITEAM_INFO(1, INFO_ONSLAUGHT_GENDESTROYED_OVERTIME_, 4,  0, 0, "", "",                      "",                     _("^TC^TT^BG generator spontaneously combusted due to overtime!"), "") \
      MSG_INFO_NOTIF(1, INFO_POWERUP_INVISIBILITY,           1, 0, "s1", "s1",                        "strength",             _("^BG%s^K1 picked up Invisibility"), "") \
      MSG_INFO_NOTIF(1, INFO_POWERUP_SHIELD,                 1, 0, "s1", "s1",                        "shield",               _("^BG%s^K1 picked up Shield"), "") \
      MSG_INFO_NOTIF(1, INFO_POWERUP_SPEED,                  1, 0, "s1", "s1",                        "shield",               _("^BG%s^K1 picked up Speed"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CAMPCHECK,                   0, 0, "",             CPID_CAMPCHECK,      "0 0", _("^F2Don't camp!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_COINTOSS,                    1, 0, "s1",           NO_CPID,             "0 0", _("^F2Throwing coin... Result: %s^F2!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_FREE,      0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGYou are now free.\n^BGFeel free to ^F2try to capture^BG the flag again\n^BGif you think you will succeed."), "") \
-     MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_SHIELDED,  0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGYou are now ^F1shielded^BG from the flag\n^BGfor ^F2too many unsuccessful attempts^BG to capture.\n^BGMake some defensive scores before trying again."), "") \
-     MULTITEAM_CENTER(1, CENTER_CTF_CAPTURE_, 2,             0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou captured the ^TC^TT^BG flag!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_INACTIVE,  0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGThis flag is currently inactive"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURESHIELD_SHIELDED,  0, 0, "",             CPID_CTF_CAPSHIELD,  "0 0", _("^BGYou are now ^F1shielded^BG from the flag(s)\n^BGfor ^F2too many unsuccessful attempts^BG to capture.\n^BGMake some defensive scores before trying again."), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_CAPTURE_, 4,             0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou captured the ^TC^TT^BG flag!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_CAPTURE_NEUTRAL,         0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou captured the flag!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_FLAG_THROW_PUNISH,       0, 1, "f1secs",       CPID_CTF_LOWPRIO,    "0 0", _("^BGToo many flag throws! Throwing disabled for %s."), "") \
-     MULTITEAM_CENTER(1, CENTER_CTF_PASS_OTHER_, 2,          2, 0, "s1 s2",        CPID_CTF_PASS,       "0 0", _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "") \
-     MULTITEAM_CENTER(1, CENTER_CTF_PASS_RECEIVED_, 2,       1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_PASS_OTHER_, 4,          2, 0, "s1 s2",        CPID_CTF_PASS,       "0 0", _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_OTHER_NEUTRAL,      2, 0, "s1 s2",        CPID_CTF_PASS,       "0 0", _("^BG%s^BG passed the flag to %s"), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_PASS_RECEIVED_, 4,       1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_RECEIVED_NEUTRAL,   1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou received the flag from %s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_REQUESTED,          1, 0, "s1 pass_key",  CPID_CTF_PASS,       "0 0", _("^BG%s^BG requests you to pass the flag%s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_REQUESTING,         1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGRequesting %s^BG to pass you the flag"), "") \
-     MULTITEAM_CENTER(1, CENTER_CTF_PASS_SENT_, 2,           1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "") \
-     MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_, 2,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the ^TC^TT^BG flag!"), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_PASS_SENT_, 4,           1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PASS_SENT_NEUTRAL,       1, 0, "s1",           CPID_CTF_PASS,       "0 0", _("^BGYou passed the flag to %s"), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_, 4,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the ^TC^TT^BG flag!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_NEUTRAL,          0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the flag!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM,             1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got your %steam^BG's flag, return it!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_ENEMY,       1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYou got the %senemy^BG's flag, return it!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY,            1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy^BG got your flag! Retrieve it!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_VERBOSE,    2, 0, "s1 s2 s1",     CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"), "") \
-     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM,             1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate^BG got the flag! Protect them!"), "") \
-     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_VERBOSE,     2, 0, "s1 s2 s1",     CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"), "") \
-     MULTITEAM_CENTER(1, CENTER_CTF_RETURN_, 2,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_NEUTRAL,    1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy^BG got the flag! Retrieve it!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_NEUTRAL_VERBOSE, 2, 0, "s1 s2 s1",CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_TEAM,        1, 0, "s1",          CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy^BG got their flag! Retrieve it!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_ENEMY_TEAM_VERBOSE,2, 0, "s1 s2 s1",    CPID_CTF_LOWPRIO,    "0 0", _("^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_TEAM_, 4,         1, 0, "s1",           CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_PICKUP_TEAM_VERBOSE_,    4, 2, 0, "s1 s2 s1",  CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_NEUTRAL,         1, 0, "s1",       CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate^BG got the flag! Protect them!"), "") \
+     MSG_CENTER_NOTIF(1, CENTER_CTF_PICKUP_TEAM_VERBOSE_NEUTRAL, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO,    "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"), "") \
+     MULTITEAM_CENTER(1, CENTER_CTF_RETURN_, 4,              0, 0, "",             CPID_CTF_LOWPRIO,    "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_STALEMATE_CARRIER,       0, 0, "",             CPID_STALEMATE,      "0 0", _("^BGStalemate! Enemies can now see you on radar!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_CTF_STALEMATE_OTHER,         0, 0, "",             CPID_STALEMATE,      "0 0", _("^BGStalemate! Flag carriers can now be seen by enemies on radar!"), "") \
      MSG_CENTER_NOTIF(1, CENTER_DEATH_MURDER_FRAG,                 1, 1, "spree_cen s1",             NO_CPID, "0 0", _("^K3%sYou fragged ^BG%s"), _("^K3%sYou scored against ^BG%s")) \
      MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVE_SELF,       0, 0, "",             NO_CPID,             "0 0", _("^K3You revived yourself"), "") \
      MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_REVIVED,           1, 0, "s1",           NO_CPID,             "0 0", _("^K3You were revived by ^BG%s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_AUTO_REVIVED,      0, 1, "f1",           NO_CPID,             "0 0", _("^K3You were automatically revived after %s second(s)"), "") \
 +    MSG_CENTER_NOTIF(1, CENTER_GENERATOR_UNDERATTACK,       0, 0, "",             NO_CPID,             "0 0", _("^BGThe generator is under attack!"), "") \
      MULTITEAM_CENTER(1, CENTER_ROUND_TEAM_WIN_, 4,          0, 0, "",             CPID_ROUND,          "0 0", _("^TC^TT^BG team wins the round"), "") \
      MSG_CENTER_NOTIF(1, CENTER_ROUND_PLAYER_WIN,            1, 0, "s1",           CPID_ROUND,          "0 0", _("^BG%s^BG wins the round"), "") \
      MSG_CENTER_NOTIF(1, CENTER_FREEZETAG_SELF,              0, 0, "",             NO_CPID,             "0 0", _("^K1You froze yourself"), "") \
      MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_ROUNDSTART,          0, 1, "",              CPID_KEYHUNT_OTHER,    "1 f1", _("^F4Round will start in ^COUNT"), "") \
      MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_SCAN,                0, 1, "",              CPID_KEYHUNT_OTHER,    "f1 0", _("^BGScanning frequency range..."), "") \
      MULTITEAM_CENTER(1, CENTER_KEYHUNT_START_, 4,           0, 0, "",              CPID_KEYHUNT,          "0 0", _("^BGYou are starting with the ^TC^TT Key"), "") \
-     MSG_CENTER_NOTIF(1, CENTER_KEYHUNT_WAIT,                0, 1, "missing_teams", CPID_KEYHUNT_OTHER,    "0 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_LMS_NOLIVES,                 0, 0, "",              CPID_LMS,              "0 0", _("^BGYou have no lives left, you must wait until the next match"), "") \
      MSG_CENTER_NOTIF(1, CENTER_MISSING_TEAMS,               0, 1, "missing_teams", CPID_MISSING_TEAMS,    "-1 0", _("^BGWaiting for players to join...\nNeed active players for: %s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_MISSING_PLAYERS,             0, 1, "f1",            CPID_MISSING_PLAYERS,  "-1 0", _("^BGWaiting for %s player(s) to join..."), "") \
      MSG_CENTER_NOTIF(1, CENTER_NIX_COUNTDOWN,               0, 2, "item_wepname",  CPID_NIX,              "1 f2", _("^F2^COUNT^BG until weapon change...\nNext weapon: ^F1%s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_NIX_NEWWEAPON,               0, 1, "item_wepname",  CPID_NIX,              "0 0", _("^F2Active weapon: ^F1%s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_NADE,                        0, 0, "",              NO_CPID,               "0 0", _("^BGPress ^F2DROPWEAPON^BG again to toss the grenade!"), "") \
 -    MSG_CENTER_NOTIF(1, CENTER_ONS_NOTSHIELDED,             0, 0, "",              CPID_ONSLAUGHT,        "0 0", _("^K1Your generator is NOT shielded!\n^BGRe-capture controlpoints to shield it!"), "") \
 +    MSG_CENTER_NOTIF(1, CENTER_ONS_CAPTURE,                 1, 0, "s1",            CPID_ONSLAUGHT,        "0 0", _("^BGYou captured %s^BG control point"), "") \
 +    MULTITEAM_CENTER(1, CENTER_ONS_CAPTURE_, 4,             1, 0, "s1",            CPID_ONSLAUGHT,        "0 0", _("^TC^TT^BG team captured %s^BG control point"), "") \
 +    MSG_CENTER_NOTIF(1, CENTER_ONS_CONTROLPOINT_SHIELDED,   0, 0, "",              CPID_ONS_CAPSHIELD,    "0 0", _("^BGThis control point currently cannot be captured"), "") \
 +    MSG_CENTER_NOTIF(1, CENTER_ONS_GENERATOR_SHIELDED,      0, 0, "",              CPID_ONS_CAPSHIELD,    "0 0", _("^BGThe enemy generator cannot be destroyed yet\n^F2Capture some control points to unshield it"), "") \
 +    MULTITEAM_CENTER(1, CENTER_ONS_NOTSHIELDED_, 4,         0, 0, "",              CPID_ONSLAUGHT,        "0 0", _("^BGThe ^TCenemy^BG generator is no longer shielded!"), "") \
 +    MSG_CENTER_NOTIF(1, CENTER_ONS_NOTSHIELDED_TEAM,        0, 0, "",              CPID_ONSLAUGHT,        "0 0", _("^K1Your generator is NOT shielded!\n^BGRe-capture control points to shield it!"), "") \
 +    MSG_CENTER_NOTIF(1, CENTER_ONS_TELEPORT,                0, 0, "pass_key",      CPID_ONSLAUGHT,        "0 0", _("^BGPress ^F2DROPFLAG%s^BG to teleport"), "") \
 +    MSG_CENTER_NOTIF(1, CENTER_ONS_TELEPORT_ANTISPAM,       0, 1, "f1secs",        CPID_ONSLAUGHT,        "0 0", _("^BGTeleporting disabled for %s"), "") \
      MSG_CENTER_NOTIF(1, CENTER_OVERTIME_FRAG,               0, 0, "",              CPID_OVERTIME,         "0 0", _("^F2Now playing ^F4OVERTIME^F2!\nKeep fragging until we have a winner!"), _("^F2Now playing ^F4OVERTIME^F2!\nKeep scoring until we have a winner!")) \
      MSG_CENTER_NOTIF(1, CENTER_OVERTIME_CONTROLPOINT,       0, 0, "",              CPID_OVERTIME,         "5 0", _("^F2Now playing ^F4OVERTIME^F2!\n\nGenerators are now decaying.\nThe more control points your team holds,\nthe faster the enemy generator decays"), "") \
      MSG_CENTER_NOTIF(1, CENTER_OVERTIME_TIME,               0, 1, "f1time",        CPID_OVERTIME,         "0 0", _("^F2Now playing ^F4OVERTIME^F2!\n^BGAdded ^F4%s^BG to the game!"), "") \
      MULTITEAM_MULTI##teams(default,prefix,anncepre,infopre,centerpre)
  
  #define MSG_MULTI_NOTIFICATIONS \
+     MSG_MULTI_NOTIF(1, DEATH_MURDER_BUFF,                    NO_MSG,        INFO_DEATH_MURDER_BUFF,                    NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_MURDER_CHEAT,                   NO_MSG,        INFO_DEATH_MURDER_CHEAT,                   NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_MURDER_DROWN,                   NO_MSG,        INFO_DEATH_MURDER_DROWN,                   NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_MURDER_FALL,                    NO_MSG,        INFO_DEATH_MURDER_FALL,                    NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_DEATH,           NO_MSG,        INFO_DEATH_MURDER_VH_WAKI_DEATH,           NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_GUN,             NO_MSG,        INFO_DEATH_MURDER_VH_WAKI_GUN,             NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_MURDER_VH_WAKI_ROCKET,          NO_MSG,        INFO_DEATH_MURDER_VH_WAKI_ROCKET,          NO_MSG) \
-     MSG_MULTI_NOTIF(1, DEATH_MURDER_VENGEANCE,               NO_MSG,        INFO_DEATH_MURDER_VENGEANCE,               NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_MURDER_VOID,                    NO_MSG,        INFO_DEATH_MURDER_VOID,                    NO_MSG) \
      MSG_MULTI_NOTIF(1, DEATH_SELF_AUTOTEAMCHANGE,            NO_MSG,        INFO_DEATH_SELF_AUTOTEAMCHANGE,            CENTER_DEATH_SELF_AUTOTEAMCHANGE) \
      MSG_MULTI_NOTIF(1, DEATH_SELF_BETRAYAL,                  NO_MSG,        INFO_DEATH_SELF_BETRAYAL,                  CENTER_DEATH_SELF_BETRAYAL) \
      MULTITEAM_CHOICE##teams(default,challow,prefix,chtype,optiona,optionb)
  
  #define MSG_CHOICE_NOTIFICATIONS \
-     MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_BROKEN_, 2,    MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_BROKEN_) \
-     MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_TIME_, 2,      MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_TIME_) \
-     MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_UNBROKEN_, 2,  MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_UNBROKEN_) \
-     MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_TEAM,           MSG_CENTER,  CENTER_CTF_PICKUP_TEAM,           CENTER_CTF_PICKUP_TEAM_VERBOSE) \
+     MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_BROKEN_, 4,    MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_BROKEN_) \
+     MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_TIME_, 4,      MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_TIME_) \
+     MULTITEAM_CHOICE(1, 2, CHOICE_CTF_CAPTURE_UNBROKEN_, 4,  MSG_INFO,    INFO_CTF_CAPTURE_,                INFO_CTF_CAPTURE_UNBROKEN_) \
+     MULTITEAM_CHOICE(1, 2, CHOICE_CTF_PICKUP_TEAM_, 4,       MSG_CENTER,  CENTER_CTF_PICKUP_TEAM_,          CENTER_CTF_PICKUP_TEAM_VERBOSE_) \
+     MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_TEAM_NEUTRAL,   MSG_CENTER,  CENTER_CTF_PICKUP_TEAM_NEUTRAL,   CENTER_CTF_PICKUP_TEAM_VERBOSE_NEUTRAL) \
      MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_ENEMY,          MSG_CENTER,  CENTER_CTF_PICKUP_ENEMY,          CENTER_CTF_PICKUP_ENEMY_VERBOSE) \
+     MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL,  MSG_CENTER,  CENTER_CTF_PICKUP_ENEMY_NEUTRAL,  CENTER_CTF_PICKUP_ENEMY_NEUTRAL_VERBOSE) \
+     MSG_CHOICE_NOTIF(1, 2, CHOICE_CTF_PICKUP_ENEMY_TEAM,     MSG_CENTER,  CENTER_CTF_PICKUP_ENEMY_TEAM,     CENTER_CTF_PICKUP_ENEMY_TEAM_VERBOSE) \
      MSG_CHOICE_NOTIF(1, 1, CHOICE_FRAG,                      MSG_CENTER,  CENTER_DEATH_MURDER_FRAG,         CENTER_DEATH_MURDER_FRAG_VERBOSE) \
      MSG_CHOICE_NOTIF(1, 1, CHOICE_FRAGGED,                   MSG_CENTER,  CENTER_DEATH_MURDER_FRAGGED,      CENTER_DEATH_MURDER_FRAGGED_VERBOSE) \
      MSG_CHOICE_NOTIF(1, 1, CHOICE_TYPEFRAG,                  MSG_CENTER,  CENTER_DEATH_MURDER_TYPEFRAG,     CENTER_DEATH_MURDER_TYPEFRAG_VERBOSE) \
@@@ -1081,7 -1094,8 +1106,8 @@@ const float ARG_DC = 6; // unique resul
      ARG_CASE(ARG_CS_SV,     "spree_end",     (autocvar_notification_show_sprees ? notif_arg_spree_inf(-1, "", "", f1) : "")) \
      ARG_CASE(ARG_CS_SV,     "spree_lost",    (autocvar_notification_show_sprees ? notif_arg_spree_inf(-2, "", "", f1) : "")) \
      ARG_CASE(ARG_CS_SV,     "item_wepname",  WEP_NAME(f1)) \
-     ARG_CASE(ARG_CS_SV,     "item_buffname", sprintf("%s%s", rgb_to_hexcolor(Buff_Color(f1)), Buff_PrettyName(f1))) \
+     ARG_CASE(ARG_CS_SV,     "item_buffname", sprintf("%s%s", rgb_to_hexcolor(BUFFS[f1].m_color), BUFFS[f1].m_prettyName)) \
+     ARG_CASE(ARG_CS_SV,     "f3buffname",    sprintf("%s%s", rgb_to_hexcolor(BUFFS[f3].m_color), BUFFS[f3].m_prettyName)) \
      ARG_CASE(ARG_CS_SV,     "item_wepammo",  (s1 != "" ? sprintf(_(" with %s"), s1) : "")) \
      ARG_CASE(ARG_DC,        "item_centime",  ftos(autocvar_notification_item_centerprinttime)) \
      ARG_CASE(ARG_SV,        "death_team",    Team_ColoredFullName(f1)) \
@@@ -1314,7 -1328,6 +1340,7 @@@ enum 
  ,   CPID_MOTD
  ,   CPID_NIX
  ,   CPID_ONSLAUGHT
 +,   CPID_ONS_CAPSHIELD
  ,   CPID_OVERTIME
  ,   CPID_POWERUP
  ,   CPID_RACE_FINISHLAP
@@@ -1334,9 -1347,9 +1360,9 @@@ float NOTIF_CHOICE_COUNT
  // notification limits -- INCREASE AS NECESSARY
  const float NOTIF_ANNCE_MAX   = 100;
  const float NOTIF_INFO_MAX    = 300;
- const float NOTIF_CENTER_MAX  = 200;
+ const float NOTIF_CENTER_MAX  = 250;
  const float NOTIF_MULTI_MAX   = 200;
- const float NOTIF_CHOICE_MAX  = 20;
+ const float NOTIF_CHOICE_MAX  = 30;
  
  // notification entities
  entity msg_annce_notifs[NOTIF_ANNCE_MAX];
diff --combined qcsrc/common/stats.qh
index f461d8b62cfee12e99b0f2a4cccf6b1a585e969c,eb6b0ea9704c67fadbe0c65fccf0901e903b9c04..e6c44368c15e22cff176cdf8d01f124825af8f0a
@@@ -109,18 -109,17 +109,17 @@@ const int STAT_OK_AMMO_CHARGE         
  const int STAT_OK_AMMO_CHARGEPOOL     = 86;
  const int STAT_FROZEN                 = 87;
  const int STAT_REVIVE_PROGRESS        = 88;
- const int STAT_ROUNDLOST              = 89;
- // 90 empty?
- // 91 empty?
- // 92 empty?
- // 93 empty?
- // 94 empty?
- // 95 empty?
- // 96 empty?
- // 97 empty?
- // 98 empty?
- // 99 empty?
+ const int STAT_ARMOR_LARGE_TIME       = 89;
+ const int STAT_HEALTH_MEGA_TIME       = 90;
+ const int STAT_INVISIBLE_TIME         = 91;
+ const int STAT_SPEED_TIME             = 92;
+ const int STAT_EXTRALIFE_TIME         = 93;
+ const int STAT_STRENGTH_TIME          = 94;
+ const int STAT_SHIELD_TIME            = 95;
+ const int STAT_FUELREGEN_TIME         = 96;
+ const int STAT_JETPACK_TIME           = 97;
+ const int STAT_SUPERWEAPONS_TIME      = 98;
 -// 99 empty?
++const int STAT_ROUNDLOST              = 99;
  
  /* The following stats change depending on the gamemode, so can share the same ID */
  // IDs 100 to 104 reserved for gamemodes
@@@ -171,11 -170,11 +170,11 @@@ const int STAT_PL_CROUCH_MAX3         
  const int STAT_PL_CROUCH_VIEW_OFS1    = 117;
  const int STAT_PL_CROUCH_VIEW_OFS2    = 118;
  const int STAT_PL_CROUCH_VIEW_OFS3    = 119;
- // 120 empty?
- // 121 empty?
- // 122 empty?
- // 123 empty?
- // 124 empty?
+ const int STAT_WEAPONSINMAP           = 120;
+ const int STAT_WEAPONSINMAP2          = 121;
+ const int STAT_WEAPONSINMAP3          = 122;
+ const int STAT_BUFF_TIME              = 123;
+ const int STAT_CTF_FLAGSTATUS         = 124;
  // 125 empty?
  // 126 empty?
  // 127 empty?
@@@ -246,8 -245,8 +245,8 @@@ const int STAT_GAMEPLAYFIX_EASIERWATERJ
  const int STAT_MOVEVARS_FRICTION_SLICK                = 191;
  const int STAT_MOVEVARS_FRICTION_ONLAND               = 192;
  const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS  = 193;
- const int STAT_MOVEVARS_JUMPSPEEDCAP_MAX              = 194;
- const int STAT_MOVEVARS_JUMPSPEEDCAP_MIN              = 195;
+ // 194 empty?
+ // 195 empty?
  const int STAT_DOUBLEJUMP                             = 196;
  const int STAT_MOVEVARS_TRACK_CANJUMP                 = 197;
  const int STAT_MULTIJUMP_ADD                          = 198;
index 4a779e0343c6d487e89608eca0257ab41f33554f,0b6d044753c6cc2e8004ef157287837daf21c16e..66161af1a8a4f96e3923587c3b7a0578902ad7a0
@@@ -238,6 -238,7 +238,7 @@@ float autocvar_g_ctf_throw_velocity_for
  float autocvar_g_ctf_throw_velocity_up;
  float autocvar_g_ctf_drop_velocity_up;
  float autocvar_g_ctf_drop_velocity_side;
+ bool autocvar_g_ctf_oneflag_reverse;
  bool autocvar_g_ctf_portalteleport;
  bool autocvar_g_ctf_pass;
  float autocvar_g_ctf_pass_arc;
@@@ -251,19 -252,18 +252,18 @@@ float autocvar_g_ctf_pass_turnrate
  float autocvar_g_ctf_pass_timelimit;
  float autocvar_g_ctf_pass_velocity;
  bool autocvar_g_ctf_dynamiclights;
- string autocvar_g_ctf_flag_blue_model;
- int autocvar_g_ctf_flag_blue_skin;
  float autocvar_g_ctf_flag_collect_delay;
  float autocvar_g_ctf_flag_damageforcescale;
int autocvar_g_ctf_flag_dropped_waypoint;
float autocvar_g_ctf_flag_dropped_floatinwater;
bool autocvar_g_ctf_flag_dropped_waypoint;
bool autocvar_g_ctf_flag_dropped_floatinwater;
  bool autocvar_g_ctf_flag_glowtrails;
float autocvar_g_ctf_flag_health;
string autocvar_g_ctf_flag_red_model;
int autocvar_g_ctf_flag_red_skin;
int autocvar_g_ctf_flag_health;
bool autocvar_g_ctf_flag_return;
float autocvar_g_ctf_flag_return_carried_radius;
  float autocvar_g_ctf_flag_return_time;
  bool autocvar_g_ctf_flag_return_when_unreachable;
  float autocvar_g_ctf_flag_return_damage;
+ float autocvar_g_ctf_flag_return_damage_delay;
  float autocvar_g_ctf_flag_return_dropped;
  float autocvar_g_ctf_flagcarrier_auto_helpme_damage;
  float autocvar_g_ctf_flagcarrier_auto_helpme_time;
@@@ -278,7 -278,6 +278,6 @@@ int autocvar_g_ctf_score_capture
  int autocvar_g_ctf_score_capture_assist;
  int autocvar_g_ctf_score_kill;
  int autocvar_g_ctf_score_penalty_drop;
- //int autocvar_g_ctf_score_penalty_suicidedrop;
  int autocvar_g_ctf_score_penalty_returned;
  int autocvar_g_ctf_score_pickup_base;
  int autocvar_g_ctf_score_pickup_dropped_early;
@@@ -434,6 -433,11 +433,6 @@@ bool autocvar_g_nix_with_powerups
  bool autocvar_g_nodepthtestitems;
  bool autocvar_g_nodepthtestplayers;
  bool autocvar_g_norecoil;
 -float autocvar_g_onslaught_cp_buildhealth;
 -float autocvar_g_onslaught_cp_buildtime;
 -float autocvar_g_onslaught_cp_health;
 -float autocvar_g_onslaught_cp_regen;
 -float autocvar_g_onslaught_gen_health;
  int autocvar_g_pickup_cells_max;
  int autocvar_g_pickup_plasma_max;
  int autocvar_g_pickup_fuel_max;
@@@ -621,9 -625,10 +620,10 @@@ float autocvar_sv_gameplayfix_q2airacce
  int autocvar_sv_gentle;
  #define autocvar_sv_gravity cvar("sv_gravity")
  string autocvar_sv_intermission_cdtrack;
- float autocvar_sv_jumpspeedcap_max;
+ float autocvar_sv_itemstime;
+ string autocvar_sv_jumpspeedcap_max;
  float autocvar_sv_jumpspeedcap_max_disable_on_ramps;
float autocvar_sv_jumpspeedcap_min;
string autocvar_sv_jumpspeedcap_min;
  float autocvar_sv_jumpvelocity;
  bool autocvar_sv_logscores_bots;
  bool autocvar_sv_logscores_console;
@@@ -829,35 -834,12 +829,36 @@@ float autocvar_g_spawn_near_teammate_di
  bool autocvar_g_spawn_near_teammate_ignore_spawnpoint;
  float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay;
  float autocvar_g_spawn_near_teammate_ignore_spawnpoint_delay_death;
 +float autocvar_g_onslaught_debug;
 +float autocvar_g_onslaught_teleport_wait;
 +bool autocvar_g_onslaught_spawn_at_controlpoints;
 +bool autocvar_g_onslaught_spawn_at_generator;
 +float autocvar_g_onslaught_cp_proxydecap;
 +float autocvar_g_onslaught_cp_proxydecap_distance = 512;
 +float autocvar_g_onslaught_cp_proxydecap_dps = 100;
 +float autocvar_g_onslaught_spawn_at_controlpoints_chance = 0.5;
 +float autocvar_g_onslaught_spawn_at_controlpoints_random;
 +float autocvar_g_onslaught_spawn_at_generator_chance;
 +float autocvar_g_onslaught_spawn_at_generator_random;
 +float autocvar_g_onslaught_cp_buildhealth;
 +float autocvar_g_onslaught_cp_buildtime;
 +float autocvar_g_onslaught_cp_health;
 +float autocvar_g_onslaught_cp_regen;
 +float autocvar_g_onslaught_gen_health;
 +float autocvar_g_onslaught_shield_force = 100;
 +float autocvar_g_onslaught_allow_vehicle_touch;
 +float autocvar_g_onslaught_round_timelimit;
 +float autocvar_g_onslaught_point_limit;
 +float autocvar_g_onslaught_warmup;
 +float autocvar_g_onslaught_teleport_radius;
 +float autocvar_g_onslaught_spawn_choose;
 +float autocvar_g_onslaught_click_radius;
  int autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health;
  bool autocvar_g_spawn_near_teammate_ignore_spawnpoint_closetodeath;
  bool autocvar_g_physics_clientselect;
  string autocvar_g_physics_clientselect_options;
  string autocvar_g_physics_clientselect_default;
+ bool  autocvar_g_buffs_effects;
  float autocvar_g_buffs_waypoint_distance;
  bool autocvar_g_buffs_randomize;
  float autocvar_g_buffs_random_lifetime;
@@@ -876,16 -858,25 +877,25 @@@ float autocvar_g_buffs_medic_regen
  float autocvar_g_buffs_vengeance_damage_multiplier;
  float autocvar_g_buffs_bash_force;
  float autocvar_g_buffs_bash_force_self;
- float autocvar_g_buffs_disability_time;
+ float autocvar_g_buffs_disability_slowtime;
  float autocvar_g_buffs_disability_speed;
  float autocvar_g_buffs_disability_rate;
+ float autocvar_g_buffs_disability_weaponspeed;
  float autocvar_g_buffs_speed_speed;
  float autocvar_g_buffs_speed_rate;
+ float autocvar_g_buffs_speed_weaponspeed;
  float autocvar_g_buffs_speed_damage_take;
  float autocvar_g_buffs_speed_regen;
  float autocvar_g_buffs_vampire_damage_steal;
  float autocvar_g_buffs_invisible_alpha;
  float autocvar_g_buffs_flight_gravity;
  float autocvar_g_buffs_jump_height;
+ float autocvar_g_buffs_inferno_burntime_factor;
+ float autocvar_g_buffs_inferno_burntime_min_time;
+ float autocvar_g_buffs_inferno_burntime_target_damage;
+ float autocvar_g_buffs_inferno_burntime_target_time;
+ float autocvar_g_buffs_inferno_damagemultiplier;
+ float autocvar_g_buffs_swapper_range;
+ float autocvar_g_buffs_magnet_range_item;
  float autocvar_sv_player_scale;
  #endif
diff --combined qcsrc/server/g_damage.qc
index 050607b4c95f005f46ffae43e6abc4d98ca81b53,c5bbfcab55ed0f132ece9d8e55d517afac328338..142d8a85b50c55419fad3e9d004fe4f6a5cc0f68
@@@ -12,6 -12,7 +12,7 @@@
  #include "weapons/accuracy.qh"
  #include "weapons/csqcprojectile.qh"
  #include "weapons/selection.qh"
+ #include "../common/buffs.qh"
  #include "../common/constants.qh"
  #include "../common/deathtypes.qh"
  #include "../common/notifications.qh"
@@@ -483,8 -484,12 +484,12 @@@ void Obituary(entity attacker, entity i
                                );
                        }
  
+                       float f3 = 0;
+                       if(deathtype == DEATH_BUFF)
+                               f3 = attacker.buffs;
                        if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker))
-                               Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker, 0);
+                               Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker.netname, deathlocation, targ.killcount, kill_count_to_attacker, f3);
                }
        }
  
@@@ -839,7 -844,7 +844,7 @@@ void Damage (entity targ, entity inflic
                // count the damage
                if(attacker)
                if(!targ.deadflag)
-               if(deathtype != DEATH_BUFF_VENGEANCE)
+               if(deathtype != DEATH_BUFF)
                if(targ.takedamage == DAMAGE_AIM)
                if(targ != attacker)
                {
                        else
                                victim = targ;
  
 -                      if(IS_PLAYER(victim) || (victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET) || (victim.flags & FL_MONSTER))
 +                      if(IS_PLAYER(victim) || (victim.turrcaps_flags & TFL_TURRCAPS_ISTURRET) || (victim.flags & FL_MONSTER) || victim.classname == "func_assault_destructible" || (victim.classname == "onslaught_generator" && !victim.isshielded) || (victim.classname == "onslaught_controlpoint_icon" && !victim.owner.isshielded))
                        {
                                if(DIFF_TEAM(victim, attacker) && !victim.frozen)
                                {
@@@ -1121,7 -1126,7 +1126,7 @@@ float RadiusDamageForSource (entity inf
        RadiusDamage_running = 0;
  
        if(!DEATH_ISSPECIAL(deathtype))
-               accuracy_add(attacker, DEATH_WEAPONOFWEAPONDEATH(deathtype), 0, min(coredamage, stat_damagedone));
+               accuracy_add(attacker, DEATH_WEAPONOF(deathtype), 0, min(coredamage, stat_damagedone));
  
        return total_damage_to_creatures;
  }
@@@ -1237,7 -1242,7 +1242,7 @@@ float Fire_AddDamage(entity e, entity o
                                }
                        }
                        if(accuracy_isgooddamage(o, e))
-                               accuracy_add(o, DEATH_WEAPONOFWEAPONDEATH(dt), 0, max(0, totaldamage - mindamage));
+                               accuracy_add(o, DEATH_WEAPONOF(dt), 0, max(0, totaldamage - mindamage));
                        return max(0, totaldamage - mindamage); // can never be negative, but to make sure
                }
                else
                e.fire_owner = o;
                e.fire_hitsound = false;
                if(accuracy_isgooddamage(o, e))
-                       accuracy_add(o, DEATH_WEAPONOFWEAPONDEATH(dt), 0, d);
+                       accuracy_add(o, DEATH_WEAPONOF(dt), 0, d);
                return d;
        }
  }
diff --combined qcsrc/server/g_world.qc
index 33cfc81b4fe0ad37a95e1a80f7fd9ef99092a80d,881f8f071915aef1eaa5428cab0b143bca65b953..f8748e94935fe62f005c8d7b0c4c41d055b619ff
@@@ -559,13 -559,10 +559,10 @@@ void spawnfunc___init_dedicated_server(
        self.classname = "worldspawn"; // safeguard against various stuff ;)
  
        // needs to be done so early because of the constants they create
+       static_init();
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
-       CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
-       CALL_ACCUMULATED_FUNCTION(RegisterItems);
-       CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
        CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
        CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
-       CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
  
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 0);
  void Map_MarkAsRecent(string m);
  float world_already_spawned;
  void Nagger_Init();
+ void Item_ItemsTime_Init();
  void ClientInit_Spawn();
  void WeaponStats_Init();
  void WeaponStats_Shutdown();
@@@ -609,13 -607,10 +607,10 @@@ void spawnfunc_worldspawn (void
        server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? true : false);
  
        // needs to be done so early because of the constants they create
+       static_init();
        CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
-       CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
-       CALL_ACCUMULATED_FUNCTION(RegisterItems);
-       CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
        CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
        CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
-       CALL_ACCUMULATED_FUNCTION(RegisterBuffs);
  
        ServerProgsDB = db_load(strcat("server.db", autocvar_sessionid));
  
        WeaponStats_Init();
  
        WepSet_AddStat();
+       WepSet_AddStat_InMap();
        addstat(STAT_SWITCHWEAPON, AS_INT, switchweapon);
        addstat(STAT_SWITCHINGWEAPON, AS_INT, switchingweapon);
        addstat(STAT_GAMESTARTTIME, AS_FLOAT, stat_game_starttime);
  
        addstat(STAT_ARC_HEAT, AS_FLOAT, arc_heat_percent);
  
+       // items time
+       addstat(STAT_ARMOR_LARGE_TIME, AS_FLOAT, item_armor_large_time);
+       addstat(STAT_HEALTH_MEGA_TIME, AS_FLOAT, item_health_mega_time);
+       addstat(STAT_INVISIBLE_TIME, AS_FLOAT, item_invisible_time);
+       addstat(STAT_SPEED_TIME, AS_FLOAT, item_speed_time);
+       addstat(STAT_EXTRALIFE_TIME, AS_FLOAT, item_extralife_time);
+       addstat(STAT_STRENGTH_TIME, AS_FLOAT, item_strength_time);
+       addstat(STAT_SHIELD_TIME, AS_FLOAT, item_shield_time);
+       addstat(STAT_FUELREGEN_TIME, AS_FLOAT, item_fuelregen_time);
+       addstat(STAT_JETPACK_TIME, AS_FLOAT, item_jetpack_time);
+       addstat(STAT_SUPERWEAPONS_TIME, AS_FLOAT, item_superweapons_time);
+       Item_ItemsTime_Init();
        // freeze attacks
        addstat(STAT_FROZEN, AS_INT, frozen);
        addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, revive_progress);
@@@ -1693,6 -1702,48 +1702,6 @@@ void ClearWinners(void
                head.winning = 0;
  }
  
 -// Onslaught winning condition:
 -// game terminates if only one team has a working generator (or none)
 -float WinningCondition_Onslaught()
 -{
 -      entity head;
 -      float t1, t2, t3, t4;
 -
 -      WinningConditionHelper(); // set worldstatus
 -
 -      if(warmup_stage)
 -              return WINNING_NO;
 -
 -      // first check if the game has ended
 -      t1 = t2 = t3 = t4 = 0;
 -      head = find(world, classname, "onslaught_generator");
 -      while (head)
 -      {
 -              if (head.health > 0)
 -              {
 -                      if (head.team == NUM_TEAM_1) t1 = 1;
 -                      if (head.team == NUM_TEAM_2) t2 = 1;
 -                      if (head.team == NUM_TEAM_3) t3 = 1;
 -                      if (head.team == NUM_TEAM_4) t4 = 1;
 -              }
 -              head = find(head, classname, "onslaught_generator");
 -      }
 -      if (t1 + t2 + t3 + t4 < 2)
 -      {
 -              // game over, only one team remains (or none)
 -              ClearWinners();
 -              if (t1) SetWinners(team, NUM_TEAM_1);
 -              if (t2) SetWinners(team, NUM_TEAM_2);
 -              if (t3) SetWinners(team, NUM_TEAM_3);
 -              if (t4) SetWinners(team, NUM_TEAM_4);
 -              dprint("Have a winner, ending game.\n");
 -              return WINNING_YES;
 -      }
 -
 -      // Two or more teams remain
 -      return WINNING_NO;
 -}
 -
  // Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
  // they win. Otherwise the defending team wins once the timelimit passes.
  void assault_new_round();
@@@ -2061,6 -2112,9 +2070,6 @@@ void CheckRules_World(
                return;
        }
  
 -      if(g_onslaught)
 -              timelimit = 0; // ONS has its own overtime rule
 -
        float wantovertime;
        wantovertime = 0;
  
        {
                checkrules_status = WinningCondition_LMS();
        }
 -      else if (g_onslaught)
 -      {
 -              checkrules_status = WinningCondition_Onslaught(); // TODO remove this?
 -      }
        else
        {
                checkrules_status = WinningCondition_Scores(fraglimit, leadlimit);
diff --combined qcsrc/server/progs.src
index 12a4f81820f7ace88dc8cd5f62325eb9ec4d403a,388d1b675486fd8e0d1e21fb5db53343a0534682..38ff5dfc7eca165a19a4a7e71e915c8ff5d6c4ce
@@@ -5,6 -5,7 +5,7 @@@ sys-pre.q
  ../dpdefs/progsdefs.qh
  ../dpdefs/dpextensions.qh
  sys-post.qh
+ ../common/util-post.qh
  
  anticheat.qc
  antilag.qc
@@@ -13,7 -14,6 +14,7 @@@ cheats.q
  cl_client.qc
  cl_impulse.qc
  cl_player.qc
 +controlpoint.qc
  csqceffects.qc
  ent_cs.qc
  g_casings.qc
@@@ -25,7 -25,6 +26,7 @@@ g_subs.q
  g_tetris.qc
  g_violence.qc
  g_world.qc
 +generator.qc
  ipban.qc
  item_key.qc
  mapvoting.qc
@@@ -56,6 -55,7 +57,6 @@@ bot/waypoints.q
  
  bot/havocbot/havocbot.qc
  bot/havocbot/role_keyhunt.qc
 -bot/havocbot/role_onslaught.qc
  bot/havocbot/roles.qc
  
  command/all.qc
@@@ -97,7 -97,9 +98,9 @@@ weapons/weaponsystem.q
  ../common/notifications.qc
  ../common/physics.qc
  ../common/playerstats.qc
+ ../common/p2mathlib.qc
  ../common/test.qc
+ ../common/viewloc.qc
  ../common/triggers/include.qc
  ../common/urllib.qc
  ../common/util.qc
diff --combined qcsrc/server/teamplay.qc
index cb03a31b46d7b83647d0f53929000368ba7968b7,ec6f5afc3d16fc1fe1073452f467c6bbe3389a2a..73332277c1be43ac93d7113504bf6f571f6d65de
@@@ -41,6 -41,7 +41,7 @@@ void ActivateTeamplay(
  {
        serverflags |= SERVERFLAG_TEAMPLAY;
        teamplay = 1;
+       cvar_set("teamplay", "2");  // DP needs this for sending proper getstatus replies.
  }
  
  void InitGameplayMode()
@@@ -57,8 -58,9 +58,9 @@@
        world.maxs = mi_max;
  
        MapInfo_LoadMapSettings(mapname);
-       teamplay = 0;
        serverflags &= ~SERVERFLAG_TEAMPLAY;
+       teamplay = 0;
+       cvar_set("teamplay", "0");  // DP needs this for sending proper getstatus replies.
  
        if (!cvar_value_issafe(world.fog))
        {
        if(g_onslaught)
        {
                ActivateTeamplay();
 +              fraglimit_override = autocvar_g_onslaught_point_limit;
                have_team_spawns = -1; // request team spawns
                MUTATOR_ADD(gamemode_onslaught);
        }
index 6c714d1f3fb438c15245ca44c4f3cb23259755b5,b0c8cb1226eaeda11f432629baabccf5dee87f33..f1183b7d1db87a3eeb16bdfddf573e4a0ef76024
@@@ -199,7 -199,14 +199,14 @@@ float WaypointSprite_visible_for_player
                        return false;
  
        // team waypoints
-       if(self.team && self.rule == SPRITERULE_DEFAULT)
+       if(self.rule == SPRITERULE_SPECTATOR)
+       {
+               if(!autocvar_sv_itemstime)
+                       return FALSE;
+               if(!warmup_stage && e.classname == "player")
+                       return FALSE;
+       }
+       else if(self.team && self.rule == SPRITERULE_DEFAULT)
        {
                if(self.team != e.team)
                        return false;
@@@ -307,27 -314,12 +314,27 @@@ float WaypointSprite_SendEntity(entity 
                WriteCoord(MSG_ENTITY, self.fade_time);
                WriteCoord(MSG_ENTITY, self.teleport_time);
                WriteShort(MSG_ENTITY, self.fade_rate); // maxdist
 -              float f;
 -              f = 0;
 +              float f = 0;
                if(self.currentammo)
                        f |= 1; // hideable
                if(self.exteriormodeltoclient == to)
                        f |= 2; // my own
 +              if(g_onslaught)
 +              {
 +                      if(self.owner.classname == "onslaught_controlpoint")
 +                      {
 +                              entity wp_owner = self.owner;
 +                              entity e = WaypointSprite_getviewentity(to);
 +                              if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { f |= 2; }
 +                              if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { f |= 2; }
 +                      }
 +                      if(self.owner.classname == "onslaught_generator")
 +                      {
 +                              entity wp_owner = self.owner;
 +                              if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { f |= 2; }
 +                              if(wp_owner.health <= 0) { f |= 2; }
 +                      }
 +              }
                WriteByte(MSG_ENTITY, f);
        }