]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/client/hud.qc
Centerprint something when configuring the hud
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud.qc
index 73c69422ee99c85cb71104b84da19b27edb6b850..f81b72fe1865d40f63f0b05b7f66131c63a5be42 100644 (file)
@@ -142,183 +142,6 @@ float stringwidth_nocolors(string s, vector theSize)
        return stringwidth(s, FALSE, theSize);
 }
 
-#define CENTERPRINT_MAX_LINES 30
-string centerprint_messages[CENTERPRINT_MAX_LINES];
-float centerprint_width[CENTERPRINT_MAX_LINES];
-float centerprint_time;
-float centerprint_expire;
-float centerprint_num;
-float centerprint_offset_hint;
-vector centerprint_fontsize;
-
-void centerprint(string strMessage)
-{
-       float i, j, n, hcount;
-       string s;
-
-       centerprint_fontsize = HUD_GetFontsize("scr_centersize");
-
-       centerprint_expire = min(centerprint_expire, time); // if any of the returns happens, this message will fade out
-
-       if(autocvar_scr_centertime <= 0)
-               return;
-
-       if(strMessage == "")
-               return;
-
-       // strip trailing newlines
-       j = strlen(strMessage) - 1;
-       while(substring(strMessage, j, 1) == "\n" && j >= 0)
-               j = j - 1;
-       strMessage = substring(strMessage, 0, j + 1);
-
-       if(strMessage == "")
-               return;
-
-       // strip leading newlines and remember them, they are a hint that the message should be lower on the screen
-       j = 0;
-       while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
-               j = j + 1;
-       strMessage = substring(strMessage, j, strlen(strMessage) - j);
-       centerprint_offset_hint = j;
-
-       if(strMessage == "")
-               return;
-
-       // if we get here, we have a message. Initialize its height.
-       centerprint_num = 0;
-
-       n = tokenizebyseparator(strMessage, "\n");
-       i = hcount = 0;
-       for(j = 0; j < n; ++j)
-       {
-               getWrappedLine_remaining = argv(j);
-               while(getWrappedLine_remaining)
-               {
-                       s = getWrappedLine(vid_conwidth * 0.75, centerprint_fontsize, stringwidth_colors);
-                       if(centerprint_messages[i] != s) // don't fade the same message in, looks stupid
-                               centerprint_time = time;
-                       if(centerprint_messages[i])
-                               strunzone(centerprint_messages[i]);
-                       centerprint_messages[i] = strzone(s);
-                       centerprint_width[i] = stringwidth(s, TRUE, centerprint_fontsize);
-                       ++i;
-
-                       // half height for empty lines looks better
-                       if(s == "")
-                               hcount += 0.5;
-                       else
-                               hcount += 1;
-
-                       if(i >= CENTERPRINT_MAX_LINES)
-                               break;
-               }
-       }
-
-       float h, havail;
-       h = centerprint_fontsize_y*hcount;
-
-       havail = vid_conheight;
-       if(autocvar_con_chatpos < 0)
-               havail -= (-autocvar_con_chatpos + autocvar_con_chat) * autocvar_con_chatsize; // avoid overlapping chat
-       if(havail > vid_conheight - 70)
-               havail = vid_conheight - 70; // avoid overlapping HUD
-
-#if 0
-       float forbiddenmin, forbiddenmax, allowedmin, allowedmax, preferred;
-
-       // here, the centerprint would cover the crosshair. REALLY BAD.
-       forbiddenmin = vid_conheight * 0.5 - h - 16;
-       forbiddenmax = vid_conheight * 0.5 + 16;
-
-       allowedmin = scoreboard_bottom;
-       allowedmax = havail - h;
-       preferred = (havail - h)/2;
-
-
-       // possible orderings (total: 4! / 4 = 6)
-       //  allowedmin allowedmax forbiddenmin forbiddenmax
-       //  forbiddenmin forbiddenmax allowedmin allowedmax
-       if(allowedmax < forbiddenmin || allowedmin > forbiddenmax)
-       {
-               // forbidden doesn't matter in this case
-               centerprint_start_y = bound(allowedmin, preferred, allowedmax);
-       }
-       //  allowedmin forbiddenmin allowedmax forbiddenmax
-       else if(allowedmin < forbiddenmin && allowedmax < forbiddenmax)
-       {
-               centerprint_start_y = bound(allowedmin, preferred, forbiddenmin);
-       }
-       //  allowedmin forbiddenmin forbiddenmax allowedmax
-       else if(allowedmin < forbiddenmin)
-       {
-               // make sure the forbidden zone is not covered
-               if(preferred > (forbiddenmin + forbiddenmax) * 0.5)
-                       centerprint_start_y = bound(allowedmin, preferred, forbiddenmin);
-               else
-                       centerprint_start_y = bound(forbiddenmax, preferred, allowedmin);
-       }
-       //  forbiddenmin allowedmin allowedmax forbiddenmax
-       else if(allowedmax < forbiddenmax)
-       {
-               // it's better to leave the allowed zone (overlap with scoreboard) than
-               // to cover the forbidden zone (crosshair)
-               if(preferred > (forbiddenmin + forbiddenmax) * 0.5)
-                       centerprint_start_y = forbiddenmax;
-               else
-                       centerprint_start_y = forbiddenmin;
-       }
-       //  forbiddenmin allowedmin forbiddenmax allowedmax
-       else
-       {
-               centerprint_start_y = bound(forbiddenmax, preferred, allowedmax);
-       }
-#else
-#endif
-
-       centerprint_num = i;
-
-       centerprint_expire = time + autocvar_scr_centertime;
-}
-
-void HUD_DrawCenterPrint (void)
-{
-       float i;
-       vector pos;
-       string ts;
-       float a, sz;
-
-       if(time - centerprint_time < 0.25)
-               a = (time - centerprint_time) / 0.25;
-       else
-               a = bound(0, 1 - 4 * (time - centerprint_expire), 1);
-
-       if(a <= 0)
-               return;
-
-       sz = 0.8 + (a / 5);
-
-       if(centerprint_num * autocvar_scr_centersize > 24 && scoreboard_active) // 24 = height of Scoreboard text
-               centerprint_start_y = scoreboard_bottom + centerprint_fontsize_y;
-
-       pos = centerprint_start;
-       for (i=0; i<centerprint_num; i = i + 1)
-       {
-               ts = centerprint_messages[i];
-               drawfontscale = sz * '1 1 0';
-               pos_x = (vid_conwidth - stringwidth(ts, TRUE, centerprint_fontsize)) * 0.5;
-               if (ts != "")
-               {
-                       drawcolorcodedstring(pos + '0 1 0' * (1 - sz) * 0.5 *centerprint_fontsize_y, ts, centerprint_fontsize, a, DRAWFLAG_NORMAL);
-                       pos_y = pos_y + centerprint_fontsize_y;
-               }
-               else
-                       // half height for empty lines looks better
-                       pos_y = pos_y + sz * centerprint_fontsize_y * 0.5;
-               drawfontscale = '1 1 0';
-       }
-}
-
 void drawstringright(vector position, string text, vector scale, vector rgb, float alpha, float flag)
 {
        position_x -= 2 / 3 * strlen(text) * scale_x;
@@ -600,7 +423,7 @@ float GetAmmoTypeForWep(float i)
                case WEP_HLAC: return 3;
                case WEP_MINSTANEX: return 3;
                case WEP_NEX: return 3;
-               case WEP_SNIPERRIFLE: return 1;
+               case WEP_RIFLE: return 1;
                case WEP_HAGAR: return 2;
                case WEP_ROCKET_LAUNCHER: return 2;
                case WEP_SEEKER: return 2;
@@ -614,7 +437,7 @@ void HUD_Weapons(void)
 {
        float f, screen_ar;
        float center_x, center_y;
-
+    if(hud != HUD_NORMAL) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_weapons) return;
@@ -643,6 +466,7 @@ void HUD_Weapons(void)
        }
 
        HUD_Panel_UpdateCvars(weapons);
+       HUD_Panel_ApplyFadeAlpha();
 
        if (timeout && time >= weapontime + timeout && !autocvar__hud_configure)
        {
@@ -1019,6 +843,7 @@ void DrawAmmoItem(vector myPos, vector mySize, float itemcode, float currently_s
 
 void HUD_Ammo(void)
 {
+    if(hud != HUD_NORMAL) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_ammo) return;
@@ -1028,6 +853,7 @@ void HUD_Ammo(void)
                hud_configure_active_panel = HUD_PANEL_AMMO;
 
        HUD_Panel_UpdateCvars(ammo);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -1213,6 +1039,7 @@ void HUD_Powerups(void)
        }
 
        HUD_Panel_UpdateCvars(powerups);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -1302,22 +1129,16 @@ void HUD_Powerups(void)
 //
 
 // prev_* vars contain the health/armor at the previous FRAME
+// set to -1 when player is dead or was not playing
 float prev_health, prev_armor;
-
-// *_time vars contain time at which damage happened
-       // health_time -1 remembers that player was dead
-float health_time, armor_time;
-
-// saved_* vars contain the old health/armor value (before the damage happened)
-// set to -1 when load or damage effect are ended normally
-float saved_health, saved_armor;
-
-// old_* vars keep track of previous values when smoothing value changes of the progressbar
-float old_health, old_armor;
-float old_healthtime, old_armortime;
-
+float health_damagetime, armor_damagetime;
+float health_beforedamage, armor_beforedamage;
+// old_p_* vars keep track of previous values when smoothing value changes of the progressbar
+float old_p_health, old_p_armor;
+float old_p_healthtime, old_p_armortime;
+// prev_p_* vars contain the health/armor progressbar value at the previous FRAME
 // set to -1 to forcedly stop effects when we switch spectated player (e.g. from playerX: 70h to playerY: 50h)
-float last_p_health, last_p_armor;
+float prev_p_health, prev_p_armor;
 
 void HUD_HealthArmor(void)
 {
@@ -1325,38 +1146,39 @@ void HUD_HealthArmor(void)
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_healtharmor) return;
+               if(hud != HUD_NORMAL) return;
                if(spectatee_status == -1) return;
 
                health = getstati(STAT_HEALTH);
                if(health <= 0)
                {
-                       health_time = -1;
+                       prev_health = -1;
                        return;
                }
                armor = getstati(STAT_ARMOR);
 
                // code to check for spectatee_status changes is in Ent_ClientData()
-               // last_p_health and health_time can be set to -1 there
+               // prev_p_health and prev_health can be set to -1 there
 
-               if (last_p_health == -1)
+               if (prev_p_health == -1)
                {
                        // no effect
-                       saved_health = 0;
-                       saved_armor = 0;
-                       health_time = 0;
-                       armor_time = 0;
+                       health_beforedamage = 0;
+                       armor_beforedamage = 0;
+                       health_damagetime = 0;
+                       armor_damagetime = 0;
                        prev_health = health;
                        prev_armor = armor;
-                       old_health = health;
-                       old_armor = armor;
-                       last_p_health = health;
-                       last_p_armor = armor;
+                       old_p_health = health;
+                       old_p_armor = armor;
+                       prev_p_health = health;
+                       prev_p_armor = armor;
                }
-               else if (health_time == -1)
+               else if (prev_health == -1)
                {
                        //start the load effect
-                       health_time = time;
-                       armor_time = time;
+                       health_damagetime = 0;
+                       armor_damagetime = 0;
                        prev_health = 0;
                        prev_armor = 0;
                }
@@ -1372,6 +1194,7 @@ void HUD_HealthArmor(void)
        }
 
        HUD_Panel_UpdateCvars(healtharmor);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -1482,42 +1305,39 @@ void HUD_HealthArmor(void)
                                pain_health_alpha = 1;
                                if (autocvar_hud_panel_healtharmor_progressbar_gfx)
                                {
-                                       if (fabs(prev_health - health) >= 2)
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
                                        {
-                                               if (time - old_healthtime < 1)
-                                                       old_health = last_p_health;
-                                               else
-                                                       old_health = prev_health;
-                                               old_healthtime = time;
-                                       }
-                                       if (time - old_healthtime < 1)
-                                       {
-                                               p_health += (old_health - health) * (1 - (time - old_healthtime));
-                                               last_p_health = p_health;
-                                       }
-                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0 && saved_health == -1)
-                                       {
-                                               if (prev_health == 0 || prev_health - health >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
+                                               if (fabs(prev_health - health) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
+                                               {
+                                                       if (time - old_p_healthtime < 1)
+                                                               old_p_health = prev_p_health;
+                                                       else
+                                                               old_p_health = prev_health;
+                                                       old_p_healthtime = time;
+                                               }
+                                               if (time - old_p_healthtime < 1)
                                                {
-                                                       health_time = time;
-                                                       saved_health = prev_health;
+                                                       p_health += (old_p_health - health) * (1 - (time - old_p_healthtime));
+                                                       prev_p_health = p_health;
                                                }
                                        }
-                                       if (saved_health != -1)
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
                                        {
-                                               float d = time - health_time;
-                                               if (d < 1)
+                                               if (prev_health - health >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
+                                               {
+                                                       if (time - health_damagetime >= 1)
+                                                               health_beforedamage = prev_health;
+                                                       health_damagetime = time;
+                                               }
+                                               if (time - health_damagetime < 1)
                                                {
-                                                       HUD_Panel_DrawProgressBar(pos + health_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_health, saved_health/maxhealth, is_vertical, health_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * (1 - d * d), DRAWFLAG_NORMAL);
-                                                       if (prev_health - health >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage) //refresh the effect if repeatedly damaged
-                                                               health_time = time;
+                                                       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);
                                                }
-                                               else
-                                                       saved_health = -1; //damage effect ended
                                        }
                                        prev_health = health;
 
-                                       if (health <= 40)
+                                       if (health <= autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth)
                                        {
                                                float BLINK_FACTOR = 0.15;
                                                float BLINK_BASE = 0.85;
@@ -1540,38 +1360,35 @@ void HUD_HealthArmor(void)
                                p_armor = armor;
                                if (autocvar_hud_panel_healtharmor_progressbar_gfx)
                                {
-                                       if (fabs(prev_armor - armor) >= 2)
-                                       {
-                                               if (time - old_armortime < 1)
-                                                       old_armor = last_p_armor;
-                                               else
-                                                       old_armor = prev_armor;
-                                               old_armortime = time;
-                                       }
-                                       if (time - old_armortime < 1)
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_smooth > 0)
                                        {
-                                               p_armor += (old_armor - armor) * (1 - (time - old_armortime));
-                                               last_p_armor = p_armor;
-                                       }
-                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0 && saved_armor == -1)
-                                       {
-                                               if (prev_armor == 0 || prev_armor - armor >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
+                                               if (fabs(prev_armor - armor) >= autocvar_hud_panel_healtharmor_progressbar_gfx_smooth)
+                                               {
+                                                       if (time - old_p_armortime < 1)
+                                                               old_p_armor = prev_p_armor;
+                                                       else
+                                                               old_p_armor = prev_armor;
+                                                       old_p_armortime = time;
+                                               }
+                                               if (time - old_p_armortime < 1)
                                                {
-                                                       armor_time = time;
-                                                       saved_armor = prev_armor;
+                                                       p_armor += (old_p_armor - armor) * (1 - (time - old_p_armortime));
+                                                       prev_p_armor = p_armor;
                                                }
                                        }
-                                       if (saved_armor != -1)
+                                       if (autocvar_hud_panel_healtharmor_progressbar_gfx_damage > 0)
                                        {
-                                               float d = time - armor_time;
-                                               if (d < 1)
+                                               if (prev_armor - armor >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage)
                                                {
-                                                       HUD_Panel_DrawProgressBar(pos + armor_offset, mySize, autocvar_hud_panel_healtharmor_progressbar_armor, saved_armor/maxarmor, is_vertical, armor_baralign, progressbar_color, autocvar_hud_progressbar_alpha * panel_fg_alpha * (1 - d * d), DRAWFLAG_NORMAL);
-                                                       if (prev_armor - armor >= autocvar_hud_panel_healtharmor_progressbar_gfx_damage) //refresh the effect if repeatedly damaged
-                                                               armor_time = time;
+                                                       if (time - armor_damagetime >= 1)
+                                                               armor_beforedamage = prev_armor;
+                                                       armor_damagetime = time;
+                                               }
+                                               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);
                                                }
-                                               else
-                                                       saved_armor = -1; //damage effect ended
                                        }
                                        prev_armor = armor;
                                }
@@ -1692,7 +1509,7 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s
        } else if(msg == MSG_KILL) {
                w = DEATH_WEAPONOF(type);
                if(WEP_VALID(w)) {
-                       if((w == WEP_SNIPERRIFLE || w == WEP_MINSTANEX) && type & HITTYPE_HEADSHOT) // all headshot weapons go here
+                       if((w == WEP_RIFLE || w == WEP_MINSTANEX) && type & HITTYPE_HEADSHOT) // all headshot weapons go here
                                HUD_KillNotify_Push(s1, s2, 1, DEATH_HEADSHOT);
                        else
                                HUD_KillNotify_Push(s1, s2, 1, type);
@@ -1767,7 +1584,7 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s
                        HUD_KillNotify_Push(s1, s2, 1, DEATH_HURTTRIGGER);
                        if(alsoprint)
                                print(sprintf(_("^1%s^1 was thrown into a world of hurt by %s\n"), s2, s1));
-               } else if(type == DEATH_SBCRUSH) {
+               } else if(type == DEATH_VHCRUSH) {
                        HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
                        if(alsoprint)
                                print (sprintf(_("^1%s^1 was crushed by %s\n"), s2, s1));
@@ -1795,6 +1612,18 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s
                        HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
                        if(alsoprint)
                                print (sprintf(_("^1%s^1 dies when %s^1's wakizashi dies.\n"), s2, s1));
+               } else if(type == DEATH_RAPTOR_CANNON) {
+                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
+                       if(alsoprint)
+                               print (sprintf(_("^1%s^1 nailed to hell by %s\n"), s2, s1));
+               } else if(type == DEATH_RAPTOR_BOMB) {
+                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
+                       if(alsoprint)
+                               print (sprintf(_("^1%s^1 cluster crushed by %s\n"), s2, s1));
+               } else if(type == DEATH_RAPTOR_DEATH) {
+                       HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
+                       if(alsoprint)
+                               print (sprintf(_("^1%s^1 dies when %s^1's raptor dies.\n"), s2, s1));
                } else if(type == DEATH_TURRET) {
                        HUD_KillNotify_Push(s1, s2, 1, DEATH_GENERIC);
                        if(alsoprint)
@@ -1862,7 +1691,7 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s
                                print (sprintf(_("%s^7 is a ^1BERSERKER!\n"), s1));
                } else if(type == KILL_SPREE_25) {
                        if(gentle)
-                               print (sprintf(_("%s^7 made ^1TWENTY FIFE SCORES IN A ROW!\n"), s1));
+                               print (sprintf(_("%s^7 made ^1TWENTY FIVE SCORES IN A ROW!\n"), s1));
                        else
                                print (sprintf(_("%s^7 inflicts ^1CARNAGE!\n"), s1));
                } else if(type == KILL_SPREE_30) {
@@ -2004,92 +1833,90 @@ void HUD_KillNotify(string s1, string s2, string s3, float type, float msg) // s
        }
 }
 
-#define DAMAGE_CENTERPRINT_SPACER NEWLINES
-
 void HUD_Centerprint(string s1, string s2, float type, float msg)
 {
        float gentle;
        gentle = (autocvar_cl_gentle || autocvar_cl_gentle_messages);
        if(msg == MSG_SUICIDE) {
                if (type == DEATH_TEAMCHANGE) {
-                       centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("You are now on: %s"), s1)));
+                       centerprint(strcat(sprintf(_("You are now on: %s"), s1)));
                } else if (type == DEATH_AUTOTEAMCHANGE) {
-                       centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("You have been moved into a different team to improve team balance\nYou are now on: %s"), s1)));
+                       centerprint(strcat(sprintf(_("You have been moved into a different team to improve team balance\nYou are now on: %s"), s1)));
                } else if (type == DEATH_CAMP) {
                        if(gentle)
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Reconsider your tactics, camper!")));
+                               centerprint(strcat(_("^1Reconsider your tactics, camper!")));
                        else
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Die camper!")));
+                               centerprint(strcat(_("^1Die camper!")));
                } else if (type == DEATH_NOAMMO) {
                        if(gentle)
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You are reinserted into the game for running out of ammo...")));
+                               centerprint(strcat(_("^1You are reinserted into the game for running out of ammo...")));
                        else
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You were killed for running out of ammo...")));
+                               centerprint(strcat(_("^1You were killed for running out of ammo...")));
                } else if (type == DEATH_ROT) {
                        if(gentle)
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You need to preserve your health")));
+                               centerprint(strcat(_("^1You need to preserve your health")));
                        else
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You grew too old without taking your medicine")));
+                               centerprint(strcat(_("^1You grew too old without taking your medicine")));
                } else if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) {
                        if(gentle)
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Don't go against team mates!")));
+                               centerprint(strcat(_("^1Don't go against team mates!")));
                        else
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Don't shoot your team mates!")));
+                               centerprint(strcat(_("^1Don't shoot your team mates!")));
                } else if (type == DEATH_QUIET) {
                        // do nothing
                } else { // generic message
                        if(gentle)
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You need to be more careful!")));
+                               centerprint(strcat(_("^1You need to be more careful!")));
                        else
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1You killed your own dumb self!")));
+                               centerprint(strcat(_("^1You killed your own dumb self!")));
                }
        } else if(msg == MSG_KILL) {
                if (type == KILL_TEAM_RED || type == KILL_TEAM_BLUE) {
                        if(gentle) {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1Moron! You went against %s, a team mate!"), s1)));
+                               centerprint(strcat(sprintf(_("^1Moron! You went against ^7%s^1, a team mate!"), s1)));
                        } else {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1Moron! You fragged %s, a team mate!"), s1)));
+                               centerprint(strcat(sprintf(_("^1Moron! You fragged ^7%s^1, a team mate!"), s1)));
                        }
                } else if (type == KILL_FIRST_BLOOD) {
                        if(gentle) {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First score")));
+                               centerprint(strcat(_("^1First score")));
                        } else {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First blood")));
+                               centerprint(strcat(_("^1First blood")));
                        }
                } else if (type == KILL_FIRST_VICTIM) {
                        if(gentle) {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First casualty")));
+                               centerprint(strcat(_("^1First casualty")));
                        } else {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1First victim")));
+                               centerprint(strcat(_("^1First victim")));
                        }
                } else if (type == KILL_TYPEFRAG) { // s2 contains "advanced kill messages" such as ping, handicap...
                        if(gentle) {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You scored against ^7%s^1 who was typing!"), s1), s2));
+                               centerprint(strcat(sprintf(_("^1You scored against ^7%s^1 who was typing!"), s1), s2));
                        } else {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You typefragged ^7%s"), s1), s2));
+                               centerprint(strcat(sprintf(_("^1You typefragged ^7%s"), s1), s2));
                        }
                } else if (type == KILL_TYPEFRAGGED) {
                        if(gentle) {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were scored against by ^7%s^1 while you were typing!"), s1), s2));
+                               centerprint(strcat(sprintf(_("^1You were scored against by ^7%s^1 while you were typing!"), s1), s2));
                        } else {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were typefragged by ^7%s"), s1), s2));
+                               centerprint(strcat(sprintf(_("^1You were typefragged by ^7%s"), s1), s2));
                        }
                } else if (type == KILL_FRAG) {
                        if(gentle) {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^4You scored against ^7%s"), s1), s2));
+                               centerprint(strcat(sprintf(_("^4You scored against ^7%s"), s1), s2));
                        } else {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^4You fragged ^7%s"), s1), s2));
+                               centerprint(strcat(sprintf(_("^4You fragged ^7%s"), s1), s2));
                        }
                } else { // generic message
                        if(gentle) {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were scored against by ^7%s"), s1), s2));
+                               centerprint(strcat(sprintf(_("^1You were scored against by ^7%s"), s1), s2));
                        } else {
-                               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, sprintf(_("^1You were fragged by ^7%s"), s1), s2));
+                               centerprint(strcat(sprintf(_("^1You were fragged by ^7%s"), s1), s2));
                        }
                }
        } else if(msg == MSG_KILL_ACTION) {
                // TODO: invent more centerprints here?
-               centerprint(strcat(DAMAGE_CENTERPRINT_SPACER, _("^1Watch your step!")));
+               centerprint(strcat(_("^1Watch your step!")));
        }
 }
 
@@ -2103,6 +1930,7 @@ void HUD_Notify (void)
                hud_configure_active_panel = HUD_PANEL_NOTIFY;
 
        HUD_Panel_UpdateCvars(notify);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -2416,6 +2244,7 @@ void HUD_Timer(void)
                hud_configure_active_panel = HUD_PANEL_TIMER;
 
        HUD_Panel_UpdateCvars(timer);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -2473,6 +2302,7 @@ void HUD_Radar(void)
                hud_configure_active_panel = HUD_PANEL_RADAR;
 
        HUD_Panel_UpdateCvars(radar);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -2591,6 +2421,128 @@ void HUD_Radar(void)
 // Score (#7)
 //
 void HUD_UpdatePlayerTeams();
+void HUD_Score_Rankings(vector pos, vector mySize, entity me, float team_count)
+{
+       float score;
+       entity tm, pl;
+#define SCOREPANEL_MAX_ENTRIES 6
+#define SCOREPANEL_ASPECTRATIO 2
+       const float entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize_y/mySize_x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
+       const vector fontsize = '1 1 0' * (mySize_y/entries);
+
+       vector rgb, score_color;
+       rgb = '1 1 1';
+       score_color = '1 1 1';
+
+       const float name_size = mySize_x*0.75;
+       const float spacing_size = mySize_x*0.04;
+       const float highlight_alpha = 0.2;
+       float i, me_printed, first_pl;
+       string s;
+       i, first_pl = 0;
+       if (autocvar__hud_configure)
+       {
+               float players_per_team;
+               if (team_count)
+               {
+                       // show team scores in the first line
+                       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, GetTeamRGB(ColorByTeam(i)) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       }
+                       first_pl = 1;
+                       pos_y += fontsize_y;
+               }
+               score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
+               for (i=first_pl; i<entries; ++i)
+               {
+                       //simulate my score is lower than all displayed players,
+                       //so that I don't appear at all showing pure rankings.
+                       //This is to better show the difference between the 2 ranking views
+                       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);
+                               s = GetPlayerName(pl.sv_entnum);
+                               score = 7;
+                       }
+                       else
+                       {
+                               s = sprintf(_("Player %d"), i + 1 - first_pl);
+                               score -= 3;
+                       }
+
+                       if (team_count)
+                               score_color = GetTeamRGB(ColorByTeam(floor((i - first_pl) / players_per_team))) * 0.8;
+                       s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
+                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, TRUE, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring(pos + eX * (name_size + spacing_size), ftos(score), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       pos_y += fontsize_y;
+               }
+               return;
+       }
+
+       if (!scoreboard_fade_alpha) // the scoreboard too calls HUD_UpdatePlayerTeams
+               HUD_UpdatePlayerTeams();
+       if (team_count)
+       {
+               // show team scores in the first line
+               float score_size = mySize_x / team_count;
+               for(tm = teams.sort_next; tm; tm = tm.sort_next) {
+                       if(tm.team == COLOR_SPECTATOR)
+                               continue;
+                       if (tm.team == myteam)
+                               drawfill(pos + eX * score_size * i, eX * score_size + eY * fontsize_y, '1 1 1', highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+                       drawstring_aspect(pos + eX * score_size * i, ftos(tm.(teamscores[ts_primary])), eX * score_size + eY * fontsize_y, GetTeamRGB(tm.team) * 0.8, panel_fg_alpha, DRAWFLAG_NORMAL);
+                       ++i;
+               }
+               first_pl = 1;
+               pos_y += fontsize_y;
+               tm = teams.sort_next;
+       }
+       i = first_pl;
+
+       do
+       for (pl = players.sort_next; pl && i<entries; pl = pl.sort_next)
+       {
+               if ((team_count && pl.team != tm.team) || pl.team == COLOR_SPECTATOR)
+                       continue;
+
+               if (i == entries-1 && !me_printed && pl != me)
+               if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
+               {
+                       for (pl = me.sort_next; pl; pl = pl.sort_next)
+                               if (pl.team != COLOR_SPECTATOR)
+                                       break;
+
+                       if (pl)
+                               rgb = '1 1 0'; //not last but not among the leading players: yellow
+                       else
+                               rgb = '1 0 0'; //last: red
+                       pl = me;
+               }
+
+               if (pl == me)
+               {
+                       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);
+               }
+               if (team_count)
+                       score_color = GetTeamRGB(pl.team) * 0.8;
+               s = textShortenToWidth(GetPlayerName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
+               drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, TRUE, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring(pos + eX * (name_size + spacing_size), ftos(pl.(scores[ps_primary])), fontsize, score_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               pos_y += fontsize_y;
+               ++i;
+       }
+       while (i<entries && team_count && (tm = tm.sort_next) && (tm.team != COLOR_SPECTATOR || (tm = tm.sort_next)));
+}
+
 void HUD_Score(void)
 {
        if(!autocvar__hud_configure)
@@ -2602,6 +2554,7 @@ void HUD_Score(void)
                hud_configure_active_panel = HUD_PANEL_SCORE;
 
        HUD_Panel_UpdateCvars(score);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -2655,83 +2608,7 @@ void HUD_Score(void)
        } else if (!teamplay) { // non-teamgames
                if ((spectatee_status == -1 && !autocvar__hud_configure) || autocvar_hud_panel_score_rankings)
                {
-#define SCOREPANEL_MAX_ENTRIES 6
-#define SCOREPANEL_ASPECTRATIO 2
-                       const float entries = bound(1, floor(SCOREPANEL_MAX_ENTRIES * mySize_y/mySize_x * SCOREPANEL_ASPECTRATIO), SCOREPANEL_MAX_ENTRIES);
-                       const float height = mySize_y/entries;
-                       const vector fontsize = '0.9 0.9 0' * height;
-                       pos_y += height * (1 - 0.9) / 2;
-
-                       vector rgb;
-                       rgb = '1 1 1';
-
-                       const float name_size = mySize_x*0.75;
-                       const float highlight_alpha = 0.2;
-                       float i, me_printed;
-                       string s;
-                       if (autocvar__hud_configure)
-                       {
-                               score = 10 + SCOREPANEL_MAX_ENTRIES * 3;
-                               for (i=0; i<entries; ++i)
-                               {
-                                       //simulate my score is lower than all displayed players,
-                                       //so that I don't appear at all showing pure rankings.
-                                       //This is to better show the difference between the 2 ranking views
-                                       if (i == entries-1 && autocvar_hud_panel_score_rankings == 1)
-                                       {
-                                               rgb = '1 1 0';
-                                               drawfill(pos - eY * (height * (1 - 0.9) / 2), eX * mySize_x + eY * height, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                                               s = GetPlayerName(pl.sv_entnum);
-                                               score = 7;
-                                       }
-                                       else
-                                       {
-                                               s = sprintf(_("Player %d"), i+1);
-                                               score -= 3;
-                                       }
-
-                                       s = textShortenToWidth(s, name_size, fontsize, stringwidth_colors);
-                                       drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, TRUE, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
-                                       drawstring(pos + eX * mySize_x*0.79, ftos(score), fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                                       pos_y += height;
-                               }
-                               return;
-                       }
-
-                       if (!scoreboard_fade_alpha) // the scoreboard too calls HUD_UpdatePlayerTeams
-                               HUD_UpdatePlayerTeams();
-
-                       for (pl = players.sort_next, i=0; pl && i<entries; pl = pl.sort_next, ++i)
-                       {
-                               if (pl.team == COLOR_SPECTATOR)
-                                       continue;
-
-                               if (i == entries-1 && !me_printed && pl != me)
-                               if (autocvar_hud_panel_score_rankings == 1 && spectatee_status != -1)
-                               {
-                                       for (pl = me.sort_next; pl; pl = pl.sort_next)
-                                               if (pl.team != COLOR_SPECTATOR)
-                                                       break;
-
-                                       if (pl)
-                                               rgb = '1 1 0'; //not last but not among the leading players: yellow
-                                       else
-                                               rgb = '1 0 0'; //last: red
-                                       pl = me;
-                               }
-
-                               if (pl == me)
-                               {
-                                       if (i == 0)
-                                               rgb = '0 1 0'; //first: green
-                                       me_printed = 1;
-                                       drawfill(pos - eY * (height * (1 - 0.9) / 2), eX * mySize_x + eY * height, rgb, highlight_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
-                               }
-                               s = textShortenToWidth(GetPlayerName(pl.sv_entnum), name_size, fontsize, stringwidth_colors);
-                               drawcolorcodedstring(pos + eX * (name_size - stringwidth(s, TRUE, fontsize)), s, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
-                               drawstring(pos + eX * mySize_x*0.79, ftos(pl.(scores[ps_primary])), fontsize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-                               pos_y += height;
-                       }
+                       HUD_Score_Rankings(pos, mySize, me, 0);
                        return;
                }
                // me vector := [team/connected frags id]
@@ -2770,20 +2647,17 @@ void HUD_Score(void)
                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);
        } else { // teamgames
-               float max_fragcount;
-               max_fragcount = -99;
-
                float scores_count, row, column, rows, columns;
                vector offset;
                vector score_pos, score_size; //for scores other than myteam
-               if (spectatee_status == -1)
+               if (spectatee_status == -1 || autocvar_hud_panel_score_rankings)
                {
-                       if (autocvar__hud_configure)
-                               scores_count = 4;
-                       else for(tm = teams.sort_next; tm; tm = tm.sort_next) {
-                               if(tm.team == COLOR_SPECTATOR)
-                                       continue;
+                       for(tm = teams.sort_next; tm, tm.team != COLOR_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);
@@ -2811,6 +2685,9 @@ void HUD_Score(void)
                }
                else
                        score_size = eX * mySize_x*(1/4) + eY * mySize_y*(1/3);
+
+               float max_fragcount;
+               max_fragcount = -99;
                for(tm = teams.sort_next; tm; tm = tm.sort_next) {
                        if(tm.team == COLOR_SPECTATOR)
                                continue;
@@ -2862,6 +2739,7 @@ void HUD_RaceTimer (void)
                hud_configure_active_panel = HUD_PANEL_RACETIMER;
 
        HUD_Panel_UpdateCvars(racetimer);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -3057,6 +2935,7 @@ void HUD_VoteWindow(void)
                return;
 
        HUD_Panel_UpdateCvars(vote);
+       HUD_Panel_ApplyFadeAlpha();
 
        if(uid2name_dialog)
        {
@@ -3812,6 +3691,7 @@ void HUD_ModIcons(void)
                hud_configure_active_panel = HUD_PANEL_MODICONS;
 
        HUD_Panel_UpdateCvars(modicons);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -3866,6 +3746,7 @@ void HUD_DrawPressedKeys(void)
 
 
        HUD_Panel_UpdateCvars(pressedkeys);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -3930,6 +3811,7 @@ void HUD_Chat(void)
                hud_configure_active_panel = HUD_PANEL_CHAT;
 
        HUD_Panel_UpdateCvars(chat);
+       HUD_Panel_ApplyFadeAlpha();
 
        if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
        {
@@ -4005,6 +3887,7 @@ void HUD_EngineInfo(void)
                hud_configure_active_panel = HUD_PANEL_ENGINEINFO;
 
        HUD_Panel_UpdateCvars(engineinfo);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -4067,6 +3950,7 @@ void HUD_InfoMessages(void)
                hud_configure_active_panel = HUD_PANEL_INFOMESSAGES;
 
        HUD_Panel_UpdateCvars(infomessages);
+       HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@ -4104,16 +3988,14 @@ void HUD_InfoMessages(void)
        fontsize = '0.20 0.20 0' * mySize_y;
        
        float a;
-       if(spectatee_status != 0)
-               a = 1;
-       else
-               a = panel_fg_alpha;
+       a = panel_fg_alpha;
 
        string s;
        if(!autocvar__hud_configure)
        {
                if(spectatee_status && !intermission)
                {
+                       a = 1;
                        if(spectatee_status == -1)
                                s = _("^1Observing");
                        else
@@ -4254,6 +4136,7 @@ void HUD_Physics(void)
                hud_configure_active_panel = HUD_PANEL_PHYSICS;
 
        HUD_Panel_UpdateCvars(physics);
+       HUD_Panel_ApplyFadeAlpha();
 
        HUD_Panel_DrawBg(1);
        if(panel_bg_padding)
@@ -4464,6 +4347,238 @@ void HUD_Physics(void)
                drawstring_aspect(panel_pos + acceleration_offset, strcat(ftos_decimals(acceleration, 2), "g"), panel_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 }
 
+#define CENTERPRINT_MAX_MSGS 10
+#define CENTERPRINT_MAX_ENTRIES 50
+float cpm_index;
+string centerprint_messages[CENTERPRINT_MAX_MSGS];
+float centerprint_msgID[CENTERPRINT_MAX_MSGS];
+float centerprint_time[CENTERPRINT_MAX_MSGS];
+float centerprint_expire_time[CENTERPRINT_MAX_MSGS];
+float centerprint_countdown_num[CENTERPRINT_MAX_MSGS];
+
+void centerprint_generic(float new_id, string strMessage, float duration, float countdown_num)
+{
+       float i, j;
+
+       if(strMessage == "" && new_id == 0)
+               return;
+
+       if(duration == 0)
+               duration = max(1, autocvar_hud_panel_centerprint_time);
+
+       for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
+       {
+               if (j == CENTERPRINT_MAX_MSGS)
+                       j = 0;
+               if (new_id && new_id == centerprint_msgID[j])
+                       break; // found a msg with the same id, at position j
+       }
+
+       if (i == CENTERPRINT_MAX_MSGS)
+       {
+               // a msg with the same id was not found, add the msg at the next position
+               --cpm_index;
+               if (cpm_index == -1)
+                       cpm_index = CENTERPRINT_MAX_MSGS - 1;
+               j = cpm_index;
+       }
+       if(centerprint_messages[j])
+               strunzone(centerprint_messages[j]);
+       centerprint_messages[j] = strzone(strMessage);
+       centerprint_msgID[j] = new_id;
+       if (duration < 0)
+               centerprint_time[j] = -1;
+       else
+       {
+               centerprint_time[j] = duration;
+               centerprint_expire_time[j] = time + duration;
+       }
+       centerprint_countdown_num[j] = countdown_num;
+}
+
+void centerprint(string strMessage)
+{
+       centerprint_generic(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
+}
+
+// CenterPrint (#16)
+//
+float hud_configure_cp_generation_time;
+void reset_centerprint_messages(void)
+{
+       float i;
+       for (i=0; i<CENTERPRINT_MAX_MSGS; ++i)
+       {
+               centerprint_expire_time[i] = 0;
+               centerprint_time[i] = 1;
+               centerprint_msgID[i] = 0;
+               if(centerprint_messages[i])
+                       strunzone(centerprint_messages[i]);
+               centerprint_messages[i] = strzone("");
+       }
+}
+void HUD_CenterPrint (void)
+{
+       if(!autocvar__hud_configure)
+       {
+               if(!autocvar_hud_panel_centerprint) return;
+
+               if (hud_configure_prev)
+                       reset_centerprint_messages();
+       }
+       else
+       {
+               hud_configure_active_panel = HUD_PANEL_CENTERPRINT;
+
+               if (!hud_configure_prev)
+                       reset_centerprint_messages();
+               if (time > hud_configure_cp_generation_time)
+               {
+                       float r;
+                       r = random();
+                       if (r > 0.9)
+                               centerprint_generic(floor(r*1000), strcat(sprintf("Countdown message at time %d", time), " %d seconds left"), 1, 10);
+                       else if (r > 0.7)
+                               centerprint_generic(0, sprintf("Multiline message at time %d that\nlasts longer than normal", time), 25, 0);
+                       else
+                               centerprint(sprintf("Message at time %d", time));
+                       hud_configure_cp_generation_time = time + 1 + random()*4;
+               }
+       }
+
+       HUD_Panel_UpdateCvars(centerprint);
+
+       // this panel doesn't fade when showing the scoreboard
+       if(autocvar__menu_alpha)
+               HUD_Panel_ApplyFadeAlpha();
+
+       if(scoreboard_fade_alpha)
+       {
+               // move the panel below the scoreboard
+               if (scoreboard_bottom >= 0.96 * vid_conheight)
+                       return;
+               vector target_pos;
+               target_pos = eY * scoreboard_bottom + eX * 0.5 * (vid_conwidth - panel_size_x);
+               panel_pos = panel_pos + (target_pos - panel_pos) * sqrt(scoreboard_fade_alpha);
+               panel_size_y = min(panel_size_y, vid_conheight - scoreboard_bottom);
+       }
+
+       HUD_Panel_DrawBg(1);
+       if(panel_bg_padding)
+       {
+               panel_pos += '1 1 0' * panel_bg_padding;
+               panel_size -= '2 2 0' * panel_bg_padding;
+       }
+
+       float entries, height;
+       vector fontsize;
+       // entries = bound(1, floor(CENTERPRINT_MAX_ENTRIES * 4 * panel_size_y/panel_size_x), CENTERPRINT_MAX_ENTRIES);
+       // height = panel_size_y/entries;
+       // fontsize = '1 1 0' * height;
+       height = vid_conheight/40 * autocvar_hud_panel_centerprint_fontscale;
+       fontsize = '1 1 0' * height;
+       entries = bound(1, floor(panel_size_y/height), CENTERPRINT_MAX_ENTRIES);
+
+       float i, j, k, n;
+       float a, sz, fade, align, next_msg_pos_y;
+       vector pos;
+       string ts;
+
+       pos = panel_pos;
+       if (autocvar_hud_panel_centerprint_flip)
+               pos_y += panel_size_y - fontsize_y;
+       fade = min(autocvar_hud_panel_centerprint_time/8, 0.25);
+       align = bound(0, autocvar_hud_panel_centerprint_align, 1);
+       float alpha_factor;
+       alpha_factor = panel_fg_alpha;
+       if (autocvar__menu_alpha)
+               alpha_factor *= hud_fade_alpha;
+       for (i=0, j=cpm_index; i<CENTERPRINT_MAX_MSGS; ++i, ++j)
+       {
+               if (j == CENTERPRINT_MAX_MSGS)
+                       j = 0;
+               if (centerprint_time[j] > 0 && centerprint_expire_time[j] < time)
+               {
+                       if (centerprint_countdown_num[j])
+                       {
+                               centerprint_countdown_num[j] = centerprint_countdown_num[j] - 1;
+                               if (centerprint_countdown_num[j] == 0)
+                                       continue;
+                               centerprint_expire_time[j] = centerprint_expire_time[j] + centerprint_time[j];
+                       }
+                       else
+                               continue;
+               }
+               if (centerprint_time[j] < 0 || centerprint_expire_time[j] - fade > time)
+               {
+                       a = 1 * alpha_factor;
+                       sz = 1;
+               }
+               else if (centerprint_expire_time[j] > time)
+               {
+                       a = (centerprint_expire_time[j] - time) / fade * alpha_factor;
+                       sz = 0.8 + a * (1 - 0.8);
+               }
+
+               drawfontscale = sz * '1 1 0';
+               if (centerprint_countdown_num[j])
+                       n = tokenizebyseparator(sprintf(centerprint_messages[j], centerprint_countdown_num[j]), "\n");
+               else
+                       n = tokenizebyseparator(centerprint_messages[j], "\n");
+               if (autocvar_hud_panel_centerprint_flip)
+               {
+                       // check if the message can be entirely shown
+                       for(k = 0; k < n; ++k)
+                       {
+                               getWrappedLine_remaining = argv(k);
+                               ts = getWrappedLine(panel_size_x, fontsize, stringwidth_colors);
+                               if (ts != "")
+                                       pos_y -= fontsize_y * 1.5;
+                               else
+                                       pos_y -= fontsize_y;
+                               if (pos_y < panel_pos_y) // check if the next line can be shown
+                                       return;
+                       }
+                       next_msg_pos_y = pos_y; // save pos of the next message
+               }
+
+               for(k = 0; k < n; ++k)
+               {
+                       getWrappedLine_remaining = argv(k);
+                       while(getWrappedLine_remaining)
+                       {
+                               ts = getWrappedLine(panel_size_x, fontsize, stringwidth_colors);
+                               if (ts != "")
+                               {
+                                       if (align)
+                                               pos_x = panel_pos_x + (panel_size_x - stringwidth(ts, TRUE, fontsize)) * align;
+                                       drawcolorcodedstring(pos + '0 1 0' * 1.5 * (1 - sz) * fontsize_y, ts, fontsize, a, DRAWFLAG_NORMAL);
+                                       pos_y += fontsize_y * 1.5;
+                               }
+                               else
+                                       pos_y += fontsize_y;
+                               if (pos_y > panel_pos_y + panel_size_y - fontsize_y) // check if the next line can be shown
+                               {
+                                       drawfontscale = '1 1 0';
+                                       return;
+                               }
+                       }
+               }
+               if (autocvar_hud_panel_centerprint_flip)
+               {
+                       pos_y = next_msg_pos_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 += 1.5 * fontsize_y * (1 - a*a);
+               }
+               else
+               {
+                       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 -= 1.5 * fontsize_y * (1 - a*a);
+               }
+               drawfontscale = '1 1 0';
+       }
+}
+
 /*
 ==================
 Main HUD system
@@ -4513,6 +4628,8 @@ switch (id) {\
                 HUD_InfoMessages(); break;\
        case (HUD_PANEL_PHYSICS):\
                 HUD_Physics(); break;\
+       case (HUD_PANEL_CENTERPRINT):\
+                HUD_CenterPrint(); break;\
 } ENDS_WITH_CURLY_BRACE
 
 void HUD_Main (void)
@@ -4528,10 +4645,29 @@ void HUD_Main (void)
                hud_fade_alpha = (1 - scoreboard_fade_alpha);
 
        if(intermission == 2) // no hud during mapvote
+       {
+               if (autocvar__hud_configure) //force exit from hud config
+               {
+                       if (menu_enabled)
+                       {
+                               menu_enabled = 0;
+                               localcmd("togglemenu\n");
+                       }
+                       cvar_set("_hud_configure", "0");
+               }
                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
+       if(scoreboard_fade_alpha == 1)
+       {
+               HUD_CenterPrint();
+               return;
+       }
+
        if(!autocvar__hud_configure && !hud_fade_alpha)
                return;