Merge branch 'master' into Mario/showspecs
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud.qc
index 08dcd6d..2aaa81b 100644 (file)
@@ -1,3 +1,11 @@
+#include "scoreboard.qh"
+#include "teamradar.qh"
+#include "../common/buffs.qh"
+#include "../common/counting.qh"
+#include "../common/mapinfo.qh"
+#include "../common/nades.qh"
+#include "../server/t_items.qh"
+
 /*
 ==================
 Misc HUD functions
@@ -14,12 +22,12 @@ Misc HUD functions
 //   1/4 height: bottom part
 void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector theColor, float theAlpha, vector theBorderSize)
 {
-    if (theBorderSize_x < 0 && theBorderSize_y < 0) // draw whole image as it is
+    if (theBorderSize.x < 0 && theBorderSize.y < 0) // draw whole image as it is
     {
                drawpic(theOrigin, pic, theSize, theColor, theAlpha, 0);
                return;
     }
-       if (theBorderSize_x == 0 && theBorderSize_y == 0) // no border
+       if (theBorderSize.x == 0 && theBorderSize.y == 0) // no border
        {
                // draw only the central part
                drawsubpic(theOrigin, theSize, pic, '0.25 0.25 0', '0.5 0.5 0', theColor, theAlpha, 0);
@@ -30,16 +38,16 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the
        vector width, height;
        vector bW, bH;
        //pic = draw_UseSkinFor(pic);
-       width = eX * theSize_x;
-       height = eY * theSize_y;
-       if(theSize_x <= theBorderSize_x * 2)
+       width = eX * theSize.x;
+       height = eY * theSize.y;
+       if(theSize.x <= theBorderSize.x * 2)
        {
                // not wide enough... draw just left and right then
-               bW = eX * (0.25 * theSize_x / (theBorderSize_x * 2));
-               if(theSize_y <= theBorderSize_y * 2)
+               bW = eX * (0.25 * theSize.x / (theBorderSize.x * 2));
+               if(theSize.y <= theBorderSize.y * 2)
                {
                        // not high enough... draw just corners
-                       bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2));
+                       bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
                        drawsubpic(theOrigin,                 width * 0.5 + height * 0.5, pic, '0 0 0',           bW + bH, theColor, theAlpha, 0);
                        drawsubpic(theOrigin + width   * 0.5, width * 0.5 + height * 0.5, pic, eX - bW,           bW + bH, theColor, theAlpha, 0);
                        drawsubpic(theOrigin + height  * 0.5, width * 0.5 + height * 0.5, pic, eY - bH,           bW + bH, theColor, theAlpha, 0);
@@ -47,7 +55,7 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the
                }
                else
                {
-                       dY = theBorderSize_x * eY;
+                       dY = theBorderSize.x * eY;
                        drawsubpic(theOrigin,                             width * 0.5          +     dY, pic, '0 0    0',           '0 0.25 0' + bW, theColor, theAlpha, 0);
                        drawsubpic(theOrigin + width * 0.5,               width * 0.5          +     dY, pic, '0 0    0' + eX - bW, '0 0.25 0' + bW, theColor, theAlpha, 0);
                        drawsubpic(theOrigin                        + dY, width * 0.5 + height - 2 * dY, pic, '0 0.25 0',           '0 0.5  0' + bW, theColor, theAlpha, 0);
@@ -58,11 +66,11 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the
        }
        else
        {
-               if(theSize_y <= theBorderSize_y * 2)
+               if(theSize.y <= theBorderSize.y * 2)
                {
                        // not high enough... draw just top and bottom then
-                       bH = eY * (0.25 * theSize_y / (theBorderSize_y * 2));
-                       dX = theBorderSize_x * eX;
+                       bH = eY * (0.25 * theSize.y / (theBorderSize.y * 2));
+                       dX = theBorderSize.x * eX;
                        drawsubpic(theOrigin,                                         dX + height * 0.5, pic, '0    0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
                        drawsubpic(theOrigin + dX,                        width - 2 * dX + height * 0.5, pic, '0.25 0 0',           '0.5  0 0' + bH, theColor, theAlpha, 0);
                        drawsubpic(theOrigin + width - dX,                            dX + height * 0.5, pic, '0.75 0 0',           '0.25 0 0' + bH, theColor, theAlpha, 0);
@@ -72,8 +80,8 @@ void draw_BorderPicture(vector theOrigin, string pic, vector theSize, vector the
                }
                else
                {
-                       dX = theBorderSize_x * eX;
-                       dY = theBorderSize_x * eY;
+                       dX = theBorderSize.x * eX;
+                       dY = theBorderSize.x * eY;
                        drawsubpic(theOrigin,                                        dX          +     dY, pic, '0    0    0', '0.25 0.25 0', theColor, theAlpha, 0);
                        drawsubpic(theOrigin                  + dX,      width - 2 * dX          +     dY, pic, '0.25 0    0', '0.5  0.25 0', theColor, theAlpha, 0);
                        drawsubpic(theOrigin          + width - dX,                  dX          +     dY, pic, '0.75 0    0', '0.25 0.25 0', theColor, theAlpha, 0);
@@ -92,65 +100,111 @@ vector HUD_Get_Num_Color (float x, float maxvalue)
        float blinkingamt;
        vector color;
        if(x >= maxvalue) {
-               color_x = sin(2*M_PI*time);
-               color_y = 1;
-               color_z = sin(2*M_PI*time);
+               color.x = sin(2*M_PI*time);
+               color.y = 1;
+               color.z = sin(2*M_PI*time);
        }
        else if(x > maxvalue * 0.75) {
-               color_x = 0.4 - (x-150)*0.02 * 0.4; //red value between 0.4 -> 0
-               color_y = 0.9 + (x-150)*0.02 * 0.1; // green value between 0.9 -> 1
-               color_z = 0;
+               color.x = 0.4 - (x-150)*0.02 * 0.4; //red value between 0.4 -> 0
+               color.y = 0.9 + (x-150)*0.02 * 0.1; // green value between 0.9 -> 1
+               color.z = 0;
        }
        else if(x > maxvalue * 0.5) {
-               color_x = 1 - (x-100)*0.02 * 0.6; //red value between 1 -> 0.4
-               color_y = 1 - (x-100)*0.02 * 0.1; // green value between 1 -> 0.9
-               color_z = 1 - (x-100)*0.02; // blue value between 1 -> 0
+               color.x = 1 - (x-100)*0.02 * 0.6; //red value between 1 -> 0.4
+               color.y = 1 - (x-100)*0.02 * 0.1; // green value between 1 -> 0.9
+               color.z = 1 - (x-100)*0.02; // blue value between 1 -> 0
        }
        else if(x > maxvalue * 0.25) {
-               color_x = 1;
-               color_y = 1;
-               color_z = 0.2 + (x-50)*0.02 * 0.8; // blue value between 0.2 -> 1
+               color.x = 1;
+               color.y = 1;
+               color.z = 0.2 + (x-50)*0.02 * 0.8; // blue value between 0.2 -> 1
        }
        else if(x > maxvalue * 0.1) {
-               color_x = 1;
-               color_y = (x-20)*90/27/100; // green value between 0 -> 1
-               color_z = (x-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
+               color.x = 1;
+               color.y = (x-20)*90/27/100; // green value between 0 -> 1
+               color.z = (x-20)*90/27/100 * 0.2; // blue value between 0 -> 0.2
        }
        else {
-               color_x = 1;
-               color_y = 0;
-               color_z = 0;
+               color.x = 1;
+               color.y = 0;
+               color.z = 0;
        }
 
        blinkingamt = (1 - x/maxvalue/0.25);
        if(blinkingamt > 0)
        {
-               color_x = color_x - color_x * blinkingamt * sin(2*M_PI*time);
-               color_y = color_y - color_y * blinkingamt * sin(2*M_PI*time);
-               color_z = color_z - color_z * blinkingamt * sin(2*M_PI*time);
+               color.x = color.x - color.x * blinkingamt * sin(2*M_PI*time);
+               color.y = color.y - color.y * blinkingamt * sin(2*M_PI*time);
+               color.z = color.z - color.z * blinkingamt * sin(2*M_PI*time);
        }
        return color;
 }
 
+float HUD_GetRowCount(float item_count, vector size, float item_aspect)
+{
+       float aspect = size_y / size_x;
+       return bound(1, floor((sqrt(4 * item_aspect * aspect * item_count + aspect * aspect) + aspect + 0.5) / 2), item_count);
+}
+
+vector HUD_GetTableSize(float item_count, vector psize, float item_aspect)
+{
+       float columns, rows;
+       float ratio, best_ratio = 0;
+       float best_columns = 1, best_rows = 1;
+       bool vertical = (psize.x / psize.y >= item_aspect);
+       if(vertical)
+       {
+               psize = eX * psize.y + eY * psize.x;
+               item_aspect = 1 / item_aspect;
+       }
+
+       rows = ceil(sqrt(item_count));
+       columns = ceil(item_count/rows);
+       while(columns >= 1)
+       {
+               ratio = (psize.x/columns) / (psize.y/rows);
+               if(ratio > item_aspect)
+                       ratio = item_aspect * item_aspect / ratio;
+
+               if(ratio <= best_ratio)
+                       break; // ratio starts decreasing by now, skip next configurations
+
+               best_columns = columns;
+               best_rows = rows;
+               best_ratio = ratio;
+
+               if(columns == 1)
+                       break;
+
+               --columns;
+               rows = ceil(item_count/columns);
+       }
+
+       if(vertical)
+               return eX * best_rows + eY * best_columns;
+       else
+               return eX * best_columns + eY * best_rows;
+}
+
 float stringwidth_colors(string s, vector theSize)
 {
-       return stringwidth(s, TRUE, theSize);
+       return stringwidth(s, true, theSize);
 }
 
 float stringwidth_nocolors(string s, vector theSize)
 {
-       return stringwidth(s, FALSE, theSize);
+       return stringwidth(s, false, theSize);
 }
 
 void drawstringright(vector position, string text, vector theScale, vector rgb, float theAlpha, float flag)
 {
-       position_x -= 2 / 3 * strlen(text) * theScale_x;
+       position.x -= 2 / 3 * strlen(text) * theScale.x;
        drawstring(position, text, theScale, rgb, theAlpha, flag);
 }
 
 void drawstringcenter(vector position, string text, vector theScale, vector rgb, float theAlpha, float flag)
 {
-       position_x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale_x);
+       position.x = 0.5 * (vid_conwidth - 0.6025 * strlen(text) * theScale.x);
        drawstring(position, text, theScale, rgb, theAlpha, flag);
 }
 
@@ -218,9 +272,9 @@ string MakeRaceString(float cp, float mytime, float histime, float lapdelta, str
        if(histime < 0)
                return strcat(col, cpname);
        else if(hisname == "")
-               return strcat(col, sprintf(_("%s (%s)"), cpname, timestr));
+               return strcat(col, sprintf("%s (%s)", cpname, timestr));
        else
-               return strcat(col, sprintf(_("%s (%s %s)"), cpname, timestr, strcat(hisname, col, lapstr)));
+               return strcat(col, sprintf("%s (%s %s)", cpname, timestr, strcat(hisname, col, lapstr)));
 }
 
 // Check if the given name already exist in race rankings? In that case, where? (otherwise return 0)
@@ -232,7 +286,7 @@ float race_CheckName(string net_name) {
        return 0;
 }
 
-float GetPlayerColorForce(float i)
+float GetPlayerColorForce(int i)
 {
        if(!teamplay)
                return 0;
@@ -240,7 +294,7 @@ float GetPlayerColorForce(float i)
                return stof(getplayerkeyvalue(i, "colors")) & 15;
 }
 
-float GetPlayerColor(float i)
+float GetPlayerColor(int i)
 {
        if(!playerslots[i].gotscores) // unconnected
                return NUM_SPECTATOR;
@@ -250,7 +304,7 @@ float GetPlayerColor(float i)
                return GetPlayerColorForce(i);
 }
 
-string GetPlayerName(float i)
+string GetPlayerName(int i)
 {
        return ColorTranslateRGB(getplayerkeyvalue(i, "name"));
 }
@@ -263,9 +317,10 @@ HUD panels
 */
 
 // draw the background/borders
-#define HUD_Panel_DrawBg(theAlpha)\
-if(panel_bg != "0" && panel_bg != "")\
-       draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER))
+#define HUD_Panel_DrawBg(theAlpha) do {                                                                                                                                                                \
+       if(panel.current_panel_bg != "0" && panel.current_panel_bg != "")                                                                                               \
+               draw_BorderPicture(panel_pos - '1 1 0' * panel_bg_border, panel.current_panel_bg, panel_size + '1 1 0' * 2 * panel_bg_border, panel_bg_color, panel_bg_alpha * theAlpha, '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));\
+} while(0)
 
 //basically the same code of draw_ButtonPicture and draw_VertButtonPicture for the menu
 void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, float vertical, float baralign, vector theColor, float theAlpha, float drawflag)
@@ -291,37 +346,37 @@ void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, flo
                }
 
         if (baralign == 1) // bottom align
-                       theOrigin_y += (1 - length_ratio) * theSize_y;
+                       theOrigin.y += (1 - length_ratio) * theSize.y;
         else if (baralign == 2) // center align
-            theOrigin_y += 0.5 * (1 - length_ratio) * theSize_y;
+            theOrigin.y += 0.5 * (1 - length_ratio) * theSize.y;
         else if (baralign == 3) // center align, positive values down, negative up
                {
-                       theSize_y *= 0.5;
+                       theSize.y *= 0.5;
                        if (length_ratio > 0)
-                               theOrigin_y += theSize_y;
+                               theOrigin.y += theSize.y;
                        else
                        {
-                               theOrigin_y += (1 + length_ratio) * theSize_y;
+                               theOrigin.y += (1 + length_ratio) * theSize.y;
                                length_ratio = -length_ratio;
                        }
                }
-               theSize_y *= length_ratio;
+               theSize.y *= length_ratio;
 
                vector bH;
-               width = eX * theSize_x;
-               height = eY * theSize_y;
-               if(theSize_y <= theSize_x * 2)
+               width = eX * theSize.x;
+               height = eY * theSize.y;
+               if(theSize.y <= theSize.x * 2)
                {
                        // button not high enough
                        // draw just upper and lower part then
-                       square = eY * theSize_y * 0.5;
-                       bH = eY * (0.25 * theSize_y / (theSize_x * 2));
+                       square = eY * theSize.y * 0.5;
+                       bH = eY * (0.25 * theSize.y / (theSize.x * 2));
                        drawsubpic(theOrigin,          square + width, pic, '0 0 0', eX + bH, theColor, theAlpha, drawflag);
                        drawsubpic(theOrigin + square, square + width, pic, eY - bH, eX + bH, theColor, theAlpha, drawflag);
                }
                else
                {
-                       square = eY * theSize_x;
+                       square = eY * theSize.x;
                        drawsubpic(theOrigin,                   width   +     square, pic, '0 0    0', '1 0.25 0', theColor, theAlpha, drawflag);
                        drawsubpic(theOrigin +          square, theSize - 2 * square, pic, '0 0.25 0', '1 0.5  0', theColor, theAlpha, drawflag);
                        drawsubpic(theOrigin + height - square, width   +     square, pic, '0 0.75 0', '1 0.25 0', theColor, theAlpha, drawflag);
@@ -333,37 +388,37 @@ void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, flo
                }
 
                if (baralign == 1) // right align
-                       theOrigin_x += (1 - length_ratio) * theSize_x;
+                       theOrigin.x += (1 - length_ratio) * theSize.x;
         else if (baralign == 2) // center align
-            theOrigin_x += 0.5 * (1 - length_ratio) * theSize_x;
+            theOrigin.x += 0.5 * (1 - length_ratio) * theSize.x;
         else if (baralign == 3) // center align, positive values on the right, negative on the left
                {
-                       theSize_x *= 0.5;
+                       theSize.x *= 0.5;
                        if (length_ratio > 0)
-                               theOrigin_x += theSize_x;
+                               theOrigin.x += theSize.x;
                        else
                        {
-                               theOrigin_x += (1 + length_ratio) * theSize_x;
+                               theOrigin.x += (1 + length_ratio) * theSize.x;
                                length_ratio = -length_ratio;
                        }
                }
-               theSize_x *= length_ratio;
+               theSize.x *= length_ratio;
 
                vector bW;
-               width = eX * theSize_x;
-               height = eY * theSize_y;
-               if(theSize_x <= theSize_y * 2)
+               width = eX * theSize.x;
+               height = eY * theSize.y;
+               if(theSize.x <= theSize.y * 2)
                {
                        // button not wide enough
                        // draw just left and right part then
-                       square = eX * theSize_x * 0.5;
-                       bW = eX * (0.25 * theSize_x / (theSize_y * 2));
+                       square = eX * theSize.x * 0.5;
+                       bW = eX * (0.25 * theSize.x / (theSize.y * 2));
                        drawsubpic(theOrigin,          square + height, pic, '0 0 0', eY + bW, theColor, theAlpha, drawflag);
                        drawsubpic(theOrigin + square, square + height, pic, eX - bW, eY + bW, theColor, theAlpha, drawflag);
                }
                else
                {
-                       square = eX * theSize_y;
+                       square = eX * theSize.y;
                        drawsubpic(theOrigin,                  height  +     square, pic, '0    0 0', '0.25 1 0', theColor, theAlpha, drawflag);
                        drawsubpic(theOrigin +         square, theSize - 2 * square, pic, '0.25 0 0', '0.5  1 0', theColor, theAlpha, drawflag);
                        drawsubpic(theOrigin + width - square, height  +     square, pic, '0.75 0 0', '0.25 1 0', theColor, theAlpha, drawflag);
@@ -382,19 +437,18 @@ void HUD_Panel_DrawHighlight(vector pos, vector mySize, vector color, float theA
                pic = "gfx/hud/default/num_leading";
        }
 
-       drawsubpic(pos, eX * min(mySize_x * 0.5, mySize_y) + eY * mySize_y, pic, '0 0 0', '0.25 1 0', color, theAlpha, drawflag);
-       if(mySize_x/mySize_y > 2)
-               drawsubpic(pos + eX * mySize_y, eX * (mySize_x - 2 * mySize_y) + eY * mySize_y, pic, '0.25 0 0', '0.5 1 0', color, theAlpha, drawflag);
-       drawsubpic(pos + eX * mySize_x - eX * min(mySize_x * 0.5, mySize_y), eX * min(mySize_x * 0.5, mySize_y) + eY * mySize_y, pic, '0.75 0 0', '0.25 1 0', color, theAlpha, drawflag);
+       drawsubpic(pos, eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0 0 0', '0.25 1 0', color, theAlpha, drawflag);
+       if(mySize.x/mySize.y > 2)
+               drawsubpic(pos + eX * mySize.y, eX * (mySize.x - 2 * mySize.y) + eY * mySize.y, pic, '0.25 0 0', '0.5 1 0', color, theAlpha, drawflag);
+       drawsubpic(pos + eX * mySize.x - eX * min(mySize.x * 0.5, mySize.y), eX * min(mySize.x * 0.5, mySize.y) + eY * mySize.y, pic, '0.75 0 0', '0.25 1 0', color, theAlpha, drawflag);
 }
 
 // Weapon icons (#0)
 //
 entity weaponorder[WEP_MAXCOUNT];
-void weaponorder_swap(float i, float j, entity pass)
+void weaponorder_swap(int i, int j, entity pass)
 {
-       entity h;
-       h = weaponorder[i];
+       entity h = weaponorder[i];
        weaponorder[i] = weaponorder[j];
        weaponorder[j] = h;
 }
@@ -408,60 +462,23 @@ float weaponorder_cmp(float i, float j, entity pass)
        return aj - ai; // the string is in REVERSE order (higher prio at the right is what we want, but higher prio first is the string)
 }
 
-float GetAmmoStat(float i)
-{
-       switch(i)
-       {
-               case 0: return STAT_SHELLS;
-               case 1: return STAT_NAILS;
-               case 2: return STAT_ROCKETS;
-               case 3: return STAT_CELLS;
-               case 4: return STAT_FUEL;
-               default: return -1;
-       }
-}
-
-float GetAmmoTypeForWep(float i)
-{
-       switch(i)
-       {
-               case WEP_SHOTGUN: return 0;
-               case WEP_UZI: return 1;
-               case WEP_GRENADE_LAUNCHER: return 2;
-               case WEP_MINE_LAYER: return 2;
-               case WEP_ELECTRO: return 3;
-               case WEP_CRYLINK: return 3;
-               case WEP_HLAC: return 3;
-               case WEP_MINSTANEX: return 3;
-               case WEP_NEX: return 3;
-               case WEP_RIFLE: return 1;
-               case WEP_HAGAR: return 2;
-               case WEP_ROCKET_LAUNCHER: return 2;
-               case WEP_SEEKER: return 2;
-               case WEP_FIREBALL: return 4;
-               case WEP_HOOK: return 3;
-               default: return -1;
-       }
-}
-
 void HUD_Weapons(void)
 {
        // declarations
        WepSet weapons_stat = WepSet_GetFromStat();
        float i, f, a;
-       float screen_ar, center_x = 0, center_y;
+       float screen_ar;
+       vector center = '0 0 0';
        float weapon_count, weapon_id;
-       float row, column, rows = 0, columns;
+       float row, column, rows = 0, columns = 0;
+       bool vertical_order = true;
        float aspect = autocvar_hud_panel_weapons_aspect;
 
-       float panel_weapon_accuracy;
-
        float timeout = autocvar_hud_panel_weapons_timeout;
        float timein_effect_length = autocvar_hud_panel_weapons_timeout_speed_in; //? 0.375 : 0);
        float timeout_effect_length = autocvar_hud_panel_weapons_timeout_speed_out; //? 0.75 : 0);
 
-       float ammo_type, ammo_full;
-       float barsize_x = 0, barsize_y = 0, baroffset_x = 0, baroffset_y = 0;
+       vector barsize = '0 0 0', baroffset = '0 0 0';
        vector ammo_color = '1 0 1';
        float ammo_alpha = 1;
 
@@ -469,7 +486,6 @@ void HUD_Weapons(void)
        float fadetime = max(0, autocvar_hud_panel_weapons_complainbubble_fadetime);
 
        vector weapon_pos, weapon_size = '0 0 0';
-       local noref vector old_panel_size; // fteqcc sucks
        vector color;
 
        // check to see if we want to continue
@@ -489,14 +505,13 @@ void HUD_Weapons(void)
 
        // update generic hud functions
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        draw_beginBoldFont();
 
        // figure out weapon order (how the weapons are sorted) // TODO make this configurable
        if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
        {
-               float weapon_cnt;
+               int weapon_cnt;
                if(weaponorder_bypriority)
                        strunzone(weaponorder_bypriority);
                if(weaponorder_byimpulse)
@@ -526,15 +541,29 @@ void HUD_Weapons(void)
        if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
                complain_weapon = 0;
 
+       if(autocvar__hud_configure)
+       {
+               if(!weapons_stat)
+                       for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
+                               weapons_stat |= WepSet_FromWeapon(i);
+
+               #if 0
+               /// debug code
+               if(cvar("wep_add"))
+               {
+                       weapons_stat = '0 0 0';
+                       float countw = 1 + floor((floor(time * cvar("wep_add"))) % WEP_COUNT);
+                       for(i = WEP_FIRST; i <= countw; ++i)
+                               weapons_stat |= WepSet_FromWeapon(i);
+               }
+               #endif
+       }
+
        // determine which weapons are going to be shown
        if (autocvar_hud_panel_weapons_onlyowned)
        {
                if(autocvar__hud_configure)
                {
-                       if (!weapons_stat)
-                               for(i = WEP_FIRST; i <= WEP_LAST; i += floor((WEP_LAST-WEP_FIRST)/5))
-                                       weapons_stat |= WepSet_FromWeapon(i);
-
                        if(menu_enabled != 2)
                                HUD_Panel_DrawBg(1); // also draw the bg of the entire panel
                }
@@ -542,12 +571,9 @@ void HUD_Weapons(void)
                // do we own this weapon?
                weapon_count = 0;
                for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
-                       if(weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon))
+                       if((weapons_stat & WepSet_FromWeapon(weaponorder[i].weapon)) || (weaponorder[i].weapon == complain_weapon))
                                ++weapon_count;
 
-               // add it anyway if weaponcomplain is shown
-               if(complain_weapon)
-                       ++weapon_count;
 
                // might as well commit suicide now, no reason to live ;)
                if (weapon_count == 0)
@@ -556,34 +582,63 @@ void HUD_Weapons(void)
                        return;
                }
 
-               old_panel_size = panel_size;
-               if(panel_bg_padding)
-                       old_panel_size -= '2 2 0' * panel_bg_padding;
+               vector old_panel_size = panel_size;
+               vector padded_panel_size = panel_size - '2 2 0' * panel_bg_padding;
 
-               // first find values for the standard table (with all the weapons)
-               rows = old_panel_size_y/old_panel_size_x;
-               rows = bound(1, floor((sqrt(4 * aspect * rows * WEP_COUNT + rows * rows) + rows + 0.5) / 2), WEP_COUNT);
-               columns = ceil(WEP_COUNT/rows);
-               weapon_size_x = old_panel_size_x / columns;
-               weapon_size_y = old_panel_size_y / rows;
+               // get the all-weapons layout
+               vector table_size = HUD_GetTableSize(WEP_COUNT, padded_panel_size, aspect);
+               columns = table_size.x;
+               rows = table_size.y;
+               weapon_size.x = padded_panel_size.x / columns;
+               weapon_size.y = padded_panel_size.y / rows;
 
-               // change table values to include only the owned weapons
-               // weapon_size won't be changed
-               if(weapon_count <= rows)
+               // NOTE: although weapons should aways look the same even if onlyowned is enabled,
+               // we enlarge them a bit when possible to better match the desired aspect ratio
+               if(padded_panel_size.x / padded_panel_size.y < aspect)
                {
-                       rows = weapon_count;
-                       columns = 1;
+                       // maximum number of rows that allows to display items with the desired aspect ratio
+                       float max_rows = floor(padded_panel_size.y / (weapon_size.x / aspect));
+                       columns = min(columns, ceil(weapon_count / max_rows));
+                       rows = ceil(weapon_count / columns);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+                       vertical_order = false;
                }
                else
+               {
+                       float max_columns = floor(padded_panel_size.x / (weapon_size.y * aspect));
+                       rows = min(rows, ceil(weapon_count / max_columns));
                        columns = ceil(weapon_count / rows);
+                       weapon_size.x = min(padded_panel_size.x / columns, aspect * weapon_size.y);
+                       weapon_size.y = min(padded_panel_size.y / rows, weapon_size.x / aspect);
+                       vertical_order = true;
+               }
 
                // reduce size of the panel
-               panel_size_x = columns * weapon_size_x;
-               panel_size_y = rows * weapon_size_y;
-               panel_pos_x += (old_panel_size_x - panel_size_x) / 2;
-               panel_pos_y += (old_panel_size_y - panel_size_y) / 2;
-               if(panel_bg_padding)
-                       panel_size += '2 2 0' * panel_bg_padding;
+               panel_size.x = columns * weapon_size.x;
+               panel_size.y = rows * weapon_size.y;
+               panel_size += '2 2 0' * panel_bg_padding;
+
+               // center the resized panel, or snap it to the screen edge when close enough
+               if(panel_pos.x > vid_conwidth * 0.001)
+               {
+                       if(panel_pos.x + old_panel_size.x > vid_conwidth * 0.999)
+                               panel_pos.x += old_panel_size.x - panel_size.x;
+                       else
+                               panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+               }
+               else if(old_panel_size.x > vid_conwidth * 0.999)
+                       panel_pos.x += (old_panel_size.x - panel_size.x) / 2;
+
+               if(panel_pos.y > vid_conheight * 0.001)
+               {
+                       if(panel_pos.y + old_panel_size.y > vid_conheight * 0.999)
+                               panel_pos.y += old_panel_size.y - panel_size.y;
+                       else
+                               panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
+               }
+               else if(old_panel_size.y > vid_conheight * 0.999)
+                       panel_pos.y += (old_panel_size.y - panel_size.y) / 2;
        }
        else
                weapon_count = WEP_COUNT;
@@ -611,25 +666,25 @@ void HUD_Weapons(void)
                        if (autocvar_hud_panel_weapons_timeout_effect == 2 || autocvar_hud_panel_weapons_timeout_effect == 3)
                        {
                                f *= f; // for a cooler movement
-                               center_x = panel_pos_x + panel_size_x/2;
-                               center_y = panel_pos_y + panel_size_y/2;
+                               center.x = panel_pos.x + panel_size.x/2;
+                               center.y = panel_pos.y + panel_size.y/2;
                                screen_ar = vid_conwidth/vid_conheight;
-                               if (center_x/center_y < screen_ar) //bottom left
+                               if (center.x/center.y < screen_ar) //bottom left
                                {
-                                       if ((vid_conwidth - center_x)/center_y < screen_ar) //bottom
-                                               panel_pos_y += f * (vid_conheight - panel_pos_y);
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
+                                               panel_pos.y += f * (vid_conheight - panel_pos.y);
                                        else //left
-                                               panel_pos_x -= f * (panel_pos_x + panel_size_x);
+                                               panel_pos.x -= f * (panel_pos.x + panel_size.x);
                                }
                                else //top right
                                {
-                                       if ((vid_conwidth - center_x)/center_y < screen_ar) //right
-                                               panel_pos_x += f * (vid_conwidth - panel_pos_x);
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //right
+                                               panel_pos.x += f * (vid_conwidth - panel_pos.x);
                                        else //top
-                                               panel_pos_y -= f * (panel_pos_y + panel_size_y);
+                                               panel_pos.y -= f * (panel_pos.y + panel_size.y);
                                }
                                if(f == 1)
-                                       center_x = -1; // mark the panel as off screen
+                                       center.x = -1; // mark the panel as off screen
                        }
                        weaponprevtime = time - (1 - f) * timein_effect_length;
                }
@@ -654,22 +709,22 @@ void HUD_Weapons(void)
                        {
                                f *= f; // for a cooler movement
                                f = 1 - f;
-                               center_x = panel_pos_x + panel_size_x/2;
-                               center_y = panel_pos_y + panel_size_y/2;
+                               center.x = panel_pos.x + panel_size.x/2;
+                               center.y = panel_pos.y + panel_size.y/2;
                                screen_ar = vid_conwidth/vid_conheight;
-                               if (center_x/center_y < screen_ar) //bottom left
+                               if (center.x/center.y < screen_ar) //bottom left
                                {
-                                       if ((vid_conwidth - center_x)/center_y < screen_ar) //bottom
-                                               panel_pos_y += f * (vid_conheight - panel_pos_y);
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //bottom
+                                               panel_pos.y += f * (vid_conheight - panel_pos.y);
                                        else //left
-                                               panel_pos_x -= f * (panel_pos_x + panel_size_x);
+                                               panel_pos.x -= f * (panel_pos.x + panel_size.x);
                                }
                                else //top right
                                {
-                                       if ((vid_conwidth - center_x)/center_y < screen_ar) //right
-                                               panel_pos_x += f * (vid_conwidth - panel_pos_x);
+                                       if ((vid_conwidth - center.x)/center.y < screen_ar) //right
+                                               panel_pos.x += f * (vid_conwidth - panel_pos.x);
                                        else //top
-                                               panel_pos_y -= f * (panel_pos_y + panel_size_y);
+                                               panel_pos.y -= f * (panel_pos.y + panel_size.y);
                                }
                        }
                }
@@ -678,7 +733,7 @@ void HUD_Weapons(void)
        // draw the background, then change the virtual size of it to better fit other items inside
        HUD_Panel_DrawBg(1);
 
-       if(center_x == -1)
+       if(center.x == -1)
        {
                draw_endBoldFont();
                return;
@@ -694,10 +749,12 @@ void HUD_Weapons(void)
 
        if(!rows) // if rows is > 0 onlyowned code has already updated these vars
        {
-               rows = panel_size_y/panel_size_x;
-               rows = bound(1, floor((sqrt(4 * aspect * rows * weapon_count + rows * rows) + rows + 0.5) / 2), weapon_count);
-               columns = ceil(weapon_count/rows);
-               weapon_size = eX * panel_size_x*(1/columns) + eY * panel_size_y*(1/rows);
+               vector table_size = HUD_GetTableSize(WEP_COUNT, panel_size, aspect);
+               columns = table_size.x;
+               rows = table_size.y;
+               weapon_size.x = panel_size.x / columns;
+               weapon_size.y = panel_size.y / rows;
+               vertical_order = (panel_size.x / panel_size.y >= aspect);
        }
 
        // calculate position/size for visual bar displaying ammount of ammo status
@@ -706,23 +763,25 @@ void HUD_Weapons(void)
                ammo_color = stov(autocvar_hud_panel_weapons_ammo_color);
                ammo_alpha = panel_fg_alpha * autocvar_hud_panel_weapons_ammo_alpha;
 
-               if(weapon_size_x/weapon_size_y > aspect)
+               if(weapon_size.x/weapon_size.y > aspect)
                {
-                       barsize_x = aspect * weapon_size_y;
-                       barsize_y = weapon_size_y;
-                       baroffset_x = (weapon_size_x - barsize_x) / 2;
+                       barsize.x = aspect * weapon_size.y;
+                       barsize.y = weapon_size.y;
+                       baroffset.x = (weapon_size.x - barsize.x) / 2;
                }
                else
                {
-                       barsize_y = 1/aspect * weapon_size_x;
-                       barsize_x = weapon_size_x;
-                       baroffset_y = (weapon_size_y - barsize_y) / 2;
+                       barsize.y = 1/aspect * weapon_size.x;
+                       barsize.x = weapon_size.x;
+                       baroffset.y = (weapon_size.y - barsize.y) / 2;
                }
        }
        if(autocvar_hud_panel_weapons_accuracy)
                Accuracy_LoadColors();
 
+       // 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);
        for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
        {
                // retrieve information about the current weapon to be drawn
@@ -739,8 +798,8 @@ void HUD_Weapons(void)
 
                // figure out the drawing position of weapon
                weapon_pos = (panel_pos
-                       + eX * column * weapon_size_x
-                       + eY * row * weapon_size_y);
+                       + eX * column * weapon_size.x
+                       + eY * row * weapon_size.y);
 
                // draw background behind currently selected weapon
                if(self.weapon == switchweapon)
@@ -749,7 +808,7 @@ void HUD_Weapons(void)
                // draw the weapon accuracy
                if(autocvar_hud_panel_weapons_accuracy)
                {
-                       panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
+                       float panel_weapon_accuracy = weapon_accuracy[self.weapon-WEP_FIRST];
                        if(panel_weapon_accuracy >= 0)
                        {
                                color = Accuracy_GetColor(panel_weapon_accuracy);
@@ -761,21 +820,21 @@ void HUD_Weapons(void)
                if(weapons_stat & WepSet_FromWeapon(self.weapon))
                {
                        // draw the weapon image
-                       drawpic_aspect_skin(weapon_pos, strcat("weapon", self.netname), weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 
                        // draw weapon label string
                        switch(autocvar_hud_panel_weapons_label)
                        {
                                case 1: // weapon number
-                                       drawstring(weapon_pos, ftos(weapon_id), '1 1 0' * 0.5 * weapon_size_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       drawstring(weapon_pos, ftos(weapon_id), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                                        break;
 
                                case 2: // bind
-                                       drawstring(weapon_pos, getcommandkey(ftos(weapon_id), strcat("weapon_group_", ftos(weapon_id))), '1 1 0' * 0.5 * weapon_size_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       drawstring(weapon_pos, getcommandkey(ftos(weapon_id), strcat("weapon_group_", ftos(weapon_id))), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                                        break;
 
                                case 3: // weapon name
-                                       drawstring(weapon_pos, self.netname, '1 1 0' * 0.5 * weapon_size_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       drawstring(weapon_pos, strtolower(self.message), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                                        break;
 
                                default: // nothing
@@ -783,37 +842,47 @@ void HUD_Weapons(void)
                        }
 
                        // draw ammo status bar
-                       if(autocvar_hud_panel_weapons_ammo && self.weapon != WEP_TUBA && self.weapon != WEP_LASER && self.weapon != WEP_PORTO)
+                       if(autocvar_hud_panel_weapons_ammo && (self.ammo_field != ammo_none))
                        {
-                               a = 0;
-                               ammo_type = GetAmmoTypeForWep(self.weapon);
-                               if(ammo_type != -1)
-                                       a = getstati(GetAmmoStat(ammo_type)); // how much ammo do we have?
+                               float ammo_full;
+                               a = getstati(GetAmmoStat(self.ammo_field)); // how much ammo do we have?
 
                                if(a > 0)
                                {
-                                       switch(ammo_type) {
-                                               case 0: ammo_full = autocvar_hud_panel_weapons_ammo_full_shells; break;
-                                               case 1: ammo_full = autocvar_hud_panel_weapons_ammo_full_nails; break;
-                                               case 2: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
-                                               case 3: ammo_full = autocvar_hud_panel_weapons_ammo_full_cells; break;
-                                               case 4: ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel; break;
+                                       switch(self.ammo_field)
+                                       {
+                                               case ammo_shells:  ammo_full = autocvar_hud_panel_weapons_ammo_full_shells;  break;
+                                               case ammo_nails:   ammo_full = autocvar_hud_panel_weapons_ammo_full_nails;   break;
+                                               case ammo_rockets: ammo_full = autocvar_hud_panel_weapons_ammo_full_rockets; break;
+                                               case ammo_cells:   ammo_full = autocvar_hud_panel_weapons_ammo_full_cells;   break;
+                                               case ammo_plasma:  ammo_full = autocvar_hud_panel_weapons_ammo_full_plasma;  break;
+                                               case ammo_fuel:    ammo_full = autocvar_hud_panel_weapons_ammo_full_fuel;    break;
                                                default: ammo_full = 60;
                                        }
 
                                        drawsetcliparea(
-                                               weapon_pos_x + baroffset_x,
-                                               weapon_pos_y + baroffset_y,
-                                               barsize_x * bound(0, a/ammo_full, 1),
-                                               barsize_y);
-                                       drawpic_aspect_skin(weapon_pos, "weapon_ammo", weapon_size, ammo_color, ammo_alpha, DRAWFLAG_NORMAL);
+                                               weapon_pos.x + baroffset.x,
+                                               weapon_pos.y + baroffset.y,
+                                               barsize.x * bound(0, a/ammo_full, 1),
+                                               barsize.y
+                                       );
+
+                                       drawpic_aspect_skin(
+                                               weapon_pos,
+                                               "weapon_ammo",
+                                               weapon_size,
+                                               ammo_color,
+                                               ammo_alpha,
+                                               DRAWFLAG_NORMAL
+                                       );
+
                                        drawresetcliparea();
                                }
                        }
                }
                else // draw a "ghost weapon icon" if you don't have the weapon
                {
-                       drawpic_aspect_skin(weapon_pos, strcat("weapon", self.netname), weapon_size, '0 0 0', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
+                       drawpic_aspect_skin(weapon_pos, self.model2, weapon_size, '0 0 0', panel_fg_alpha * 0.5, DRAWFLAG_NORMAL);
                }
 
                // draw the complain message
@@ -842,12 +911,33 @@ void HUD_Weapons(void)
                        drawstring_aspect(weapon_pos + '1 1 0' * padding, s, weapon_size - '2 2 0' * padding, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
                }
 
+               #if 0
+               /// debug code
+               if(!autocvar_hud_panel_weapons_onlyowned)
+               {
+                       drawfill(weapon_pos + '1 1 0', weapon_size - '2 2 0', '1 1 1', panel_fg_alpha * 0.2, DRAWFLAG_NORMAL);
+                       drawstring(weapon_pos, ftos(i + 1), label_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               }
+               #endif
+
                // continue with new position for the next weapon
-               ++row;
-               if(row >= rows)
+               if(vertical_order)
                {
-                       row = 0;
                        ++column;
+                       if(column >= columns)
+                       {
+                               column = 0;
+                               ++row;
+                       }
+               }
+               else
+               {
+                       ++row;
+                       if(row >= rows)
+                       {
+                               row = 0;
+                               ++column;
+                       }
                }
        }
 
@@ -855,93 +945,132 @@ void HUD_Weapons(void)
 }
 
 // Ammo (#1)
-//
-// TODO: macro
-float GetAmmoItemCode(float i)
+void DrawNadeScoreBar(vector myPos, vector mySize, vector color)
 {
-       switch(i)
-       {
-               case 0: return IT_SHELLS;
-               case 1: return IT_NAILS;
-               case 2: return IT_ROCKETS;
-               case 3: return IT_CELLS;
-               case 4: return IT_FUEL;
-               default: return -1;
-       }
+
+       HUD_Panel_DrawProgressBar(
+               myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
+               mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x,
+               autocvar_hud_panel_ammo_progressbar_name,
+               getstatf(STAT_NADE_BONUS_SCORE), 0, 0, color,
+               autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+
 }
 
-string GetAmmoPicture(float i)
+void DrawAmmoNades(vector myPos, vector mySize, float draw_expanding, float expand_time)
 {
-       switch(i)
+       float theAlpha = 1, a, b;
+       vector nade_color, picpos, numpos;
+
+       nade_color = Nade_Color(getstati(STAT_NADE_BONUS_TYPE));
+
+       a = getstatf(STAT_NADE_BONUS);
+       b = getstatf(STAT_NADE_BONUS_SCORE);
+
+       if(autocvar_hud_panel_ammo_iconalign)
+       {
+               numpos = myPos;
+               picpos = myPos + eX * 2 * mySize.y;
+       }
+       else
        {
-               case 0: return "ammo_shells";
-               case 1: return "ammo_bullets";
-               case 2: return "ammo_rockets";
-               case 3: return "ammo_cells";
-               case 4: return "ammo_fuel";
-               default: return "";
+               numpos = myPos + eX * mySize.y;
+               picpos = myPos;
+       }
+
+       DrawNadeScoreBar(myPos, mySize, nade_color);
+
+       if(b > 0 || a > 0)
+       {
+               if(autocvar_hud_panel_ammo_text)
+                       drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+
+               if(draw_expanding)
+                       drawpic_aspect_skin_expanding(picpos, "nade_nbg", '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, expand_time);
+
+               drawpic_aspect_skin(picpos, "nade_bg" , '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(picpos, "nade_nbg" , '1 1 0' * mySize.y, nade_color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
        }
 }
 
-void DrawAmmoItem(vector myPos, vector mySize, float itemcode, float currently_selected, float infinite_ammo)
+void DrawAmmoItem(vector myPos, vector mySize, .float ammoType, float isCurrent, float isInfinite)
 {
-       float a;
+       if(ammoType == ammo_none)
+               return;
+
+       // Initialize variables
+
+       float ammo;
        if(autocvar__hud_configure)
        {
-               currently_selected = (itemcode == 2); //rockets always selected
-               a = 31 + mod(itemcode*93, 128);
+               isCurrent = (ammoType == ammo_rockets); // Rockets always current
+               ammo = 60;
        }
        else
-               a = getstati(GetAmmoStat(itemcode)); // how much ammo do we have of type itemcode?
-
-       vector color;
-       if(infinite_ammo)
-               color = '0 0.5 0.75';
-       else if(a < 10)
-               color = '0.7 0 0';
-       else
-               color = '1 1 1';
+               ammo = getstati(GetAmmoStat(ammoType));
 
-       float theAlpha;
-       if(currently_selected)
-               theAlpha = 1;
-       else
-               theAlpha = 0.7;
+       if(!isCurrent)
+       {
+               float scale = bound(0, autocvar_hud_panel_ammo_noncurrent_scale, 1);
+               myPos = myPos + (mySize - mySize * scale) * 0.5;
+               mySize = mySize * scale;
+       }
 
-       vector picpos, numpos;
+       vector iconPos, textPos;
        if(autocvar_hud_panel_ammo_iconalign)
        {
-               numpos = myPos;
-               picpos = myPos + eX * 2 * mySize_y;
+               iconPos = myPos + eX * 2 * mySize.y;
+               textPos = myPos;
        }
        else
        {
-               numpos = myPos + eX * mySize_y;
-               picpos = myPos;
+               iconPos = myPos;
+               textPos = myPos + eX * mySize.y;
        }
 
-       if (currently_selected)
+       float isShadowed = (ammo <= 0 && !isCurrent && !isInfinite);
+
+       vector iconColor = isShadowed ? '0 0 0' : '1 1 1';
+       vector textColor;
+       if(isInfinite)
+               textColor = '0.2 0.95 0';
+       else if(isShadowed)
+               textColor = '0 0 0';
+       else if(ammo < 10)
+               textColor = '0.8 0.04 0';
+       else
+               textColor = '1 1 1';
+
+       float alpha;
+       if(isCurrent)
+               alpha = panel_fg_alpha;
+       else if(isShadowed)
+               alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1) * 0.5;
+       else
+               alpha = panel_fg_alpha * bound(0, autocvar_hud_panel_ammo_noncurrent_alpha, 1);
+
+       string text = isInfinite ? "\xE2\x88\x9E" : ftos(ammo); // Use infinity symbol (U+221E)
+
+       // Draw item
+
+       if(isCurrent)
                drawpic_aspect_skin(myPos, "ammo_current_bg", mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 
-    if(a > 0 && autocvar_hud_panel_ammo_progressbar)
-        HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize_x, autocvar_hud_panel_ammo_progressbar_name, a/autocvar_hud_panel_ammo_maxammo, 0, 0, color, autocvar_hud_progressbar_alpha * panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
+       if(ammo > 0 && autocvar_hud_panel_ammo_progressbar)
+               HUD_Panel_DrawProgressBar(myPos + eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, mySize - eX * autocvar_hud_panel_ammo_progressbar_xoffset * mySize.x, autocvar_hud_panel_ammo_progressbar_name, ammo/autocvar_hud_panel_ammo_maxammo, 0, 0, textColor, autocvar_hud_progressbar_alpha * alpha, DRAWFLAG_NORMAL);
 
-    if(autocvar_hud_panel_ammo_text)
-    {
-        if(a > 0 || infinite_ammo)
-            drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
-        else // "ghost" ammo count
-            drawstring_aspect(numpos, ftos(a), eX * (2/3) * mySize_x + eY * mySize_y, '0 0 0', panel_fg_alpha * theAlpha * 0.5, DRAWFLAG_NORMAL);
-    }
-       if(a > 0 || infinite_ammo)
-               drawpic_aspect_skin(picpos, GetAmmoPicture(itemcode), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
-       else // "ghost" ammo icon
-               drawpic_aspect_skin(picpos, GetAmmoPicture(itemcode), '1 1 0' * mySize_y, '0 0 0', panel_fg_alpha * theAlpha * 0.5, DRAWFLAG_NORMAL);
+       if(autocvar_hud_panel_ammo_text)
+               drawstring_aspect(textPos, text, eX * (2/3) * mySize.x + eY * mySize.y, textColor, alpha, DRAWFLAG_NORMAL);
+
+       drawpic_aspect_skin(iconPos, GetAmmoPicture(ammoType), '1 1 0' * mySize.y, iconColor, alpha, DRAWFLAG_NORMAL);
 }
 
+float nade_prevstatus;
+float nade_prevframe;
+float nade_statuschange_time;
 void HUD_Ammo(void)
 {
-    if(hud != HUD_NORMAL) return;
+       if(hud != HUD_NORMAL) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_ammo) return;
@@ -949,7 +1078,6 @@ void HUD_Ammo(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        draw_beginBoldFont();
 
@@ -965,69 +1093,92 @@ void HUD_Ammo(void)
        }
 
        float rows = 0, columns, row, column;
+       float nade_cnt = getstatf(STAT_NADE_BONUS), nade_score = getstatf(STAT_NADE_BONUS_SCORE);
+       float draw_nades = (nade_cnt > 0 || nade_score > 0), nade_statuschange_elapsedtime;
+       float total_ammo_count;
+
        vector ammo_size;
        if (autocvar_hud_panel_ammo_onlycurrent)
-               ammo_size = mySize;
+               total_ammo_count = 1;
        else
-       {
-               rows = mySize_y/mySize_x;
-               rows = bound(1, floor((sqrt(4 * (3/1) * rows * AMMO_COUNT + rows * rows) + rows + 0.5) / 2), AMMO_COUNT);
-               //                               ^^^ ammo item aspect goes here
+               total_ammo_count = AMMO_COUNT;
 
-               columns = ceil(AMMO_COUNT/rows);
-
-               ammo_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+       if(draw_nades)
+       {
+               ++total_ammo_count;
+               if (nade_cnt != nade_prevframe)
+               {
+                       nade_statuschange_time = time;
+                       nade_prevstatus = nade_prevframe;
+                       nade_prevframe = nade_cnt;
+               }
        }
+       else
+               nade_prevstatus = nade_prevframe = nade_statuschange_time = 0;
+
+       rows = HUD_GetRowCount(total_ammo_count, mySize, 3);
+       columns = ceil((total_ammo_count)/rows);
+       ammo_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
 
-       local vector offset = '0 0 0'; // fteqcc sucks
+       vector offset = '0 0 0'; // fteqcc sucks
        float newSize;
-       if(ammo_size_x/ammo_size_y > 3)
+       if(ammo_size.x/ammo_size.y > 3)
        {
-               newSize = 3 * ammo_size_y;
-               offset_x = ammo_size_x - newSize;
-               pos_x += offset_x/2;
-               ammo_size_x = newSize;
+               newSize = 3 * ammo_size.y;
+               offset.x = ammo_size.x - newSize;
+               pos.x += offset.x/2;
+               ammo_size.x = newSize;
        }
        else
        {
-               newSize = 1/3 * ammo_size_x;
-               offset_y = ammo_size_y - newSize;
-               pos_y += offset_y/2;
-               ammo_size_y = newSize;
+               newSize = 1/3 * ammo_size.x;
+               offset.y = ammo_size.y - newSize;
+               pos.y += offset.y/2;
+               ammo_size.y = newSize;
        }
 
-       float i, stat_items, currently_selected, infinite_ammo;
-       infinite_ammo = FALSE;
-       if (autocvar_hud_panel_ammo_onlycurrent)
+       float i;
+       float infinite_ammo = (getstati(STAT_ITEMS, 0, 24) & IT_UNLIMITED_WEAPON_AMMO);
+       row = column = 0;
+       if(autocvar_hud_panel_ammo_onlycurrent)
        {
                if(autocvar__hud_configure)
                {
-                       DrawAmmoItem(pos, ammo_size, 2, true, FALSE); //show rockets
+                       DrawAmmoItem(pos, ammo_size, ammo_rockets, true, false);
                }
                else
                {
-                       stat_items = getstati(STAT_ITEMS, 0, 24);
-                       if (stat_items & IT_UNLIMITED_WEAPON_AMMO)
-                               infinite_ammo = TRUE;
-                       for (i = 0; i < AMMO_COUNT; ++i) {
-                               currently_selected = stat_items & GetAmmoItemCode(i);
-                               if (currently_selected)
-                               {
-                                       DrawAmmoItem(pos, ammo_size, i, true, infinite_ammo);
-                                       break;
-                               }
-                       }
+                       DrawAmmoItem(
+                               pos,
+                               ammo_size,
+                               (get_weaponinfo(switchweapon)).ammo_field,
+                               true,
+                               infinite_ammo
+                       );
+               }
+
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       column = column + 1;
                }
        }
        else
        {
-               stat_items = getstati(STAT_ITEMS, 0, 24);
-               if (stat_items & IT_UNLIMITED_WEAPON_AMMO)
-                       infinite_ammo = TRUE;
+               .float ammotype;
                row = column = 0;
-               for (i = 0; i < AMMO_COUNT; ++i) {
-                       currently_selected = stat_items & GetAmmoItemCode(i);
-                       DrawAmmoItem(pos + eX * column * (ammo_size_x + offset_x) + eY * row * (ammo_size_y + offset_y), ammo_size, i, currently_selected, infinite_ammo);
+               for(i = 0; i < AMMO_COUNT; ++i)
+               {
+                       ammotype = GetAmmoFieldFromNum(i);
+                       DrawAmmoItem(
+                               pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y),
+                               ammo_size,
+                               ammotype,
+                               ((get_weaponinfo(switchweapon)).ammo_field == ammotype),
+                               infinite_ammo
+                       );
+
                        ++row;
                        if(row >= rows)
                        {
@@ -1037,6 +1188,15 @@ void HUD_Ammo(void)
                }
        }
 
+       if (draw_nades)
+       {
+               nade_statuschange_elapsedtime = time - nade_statuschange_time;
+
+               float f = bound(0, nade_statuschange_elapsedtime*2, 1);
+
+               DrawAmmoNades(pos + eX * column * (ammo_size.x + offset.x) + eY * row * (ammo_size.y + offset.y), ammo_size, nade_prevstatus < nade_cnt && nade_cnt != 0 && f < 1, f);
+       }
+
        draw_endBoldFont();
 }
 
@@ -1047,76 +1207,76 @@ void DrawNumIcon_expanding(vector myPos, vector mySize, float x, string icon, fl
 
        if (vertical)
        {
-               if(mySize_y/mySize_x > 2)
+               if(mySize.y/mySize.x > 2)
                {
-                       newSize_y = 2 * mySize_x;
-                       newSize_x = mySize_x;
+                       newSize.y = 2 * mySize.x;
+                       newSize.x = mySize.x;
 
-                       newPos_y = myPos_y + (mySize_y - newSize_y) / 2;
-                       newPos_x = myPos_x;
+                       newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
+                       newPos.x = myPos.x;
                }
                else
                {
-                       newSize_x = 1/2 * mySize_y;
-                       newSize_y = mySize_y;
+                       newSize.x = 1/2 * mySize.y;
+                       newSize.y = mySize.y;
 
-                       newPos_x = myPos_x + (mySize_x - newSize_x) / 2;
-                       newPos_y = myPos_y;
+                       newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
+                       newPos.y = myPos.y;
                }
 
                if(icon_right_align)
                {
                        numpos = newPos;
-                       picpos = newPos + eY * newSize_x;
+                       picpos = newPos + eY * newSize.x;
                }
                else
                {
                        picpos = newPos;
-                       numpos = newPos + eY * newSize_x;
+                       numpos = newPos + eY * newSize.x;
                }
 
-               newSize_y /= 2;
+               newSize.y /= 2;
                drawpic_aspect_skin(picpos, icon, newSize, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
                // make number smaller than icon, it looks better
                // reduce only y to draw numbers with different number of digits with the same y size
-               numpos_y += newSize_y * ((1 - 0.7) / 2);
-               newSize_y *= 0.7;
+               numpos.y += newSize.y * ((1 - 0.7) / 2);
+               newSize.y *= 0.7;
                drawstring_aspect(numpos, ftos(x), newSize, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL);
                return;
        }
 
-       if(mySize_x/mySize_y > 3)
+       if(mySize.x/mySize.y > 3)
        {
-               newSize_x = 3 * mySize_y;
-               newSize_y = mySize_y;
+               newSize.x = 3 * mySize.y;
+               newSize.y = mySize.y;
 
-               newPos_x = myPos_x + (mySize_x - newSize_x) / 2;
-               newPos_y = myPos_y;
+               newPos.x = myPos.x + (mySize.x - newSize.x) / 2;
+               newPos.y = myPos.y;
        }
        else
        {
-               newSize_y = 1/3 * mySize_x;
-               newSize_x = mySize_x;
+               newSize.y = 1/3 * mySize.x;
+               newSize.x = mySize.x;
 
-               newPos_y = myPos_y + (mySize_y - newSize_y) / 2;
-               newPos_x = myPos_x;
+               newPos.y = myPos.y + (mySize.y - newSize.y) / 2;
+               newPos.x = myPos.x;
        }
 
        if(icon_right_align) // right align
        {
                numpos = newPos;
-               picpos = newPos + eX * 2 * newSize_y;
+               picpos = newPos + eX * 2 * newSize.y;
        }
        else // left align
        {
-               numpos = newPos + eX * newSize_y;
+               numpos = newPos + eX * newSize.y;
                picpos = newPos;
        }
 
        // NOTE: newSize_x is always equal to 3 * mySize_y so we can use
        // '2 1 0' * newSize_y instead of eX * (2/3) * newSize_x + eY * newSize_y
-       drawstring_aspect_expanding(numpos, ftos(x), '2 1 0' * newSize_y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
-       drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize_y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
+       drawstring_aspect_expanding(numpos, ftos(x), '2 1 0' * newSize.y, color, panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
+       drawpic_aspect_skin_expanding(picpos, icon, '1 1 0' * newSize.y, '1 1 1', panel_fg_alpha * theAlpha, DRAWFLAG_NORMAL, fadelerp);
 }
 
 void DrawNumIcon(vector myPos, vector mySize, float x, string icon, float vertical, float icon_right_align, vector color, float theAlpha)
@@ -1155,7 +1315,6 @@ void HUD_Powerups(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        draw_beginBoldFont();
 
@@ -1170,7 +1329,7 @@ void HUD_Powerups(void)
                mySize -= '2 2 0' * panel_bg_padding;
        }
 
-       float panel_ar = mySize_x/mySize_y;
+       float panel_ar = mySize.x/mySize.y;
        float is_vertical = (panel_ar < 1);
        vector shield_offset = '0 0 0', strength_offset = '0 0 0', superweapons_offset = '0 0 0';
 
@@ -1199,40 +1358,40 @@ void HUD_Powerups(void)
        {
                if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
                {
-                       mySize_x *= (1.0 / 3.0);
-                       superweapons_offset_x = mySize_x;
+                       mySize.x *= (1.0 / 3.0);
+                       superweapons_offset.x = mySize.x;
                        if (autocvar_hud_panel_powerups_flip)
-                               shield_offset_x = 2*mySize_x;
+                               shield_offset.x = 2*mySize.x;
                        else
-                               strength_offset_x = 2*mySize_x;
+                               strength_offset.x = 2*mySize.x;
                }
                else
                {
-                       mySize_y *= (1.0 / 3.0);
-                       superweapons_offset_y = mySize_y;
+                       mySize.y *= (1.0 / 3.0);
+                       superweapons_offset.y = mySize.y;
                        if (autocvar_hud_panel_powerups_flip)
-                               shield_offset_y = 2*mySize_y;
+                               shield_offset.y = 2*mySize.y;
                        else
-                               strength_offset_y = 2*mySize_y;
+                               strength_offset.y = 2*mySize.y;
                }
        }
        else
        {
                if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
                {
-                       mySize_x *= 0.5;
+                       mySize.x *= 0.5;
                        if (autocvar_hud_panel_powerups_flip)
-                               shield_offset_x = mySize_x;
+                               shield_offset.x = mySize.x;
                        else
-                               strength_offset_x = mySize_x;
+                               strength_offset.x = mySize.x;
                }
                else
                {
-                       mySize_y *= 0.5;
+                       mySize.y *= 0.5;
                        if (autocvar_hud_panel_powerups_flip)
-                               shield_offset_y = mySize_y;
+                               shield_offset.y = mySize.y;
                        else
-                               strength_offset_y = mySize_y;
+                               strength_offset.y = mySize.y;
                }
        }
 
@@ -1277,10 +1436,7 @@ void HUD_Powerups(void)
                const float maxshield = 30;
                float shield = ceil(shield_time);
                if(autocvar_hud_panel_powerups_progressbar)
-               {
-                       HUD_Panel_GetProgressBarColor(shield);
-                       HUD_Panel_DrawProgressBar(pos + shield_offset, mySize, autocvar_hud_panel_powerups_progressbar_shield, shield/maxshield, is_vertical, shield_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
+                       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)
@@ -1295,10 +1451,7 @@ void HUD_Powerups(void)
                const float maxstrength = 30;
                float strength = ceil(strength_time);
                if(autocvar_hud_panel_powerups_progressbar)
-               {
-                       HUD_Panel_GetProgressBarColor(strength);
-                       HUD_Panel_DrawProgressBar(pos + strength_offset, mySize, autocvar_hud_panel_powerups_progressbar_strength, strength/maxstrength, is_vertical, strength_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
+                       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);
                if(autocvar_hud_panel_powerups_text)
                {
                        if(strength > 1)
@@ -1313,10 +1466,7 @@ void HUD_Powerups(void)
                const float maxsuperweapons = 30;
                float superweapons = ceil(superweapons_time);
                if(autocvar_hud_panel_powerups_progressbar)
-               {
-                       HUD_Panel_GetProgressBarColor(superweapons);
-                       HUD_Panel_DrawProgressBar(pos + superweapons_offset, mySize, autocvar_hud_panel_powerups_progressbar_superweapons, superweapons/maxsuperweapons, is_vertical, superweapons_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               }
+                       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)
                {
                        if(superweapons > 1)
@@ -1396,7 +1546,6 @@ void HUD_HealthArmor(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -1419,63 +1568,54 @@ void HUD_HealthArmor(void)
                v = healtharmor_maxdamage(health, armor, armorblockpercent, DEATH_WEAPON);
 
                float x;
-               x = floor(v_x + 1);
+               x = floor(v.x + 1);
 
         float maxtotal = maxhealth + maxarmor;
                string biggercount;
-               if(v_z) // NOT fully armored
+               if(v.z) // NOT fully armored
                {
                        biggercount = "health";
                        if(autocvar_hud_panel_healtharmor_progressbar)
-                       {
-                               HUD_Panel_GetProgressBarColor(health);
-                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
+                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_health, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        if(armor)
             if(autocvar_hud_panel_healtharmor_text)
-                               drawpic_aspect_skin(pos + eX * mySize_x - eX * 0.5 * mySize_y, "armor", '0.5 0.5 0' * mySize_y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
+                               drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "armor", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha * armor / health, DRAWFLAG_NORMAL);
                }
                else
                {
                        biggercount = "armor";
                        if(autocvar_hud_panel_healtharmor_progressbar)
-                       {
-                               HUD_Panel_GetProgressBarColor(armor);
-                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       }
+                               HUD_Panel_DrawProgressBar(pos, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, x/maxtotal, 0, (baralign == 1 || baralign == 2), autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        if(health)
             if(autocvar_hud_panel_healtharmor_text)
-                               drawpic_aspect_skin(pos + eX * mySize_x - eX * 0.5 * mySize_y, "health", '0.5 0.5 0' * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawpic_aspect_skin(pos + eX * mySize.x - eX * 0.5 * mySize.y, "health", '0.5 0.5 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                }
         if(autocvar_hud_panel_healtharmor_text)
                        DrawNumIcon(pos, mySize, x, biggercount, 0, iconalign, HUD_Get_Num_Color(x, maxtotal), 1);
 
                if(fuel)
-               {
-                       HUD_Panel_GetProgressBarColor(fuel);
-                       HUD_Panel_DrawProgressBar(pos, eX * mySize_x + eY * 0.2 * mySize_y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
-               }
+                       HUD_Panel_DrawProgressBar(pos, eX * mySize.x + eY * 0.2 * mySize.y, "progressbar", fuel/100, 0, (baralign == 1 || baralign == 3), autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
        }
        else
        {
-               float panel_ar = mySize_x/mySize_y;
+               float panel_ar = mySize.x/mySize.y;
                float is_vertical = (panel_ar < 1);
                vector health_offset = '0 0 0', armor_offset = '0 0 0';
                if (panel_ar >= 4 || (panel_ar >= 1/4 && panel_ar < 1))
                {
-                       mySize_x *= 0.5;
+                       mySize.x *= 0.5;
                        if (autocvar_hud_panel_healtharmor_flip)
-                               health_offset_x = mySize_x;
+                               health_offset.x = mySize.x;
                        else
-                               armor_offset_x = mySize_x;
+                               armor_offset.x = mySize.x;
                }
                else
                {
-                       mySize_y *= 0.5;
+                       mySize.y *= 0.5;
                        if (autocvar_hud_panel_healtharmor_flip)
-                               health_offset_y = mySize_y;
+                               health_offset.y = mySize.y;
                        else
-                               armor_offset_y = mySize_y;
+                               armor_offset.y = mySize.y;
                }
 
                float health_baralign, armor_baralign, fuel_baralign;
@@ -1501,7 +1641,6 @@ void HUD_HealthArmor(void)
                {
                        if(autocvar_hud_panel_healtharmor_progressbar)
                        {
-                               HUD_Panel_GetProgressBarColor(health);
                                float p_health, pain_health_alpha;
                                p_health = health;
                                pain_health_alpha = 1;
@@ -1534,7 +1673,7 @@ void HUD_HealthArmor(void)
                                                if (time - health_damagetime < 1)
                                                {
                                                        float health_damagealpha = 1 - (time - health_damagetime)*(time - health_damagetime);
-                                                       HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
+                                                       HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, health_beforedamage/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * health_damagealpha, DRAWFLAG_NORMAL);
                                                }
                                        }
                                        prev_health = health;
@@ -1547,7 +1686,7 @@ void HUD_HealthArmor(void)
                                                pain_health_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
                                        }
                                }
-                               HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
+                               HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, p_health/maxhealth, is_vertical, health_baralign, autocvar_hud_progressbar_health_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * pain_health_alpha, DRAWFLAG_NORMAL);
                        }
                        if(autocvar_hud_panel_healtharmor_text)
                                DrawNumIcon(pos + health_offset, mySize, health, "health", is_vertical, health_iconalign, HUD_Get_Num_Color(health, maxhealth), 1);
@@ -1557,7 +1696,6 @@ void HUD_HealthArmor(void)
                {
                        if(autocvar_hud_panel_healtharmor_progressbar)
                        {
-                               HUD_Panel_GetProgressBarColor(armor);
                                float p_armor;
                                p_armor = armor;
                                if (autocvar_hud_panel_healtharmor_progressbar_gfx)
@@ -1589,12 +1727,12 @@ void HUD_HealthArmor(void)
                                                if (time - armor_damagetime < 1)
                                                {
                                                        float armor_damagealpha = 1 - (time - armor_damagetime)*(time - armor_damagetime);
-                                                       HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
+                                                       HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, armor_beforedamage/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * armor_damagealpha, DRAWFLAG_NORMAL);
                                                }
                                        }
                                        prev_armor = armor;
                                }
-                               HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                               HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, p_armor/maxarmor, is_vertical, armor_baralign, autocvar_hud_progressbar_armor_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        if(autocvar_hud_panel_healtharmor_text)
                                DrawNumIcon(pos + armor_offset, mySize, armor, "armor", is_vertical, armor_iconalign, HUD_Get_Num_Color(armor, maxarmor), 1);
@@ -1603,15 +1741,14 @@ void HUD_HealthArmor(void)
                if(fuel)
                {
                        if (is_vertical)
-                               mySize_x *= 0.2 / 2; //if vertical always halve x to not cover too much numbers with 3 digits
+                               mySize.x *= 0.2 / 2; //if vertical always halve x to not cover too much numbers with 3 digits
                        else
-                               mySize_y *= 0.2;
+                               mySize.y *= 0.2;
                        if (panel_ar >= 4)
-                               mySize_x *= 2; //restore full panel size
+                               mySize.x *= 2; //restore full panel size
                        else if (panel_ar < 1/4)
-                               mySize_y *= 2; //restore full panel size
-                       HUD_Panel_GetProgressBarColor(fuel);
-                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, progressbar_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
+                               mySize.y *= 2; //restore full panel size
+                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", fuel/100, is_vertical, fuel_baralign, autocvar_hud_progressbar_fuel_color, panel_fg_alpha * 0.8, DRAWFLAG_NORMAL);
                }
        }
 }
@@ -1621,149 +1758,154 @@ void HUD_HealthArmor(void)
 
 void HUD_Notify_Push(string icon, string attacker, string victim)
 {
-       if(icon != "")
-       {
-               --kn_index;
-               if (kn_index == -1) { kn_index = KN_MAX_ENTRIES-1; }
-               notify_times[kn_index] = time;
+       if (icon == "")
+               return;
+
+       ++notify_count;
+       --notify_index;
+
+       if (notify_index == -1)
+               notify_index = NOTIFY_MAX_ENTRIES-1;
 
-               // icon
-               if(notify_icon[kn_index]) { strunzone(notify_icon[kn_index]); }
-               notify_icon[kn_index] = strzone(icon);
+       // Free old strings
+       if (notify_attackers[notify_index])
+               strunzone(notify_attackers[notify_index]);
 
-               // attacker
-               if(notify_attackers[kn_index]) { strunzone(notify_attackers[kn_index]); }
-               notify_attackers[kn_index] = strzone(attacker);
+       if (notify_victims[notify_index])
+               strunzone(notify_victims[notify_index]);
 
-               // victim
-               if(notify_victims[kn_index]) { strunzone(notify_victims[kn_index]); }
-               notify_victims[kn_index] = strzone(victim);
+       if (notify_icons[notify_index])
+               strunzone(notify_icons[notify_index]);
+
+       // Allocate new strings
+       if (victim != "")
+       {
+               notify_attackers[notify_index] = strzone(attacker);
+               notify_victims[notify_index] = strzone(victim);
+       }
+       else
+       {
+               // In case of a notification without a victim, the attacker
+               // is displayed on the victim's side. Instead of special
+               // treatment later on, we can simply switch them here.
+               notify_attackers[notify_index] = string_null;
+               notify_victims[notify_index] = strzone(attacker);
        }
+
+       notify_icons[notify_index] = strzone(icon);
+       notify_times[notify_index] = time;
 }
 
 void HUD_Notify(void)
 {
-       if(!autocvar__hud_configure)
-       {
-               if(!autocvar_hud_panel_notify) return;
-       }
+       if (!autocvar__hud_configure)
+               if (!autocvar_hud_panel_notify)
+                       return;
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
        HUD_Panel_DrawBg(1);
-       if(panel_bg_padding)
+
+       if (!autocvar__hud_configure)
+               if (notify_count == 0)
+                       return;
+
+       vector pos, size;
+       pos  = panel_pos;
+       size = panel_size;
+
+       if (panel_bg_padding)
        {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
+               pos  += '1 1 0' * panel_bg_padding;
+               size -= '2 2 0' * panel_bg_padding;
        }
 
-       float entries, height;
-       entries = bound(1, floor(KN_MAX_ENTRIES * mySize_y/mySize_x), KN_MAX_ENTRIES);
-       height = mySize_y/entries;
+       float fade_start = max(0, autocvar_hud_panel_notify_time);
+       float fade_time = max(0, autocvar_hud_panel_notify_fadetime);
+       float icon_aspect = max(1, autocvar_hud_panel_notify_icon_aspect);
 
-       vector fontsize;
-       float fontheight = height * autocvar_hud_panel_notify_fontsize;
-       fontsize = '0.5 0.5 0' * fontheight;
+       float entry_count = bound(1, floor(NOTIFY_MAX_ENTRIES * size.y / size.x), NOTIFY_MAX_ENTRIES);
+       float entry_height = size.y / entry_count;
 
-       float a;
-       float when;
-       when = autocvar_hud_panel_notify_time;
-       float fadetime;
-       fadetime = autocvar_hud_panel_notify_fadetime;
+       float panel_width_half = size.x * 0.5;
+       float icon_width_half = entry_height * icon_aspect / 2;
+       float name_maxwidth = panel_width_half - icon_width_half - size.x * NOTIFY_ICON_MARGIN;
+
+       vector font_size = '0.5 0.5 0' * entry_height * autocvar_hud_panel_notify_fontsize;
+       vector icon_size = (eX * icon_aspect + eY) * entry_height;
+       vector icon_left = eX * (panel_width_half - icon_width_half);
+       vector attacker_right = eX * name_maxwidth;
+       vector victim_left = eX * (size.x - name_maxwidth);
 
-       vector pos_attacker, pos_victim, pos_icon;
-       float width_attacker;
+       vector attacker_pos, victim_pos, icon_pos;
        string attacker, victim, icon;
+       float i, j, count, step, limit, alpha;
 
-       float i, j, step, limit;
-       if(autocvar_hud_panel_notify_flip) //order items from the top down
+       if (autocvar_hud_panel_notify_flip)
        {
+               // Order items from the top down
                i = 0;
                step = +1;
-               limit = entries;
+               limit = entry_count;
        }
-       else //order items from the bottom up
+       else
        {
-               i = entries - 1;
+               // Order items from the bottom up
+               i = entry_count - 1;
                step = -1;
                limit = -1;
        }
 
-       for(j = kn_index;  i != limit;  i += step, ++j)
+       for (j = notify_index, count = 0; i != limit; i += step, ++j, ++count)
        {
                if(autocvar__hud_configure)
                {
-                       if (step == +1)
-                               a = i;
-                       else // inverse order
-                               a = entries - 1 - i;
-                       attacker = textShortenToWidth(sprintf(_("Player %d"), a+1), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       victim = textShortenToWidth(sprintf(_("Player %d"), a+2), 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                       icon = strcat("weapon", get_weaponinfo(WEP_FIRST + mod(floor(a*2.4), WEP_LAST)).netname);
-                       a = bound(0, (when - a) / 4, 1);
-                       goto hud_config_notifyprint;
+                       attacker = sprintf(_("Player %d"), count + 1);
+                       victim = sprintf(_("Player %d"), count + 2);
+                       icon = get_weaponinfo(min(WEP_FIRST + count * 2, WEP_LAST)).model2;
+                       alpha = bound(0, 1.2 - count / entry_count, 1);
                }
                else
                {
-                       if (j == KN_MAX_ENTRIES)
+                       if (j == NOTIFY_MAX_ENTRIES)
                                j = 0;
 
-                       if(notify_times[j] + when > time)
-                               a = 1;
-                       else if(fadetime)
+                       if (notify_times[j] + fade_start > time)
+                               alpha = 1;
+                       else if (fade_time != 0)
                        {
-                               a = bound(0, (notify_times[j] + when + fadetime - time) / fadetime, 1);
-                               if(!a)
-                               {
+                               alpha = bound(0, (notify_times[j] + fade_start + fade_time - time) / fade_time, 1);
+                               if (alpha == 0)
                                        break;
-                               }
                        }
                        else
-                       {
                                break;
-                       }
 
                        attacker = notify_attackers[j];
                        victim = notify_victims[j];
-                       icon = notify_icon[j];
+                       icon = notify_icons[j];
                }
 
-               //type = notify_deathtype[j];
-               //w = DEATH_WEAPONOF(type);
-
-               if(icon != "")
+               if (icon != "" && victim != "")
                {
-                       if((attacker != "") && (victim == ""))
-                       {
-                               // Y [used by] X
-                               attacker = textShortenToWidth(attacker, 0.73 * mySize_x - height, fontsize, stringwidth_colors);
-                               pos_attacker = pos + eX * (0.27 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_icon = pos + eX * 0.25 * mySize_x - eX * height + eY * i * height;
+                       vector name_top = eY * (i * entry_height + 0.5 * (entry_height - font_size.y));
 
-                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                       }
-                       else if((attacker != "") && (victim != ""))
+                       icon_pos = pos + icon_left + eY * i * entry_height;
+                       drawpic_aspect_skin(icon_pos, icon, icon_size, '1 1 1', panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+                       victim = textShortenToWidth(victim, name_maxwidth, font_size, stringwidth_colors);
+                       victim_pos = pos + victim_left + name_top;
+                       drawcolorcodedstring(victim_pos, victim, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
+
+                       if (attacker != "")
                        {
-                               // X [did action to] Y
-                               attacker = textShortenToWidth(attacker, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-                               victim = textShortenToWidth(victim, 0.48 * mySize_x - height, fontsize, stringwidth_colors);
-:hud_config_notifyprint
-                               width_attacker = stringwidth(attacker, TRUE, fontsize);
-                               pos_attacker = pos + eX * (0.48 * mySize_x - height - width_attacker) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_victim = pos + eX * (0.52 * mySize_x + height) + eY * ((0.5 * fontsize_y + i * height) + (0.5 * (height - fontheight)));
-                               pos_icon = pos + eX * 0.5 * mySize_x - eX * height + eY * i * height;
-
-                               drawpic_aspect_skin(pos_icon, icon, '2 1 0' * height, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_attacker, attacker, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
-                               drawcolorcodedstring(pos_victim, victim, fontsize, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                               attacker = textShortenToWidth(attacker, name_maxwidth, font_size, stringwidth_colors);
+                               attacker_pos = pos + attacker_right - eX * stringwidth(attacker, true, font_size) + name_top;
+                               drawcolorcodedstring(attacker_pos, attacker, font_size, panel_fg_alpha * alpha, DRAWFLAG_NORMAL);
                        }
                }
        }
+
+       notify_count = count;
 }
 
 // Timer (#5)
@@ -1786,7 +1928,6 @@ void HUD_Timer(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        draw_beginBoldFont();
 
@@ -1850,24 +1991,35 @@ void HUD_Radar(void)
                {
                        if (autocvar_hud_panel_radar == 0) return;
                        if (autocvar_hud_panel_radar != 2 && !teamplay) return;
+                       if(radar_panel_modified)
+                       {
+                               panel.update_time = time; // forces reload of panel attributes
+                               radar_panel_modified = false;
+                       }
                }
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        float f = 0;
 
        if (hud_panel_radar_maximized && !autocvar__hud_configure)
        {
                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;
+               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;
 
+               string panel_bg;
                panel_bg = strcat(hud_skin_path, "/border_default"); // always use the default border when maximized
-               if(precache_pic(panel_bg) == "") { panel_bg = "gfx/hud/default/border_default"; } // fallback
+               if(precache_pic(panel_bg) == "")
+                       panel_bg = "gfx/hud/default/border_default"; // fallback
+               if(!radar_panel_modified && panel_bg != panel.current_panel_bg)
+                       radar_panel_modified = true;
+               if(panel.current_panel_bg)
+                       strunzone(panel.current_panel_bg);
+               panel.current_panel_bg = strzone(panel_bg);
 
                switch(hud_panel_radar_maximized_zoommode)
                {
@@ -1889,7 +2041,7 @@ void HUD_Radar(void)
                switch(hud_panel_radar_maximized_rotation)
                {
                        case 0:
-                               teamradar_angle = view_angles_y - 90;
+                               teamradar_angle = view_angles.y - 90;
                                break;
                        default:
                                teamradar_angle = 90 * hud_panel_radar_maximized_rotation;
@@ -1918,7 +2070,7 @@ void HUD_Radar(void)
                switch(hud_panel_radar_rotation)
                {
                        case 0:
-                               teamradar_angle = view_angles_y - 90;
+                               teamradar_angle = view_angles.y - 90;
                                break;
                        default:
                                teamradar_angle = 90 * hud_panel_radar_rotation;
@@ -1965,16 +2117,16 @@ void HUD_Radar(void)
                vector c0, c1, c2, c3, span;
                c0 = rotate(mi_min, teamradar_angle * DEG2RAD);
                c1 = rotate(mi_max, teamradar_angle * DEG2RAD);
-               c2 = rotate('1 0 0' * mi_min_x + '0 1 0' * mi_max_y, teamradar_angle * DEG2RAD);
-               c3 = rotate('1 0 0' * mi_max_x + '0 1 0' * mi_min_y, teamradar_angle * DEG2RAD);
+               c2 = rotate('1 0 0' * mi_min.x + '0 1 0' * mi_max.y, teamradar_angle * DEG2RAD);
+               c3 = rotate('1 0 0' * mi_max.x + '0 1 0' * mi_min.y, teamradar_angle * DEG2RAD);
                span = '0 0 0';
-               span_x = max(c0_x, c1_x, c2_x, c3_x) - min(c0_x, c1_x, c2_x, c3_x);
-               span_y = max(c0_y, c1_y, c2_y, c3_y) - min(c0_y, c1_y, c2_y, c3_y);
+               span.x = max(c0_x, c1_x, c2_x, c3_x) - min(c0_x, c1_x, c2_x, c3_x);
+               span.y = max(c0_y, c1_y, c2_y, c3_y) - min(c0_y, c1_y, c2_y, c3_y);
 
                // max-min distance must fit the radar in x=x, y=y
                bigsize = min(
-                       teamradar_size2d_x * scale2d / (1.05 * span_x),
-                       teamradar_size2d_y * scale2d / (1.05 * span_y)
+                       teamradar_size2d.x * scale2d / (1.05 * span.x),
+                       teamradar_size2d.y * scale2d / (1.05 * span.y)
                );
        }
 
@@ -1990,10 +2142,10 @@ void HUD_Radar(void)
                + (1 - f) * view_origin);
 
        drawsetcliparea(
-               pos_x,
-               pos_y,
-               mySize_x,
-               mySize_y
+               pos.x,
+               pos.y,
+               mySize.x,
+               mySize.y
        );
 
        draw_teamradar_background(hud_panel_radar_foreground_alpha);
@@ -2016,21 +2168,21 @@ void HUD_Radar(void)
 // Score (#7)
 //
 void HUD_UpdatePlayerTeams();
-void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
+void HUD_Score_Rankings(vector pos, vector mySize, entity me)
 {
        float score;
        entity tm = world, pl;
-#define SCOREPANEL_MAX_ENTRIES 6
-#define SCOREPANEL_ASPECTRATIO 2
-       float entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize_y/mySize_x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
-       vector fontsize = '1 1 0' * (mySize_y/entries);
+       float SCOREPANEL_MAX_ENTRIES = 6;
+       float SCOREPANEL_ASPECTRATIO = 2;
+       float entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize.y/mySize.x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
+       vector fontsize = '1 1 0' * (mySize.y/entries);
 
        vector rgb, score_color;
        rgb = '1 1 1';
        score_color = '1 1 1';
 
-       float name_size = mySize_x*0.75;
-       float spacing_size = mySize_x*0.04;
+       float name_size = mySize.x*0.75;
+       float spacing_size = mySize.x*0.04;
        const float highlight_alpha = 0.2;
        float i = 0, me_printed = 0, first_pl = 0;
        string s;
@@ -2040,15 +2192,15 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
                if (team_count)
                {
                        // show team scores in the first line
-                       float score_size = mySize_x / team_count;
+                       float score_size = mySize.x / team_count;
                        players_per_team = max(2, ceil((entries - 1) / team_count));
                        for(i=0; i<team_count; ++i) {
                                if (i == floor((entries - 2) / players_per_team) || (entries == 1 && i == 0))
-                                       HUD_Panel_DrawHighlight(pos + eX * score_size * i, eX * score_size + eY * fontsize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize_y, Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       HUD_Panel_DrawHighlight(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos + eX * score_size * i, ftos(175 - 23*i), eX * score_size + eY * fontsize.y, Team_ColorRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
                        first_pl = 1;
-                       pos_y += fontsize_y;
+                       pos.y += fontsize.y;
                }
                score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
                for (i=first_pl; i<entries; ++i)
@@ -2059,7 +2211,7 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
                        if (i == entries-1 && autocvar_hud_panel_score_rankings == 1)
                        {
                                rgb = '1 1 0';
-                               drawfill(pos, eX * mySize_x + eY * fontsize_y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                                s = GetPlayerName(player_localnum);
                                score = 7;
                        }
@@ -2072,9 +2224,9 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
                        if (team_count)
                                score_color = Team_ColorRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
                        s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
-                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, TRUE, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
                        drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-                       pos_y += fontsize_y;
+                       pos.y += fontsize.y;
                }
                return;
        }
@@ -2084,17 +2236,17 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
        if (team_count)
        {
                // show team scores in the first line
-               float score_size = mySize_x / team_count;
+               float score_size = mySize.x / team_count;
                for(tm = teams.sort_next; tm; tm = tm.sort_next) {
                        if(tm.team == NUM_SPECTATOR)
                                continue;
                        if (tm.team == myteam)
-                               drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize_y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize_y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize.y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                        ++i;
                }
                first_pl = 1;
-               pos_y += fontsize_y;
+               pos.y += fontsize.y;
                tm = teams.sort_next;
        }
        i = first_pl;
@@ -2124,14 +2276,14 @@ void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
                        if (i == first_pl)
                                rgb = '0 1 0'; //first: green
                        me_printed = 1;
-                       drawfill(pos, eX * mySize_x + eY * fontsize_y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawfill(pos, eX * mySize.x + eY * fontsize.y, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                }
                if (team_count)
                        score_color = Team_ColorRGB(pl.team) * 0.8;
                s = textShortenToWidth(GetPlayerName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
-               drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, TRUE, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, true, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
                drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores[ps_primary])), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               pos_y += fontsize_y;
+               pos.y += fontsize.y;
                ++i;
        }
        while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != NUM_SPECTATOR || (tm = tm.sort_next)));
@@ -2146,7 +2298,6 @@ void HUD_Score(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -2163,11 +2314,7 @@ void HUD_Score(void)
        vector distribution_color;
        entity tm, pl, me;
 
-#ifdef COMPAT_XON050_ENGINE
-       me = (spectatee_status > 0) ? playerslots[spectatee_status - 1] : playerslots[player_localentnum - 1];
-#else
        me = playerslots[player_localentnum - 1];
-#endif
 
        if((scores_flags[ps_primary] & SFL_TIME) && !teamplay) { // race/cts record display on HUD
                string timer, distrtimer;
@@ -2197,17 +2344,17 @@ void HUD_Score(void)
                                distribution_color = '1 0 0';
                                sign = "+";
                        }
-                       drawstring_aspect(pos + eX * 0.75 * mySize_x, strcat(sign, distrtimer), eX * 0.25 * mySize_x + eY * (1/3) * mySize_y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(pos + eX * 0.75 * mySize.x, strcat(sign, distrtimer), eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
                }
                // race record display
                if (distribution <= 0)
-                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(pos, timer, eX * 0.75 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(pos, timer, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                draw_endBoldFont();
        } else if (!teamplay) { // non-teamgames
                if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
                {
-                       HUD_Score_Rankings(pos, mySize, me, 0);
+                       HUD_Score_Rankings(pos, mySize, me);
                        return;
                }
                // me vector := [team/connected frags id]
@@ -2242,50 +2389,44 @@ void HUD_Score(void)
                {
                        if (distribution > 0)
                                distribution_str = strcat("+", distribution_str);
-                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                }
-               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize_x + eY * mySize_y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(pos + eX * 0.75 * mySize_x, distribution_str, eX * 0.25 * mySize_x + eY * (1/3) * mySize_y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(pos + eX * 0.75 * mySize.x, distribution_str, eX * 0.25 * mySize.x + eY * (1/3) * mySize.y, distribution_color, panel_fg_alpha, DRAWFLAG_NORMAL);
                draw_endBoldFont();
        } else { // teamgames
-               float scores_count = 0, row, column, rows = 0, columns = 0;
-               local noref vector offset = '0 0 0';
+               float row, column, rows = 0, columns = 0;
+               vector offset = '0 0 0';
                vector score_pos, score_size; //for scores other than myteam
-               if (spectatee_status == -1 || autocvar_hud_panel_score_rankings)
+               if(autocvar_hud_panel_score_rankings)
                {
-                       for(tm = teams.sort_next; tm, tm.team != NUM_SPECTATOR; tm = tm.sort_next)
-                               ++scores_count;
-                       if (autocvar_hud_panel_score_rankings)
-                       {
-                               HUD_Score_Rankings(pos, mySize, me, scores_count);
-                               return;
-                       }
-                       rows = mySize_y/mySize_x;
-                       rows = bound(1, floor((sqrt(4 * (3/1) * rows * scores_count + rows * rows) + rows + 0.5) / 2), scores_count);
-                       //                               ^^^ ammo item aspect goes here
-
-                       columns = ceil(scores_count/rows);
-
-                       score_size = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+                       HUD_Score_Rankings(pos, mySize, me);
+                       return;
+               }
+               if(spectatee_status == -1)
+               {
+                       rows = HUD_GetRowCount(team_count, mySize, 3);
+                       columns = ceil(team_count/rows);
+                       score_size = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
 
                        float newSize;
-                       if(score_size_x/score_size_y > 3)
+                       if(score_size.x/score_size.y > 3)
                        {
-                               newSize = 3 * score_size_y;
-                               offset_x = score_size_x - newSize;
-                               pos_x += offset_x/2;
-                               score_size_x = newSize;
+                               newSize = 3 * score_size.y;
+                               offset.x = score_size.x - newSize;
+                               pos.x += offset.x/2;
+                               score_size.x = newSize;
                        }
                        else
                        {
-                               newSize = 1/3 * score_size_x;
-                               offset_y = score_size_y - newSize;
-                               pos_y += offset_y/2;
-                               score_size_y = newSize;
+                               newSize = 1/3 * score_size.x;
+                               offset.y = score_size.y - newSize;
+                               pos.y += offset.y/2;
+                               score_size.y = newSize;
                        }
                }
                else
-                       score_size = eX * mySize_x*(1/4) + eY * mySize_y*(1/3);
+                       score_size = eX * mySize.x*(1/4) + eY * mySize.y*(1/3);
 
                float max_fragcount;
                max_fragcount = -99;
@@ -2303,7 +2444,7 @@ void HUD_Score(void)
 
                        if (spectatee_status == -1)
                        {
-                               score_pos = pos + eX * column * (score_size_x + offset_x) + eY * row * (score_size_y + offset_y);
+                               score_pos = pos + eX * column * (score_size.x + offset.x) + eY * row * (score_size.y + offset.y);
                                if (max_fragcount == score)
                                        HUD_Panel_DrawHighlight(score_pos, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                                drawstring_aspect(score_pos, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
@@ -2316,12 +2457,12 @@ void HUD_Score(void)
                        }
                        else if(tm.team == myteam) {
                                if (max_fragcount == score)
-                                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize_x + eY * mySize_y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       HUD_Panel_DrawHighlight(pos, eX * 0.75 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos, ftos(score), eX * 0.75 * mySize.x + eY * mySize.y, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                        } else {
                                if (max_fragcount == score)
-                                       HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring_aspect(pos + eX * 0.75 * mySize_x + eY * (1/3) * rows * mySize_y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                                       HUD_Panel_DrawHighlight(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, score_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+                               drawstring_aspect(pos + eX * 0.75 * mySize.x + eY * (1/3) * rows * mySize.y, ftos(score), score_size, Team_ColorRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
                                ++rows;
                        }
                }
@@ -2341,7 +2482,6 @@ void HUD_RaceTimer (void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        draw_beginBoldFont();
 
@@ -2358,19 +2498,19 @@ void HUD_RaceTimer (void)
 
        // always force 4:1 aspect
        vector newSize = '0 0 0';
-       if(mySize_x/mySize_y > 4)
+       if(mySize.x/mySize.y > 4)
        {
-               newSize_x = 4 * mySize_y;
-               newSize_y = mySize_y;
+               newSize.x = 4 * mySize.y;
+               newSize.y = mySize.y;
 
-               pos_x = pos_x + (mySize_x - newSize_x) / 2;
+               pos.x = pos.x + (mySize.x - newSize.x) / 2;
        }
        else
        {
-               newSize_y = 1/4 * mySize_x;
-               newSize_x = mySize_x;
+               newSize.y = 1/4 * mySize.x;
+               newSize.x = mySize.x;
 
-               pos_y = pos_y + (mySize_y - newSize_y) / 2;
+               pos.y = pos.y + (mySize.y - newSize.y) / 2;
        }
        mySize = newSize;
 
@@ -2380,11 +2520,11 @@ void HUD_RaceTimer (void)
        if(autocvar__hud_configure)
        {
                s = "0:13:37";
-               drawstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, FALSE, '0.60 0.60 0' * mySize_y), s, '0.60 0.60 0' * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.60 0.60 0' * mySize.y), s, '0.60 0.60 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                s = _("^1Intermediate 1 (+15.42)");
-               drawcolorcodedstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, TRUE, '1 1 0' * 0.20 * mySize_y) + eY * 0.60 * mySize_y, s, '1 1 0' * 0.20 * mySize_y, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.60 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
                s = sprintf(_("^1PENALTY: %.1f (%s)"), 2, "missing a checkpoint");
-               drawcolorcodedstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, TRUE, '1 1 0' * 0.20 * mySize_y) + eY * 0.80 * mySize_y, s, '1 1 0' * 0.20 * mySize_y, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.20 * mySize.y) + eY * 0.80 * mySize.y, s, '1 1 0' * 0.20 * mySize.y, panel_fg_alpha, DRAWFLAG_NORMAL);
        }
        else if(race_checkpointtime)
        {
@@ -2417,7 +2557,7 @@ void HUD_RaceTimer (void)
 
                if(s != "" && a > 0)
                {
-                       drawcolorcodedstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, TRUE, '1 1 0' * 0.2 * mySize_y) + eY * 0.6 * mySize_y, s, '1 1 0' * 0.2 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                }
 
                if(race_penaltytime)
@@ -2426,14 +2566,14 @@ void HUD_RaceTimer (void)
                        if(a > 0)
                        {
                                s = sprintf(_("^1PENALTY: %.1f (%s)"), race_penaltytime * 0.1, race_penaltyreason);
-                               drawcolorcodedstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, TRUE, '1 1 0' * 0.2 * mySize_y) + eY * 0.8 * mySize_y, s, '1 1 0' * 0.2 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.8 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                        }
                }
 
                if(forcetime != "")
                {
                        a = bound(0, (time - race_checkpointtime) / 0.5, 1);
-                       drawstring_expanding(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(forcetime, FALSE, '1 1 0' * 0.6 * mySize_y), forcetime, '1 1 0' * 0.6 * mySize_y, '1 1 1', panel_fg_alpha, 0, a);
+                       drawstring_expanding(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(forcetime, false, '1 1 0' * 0.6 * mySize.y), forcetime, '1 1 0' * 0.6 * mySize.y, '1 1 1', panel_fg_alpha, 0, a);
                }
                else
                        a = 1;
@@ -2441,7 +2581,7 @@ void HUD_RaceTimer (void)
                if(race_laptime && race_checkpoint != 255)
                {
                        s = TIME_ENCODED_TOSTRING(TIME_ENCODE(time + TIME_DECODE(race_penaltyaccumulator) - race_laptime));
-                       drawstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, FALSE, '0.6 0.6 0' * mySize_y), s, '0.6 0.6 0' * mySize_y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                       drawstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, false, '0.6 0.6 0' * mySize.y), s, '0.6 0.6 0' * mySize.y, '1 1 1', panel_fg_alpha * a, DRAWFLAG_NORMAL);
                }
        }
        else
@@ -2450,13 +2590,13 @@ void HUD_RaceTimer (void)
                {
                        a = bound(0, 2 - (time - race_mycheckpointtime), 1);
                        s = MakeRaceString(race_mycheckpoint, TIME_DECODE(race_mycheckpointdelta), -(race_mycheckpointenemy == ""), race_mycheckpointlapsdelta, race_mycheckpointenemy);
-                       drawcolorcodedstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, TRUE, '1 1 0' * 0.2 * mySize_y) + eY * 0.6 * mySize_y, s, '1 1 0' * 0.2 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                }
                if(race_othercheckpointtime && race_othercheckpointenemy != "")
                {
                        a = bound(0, 2 - (time - race_othercheckpointtime), 1);
                        s = MakeRaceString(race_othercheckpoint, -TIME_DECODE(race_othercheckpointdelta), -(race_othercheckpointenemy == ""), race_othercheckpointlapsdelta, race_othercheckpointenemy);
-                       drawcolorcodedstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, TRUE, '1 1 0' * 0.2 * mySize_y) + eY * 0.6 * mySize_y, s, '1 1 0' * 0.2 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                       drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                }
 
                if(race_penaltytime && !race_penaltyaccumulator)
@@ -2469,7 +2609,7 @@ void HUD_RaceTimer (void)
                                        s = sprintf(_("^1PENALTY: %.1f (%s)"), (t - time) * 0.1, race_penaltyreason);
                                else
                                        s = sprintf(_("^2PENALTY: %.1f (%s)"), 0, race_penaltyreason);
-                               drawcolorcodedstring(pos + eX * 0.5 * mySize_x - '0.5 0 0' * stringwidth(s, TRUE, '1 1 0' * 0.2 * mySize_y) + eY * 0.6 * mySize_y, s, '1 1 0' * 0.2 * mySize_y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
+                               drawcolorcodedstring(pos + eX * 0.5 * mySize.x - '0.5 0 0' * stringwidth(s, true, '1 1 0' * 0.2 * mySize.y) + eY * 0.6 * mySize.y, s, '1 1 0' * 0.2 * mySize.y, panel_fg_alpha * a, DRAWFLAG_NORMAL);
                        }
                }
        }
@@ -2542,7 +2682,6 @@ void HUD_Vote(void)
                return;
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        if(uid2name_dialog)
        {
@@ -2567,61 +2706,61 @@ void HUD_Vote(void)
 
        // always force 3:1 aspect
        vector newSize = '0 0 0';
-       if(mySize_x/mySize_y > 3)
+       if(mySize.x/mySize.y > 3)
        {
-               newSize_x = 3 * mySize_y;
-               newSize_y = mySize_y;
+               newSize.x = 3 * mySize.y;
+               newSize.y = mySize.y;
 
-               pos_x = pos_x + (mySize_x - newSize_x) / 2;
+               pos.x = pos.x + (mySize.x - newSize.x) / 2;
        }
        else
        {
-               newSize_y = 1/3 * mySize_x;
-               newSize_x = mySize_x;
+               newSize.y = 1/3 * mySize.x;
+               newSize.x = mySize.x;
 
-               pos_y = pos_y + (mySize_y - newSize_y) / 2;
+               pos.y = pos.y + (mySize.y - newSize.y) / 2;
        }
        mySize = newSize;
 
        s = _("A vote has been called for:");
        if(uid2name_dialog)
                s = _("Allow servers to store and display your name?");
-       drawstring_aspect(pos, s, eX * mySize_x + eY * (2/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
-       s = textShortenToWidth(vote_called_vote, mySize_x, '1 1 0' * mySize_y * (1/8), stringwidth_colors);
+       drawstring_aspect(pos, s, eX * mySize.x + eY * (2/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
+       s = textShortenToWidth(vote_called_vote, mySize.x, '1 1 0' * mySize.y * (1/8), stringwidth_colors);
        if(autocvar__hud_configure)
                s = _("^1Configure the HUD");
-       drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize_y, s, eX * mySize_x + eY * (1.75/8) * mySize_y, a, DRAWFLAG_NORMAL);
+       drawcolorcodedstring_aspect(pos + eY * (2/8) * mySize.y, s, eX * mySize.x + eY * (1.75/8) * mySize.y, a, DRAWFLAG_NORMAL);
 
        // print the yes/no counts
     s = sprintf(_("Yes (%s): %d"), getcommandkey("vyes", "vyes"), vote_yescount);
-       drawstring_aspect(pos + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '0 1 0', a, DRAWFLAG_NORMAL);
+       drawstring_aspect(pos + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '0 1 0', a, DRAWFLAG_NORMAL);
     s = sprintf(_("No (%s): %d"), getcommandkey("vno", "vno"), vote_nocount);
-       drawstring_aspect(pos + eX * 0.5 * mySize_x + eY * (4/8) * mySize_y, s, eX * 0.5 * mySize_x + eY * (1.5/8) * mySize_y, '1 0 0', a, DRAWFLAG_NORMAL);
+       drawstring_aspect(pos + eX * 0.5 * mySize.x + eY * (4/8) * mySize.y, s, eX * 0.5 * mySize.x + eY * (1.5/8) * mySize.y, '1 0 0', a, DRAWFLAG_NORMAL);
 
        // draw the progress bar backgrounds
-       drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_back", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
+       drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_back", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
 
        // draw the highlights
        if(vote_highlighted == 1) {
-               drawsetcliparea(pos_x, pos_y, mySize_x * 0.5, mySize_y);
-               drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawsetcliparea(pos.x, pos.y, mySize.x * 0.5, mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
        }
        else if(vote_highlighted == -1) {
-               drawsetcliparea(pos_x + 0.5 * mySize_x, pos_y, mySize_x * 0.5, mySize_y);
-               drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_voted", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawsetcliparea(pos.x + 0.5 * mySize.x, pos.y, mySize.x * 0.5, mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_voted", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
        }
 
        // draw the progress bars
        if(vote_yescount && vote_needed)
        {
-               drawsetcliparea(pos_x, pos_y, mySize_x * 0.5 * (vote_yescount/vote_needed), mySize_y);
-               drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_prog", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawsetcliparea(pos.x, pos.y, mySize.x * 0.5 * (vote_yescount/vote_needed), mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
        }
 
        if(vote_nocount && vote_needed)
        {
-               drawsetcliparea(pos_x + mySize_x - mySize_x * 0.5 * (vote_nocount/vote_needed), pos_y, mySize_x * 0.5, mySize_y);
-               drawpic_skin(pos + eY * (5/8) * mySize_y, "voteprogress_prog", eX * mySize_x + eY * (3/8) * mySize_y, '1 1 1', a, DRAWFLAG_NORMAL);
+               drawsetcliparea(pos.x + mySize.x - mySize.x * 0.5 * (vote_nocount/vote_needed), pos.y, mySize.x * 0.5, mySize.y);
+               drawpic_skin(pos + eY * (5/8) * mySize.y, "voteprogress_prog", eX * mySize.x + eY * (3/8) * mySize.y, '1 1 1', a, DRAWFLAG_NORMAL);
        }
 
        drawresetcliparea();
@@ -2632,16 +2771,11 @@ void HUD_Vote(void)
 
 float mod_active; // is there any active mod icon?
 
-void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, float i)
+void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, float i)
 {
-       float stat;
-       string pic;
-       vector color;
-#ifdef GMQCC
-       stat = -1;
-       pic = "";
-       color = '0 0 0';
-#endif
+       float stat = -1;
+       string pic = "";
+       vector color = '0 0 0';
        switch(i)
        {
                case 0:
@@ -2667,23 +2801,23 @@ void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, f
                        break;
        }
 
-       if(mySize_x/mySize_y > aspect_ratio)
+       if(mySize.x/mySize.y > aspect_ratio)
        {
-               i = aspect_ratio * mySize_y;
-               myPos_x = myPos_x + (mySize_x - i) / 2;
-               mySize_x = i;
+               i = aspect_ratio * mySize.y;
+               myPos.x = myPos.x + (mySize.x - i) / 2;
+               mySize.x = i;
        }
        else
        {
-               i = 1/aspect_ratio * mySize_x;
-               myPos_y = myPos_y + (mySize_y - i) / 2;
-               mySize_y = i;
+               i = 1/aspect_ratio * mySize.x;
+               myPos.y = myPos.y + (mySize.y - i) / 2;
+               mySize.y = i;
        }
 
        if(layout)
        {
-               drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(myPos + eX * 0.7 * mySize_x, ftos(stat), eX * 0.3 * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(myPos + eX * 0.7 * mySize.x, ftos(stat), eX * 0.3 * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
        }
        else
                drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
@@ -2693,30 +2827,24 @@ void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, f
 void HUD_Mod_CA(vector myPos, vector mySize)
 {
        mod_active = 1; // required in each mod function that always shows something
-       entity tm;
-       float teams_count = 0;
-       for(tm = teams.sort_next; tm; tm = tm.sort_next)
-               if(tm.team != NUM_SPECTATOR)
-                       ++teams_count;
 
-       float layout;
+       int layout;
        if(gametype == MAPINFO_TYPE_CA)
                layout = autocvar_hud_panel_modicons_ca_layout;
        else //if(gametype == MAPINFO_TYPE_FREEZETAG)
                layout = autocvar_hud_panel_modicons_freezetag_layout;
        float rows, columns, aspect_ratio;
-       rows = mySize_y/mySize_x;
        aspect_ratio = (layout) ? 2 : 1;
-       rows = bound(1, floor((sqrt((4 * aspect_ratio * teams_count + rows) * rows) + rows + 0.5) / 2), teams_count);
-       columns = ceil(teams_count/rows);
+       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+       columns = ceil(team_count/rows);
 
        int i;
        float row = 0, column = 0;
        vector pos, itemSize;
-       itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
-       for(i=0; i<teams_count; ++i)
+       itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+       for(i=0; i<team_count; ++i)
        {
-               pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
+               pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
 
                DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
 
@@ -2847,24 +2975,24 @@ void HUD_Mod_CTF(vector pos, vector mySize)
                        break;
        }
 
-       if(mySize_x > mySize_y) {
+       if(mySize.x > mySize.y) {
                if (myteam == NUM_TEAM_1) { // always draw own flag on left
                        redflag_pos = pos;
-                       blueflag_pos = pos + eX * 0.5 * mySize_x;
+                       blueflag_pos = pos + eX * 0.5 * mySize.x;
                } else {
                        blueflag_pos = pos;
-                       redflag_pos = pos + eX * 0.5 * mySize_x;
+                       redflag_pos = pos + eX * 0.5 * mySize.x;
                }
-               flag_size = eX * 0.5 * mySize_x + eY * mySize_y;
+               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;
+                       blueflag_pos = pos + eY * 0.5 * mySize.y;
                } else {
                        blueflag_pos = pos;
-                       redflag_pos = pos + eY * 0.5 * mySize_y;
+                       redflag_pos = pos + eY * 0.5 * mySize.y;
                }
-               flag_size = eY * 0.5 * mySize_y + eX * mySize_x;
+               flag_size = eY * 0.5 * mySize.y + eX * mySize.x;
        }
 
        f = bound(0, redflag_statuschange_elapsedtime*2, 1);
@@ -2881,148 +3009,132 @@ void HUD_Mod_CTF(vector pos, vector mySize)
 }
 
 // Keyhunt HUD modicon section
-float kh_runheretime;
-
-void HUD_Mod_KH_Reset(void)
-{
-       kh_runheretime = 0;
-}
+vector KH_SLOTS[4];
 
 void HUD_Mod_KH(vector pos, vector mySize)
 {
        mod_active = 1; // keyhunt should never hide the mod icons panel
-       float kh_keys;
-       float keyteam;
-       float a, aa;
-       vector p = '0 0 0', pa, kh_size = '0 0 0', kh_asize = '0 0 0';
 
-       kh_keys = getstati(STAT_KH_KEYS);
+       // Read current state
 
-       p_x = pos_x;
-       if(mySize_x > mySize_y)
-       {
-               p_y = pos_y + 0.25 * mySize_y;
-               pa = p - eY * 0.25 * mySize_y;
+       float state = getstati(STAT_KH_KEYS);
+       float i, key_state;
+       float all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
+       all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
 
-               kh_size_x = mySize_x * 0.25;
-               kh_size_y = 0.75 * mySize_y;
-               kh_asize_x = mySize_x * 0.25;
-               kh_asize_y = mySize_y * 0.25;
-       }
-       else
+       for(i = 0; i < 4; ++i)
        {
-               p_y = pos_y + 0.125 * mySize_y;
-               pa = p - eY * 0.125 * mySize_y;
+               key_state = (bitshift(state, i * -5) & 31) - 1;
 
-               kh_size_x = mySize_x * 0.5;
-               kh_size_y = 0.375 * mySize_y;
-               kh_asize_x = mySize_x * 0.5;
-               kh_asize_y = mySize_y * 0.125;
-       }
+               if(key_state == -1)
+                       continue;
 
-       float i, key;
+               if(key_state == 30)
+               {
+                       ++carrying_keys;
+                       key_state = myteam;
+               }
 
-       float keycount;
-       keycount = 0;
-       for(i = 0; i < 4; ++i)
-       {
-               key = floor(kh_keys / pow(32, i)) & 31;
-               keyteam = key - 1;
-               if(keyteam == 30 && keycount <= 4)
-                       keycount += 4;
-               if(keyteam == myteam || keyteam == -1 || keyteam == 30)
-                       keycount += 1;
+               switch(key_state)
+               {
+                       case NUM_TEAM_1: ++team1_keys; break;
+                       case NUM_TEAM_2: ++team2_keys; break;
+                       case NUM_TEAM_3: ++team3_keys; break;
+                       case NUM_TEAM_4: ++team4_keys; break;
+                       case 29: ++dropped_keys; break;
+               }
+
+               ++all_keys;
        }
 
-       // this yields 8 exactly if "RUN HERE" shows
+       // Calculate slot measurements
 
-       if(keycount == 8)
+       vector slot_size;
+
+       if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
        {
-               if(!kh_runheretime)
-                       kh_runheretime = time;
-               pa_y -= fabs(sin((time - kh_runheretime) * 3.5)) * 6; // make the arrows jump in case of RUN HERE
+               // Quadratic arrangement
+               slot_size = eX * mySize.x * 0.5 + eY * mySize.y * 0.5;
+               KH_SLOTS[0] = pos;
+               KH_SLOTS[1] = pos + eX * slot_size.x;
+               KH_SLOTS[2] = pos + eY * slot_size.y;
+               KH_SLOTS[3] = pos + eX * slot_size.x + eY * slot_size.y;
        }
        else
-               kh_runheretime = 0;
-
-       for(i = 0; i < 4; ++i)
        {
-               key = floor(kh_keys / pow(32, i)) & 31;
-               keyteam = key - 1;
-               switch(keyteam)
+               if(mySize.x > mySize.y)
                {
-                       case 30: // my key
-                               keyteam = myteam;
-                               a = 1;
-                               aa = 1;
-                               break;
-                       case -1: // no key
-                               a = 0;
-                               aa = 0;
-                               break;
-                       default: // owned or dropped
-                               a = 0.2;
-                               aa = 0.5;
-                               break;
+                       // Horizontal arrangement
+                       slot_size = eX * mySize.x / all_keys + eY * mySize.y;
+                       for(i = 0; i < all_keys; ++i)
+                               KH_SLOTS[i] = pos + eX * slot_size.x * i;
                }
-               a = a * panel_fg_alpha;
-               aa = aa * panel_fg_alpha;
-               if(a > 0)
+               else
                {
-                       switch(keyteam)
-                       {
-                               case NUM_TEAM_1:
-                                       drawpic_aspect_skin(pa, "kh_redarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                               case NUM_TEAM_2:
-                                       drawpic_aspect_skin(pa, "kh_bluearrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                               case NUM_TEAM_3:
-                                       drawpic_aspect_skin(pa, "kh_yellowarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                               case NUM_TEAM_4:
-                                       drawpic_aspect_skin(pa, "kh_pinkarrow", kh_asize, '1 1 1', aa, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                               default:
-                                       break;
-                       }
-                       switch(i) // YAY! switch(i) inside a for loop for i. DailyWTF, here we come!
-                       {
-                               case 0:
-                                       drawpic_aspect_skin(p, "kh_red", kh_size, '1 1 1', a, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                               case 1:
-                                       drawpic_aspect_skin(p, "kh_blue", kh_size, '1 1 1', a, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                               case 2:
-                                       drawpic_aspect_skin(p, "kh_yellow", kh_size, '1 1 1', a, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                               case 3:
-                                       drawpic_aspect_skin(p, "kh_pink", kh_size, '1 1 1', a, DRAWFLAG_NORMAL);  // show 30% theAlpha key
-                                       break;
-                       }
+                       // Vertical arrangement
+                       slot_size = eX * mySize.x + eY * mySize.y / all_keys;
+                       for(i = 0; i < all_keys; ++i)
+                               KH_SLOTS[i] = pos + eY * slot_size.y * i;
                }
-               if(mySize_x > mySize_y)
+       }
+
+       // Make icons blink in case of RUN HERE
+
+       float blink = 0.6 + sin(2*M_PI*time) / 2.5; // Oscillate between 0.2 and 1
+       float alpha;
+       alpha = 1;
+
+       if(carrying_keys)
+               switch(myteam)
+               {
+                       case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
+                       case NUM_TEAM_2: if(team2_keys == all_keys) alpha = blink; break;
+                       case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
+                       case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
+               }
+
+       // Draw icons
+
+       i = 0;
+
+       while(team1_keys--)
+               if(myteam == NUM_TEAM_1 && carrying_keys)
                {
-                       p_x += 0.25 * mySize_x;
-                       pa_x += 0.25 * mySize_x;
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
                }
                else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(team2_keys--)
+               if(myteam == NUM_TEAM_2 && carrying_keys)
                {
-                       if(i == 1)
-                       {
-                               p_y = pos_y + 0.625 * mySize_y;
-                               pa_y = pos_y + 0.5 * mySize_y;
-                               p_x = pos_x;
-                               pa_x = pos_x;
-                       }
-                       else
-                       {
-                               p_x += 0.5 * mySize_x;
-                               pa_x += 0.5 * mySize_x;
-                       }
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
                }
-       }
+               else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(team3_keys--)
+               if(myteam == NUM_TEAM_3 && carrying_keys)
+               {
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
+               }
+               else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(team4_keys--)
+               if(myteam == NUM_TEAM_4 && carrying_keys)
+               {
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+                       --carrying_keys;
+               }
+               else
+                       drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+       while(dropped_keys--)
+               drawpic_aspect_skin(KH_SLOTS[i++], "kh_dropped", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
 }
 
 // Keepaway HUD mod icon
@@ -3052,12 +3164,12 @@ void HUD_Mod_Keepaway(vector pos, vector mySize)
 
        vector kaball_pos, kaball_size;
 
-       if(mySize_x > mySize_y) {
-               kaball_pos = pos + eX * 0.25 * mySize_x;
-               kaball_size = eX * 0.5 * mySize_x + eY * mySize_y;
+       if(mySize.x > mySize.y) {
+               kaball_pos = pos + eX * 0.25 * mySize.x;
+               kaball_size = eX * 0.5 * mySize.x + eY * mySize.y;
        } else {
-               kaball_pos = pos + eY * 0.25 * mySize_y;
-               kaball_size = eY * 0.5 * mySize_y + eX * mySize_x;
+               kaball_pos = pos + eY * 0.25 * mySize.y;
+               kaball_size = eY * 0.5 * mySize.y + eX * mySize.x;
        }
 
        float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
@@ -3067,7 +3179,7 @@ void HUD_Mod_Keepaway(vector pos, vector mySize)
                drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
 
        if(kaball)
-               drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(pos, "keepawayball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
 }
 
 
@@ -3087,22 +3199,17 @@ void HUD_Mod_NexBall(vector pos, vector mySize)
        //Manage the progress bar if any
        if (nb_pb_starttime > 0)
        {
-               dt = mod(time - nb_pb_starttime, nb_pb_period);
+               dt = (time - nb_pb_starttime) % nb_pb_period;
                // one period of positive triangle
                p = 2 * dt / nb_pb_period;
                if (p > 1)
                        p = 2 - p;
 
-               //Draw the filling
-               HUD_Panel_GetProgressBarColor(nexball);
-               if(mySize_x > mySize_y)
-                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, 0, 0, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-               else
-                       HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, 1, 0, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+               HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize.x <= mySize.y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
        }
 
        if (stat_items & IT_KEY1)
-               drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 }
 
 // Race/CTS HUD mod icons
@@ -3151,16 +3258,16 @@ void HUD_Mod_Race(vector pos, vector mySize)
 
        vector textPos, medalPos;
        float squareSize;
-       if(mySize_x > mySize_y) {
+       if(mySize.x > mySize.y) {
                // text on left side
-               squareSize = min(mySize_y, mySize_x/2);
-               textPos = pos + eX * 0.5 * max(0, mySize_x/2 - squareSize) + eY * 0.5 * (mySize_y - squareSize);
-               medalPos = pos + eX * 0.5 * max(0, mySize_x/2 - squareSize) + eX * 0.5 * mySize_x + eY * 0.5 * (mySize_y - squareSize);
+               squareSize = min(mySize.y, mySize.x/2);
+               textPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eY * 0.5 * (mySize.y - squareSize);
+               medalPos = pos + eX * 0.5 * max(0, mySize.x/2 - squareSize) + eX * 0.5 * mySize.x + eY * 0.5 * (mySize.y - squareSize);
        } else {
                // text on top
-               squareSize = min(mySize_x, mySize_y/2);
-               textPos = pos + eY * 0.5 * max(0, mySize_y/2 - squareSize) + eX * 0.5 * (mySize_x - squareSize);
-               medalPos = pos + eY * 0.5 * max(0, mySize_y/2 - squareSize) + eY * 0.5 * mySize_y + eX * 0.5 * (mySize_x - squareSize);
+               squareSize = min(mySize.x, mySize.y/2);
+               textPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eX * 0.5 * (mySize.x - squareSize);
+               medalPos = pos + eY * 0.5 * max(0, mySize.y/2 - squareSize) + eY * 0.5 * mySize.y + eX * 0.5 * (mySize.x - squareSize);
        }
 
        f = time - crecordtime_change_time;
@@ -3252,16 +3359,11 @@ void HUD_Mod_Race(vector pos, vector mySize)
        }
 }
 
-void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, float layout, float i)
+void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, float i)
 {
-       float stat, pps_ratio;
-       string pic;
-       vector color;
-#ifdef GMQCC
-       stat = -1;
-       pic = "";
-       color = '0 0 0';
-#endif
+       float stat = -1;
+       string pic = "";
+       vector color = '0 0 0';
        switch(i)
        {
                case 0:
@@ -3286,19 +3388,19 @@ void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, float layout,
                        color = '1 0 1';
                        break;
        }
-       pps_ratio = stat / getstatf(STAT_DOM_TOTAL_PPS);
+       float pps_ratio = stat / getstatf(STAT_DOM_TOTAL_PPS);
 
-       if(mySize_x/mySize_y > aspect_ratio)
+       if(mySize.x/mySize.y > aspect_ratio)
        {
-               i = aspect_ratio * mySize_y;
-               myPos_x = myPos_x + (mySize_x - i) / 2;
-               mySize_x = i;
+               i = aspect_ratio * mySize.y;
+               myPos.x = myPos.x + (mySize.x - i) / 2;
+               mySize.x = i;
        }
        else
        {
-               i = 1/aspect_ratio * mySize_x;
-               myPos_y = myPos_y + (mySize_y - i) / 2;
-               mySize_y = i;
+               i = 1/aspect_ratio * mySize.x;
+               myPos.y = myPos.y + (mySize.y - i) / 2;
+               mySize.y = i;
        }
 
        if (layout) // show text too
@@ -3306,17 +3408,17 @@ void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, float layout,
                //draw the text
                color *= 0.5 + pps_ratio * (1 - 0.5); // half saturated color at min, full saturated at max
                if (layout == 2) // average pps
-                       drawstring_aspect(myPos + eX * mySize_y, ftos_decimals(stat, 2), eX * (2/3) * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(myPos + eX * mySize.y, ftos_decimals(stat, 2), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
                else // percentage of average pps
-                       drawstring_aspect(myPos + eX * mySize_y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), eX * (2/3) * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(myPos + eX * mySize.y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), eX * (2/3) * mySize.x + eY * mySize.y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
        }
 
        //draw the icon
-       drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
        if (stat > 0)
        {
-               drawsetcliparea(myPos_x, myPos_y + mySize_y * (1 - pps_ratio), mySize_y, mySize_y * pps_ratio);
-               drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawsetcliparea(myPos.x, myPos.y + mySize.y * (1 - pps_ratio), mySize.y, mySize.y * pps_ratio);
+               drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                drawresetcliparea();
        }
 }
@@ -3324,26 +3426,20 @@ void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, float layout,
 void HUD_Mod_Dom(vector myPos, vector mySize)
 {
        mod_active = 1; // required in each mod function that always shows something
-       entity tm;
-       float teams_count = 0;
-       for(tm = teams.sort_next; tm; tm = tm.sort_next)
-               if(tm.team != NUM_SPECTATOR)
-                       ++teams_count;
 
-       float layout = autocvar_hud_panel_modicons_dom_layout;
+       int layout = autocvar_hud_panel_modicons_dom_layout;
        float rows, columns, aspect_ratio;
-       rows = mySize_y/mySize_x;
        aspect_ratio = (layout) ? 3 : 1;
-       rows = bound(1, floor((sqrt((4 * aspect_ratio * teams_count + rows) * rows) + rows + 0.5) / 2), teams_count);
-       columns = ceil(teams_count/rows);
+       rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+       columns = ceil(team_count/rows);
 
        int i;
        float row = 0, column = 0;
        vector pos, itemSize;
-       itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
-       for(i=0; i<teams_count; ++i)
+       itemSize = eX * mySize.x*(1/columns) + eY * mySize.y*(1/rows);
+       for(i=0; i<team_count; ++i)
        {
-               pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
+               pos = myPos + eX * column * itemSize.x + eY * row * itemSize.y;
 
                DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
 
@@ -3356,6 +3452,22 @@ void HUD_Mod_Dom(vector myPos, vector mySize)
        }
 }
 
+void HUD_ModIcons_SetFunc()
+{
+       switch(gametype)
+       {
+               case MAPINFO_TYPE_KEYHUNT:              HUD_ModIcons_GameType = HUD_Mod_KH; break;
+               case MAPINFO_TYPE_CTF:                  HUD_ModIcons_GameType = HUD_Mod_CTF; break;
+               case MAPINFO_TYPE_NEXBALL:              HUD_ModIcons_GameType = HUD_Mod_NexBall; break;
+               case MAPINFO_TYPE_CTS:
+               case MAPINFO_TYPE_RACE:         HUD_ModIcons_GameType = HUD_Mod_Race; break;
+               case MAPINFO_TYPE_CA:
+               case MAPINFO_TYPE_FREEZETAG:    HUD_ModIcons_GameType = HUD_Mod_CA; break;
+               case MAPINFO_TYPE_DOMINATION:   HUD_ModIcons_GameType = HUD_Mod_Dom; break;
+               case MAPINFO_TYPE_KEEPAWAY:     HUD_ModIcons_GameType = HUD_Mod_Keepaway; break;
+       }
+}
+
 float mod_prev; // previous state of mod_active to check for a change
 float mod_alpha;
 float mod_change; // "time" when mod_active changed
@@ -3365,18 +3477,13 @@ void HUD_ModIcons(void)
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_modicons) return;
-               if (gametype != MAPINFO_TYPE_CTF && gametype != MAPINFO_TYPE_KEYHUNT && gametype != MAPINFO_TYPE_NEXBALL && gametype != MAPINFO_TYPE_CTS && gametype != MAPINFO_TYPE_RACE && gametype != MAPINFO_TYPE_CA && gametype != MAPINFO_TYPE_FREEZETAG && gametype != MAPINFO_TYPE_KEEPAWAY && gametype != MAPINFO_TYPE_DOMINATION) return;
+               if(!HUD_ModIcons_GameType) return;
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        draw_beginBoldFont();
 
-       vector pos, mySize;
-       pos = panel_pos;
-       mySize = panel_size;
-
        if(mod_active != mod_prev) {
                mod_change = time;
                mod_prev = mod_active;
@@ -3392,25 +3499,14 @@ void HUD_ModIcons(void)
 
        if(panel_bg_padding)
        {
-               pos += '1 1 0' * panel_bg_padding;
-               mySize -= '2 2 0' * panel_bg_padding;
+               panel_pos += '1 1 0' * panel_bg_padding;
+               panel_size -= '2 2 0' * panel_bg_padding;
        }
 
-       // these MUST be ran in order to update mod_active
-       if(gametype == MAPINFO_TYPE_KEYHUNT)
-               HUD_Mod_KH(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_CTF || autocvar__hud_configure)
-               HUD_Mod_CTF(pos, mySize); // forcealpha only needed for ctf icons, as only they are shown in config mode
-       else if(gametype == MAPINFO_TYPE_NEXBALL)
-               HUD_Mod_NexBall(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE)
-               HUD_Mod_Race(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_CA || gametype == MAPINFO_TYPE_FREEZETAG)
-               HUD_Mod_CA(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_DOMINATION)
-               HUD_Mod_Dom(pos, mySize);
-       else if(gametype == MAPINFO_TYPE_KEEPAWAY)
-               HUD_Mod_Keepaway(pos, mySize);
+       if(autocvar__hud_configure)
+               HUD_Mod_CTF(panel_pos, panel_size);
+       else
+               HUD_ModIcons_GameType(panel_pos, panel_size);
 
        draw_endBoldFont();
 }
@@ -3426,7 +3522,6 @@ void HUD_PressedKeys(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -3443,42 +3538,42 @@ void HUD_PressedKeys(void)
        if(aspect)
        {
                vector newSize = '0 0 0';
-               if(mySize_x/mySize_y > aspect)
+               if(mySize.x/mySize.y > aspect)
                {
-                       newSize_x = aspect * mySize_y;
-                       newSize_y = mySize_y;
+                       newSize.x = aspect * mySize.y;
+                       newSize.y = mySize.y;
 
-                       pos_x = pos_x + (mySize_x - newSize_x) / 2;
+                       pos.x = pos.x + (mySize.x - newSize.x) / 2;
                }
                else
                {
-                       newSize_y = 1/aspect * mySize_x;
-                       newSize_x = mySize_x;
+                       newSize.y = 1/aspect * mySize.x;
+                       newSize.x = mySize.x;
 
-                       pos_y = pos_y + (mySize_y - newSize_y) / 2;
+                       pos.y = pos.y + (mySize.y - newSize.y) / 2;
                }
                mySize = newSize;
        }
 
        vector keysize;
-       keysize = eX * mySize_x * (1/3.0) + eY * mySize_y * (1/(3.0 - !autocvar_hud_panel_pressedkeys_attack));
+       keysize = eX * mySize.x * (1/3.0) + eY * mySize.y * (1/(3.0 - !autocvar_hud_panel_pressedkeys_attack));
        float pressedkeys;
        pressedkeys = getstatf(STAT_PRESSED_KEYS);
 
        if(autocvar_hud_panel_pressedkeys_attack)
        {
-               drawpic_aspect_skin(pos + eX * keysize_x * 0.5, ((pressedkeys & KEY_ATCK) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawpic_aspect_skin(pos + eX * keysize_x * 1.5, ((pressedkeys & KEY_ATCK2) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               pos_y += keysize_y;
+               drawpic_aspect_skin(pos + eX * keysize.x * 0.5, ((pressedkeys & KEY_ATCK) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawpic_aspect_skin(pos + eX * keysize.x * 1.5, ((pressedkeys & KEY_ATCK2) ? "key_atck_inv.tga" : "key_atck.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               pos.y += keysize.y;
        }
 
        drawpic_aspect_skin(pos, ((pressedkeys & KEY_CROUCH) ? "key_crouch_inv.tga" : "key_crouch.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize_x, ((pressedkeys & KEY_FORWARD) ? "key_forward_inv.tga" : "key_forward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize_x * 2, ((pressedkeys & KEY_JUMP) ? "key_jump_inv.tga" : "key_jump.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       pos_y += keysize_y;
+       drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_FORWARD) ? "key_forward_inv.tga" : "key_forward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_JUMP) ? "key_jump_inv.tga" : "key_jump.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       pos.y += keysize.y;
        drawpic_aspect_skin(pos, ((pressedkeys & KEY_LEFT) ? "key_left_inv.tga" : "key_left.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize_x, ((pressedkeys & KEY_BACKWARD) ? "key_backward_inv.tga" : "key_backward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       drawpic_aspect_skin(pos + eX * keysize_x * 2, ((pressedkeys & KEY_RIGHT) ? "key_right_inv.tga" : "key_right.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(pos + eX * keysize.x, ((pressedkeys & KEY_BACKWARD) ? "key_backward_inv.tga" : "key_backward.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       drawpic_aspect_skin(pos + eX * keysize.x * 2, ((pressedkeys & KEY_RIGHT) ? "key_right_inv.tga" : "key_right.tga"), keysize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 }
 
 // Handle chat as a panel (#12)
@@ -3494,24 +3589,32 @@ void HUD_Chat(void)
                        return;
                }
                if(autocvar__con_chat_maximized)
+               {
                        if(!hud_draw_maximized) return;
+               }
+               else if(chat_panel_modified)
+               {
+                       panel.update_time = time; // forces reload of panel attributes
+                       chat_panel_modified = false;
+               }
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
        {
-               panel_pos_y = panel_bg_border;
-               panel_size_y = vid_conheight - panel_bg_border * 2;
-               if(panel_bg == "0") // force a border when maximized
+               panel_pos.y = panel_bg_border;
+               panel_size.y = vid_conheight - panel_bg_border * 2;
+               if(panel.current_panel_bg == "0") // force a border when maximized
                {
-                       if(precache_pic(panel_bg) == "") {
-                               panel_bg = strcat(hud_skin_path, "/border_default");
-                               if(precache_pic(panel_bg) == "") {
-                                       panel_bg = "gfx/hud/default/border_default";
-                               }
-                       }
+                       string panel_bg;
+                       panel_bg = strcat(hud_skin_path, "/border_default");
+                       if(precache_pic(panel_bg) == "")
+                               panel_bg = "gfx/hud/default/border_default";
+                       if(panel.current_panel_bg)
+                               strunzone(panel.current_panel_bg);
+                       panel.current_panel_bg = strzone(panel_bg);
+                       chat_panel_modified = true;
                }
                panel_bg_alpha = max(0.75, panel_bg_alpha); // force an theAlpha of at least 0.75
        }
@@ -3531,11 +3634,11 @@ void HUD_Chat(void)
        if (!autocvar_con_chatrect)
                cvar_set("con_chatrect", "1");
 
-       cvar_set("con_chatrect_x", ftos(pos_x/vid_conwidth));
-       cvar_set("con_chatrect_y", ftos(pos_y/vid_conheight));
+       cvar_set("con_chatrect_x", ftos(pos.x/vid_conwidth));
+       cvar_set("con_chatrect_y", ftos(pos.y/vid_conheight));
 
-       cvar_set("con_chatwidth", ftos(mySize_x/vid_conwidth));
-       cvar_set("con_chat", ftos(floor(mySize_y/autocvar_con_chatsize - 0.5)));
+       cvar_set("con_chatwidth", ftos(mySize.x/vid_conwidth));
+       cvar_set("con_chat", ftos(floor(mySize.y/autocvar_con_chatsize - 0.5)));
 
        if(autocvar__hud_configure)
        {
@@ -3549,8 +3652,8 @@ void HUD_Chat(void)
                                a = panel_fg_alpha;
                        else
                                a = panel_fg_alpha * floor(((i + 1) * 7 + autocvar_con_chattime)/45);
-                       drawcolorcodedstring(pos, textShortenToWidth(_("^3Player^7: This is the chat area."), mySize_x, chatsize, stringwidth_colors), chatsize, a, DRAWFLAG_NORMAL);
-                       pos_y += chatsize_y;
+                       drawcolorcodedstring(pos, textShortenToWidth(_("^3Player^7: This is the chat area."), mySize.x, chatsize, stringwidth_colors), chatsize, a, DRAWFLAG_NORMAL);
+                       pos.y += chatsize.y;
                }
        }
 }
@@ -3572,7 +3675,6 @@ void HUD_EngineInfo(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -3620,11 +3722,12 @@ void HUD_EngineInfo(void)
 
 // Info messages panel (#14)
 //
-#define drawInfoMessage(s)\
-       if(autocvar_hud_panel_infomessages_flip)\
-               o_x = pos_x + mySize_x - stringwidth(s, TRUE, fontsize);\
-       drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);\
-       o_y += fontsize_y;
+#define drawInfoMessage(s) do {                                                                                                                                                                                \
+       if(autocvar_hud_panel_infomessages_flip)                                                                                                                                                \
+               o.x = pos.x + mySize.x - stringwidth(s, true, fontsize);                                                                                                        \
+       drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);                                                                                                               \
+       o.y += fontsize.y;                                                                                                                                                                                              \
+} while(0)
 void HUD_InfoMessages(void)
 {
        if(!autocvar__hud_configure)
@@ -3633,7 +3736,6 @@ void HUD_InfoMessages(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -3647,19 +3749,19 @@ void HUD_InfoMessages(void)
 
        // always force 5:1 aspect
        vector newSize = '0 0 0';
-       if(mySize_x/mySize_y > 5)
+       if(mySize.x/mySize.y > 5)
        {
-               newSize_x = 5 * mySize_y;
-               newSize_y = mySize_y;
+               newSize.x = 5 * mySize.y;
+               newSize.y = mySize.y;
 
-               pos_x = pos_x + (mySize_x - newSize_x) / 2;
+               pos.x = pos.x + (mySize.x - newSize.x) / 2;
        }
        else
        {
-               newSize_y = 1/5 * mySize_x;
-               newSize_x = mySize_x;
+               newSize.y = 1/5 * mySize.x;
+               newSize.x = mySize.x;
 
-               pos_y = pos_y + (mySize_y - newSize_y) / 2;
+               pos.y = pos.y + (mySize.y - newSize.y) / 2;
        }
 
        mySize = newSize;
@@ -3668,7 +3770,7 @@ void HUD_InfoMessages(void)
        o = pos;
 
        vector fontsize;
-       fontsize = '0.20 0.20 0' * mySize_y;
+       fontsize = '0.20 0.20 0' * mySize.y;
 
        float a;
        a = panel_fg_alpha;
@@ -3682,27 +3784,23 @@ void HUD_InfoMessages(void)
                        if(spectatee_status == -1)
                                s = _("^1Observing");
                        else
-#ifdef COMPAT_XON050_ENGINE
-                               s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(spectatee_status - 1));
-#else
                                s = sprintf(_("^1Spectating: ^7%s"), GetPlayerName(player_localentnum - 1));
-#endif
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
 
                        if(spectatee_status == -1)
                                s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
                        else
                                s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
 
                        if(spectatee_status == -1)
                                s = sprintf(_("^1Use ^3%s^1 or ^3%s^1 to change the speed"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
                        else
                                s = sprintf(_("^1Press ^3%s^1 to observe"), getcommandkey("secondary fire", "+fire2"));
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
 
                        s = sprintf(_("^1Press ^3%s^1 for gamemode info"), getcommandkey("server info", "+show_info"));
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
 
                        if(gametype == MAPINFO_TYPE_LMS)
                        {
@@ -3717,7 +3815,7 @@ void HUD_InfoMessages(void)
                        }
                        else
                                s = sprintf(_("^1Press ^3%s^1 to join"), getcommandkey("jump", "+jump"));
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
 
                        //show restart countdown:
                        if (time < getstatf(STAT_GAMESTARTTIME)) {
@@ -3726,33 +3824,36 @@ void HUD_InfoMessages(void)
                                countdown = ceil(getstatf(STAT_GAMESTARTTIME) - time);
                                s = sprintf(_("^1Game starts in ^3%d^1 seconds"), countdown);
                                drawcolorcodedstring(o, s, fontsize, a, DRAWFLAG_NORMAL);
-                               o_y += fontsize_y;
+                               o.y += fontsize.y;
                        }
                }
                if(warmup_stage && !intermission)
                {
                        s = _("^2Currently in ^1warmup^2 stage!");
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
                }
-               
+
                if(autocvar_cl_showspectators)
                if(num_spectators)
-               if not(spectatee_status)
+               //if(spectatee_status != -1)
                {
-                       s = _("^1Spectating you:");
-                       drawInfoMessage(s)
+                       s = ((spectatee_status) ? _("^1Spectating this player:") : _("^1Spectating you:"));
+                       //drawInfoMessage(s)
                        float limit = min(num_spectators, MAX_SPECTATORS);
                        float i;
                        for(i = 0; i < limit; ++i)
                        {
                                float slot = spectatorlist[i];
-                               s = strcat("^3", GetPlayerName(slot));
-                               drawInfoMessage(s)
+                               if(i == 0)
+                                       s = strcat(s, " ^3", GetPlayerName(slot));
+                               else
+                                       s = strcat("^3", GetPlayerName(slot));
+                               drawInfoMessage(s);
                        }
                }
 
                string blinkcolor;
-               if(mod(time, 1) >= 0.5)
+               if(time % 1 >= 0.5)
                        blinkcolor = "^1";
                else
                        blinkcolor = "^3";
@@ -3773,12 +3874,12 @@ void HUD_InfoMessages(void)
                                else
                                        s = _("^2Waiting for others to ready up...");
                        }
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
                }
                else if(warmup_stage && !intermission && !spectatee_status)
                {
                        s = sprintf(_("^2Press ^3%s^2 to end warmup"), getcommandkey("ready", "ready"));
-                       drawInfoMessage(s)
+                       drawInfoMessage(s);
                }
 
                if(teamplay && !intermission && !spectatee_status && gametype != MAPINFO_TYPE_CA && teamnagger)
@@ -3787,7 +3888,7 @@ void HUD_InfoMessages(void)
                        tm = teams.sort_next;
                        if (tm)
                        {
-                               for(; tm.sort_next; tm = tm.sort_next)
+                               for (; tm.sort_next; tm = tm.sort_next)
                                {
                                        if(!tm.team_size || tm.team == NUM_SPECTATOR)
                                                continue;
@@ -3804,7 +3905,7 @@ void HUD_InfoMessages(void)
                                        if (tm.team != NUM_SPECTATOR)
                                        if (tm.team_size == ts_max)
                                                s = strcat(s, sprintf(_(" Press ^3%s%s to adjust"), getcommandkey("team menu", "menu_showteamselect"), blinkcolor));
-                                       drawInfoMessage(s)
+                                       drawInfoMessage(s);
                                }
                        }
                }
@@ -3812,13 +3913,13 @@ void HUD_InfoMessages(void)
        else
        {
                s = _("^7Press ^3ESC ^7to show HUD options.");
-               drawInfoMessage(s)
+               drawInfoMessage(s);
                s = _("^3Doubleclick ^7a panel for panel-specific options.");
-               drawInfoMessage(s)
+               drawInfoMessage(s);
                s = _("^3CTRL ^7to disable collision testing, ^3SHIFT ^7and");
-               drawInfoMessage(s)
+               drawInfoMessage(s);
                s = _("^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments.");
-               drawInfoMessage(s)
+               drawInfoMessage(s);
        }
 }
 
@@ -3836,7 +3937,6 @@ void HUD_Physics(void)
        }
 
        HUD_Panel_UpdateCvars();
-       HUD_Panel_ApplyFadeAlpha();
 
        draw_beginBoldFont();
 
@@ -3894,7 +3994,7 @@ void HUD_Physics(void)
        else if(autocvar_hud_panel_physics_speed_vertical)
                speed = floor( vlen(vel) * conversion_factor + 0.5 );
        else
-               speed = floor( vlen(vel - vel_z * '0 0 1') * conversion_factor + 0.5 );
+               speed = floor( vlen(vel - vel.z * '0 0 1') * conversion_factor + 0.5 );
 
        //compute acceleration
        float acceleration, f;
@@ -3907,7 +4007,7 @@ void HUD_Physics(void)
                if(autocvar_hud_panel_physics_acceleration_vertical)
                        acceleration = (vlen(vel) - vlen(acc_prevspeed));
                else
-                       acceleration = (vlen(vel - '0 0 1' * vel_z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed_z));
+                       acceleration = (vlen(vel - '0 0 1' * vel.z) - vlen(acc_prevspeed - '0 0 1' * acc_prevspeed.z));
 
                acceleration = acceleration * (1 / max(0.0001, f)) * (0.0254 / 9.80665);
 
@@ -3919,23 +4019,23 @@ void HUD_Physics(void)
        }
 
        //compute layout
-       float panel_ar = panel_size_x/panel_size_y;
+       float panel_ar = panel_size.x/panel_size.y;
        vector speed_offset = '0 0 0', acceleration_offset = '0 0 0';
        if (panel_ar >= 5 && !acceleration_progressbar_scale)
        {
-               panel_size_x *= 0.5;
+               panel_size.x *= 0.5;
                if (autocvar_hud_panel_physics_flip)
-                       speed_offset_x = panel_size_x;
+                       speed_offset.x = panel_size.x;
                else
-                       acceleration_offset_x = panel_size_x;
+                       acceleration_offset.x = panel_size.x;
        }
        else
        {
-               panel_size_y *= 0.5;
+               panel_size.y *= 0.5;
                if (autocvar_hud_panel_physics_flip)
-                       speed_offset_y = panel_size_y;
+                       speed_offset.y = panel_size.y;
                else
-                       acceleration_offset_y = panel_size_y;
+                       acceleration_offset.y = panel_size.y;
        }
        float speed_baralign, acceleration_baralign;
        if (autocvar_hud_panel_physics_baralign == 1)
@@ -3958,33 +4058,30 @@ void HUD_Physics(void)
        //draw speed
        if(speed)
        if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
-       {
-               HUD_Panel_GetProgressBarColor(speed);
-               HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
+               HUD_Panel_DrawProgressBar(panel_pos + speed_offset, panel_size, "progressbar", speed/max_speed, 0, speed_baralign, autocvar_hud_progressbar_speed_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
        vector tmp_offset = '0 0 0', tmp_size = '0 0 0';
        if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 2)
        {
-               tmp_size_x = panel_size_x * 0.75;
-               tmp_size_y = panel_size_y * text_scale;
+               tmp_size.x = panel_size.x * 0.75;
+               tmp_size.y = panel_size.y * text_scale;
                if (speed_baralign)
-                       tmp_offset_x = panel_size_x - tmp_size_x;
+                       tmp_offset.x = panel_size.x - tmp_size.x;
                //else
                        //tmp_offset_x = 0;
-               tmp_offset_y = (panel_size_y - tmp_size_y) / 2;
+               tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
                drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(speed), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 
                //draw speed unit
                if (speed_baralign)
-                       tmp_offset_x = 0;
+                       tmp_offset.x = 0;
                else
-                       tmp_offset_x = tmp_size_x;
+                       tmp_offset.x = tmp_size.x;
                if (autocvar_hud_panel_physics_speed_unit_show)
                {
                        //tmp_offset_y = 0;
-                       tmp_size_x = panel_size_x * (1 - 0.75);
-                       tmp_size_y = panel_size_y * 0.4 * text_scale;
-                       tmp_offset_y = (panel_size_y * 0.4 - tmp_size_y) / 2;
+                       tmp_size.x = panel_size.x * (1 - 0.75);
+                       tmp_size.y = panel_size.y * 0.4 * text_scale;
+                       tmp_offset.y = (panel_size.y * 0.4 - tmp_size.y) / 2;
                        drawstring_aspect(panel_pos + speed_offset + tmp_offset, unit, tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
                }
        }
@@ -4020,33 +4117,30 @@ void HUD_Physics(void)
                        if(speed < top_speed)
                        if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 2)
                        {
-                               float peak_offset_x;
+                               float peak_offsetX;
                                vector peak_size = '0 0 0';
                                if (speed_baralign == 0)
-                                       peak_offset_x = min(top_speed, max_speed)/max_speed * panel_size_x;
+                                       peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x;
                 else if (speed_baralign == 1)
-                                       peak_offset_x = (1 - min(top_speed, max_speed)/max_speed) * panel_size_x;
+                                       peak_offsetX = (1 - min(top_speed, max_speed)/max_speed) * panel_size.x;
                 else // if (speed_baralign == 2)
-                    peak_offset_x = min(top_speed, max_speed)/max_speed * panel_size_x * 0.5;
-                               //if speed is not 0 the speed progressbar already fetched the color
-                               if (speed == 0)
-                                       HUD_Panel_GetProgressBarColor(speed);
-                               peak_size_x = floor(panel_size_x * 0.01 + 1.5);
-                peak_size_y = panel_size_y;
+                    peak_offsetX = min(top_speed, max_speed)/max_speed * panel_size.x * 0.5;
+                               peak_size.x = floor(panel_size.x * 0.01 + 1.5);
+                peak_size.y = panel_size.y;
                 if (speed_baralign == 2) // draw two peaks, on both sides
                 {
-                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size_x + peak_offset_x - peak_size_x), peak_size, progressbar_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size_x - peak_offset_x + peak_size_x), peak_size, progressbar_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x + peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                    drawfill(panel_pos + speed_offset + eX * (0.5 * panel_size.x - peak_offsetX + peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                 }
                 else
-                    drawfill(panel_pos + speed_offset + eX * (peak_offset_x - peak_size_x), peak_size, progressbar_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                    drawfill(panel_pos + speed_offset + eX * (peak_offsetX - peak_size.x), peak_size, autocvar_hud_progressbar_speed_color, f * autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
                        }
 
                        //top speed
-                       tmp_offset_y = panel_size_y * 0.4;
-                       tmp_size_x = panel_size_x * (1 - 0.75);
-                       tmp_size_y = (panel_size_y - tmp_offset_y) * text_scale;
-                       tmp_offset_y += (panel_size_y - tmp_offset_y - tmp_size_y) / 2;
+                       tmp_offset.y = panel_size.y * 0.4;
+                       tmp_size.x = panel_size.x * (1 - 0.75);
+                       tmp_size.y = (panel_size.y - tmp_offset.y) * text_scale;
+                       tmp_offset.y += (panel_size.y - tmp_offset.y - tmp_size.y) / 2;
                        drawstring_aspect(panel_pos + speed_offset + tmp_offset, ftos(top_speed), tmp_size, '1 0 0', f * panel_fg_alpha, DRAWFLAG_NORMAL);
                }
                else
@@ -4057,10 +4151,11 @@ void HUD_Physics(void)
        if(acceleration)
        if(autocvar_hud_panel_physics_progressbar == 1 || autocvar_hud_panel_physics_progressbar == 3)
        {
-               if (acceleration < 0)
-                       HUD_Panel_GetProgressBarColor(acceleration_neg);
+               vector progressbar_color;
+               if(acceleration < 0)
+                       progressbar_color = autocvar_hud_progressbar_acceleration_neg_color;
                else
-                       HUD_Panel_GetProgressBarColor(acceleration);
+                       progressbar_color = autocvar_hud_progressbar_acceleration_color;
 
                f = acceleration/autocvar_hud_panel_physics_acceleration_max;
                if (autocvar_hud_panel_physics_acceleration_progressbar_nonlinear)
@@ -4068,15 +4163,15 @@ void HUD_Physics(void)
 
                if (acceleration_progressbar_scale) // allow progressbar to go out of panel bounds
                {
-                       tmp_size = acceleration_progressbar_scale * panel_size_x * eX + panel_size_y * eY;
+                       tmp_size = acceleration_progressbar_scale * panel_size.x * eX + panel_size.y * eY;
 
                        if (acceleration_baralign == 1)
-                               tmp_offset_x = panel_size_x - tmp_size_x;
+                               tmp_offset.x = panel_size.x - tmp_size.x;
                        else if (acceleration_baralign == 2 || acceleration_baralign == 3)
-                               tmp_offset_x = (panel_size_x - tmp_size_x) / 2;
+                               tmp_offset.x = (panel_size.x - tmp_size.x) / 2;
                        else
-                               tmp_offset_x = 0;
-                       tmp_offset_y = 0;
+                               tmp_offset.x = 0;
+                       tmp_offset.y = 0;
                }
                else
                {
@@ -4086,10 +4181,10 @@ void HUD_Physics(void)
 
                HUD_Panel_DrawProgressBar(panel_pos + acceleration_offset + tmp_offset, tmp_size, "accelbar", f, 0, acceleration_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
        }
-       tmp_size_x = panel_size_x;
-       tmp_size_y = panel_size_y * text_scale;
-       tmp_offset_x = 0;
-       tmp_offset_y = (panel_size_y - tmp_size_y) / 2;
+       tmp_size.x = panel_size.x;
+       tmp_size.y = panel_size.y * text_scale;
+       tmp_offset.x = 0;
+       tmp_offset.y = (panel_size.y - tmp_size.y) / 2;
        if (autocvar_hud_panel_physics_text == 1 || autocvar_hud_panel_physics_text == 3)
                drawstring_aspect(panel_pos + acceleration_offset + tmp_offset, strcat(ftos_decimals(acceleration, 2), "g"), tmp_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 
@@ -4098,9 +4193,9 @@ void HUD_Physics(void)
 
 // CenterPrint (#16)
 //
-#define CENTERPRINT_MAX_MSGS 10
-#define CENTERPRINT_MAX_ENTRIES 50
-#define CENTERPRINT_SPACING 0.7
+const float CENTERPRINT_MAX_MSGS = 10;
+const float CENTERPRINT_MAX_ENTRIES = 50;
+const float CENTERPRINT_SPACING = 0.7;
 float cpm_index;
 string centerprint_messages[CENTERPRINT_MAX_MSGS];
 float centerprint_msgID[CENTERPRINT_MAX_MSGS];
@@ -4138,7 +4233,7 @@ void centerprint_generic(float new_id, string strMessage, float duration, float
                return;
 
        if (!centerprint_showing)
-               centerprint_showing = TRUE;
+               centerprint_showing = true;
 
        for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
        {
@@ -4210,20 +4305,20 @@ void HUD_CenterPrint (void)
        {
                if(!autocvar_hud_panel_centerprint) return;
 
-               if (hud_configure_prev && hud_configure_prev != -1)
+               if(hud_configure_prev)
                        reset_centerprint_messages();
        }
        else
        {
-               if (!hud_configure_prev)
+               if(!hud_configure_prev)
                        reset_centerprint_messages();
                if (time > hud_configure_cp_generation_time)
                {
                        float r;
                        r = random();
-                       if (r > 0.9)
+                       if (r > 0.75)
                                centerprint_generic(floor(r*1000), strcat(sprintf("^3Countdown message at time %s", seconds_tostring(time)), ", seconds left: ^COUNT"), 1, 10);
-                       else if (r > 0.8)
+                       else if (r > 0.5)
                                centerprint_generic(0, sprintf("^1Multiline message at time %s that\n^1lasts longer than normal", seconds_tostring(time)), 20, 0);
                        else
                                centerprint_hud(sprintf("Message at time %s", seconds_tostring(time)));
@@ -4231,25 +4326,30 @@ void HUD_CenterPrint (void)
                }
        }
 
+       // this panel fades only when the menu does
+       float hud_fade_alpha_save = 0;
+       if(scoreboard_fade_alpha)
+       {
+               hud_fade_alpha_save = hud_fade_alpha;
+               hud_fade_alpha = 1 - autocvar__menu_alpha;
+       }
        HUD_Panel_UpdateCvars();
 
-       // this panel doesn't fade when showing the scoreboard
-       if(autocvar__menu_alpha)
-               HUD_Panel_ApplyFadeAlpha();
-
        if(scoreboard_fade_alpha)
        {
+               hud_fade_alpha = hud_fade_alpha_save;
+
                // move the panel below the scoreboard
                if (scoreboard_bottom >= 0.96 * vid_conheight)
                        return;
                vector target_pos;
 
-               target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
+               target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size.x);
 
-               if(target_pos_y > panel_pos_y)
+               if(target_pos.y > panel_pos.y)
                {
                        panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
-                       panel_size_y = min(panel_size_y, vid_conheight - scoreboard_bottom);
+                       panel_size.y = min(panel_size.y, vid_conheight - scoreboard_bottom);
                }
        }
 
@@ -4271,17 +4371,17 @@ void HUD_CenterPrint (void)
        // fontsize = '1 1 0' * height;
        height = vid_conheight/50 * autocvar_hud_panel_centerprint_fontscale;
        fontsize = '1 1 0' * height;
-       entries = bound(1, floor(panel_size_y/height), CENTERPRINT_MAX_ENTRIES);
+       entries = bound(1, floor(panel_size.y/height), CENTERPRINT_MAX_ENTRIES);
 
        float i, j, k, n, g;
-       float a, sz, align, current_msg_pos_y = 0, msg_size;
+       float a, sz, align, current_msg_posY = 0, msg_size;
        vector pos;
        string ts;
-       float all_messages_expired = TRUE;
+       float all_messages_expired = true;
 
        pos = panel_pos;
        if (autocvar_hud_panel_centerprint_flip)
-               pos_y += panel_size_y;
+               pos.y += panel_size.y;
        align = bound(0, autocvar_hud_panel_centerprint_align, 1);
        for (g=0, i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
        {
@@ -4300,7 +4400,7 @@ void HUD_CenterPrint (void)
                                continue;
                }
 
-               all_messages_expired = FALSE;
+               all_messages_expired = false;
 
                // fade the centerprint_hud in/out
                if(centerprint_time[j] < 0)  // Expired but forced. Expire time is the fade-in time.
@@ -4310,7 +4410,8 @@ void HUD_CenterPrint (void)
                else // Expiring soon, so fade it out.
                        a = (centerprint_expire_time[j] - time) / max(0.0001, autocvar_hud_panel_centerprint_fade_out);
 
-               if (a <= 0.5/255.0)  // Guaranteed invisible - don't show.
+               // while counting down show it anyway in order to hold the current message position
+               if (a <= 0.5/255.0 && centerprint_countdown_num[j] == 0)  // Guaranteed invisible - don't show.
                        continue;
                if (a > 1)
                        a = 1;
@@ -4343,46 +4444,46 @@ void HUD_CenterPrint (void)
                                getWrappedLine_remaining = argv(k);
                                while(getWrappedLine_remaining)
                                {
-                                       ts = getWrappedLine(panel_size_x * sz, fontsize, stringwidth_colors);
+                                       ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
                                        if (ts != "")
-                                               pos_y -= fontsize_y;
+                                               pos.y -= fontsize.y;
                                        else
-                                               pos_y -= fontsize_y * CENTERPRINT_SPACING/2;
+                                               pos.y -= fontsize.y * CENTERPRINT_SPACING/2;
                                }
                        }
-                       current_msg_pos_y = pos_y; // save starting pos (first line) of the current message
+                       current_msg_posY = pos.y; // save starting pos (first line) of the current message
                }
 
-               msg_size = pos_y;
+               msg_size = pos.y;
                for(k = 0; k < n; ++k)
                {
                        getWrappedLine_remaining = argv(k);
                        while(getWrappedLine_remaining)
                        {
-                               ts = getWrappedLine(panel_size_x * sz, fontsize, stringwidth_colors);
+                               ts = getWrappedLine(panel_size.x * sz, fontsize, stringwidth_colors);
                                if (ts != "")
                                {
                                        if (align)
-                                               pos_x = panel_pos_x + (panel_size_x - stringwidth(ts, TRUE, fontsize)) * align;
+                                               pos.x = panel_pos.x + (panel_size.x - stringwidth(ts, true, fontsize)) * align;
                                        if (a > 0.5/255.0)  // Otherwise guaranteed invisible - don't show. This is checked a second time after some multiplications with other factors were done so temporary changes of these cannot cause flicker.
-                                               drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize_y, ts, fontsize, a, DRAWFLAG_NORMAL);
-                                       pos_y += fontsize_y;
+                                               drawcolorcodedstring(pos + eY * 0.5 * (1 - sz) * fontsize.y, ts, fontsize, a, DRAWFLAG_NORMAL);
+                                       pos.y += fontsize.y;
                                }
                                else
-                                       pos_y += fontsize_y * CENTERPRINT_SPACING/2;
+                                       pos.y += fontsize.y * CENTERPRINT_SPACING/2;
                        }
                }
 
                ++g; // move next position number up
 
-               msg_size = pos_y - msg_size;
+               msg_size = pos.y - msg_size;
                if (autocvar_hud_panel_centerprint_flip)
                {
-                       pos_y = current_msg_pos_y - CENTERPRINT_SPACING * fontsize_y;
+                       pos.y = current_msg_posY - CENTERPRINT_SPACING * fontsize.y;
                        if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
-                               pos_y += (msg_size + CENTERPRINT_SPACING * fontsize_y) * (1 - sqrt(sz));
+                               pos.y += (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
 
-                       if (pos_y < panel_pos_y) // check if the next message can be shown
+                       if (pos.y < panel_pos.y) // check if the next message can be shown
                        {
                                drawfontscale = '1 1 0';
                                return;
@@ -4390,11 +4491,11 @@ void HUD_CenterPrint (void)
                }
                else
                {
-                       pos_y += CENTERPRINT_SPACING * fontsize_y;
+                       pos.y += CENTERPRINT_SPACING * fontsize.y;
                        if (a < 1 && centerprint_msgID[j] == 0) // messages with id can be replaced just after they are faded out, so never move over them the next messages
-                               pos_y -= (msg_size + CENTERPRINT_SPACING * fontsize_y) * (1 - sqrt(sz));
+                               pos.y -= (msg_size + CENTERPRINT_SPACING * fontsize.y) * (1 - sqrt(sz));
 
-                       if(pos_y > panel_pos_y + panel_size_y - fontsize_y) // check if the next message can be shown
+                       if(pos.y > panel_pos.y + panel_size.y - fontsize.y) // check if the next message can be shown
                        {
                                drawfontscale = '1 1 0';
                                return;
@@ -4404,11 +4505,71 @@ void HUD_CenterPrint (void)
        drawfontscale = '1 1 0';
        if (all_messages_expired)
        {
-               centerprint_showing = FALSE;
+               centerprint_showing = false;
                reset_centerprint_messages();
        }
 }
 
+// Buffs (#18)
+//
+void HUD_Buffs(void)
+{
+       float buffs = getstati(STAT_BUFFS, 0, 24);
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_buffs) return;
+               if(spectatee_status == -1) return;
+               if(getstati(STAT_HEALTH) <= 0) return;
+               if(!buffs) return;
+       }
+       else
+       {
+               buffs = Buff_Type_first.items; // force first buff
+       }
+
+       float 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)
+       {
+               ++b;
+               string o = strcat(rgb_to_hexcolor(Buff_Color(e.items)), Buff_PrettyName(e.items));
+               if(s == "")
+                       s = o;
+               else
+                       s = strcat(s, " ", o);
+       }
+
+       HUD_Panel_UpdateCvars();
+
+       draw_beginBoldFont();
+
+       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;
+       //float is_vertical = (panel_ar < 1);
+       //float buff_iconalign = autocvar_hud_panel_buffs_iconalign;
+       vector buff_offset = '0 0 0';
+
+       for(e = Buff_Type_first; e; e = e.enemy) if(buffs & e.items)
+       {
+               //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);
+       }
+
+       draw_endBoldFont();
+}
+
+
 /*
 ==================
 Main HUD system
@@ -4418,15 +4579,13 @@ Main HUD system
 void HUD_Reset (void)
 {
        // reset gametype specific icons
-       if(gametype == MAPINFO_TYPE_KEYHUNT)
-               HUD_Mod_KH_Reset();
-       else if(gametype == MAPINFO_TYPE_CTF)
+       if(gametype == MAPINFO_TYPE_CTF)
                HUD_Mod_CTF_Reset();
 }
 
 void HUD_Main (void)
 {
-       float i;
+       int i;
        // global hud theAlpha fade
        if(menu_enabled == 1)
                hud_fade_alpha = 1;
@@ -4436,21 +4595,13 @@ void HUD_Main (void)
        if(scoreboard_fade_alpha)
                hud_fade_alpha = (1 - scoreboard_fade_alpha);
 
-       if(autocvar__hud_configure)
-               if(isdemo())
-                       HUD_Configure_Exit_Force();
+       HUD_Configure_Frame();
 
        if(intermission == 2) // no hud during mapvote
-       {
-               if (autocvar__hud_configure)
-                       HUD_Configure_Exit_Force();
                hud_fade_alpha = 0;
-       }
-       else if(autocvar__menu_alpha == 0 && scoreboard_fade_alpha == 0)
-               hud_fade_alpha = 1;
 
        // panels that we want to be active together with the scoreboard
-       // they must call HUD_Panel_ApplyFadeAlpha(); only when showing the menu
+       // they must fade only when the menu does
        if(scoreboard_fade_alpha == 1)
        {
                (panel = HUD_PANEL(CENTERPRINT)).panel_draw();
@@ -4471,29 +4622,7 @@ void HUD_Main (void)
                hud_skin_prev = strzone(autocvar_hud_skin);
        }
 
-       // HUD configure visible grid
-       if(autocvar__hud_configure && autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
-       {
-               hud_configure_gridSize_x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
-               hud_configure_gridSize_y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
-               hud_configure_realGridSize_x = hud_configure_gridSize_x * vid_conwidth;
-               hud_configure_realGridSize_y = hud_configure_gridSize_y * vid_conheight;
-               vector s;
-               // x-axis
-               s = eX + eY * vid_conheight;
-               for(i = 1; i < 1/hud_configure_gridSize_x; ++i)
-                       drawfill(eX * i * hud_configure_realGridSize_x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
-               // y-axis
-               s = eY + eX * vid_conwidth;
-               for(i = 1; i < 1/hud_configure_gridSize_y; ++i)
-                       drawfill(eY * i * hud_configure_realGridSize_y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
-       }
-
-#ifdef COMPAT_XON050_ENGINE
-    current_player = (spectatee_status > 0) ? spectatee_status : player_localentnum;
-#else
     current_player = player_localentnum;
-#endif
 
        // draw the dock
        if(autocvar_hud_dock != "" && autocvar_hud_dock != "0")
@@ -4519,7 +4648,7 @@ void HUD_Main (void)
                        }
                        else if(hud_dock_color == "pants") {
                                f = stof(getplayerkeyvalue(current_player - 1, "colors"));
-                               color = colormapPaletteColor(mod(f, 16), 1);
+                               color = colormapPaletteColor(f % 16, 1);
                        }
                        else
                                color = stov(hud_dock_color);
@@ -4563,7 +4692,7 @@ void HUD_Main (void)
                        }
                }
                if (warning)
-                       print(_("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n"));
+                       dprint("Automatically fixed wrong/missing panel numbers in _hud_panelorder\n");
 
                cvar_set("_hud_panelorder", s);
                if(hud_panelorder_prev)
@@ -4589,34 +4718,7 @@ void HUD_Main (void)
        if(autocvar__con_chat_maximized)
                (panel = HUD_PANEL(CHAT)).panel_draw();
 
-       if(autocvar__hud_configure)
-       {
-               if(tab_panel)
-               {
-                       panel = tab_panel;
-                       HUD_Panel_UpdatePosSize()
-                       drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
-               }
-               if(highlightedPanel)
-               {
-                       panel = highlightedPanel;
-                       HUD_Panel_UpdatePosSize()
-                       HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha));
-               }
-               if(!hud_configure_prev || hud_configure_prev == -1)
-               {
-                       if(autocvar_hud_cursormode) { setcursormode(1); }
-                       hudShiftState = 0;
-                       for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
-                               hud_panel[panel_order[i]].update_time = time;
-               }
-       }
-       else if(hud_configure_prev && hud_configure_prev != -1 && autocvar_hud_cursormode)
-               setcursormode(0);
+       HUD_Configure_PostDraw();
 
        hud_configure_prev = autocvar__hud_configure;
-
-       if (!autocvar__hud_configure) // hud config mode disabled, enable normal theAlpha stuff again
-               if (menu_enabled)
-                       menu_enabled = 0;
 }