]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into terencehill/centerprint_stuff
authorterencehill <piuntn@gmail.com>
Wed, 22 Jun 2011 23:04:33 +0000 (01:04 +0200)
committerterencehill <piuntn@gmail.com>
Wed, 22 Jun 2011 23:04:33 +0000 (01:04 +0200)
Conflicts:
qcsrc/client/View.qc

14 files changed:
1  2 
qcsrc/client/Main.qc
qcsrc/client/View.qc
qcsrc/client/autocvars.qh
qcsrc/client/hud.qc
qcsrc/client/main.qh
qcsrc/common/constants.qh
qcsrc/server/cl_client.qc
qcsrc/server/ctf.qc
qcsrc/server/defs.qh
qcsrc/server/gamecommand.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/gamemode_keepaway.qc
qcsrc/server/mutators/gamemode_keyhunt.qc
qcsrc/server/t_items.qc

diff --combined qcsrc/client/Main.qc
index 506c37eda80390f1fe25372148cebc869df504aa,fb9a1bb74db3e4725911dacbbd8d50327579b1fb..df07be650503130779b95faf35c0e18d80fc20d0
@@@ -47,7 -47,7 +47,7 @@@ void WaypointSprite_Load()
  void CSQC_Init(void)
  {
        prvm_language = cvar_string("prvm_language");
-       
  #ifdef USE_FTE
  #pragma target ID
        __engine_check = checkextension("DP_SV_WRITEPICTURE");
        GibSplash_Precache();
        Casings_Precache();
        DamageInfo_Precache();
+       Vehicles_Precache();
+       turrets_precache();
        if(autocvar_cl_announcer != cl_announcer_prev) {
                Announcer_Precache();
                if(cl_announcer_prev)
@@@ -902,7 -905,7 +905,7 @@@ void Ent_ReadAccuracy(void
                        weapon_accuracy[w] = -1;
                return;
        }
-       
        for(w = 0, f = 1; w <= WEP_LAST - WEP_FIRST; ++w, f *= 2)
        {
                if(sf & f)
@@@ -984,6 -987,8 +987,8 @@@ void(float bIsNewEntity) CSQC_Ent_Updat
                case ENT_CLIENT_LGBEAM: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_LGBEAM); break;
                case ENT_CLIENT_GAUNTLET: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_GAUNTLET); break;
                case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
+               case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
+               case ENT_CLIENT_TURRET: ent_turret(); break; 
                default:
                        //error(strcat(_("unknown entity type in CSQC_Ent_Update: %d\n"), self.enttype));
                        error(sprintf(_("Unknown entity type in CSQC_Ent_Update (enttype: %d, edict: %d, classname: %s)\n"), self.enttype, num_for_edict(self), self.classname));
@@@ -1325,16 -1330,6 +1330,16 @@@ void Net_Notify() 
        {
                HUD_Centerprint(ReadString(), ReadString(), ReadShort(), ReadByte());
        }
 +      else if(type == CSQC_CENTERPRINT_GENERIC)
 +      {
 +                                                              //      id                      string          time    countdown_num
 +              float id;
 +              id = ReadByte();
 +              if (id == 0)
 +                      centerprint_generic(id, ReadString(), 0, 0);
 +              else
 +                      centerprint_generic(id, ReadString(), ReadByte(), ReadByte());
 +      }
  }
  
  void Net_WeaponComplain() {
@@@ -1420,6 -1415,10 +1425,10 @@@ float CSQC_Parse_TempEntity(
                        Net_WeaponComplain();
                        bHandled = true;
                        break;
+         case TE_CSQC_VEHICLESETUP:
+             Net_VehicleSetup();
+             bHandled = true;
+             break;
                default:
                        // No special logic for this temporary entity; return 0 so the engine can handle it
                        bHandled = false;
diff --combined qcsrc/client/View.qc
index 19a91077234b7033e61349946a92c8572daf7650,870da0d7b04824cfb8dafa007dcc4a62f65d1f62..5b7a1b7cf89d0891748ae05ec10fb6d658044ab6
@@@ -1,12 -1,3 +1,3 @@@
- #define spider_rocket_icon "gfx/vehicles/rocket_ico.tga"
- #define spider_rocket_targ "gfx/vehicles/target.tga"
- #define SPIDER_CROSS "textures/spiderbot/cross.tga"
- #define rkt_size 32
- #define rld_size_x 256
- #define rld_size_y 16
- void CSQC_WAKIZASHI_HUD();
  entity porto;
  vector polyline[16];
  float trace_dphitcontents;
@@@ -137,6 -128,7 +128,7 @@@ vector GetCurrentFov(float fov
                        zoomspeed = 3.5;
  
        zoomdir = button_zoom;
+       if(hud == HUD_NORMAL)
        if((getstati(STAT_ACTIVEWEAPON) == WEP_NEX && nex_scope) || (getstati(STAT_ACTIVEWEAPON) == WEP_RIFLE && rifle_scope)) // do NOT use switchweapon here
                zoomdir += button_attack2;
        if(spectatee_status > 0 || isdemo())
@@@ -377,6 -369,7 +369,7 @@@ void CSQC_UpdateView(float w, float h
        vector v, vo;
        vector vf_size, vf_min;
        float a;
+       hud = getstati(STAT_HUD);
  
        button_attack2 = (input_buttons & BUTTON_3);
        button_zoom = (input_buttons & BUTTON_4);
                R_PolygonVertex(autocvar_vid_conheight * '0 1 0', tc_01, rgb, a);
                R_EndPolygon();
        }
+         
        // Draw the aiming reticle for weapons that use it
        // reticle_type is changed to the item we are zooming / aiming with, to decide which reticle to use
        // It must be a persisted float for fading out to work properly (you let go of the zoom button for
        // the view to go back to normal, so reticle_type would become 0 as we fade out)
-       if(spectatee_status || getstati(STAT_HEALTH) <= 0)
+       if(spectatee_status || getstati(STAT_HEALTH) <= 0 || hud != HUD_NORMAL)
                reticle_type = 0; // prevent reticle from showing during the respawn zoom effect or for spectators
        else if(activeweapon == WEP_NEX && (button_zoom || zoomscript_caught) || activeweapon == WEP_RIFLE && (button_zoom || zoomscript_caught) || activeweapon == WEP_MINSTANEX && (button_zoom || zoomscript_caught))
                reticle_type = 2; // nex zoom
                reticle_type = 1; // normal zoom
        else if(activeweapon == WEP_NEX && button_attack2 || activeweapon == WEP_RIFLE && button_attack2)
                reticle_type = 2; // nex zoom
+     
        if (reticle_type)
        {
                if(autocvar_cl_reticle_stretch)
        {
                float contentalpha_temp, incontent, liquidalpha, contentfadetime;
                vector liquidcolor;
-               
                switch(pointcontents(view_origin))
                {
                        case CONTENT_WATER:
                                liquidcolor = stov(autocvar_hud_contents_water_color);
                                incontent = 1;
                                break;
-                               
                        case CONTENT_LAVA:
                                liquidalpha = autocvar_hud_contents_lava_alpha;
                                liquidcolor = stov(autocvar_hud_contents_lava_color);
                                incontent = 1;
-                               break;  
-                                                       
+                               break;
                        case CONTENT_SLIME:
                                liquidalpha = autocvar_hud_contents_slime_alpha;
                                liquidcolor = stov(autocvar_hud_contents_slime_color);
                                incontent = 1;
                                break;
-                               
                        default:
                                liquidalpha = 0;
                                liquidcolor = '0 0 0';
                                incontent = 0;
                                break;
                }
-               
                if(incontent) // fade in/out at different speeds so you can do e.g. instant fade when entering water and slow when leaving it.
                { // also lets delcare previous values for blending properties, this way it isn't reset until after you have entered a different content
                        contentfadetime = autocvar_hud_contents_fadeintime;
                }
                else
                        contentfadetime = autocvar_hud_contents_fadeouttime;
-                       
                contentalpha_temp = bound(0, drawframetime / max(0.0001, contentfadetime), 1);
                contentavgalpha = contentavgalpha * (1 - contentalpha_temp) + incontent * contentalpha_temp;
-               
                if(contentavgalpha)
                        drawfill('0 0 0', eX * vid_conwidth + eY * vid_conheight, liquidcolor_prev, contentavgalpha * liquidalpha_prev, DRAWFLAG_NORMAL);
        }
        
        if(autocvar_hud_damage && !autocvar_chase_active)
        {
                splash_size_x = max(vid_conwidth, vid_conheight);
                splash_size_y = max(vid_conwidth, vid_conheight);
                nextsound_typehit_time = time + autocvar_cl_hitsound_antispam_time;
        }
  
-       float hud;
-       hud = getstati(STAT_HUD);
-       if(hud == HUD_SPIDERBOT)
-               CSQC_SPIDER_HUD();
-       else if(hud == HUD_WAKIZASHI)
-         CSQC_WAKIZASHI_HUD();
-     else if(hud == HUD_RAPTOR)
-         CSQC_RAPTOR_HUD();
-       else
+       //else
        {
                if(gametype == GAME_FREEZETAG)
                {
                                CSQC_common_hud();
  
                // crosshair goes VERY LAST
-               if(!scoreboard_active && !camera_active && intermission != 2 && spectatee_status != -1) {
+               if(!scoreboard_active && !camera_active && intermission != 2 && spectatee_status != -1 && hud == HUD_NORMAL) {
                        string wcross_style;
                        float wcross_alpha, wcross_resolution;
                        wcross_style = autocvar_crosshair;
                        else if(autocvar_crosshair_color_by_health)
                        {
                                local float x = getstati(STAT_HEALTH);
-                               
                                //x = red
                                //y = green
                                //z = blue
-                               
                                wcross_color_z = 0;
-                               
                                if(x > 200)
                                {
                                        wcross_color_x = 0;
                                {
                                        wcross_color_x = 1;
                                        wcross_color_y = 1;
-                                       wcross_color_z = 0.2 + (x-50)*0.02 * 0.8;  
+                                       wcross_color_z = 0.2 + (x-50)*0.02 * 0.8;
                                }
                                else if(x > 20)
                                {
  
                                wcross_scale += sin(pickup_crosshair_size) * autocvar_crosshair_pickup;
                        }
-                       
                        vector hitindication_color;
                        if(autocvar_crosshair_hitindication)
                        {
                        wcross_alpha *= 1 - autocvar__menu_alpha;
                        wcross_size = drawgetimagesize(wcross_name) * wcross_scale;
  
-                       // crosshair rings for weapon stats
-                       if (autocvar_crosshair_ring || autocvar_crosshair_ring_reload)
+                       if(wcross_scale >= 0.001 && wcross_alpha >= 0.001)
                        {
-                               // declarations and stats
-                               float ring_value, ring_scale, ring_alpha, ring_inner_value, ring_inner_alpha;
-                               string ring_image, ring_inner_image;
-                               vector ring_rgb, ring_inner_rgb;
-                               
-                               ring_scale = autocvar_crosshair_ring_size;
-                               float weapon_clipload, weapon_clipsize;
-                               weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD);
-                               weapon_clipsize = getstati(STAT_WEAPON_CLIPSIZE);
-                               float nex_charge, nex_chargepool;
-                               nex_charge = getstatf(STAT_NEX_CHARGE);
-                               nex_chargepool = getstatf(STAT_NEX_CHARGEPOOL);
-                               if(nex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
-                                       nex_charge_movingavg = nex_charge;
-                                       
-                               // handle the values
-                               if (autocvar_crosshair_ring && activeweapon == WEP_NEX && nex_charge && autocvar_crosshair_ring_nex) // ring around crosshair representing velocity-dependent damage for the nex
+                               // crosshair rings for weapon stats
+                               if (autocvar_crosshair_ring || autocvar_crosshair_ring_reload)
                                {
-                                       if (nex_chargepool || use_nex_chargepool) { 
-                                               use_nex_chargepool = 1; 
-                                               ring_inner_value = nex_chargepool;
-                                       } else { 
-                                               nex_charge_movingavg = (1 - autocvar_crosshair_ring_nex_currentcharge_movingavg_rate) * nex_charge_movingavg + autocvar_crosshair_ring_nex_currentcharge_movingavg_rate * nex_charge;
-                                               ring_inner_value = bound(0, autocvar_crosshair_ring_nex_currentcharge_scale * (nex_charge - nex_charge_movingavg), 1); 
-                                       }
-                                               
-                                       ring_inner_alpha = autocvar_crosshair_ring_nex_inner_alpha;
-                                       ring_inner_rgb = eX * autocvar_crosshair_ring_nex_inner_color_red + eY * autocvar_crosshair_ring_nex_inner_color_green + eZ * autocvar_crosshair_ring_nex_inner_color_blue;
-                                       ring_inner_image = "gfx/crosshair_ring_inner.tga";
-                                       
-                                       // draw the outer ring to show the current charge of the weapon
-                                       ring_value = nex_charge;
-                                       ring_alpha = autocvar_crosshair_ring_nex_alpha;
-                                       ring_rgb = wcross_color;
-                                       ring_image = "gfx/crosshair_ring_nexgun.tga";
-                               }
-                               else if (autocvar_crosshair_ring && activeweapon == WEP_MINE_LAYER && minelayer_maxmines && autocvar_crosshair_ring_minelayer) 
-                               {
-                                       ring_value = bound(0, getstati(STAT_LAYED_MINES) / minelayer_maxmines, 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to.
-                                       ring_alpha = autocvar_crosshair_ring_minelayer_alpha;
-                                       ring_rgb = wcross_color;
-                                       ring_image = "gfx/crosshair_ring.tga";
-                               }
-                               else if (activeweapon == WEP_HAGAR && getstati(STAT_HAGAR_LOAD) && autocvar_crosshair_ring_hagar)
-                               {
-                                       ring_value = bound(0, getstati(STAT_HAGAR_LOAD) / hagar_maxrockets, 1);
-                                       ring_alpha = autocvar_crosshair_ring_hagar_alpha;
-                                       ring_rgb = wcross_color;
-                                       ring_image = "gfx/crosshair_ring.tga";
-                               }
+                                       // declarations and stats
+                                       float ring_value, ring_scale, ring_alpha, ring_inner_value, ring_inner_alpha;
+                                       string ring_image, ring_inner_image;
+                                       vector ring_rgb, ring_inner_rgb;
  
-                               if(autocvar_crosshair_ring_reload && weapon_clipsize) // forces there to be only an ammo ring 
-                               {
-                                       ring_value = bound(0, weapon_clipload / weapon_clipsize, 1);
-                                       ring_scale = autocvar_crosshair_ring_reload_size;
-                                       ring_alpha = autocvar_crosshair_ring_reload_alpha;
-                                       ring_rgb = wcross_color;
-                                       
-                                       // Note: This is to stop Taoki from complaining that the image doesn't match all potential balances.
-                                       // if a new image for another weapon is added, add the code (and its respective file/value) here
-                                       if ((activeweapon == WEP_RIFLE) && (weapon_clipsize == 80))
-                                               ring_image = "gfx/crosshair_ring_rifle.tga";
-                                       else
+                                       ring_scale = autocvar_crosshair_ring_size;
+                                       float weapon_clipload, weapon_clipsize;
+                                       weapon_clipload = getstati(STAT_WEAPON_CLIPLOAD);
+                                       weapon_clipsize = getstati(STAT_WEAPON_CLIPSIZE);
+                                       float nex_charge, nex_chargepool;
+                                       nex_charge = getstatf(STAT_NEX_CHARGE);
+                                       nex_chargepool = getstatf(STAT_NEX_CHARGEPOOL);
+                                       if(nex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
+                                               nex_charge_movingavg = nex_charge;
+                                       // handle the values
+                                       if (autocvar_crosshair_ring && activeweapon == WEP_NEX && nex_charge && autocvar_crosshair_ring_nex) // ring around crosshair representing velocity-dependent damage for the nex
+                                       {
+                                               if (nex_chargepool || use_nex_chargepool) { 
+                                                       use_nex_chargepool = 1; 
+                                                       ring_inner_value = nex_chargepool;
+                                               } else { 
+                                                       nex_charge_movingavg = (1 - autocvar_crosshair_ring_nex_currentcharge_movingavg_rate) * nex_charge_movingavg + autocvar_crosshair_ring_nex_currentcharge_movingavg_rate * nex_charge;
+                                                       ring_inner_value = bound(0, autocvar_crosshair_ring_nex_currentcharge_scale * (nex_charge - nex_charge_movingavg), 1); 
+                                               }
+                                               ring_inner_alpha = autocvar_crosshair_ring_nex_inner_alpha;
+                                               ring_inner_rgb = eX * autocvar_crosshair_ring_nex_inner_color_red + eY * autocvar_crosshair_ring_nex_inner_color_green + eZ * autocvar_crosshair_ring_nex_inner_color_blue;
+                                               ring_inner_image = "gfx/crosshair_ring_inner.tga";
+                                               // draw the outer ring to show the current charge of the weapon
+                                               ring_value = nex_charge;
+                                               ring_alpha = autocvar_crosshair_ring_nex_alpha;
+                                               ring_rgb = wcross_color;
+                                               ring_image = "gfx/crosshair_ring_nexgun.tga";
+                                       }
+                                       else if (autocvar_crosshair_ring && activeweapon == WEP_MINE_LAYER && minelayer_maxmines && autocvar_crosshair_ring_minelayer) 
+                                       {
+                                               ring_value = bound(0, getstati(STAT_LAYED_MINES) / minelayer_maxmines, 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to.
+                                               ring_alpha = autocvar_crosshair_ring_minelayer_alpha;
+                                               ring_rgb = wcross_color;
                                                ring_image = "gfx/crosshair_ring.tga";
-                               }
+                                       }
+                                       else if (activeweapon == WEP_HAGAR && getstati(STAT_HAGAR_LOAD) && autocvar_crosshair_ring_hagar)
+                                       {
+                                               ring_value = bound(0, getstati(STAT_HAGAR_LOAD) / hagar_maxrockets, 1);
+                                               ring_alpha = autocvar_crosshair_ring_hagar_alpha;
+                                               ring_rgb = wcross_color;
+                                               ring_image = "gfx/crosshair_ring.tga";
+                                       }
  
-                               if (autocvar_crosshair_ring_inner && ring_inner_value) // lets draw a ring inside a ring so you can ring while you ring
-                                       DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, ring_inner_image, ring_inner_value, ring_inner_rgb, wcross_alpha * ring_inner_alpha, DRAWFLAG_ADDITIVE);
+                                       if(autocvar_crosshair_ring_reload && weapon_clipsize) // forces there to be only an ammo ring 
+                                       {
+                                               ring_value = bound(0, weapon_clipload / weapon_clipsize, 1);
+                                               ring_scale = autocvar_crosshair_ring_reload_size;
+                                               ring_alpha = autocvar_crosshair_ring_reload_alpha;
+                                               ring_rgb = wcross_color;
+                                               // Note: This is to stop Taoki from complaining that the image doesn't match all potential balances.
+                                               // if a new image for another weapon is added, add the code (and its respective file/value) here
+                                               if ((activeweapon == WEP_RIFLE) && (weapon_clipsize == 80))
+                                                       ring_image = "gfx/crosshair_ring_rifle.tga";
+                                               else
+                                                       ring_image = "gfx/crosshair_ring.tga";
+                                       }
  
-                               if (ring_value)
-                                       DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, ring_image, ring_value, ring_rgb, wcross_alpha * ring_alpha, DRAWFLAG_ADDITIVE);
-                       }
+                                       if (autocvar_crosshair_ring_inner && ring_inner_value) // lets draw a ring inside a ring so you can ring while you ring
+                                               DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, ring_inner_image, ring_inner_value, ring_inner_rgb, wcross_alpha * ring_inner_alpha, DRAWFLAG_ADDITIVE);
+                                       if (ring_value)
+                                               DrawCircleClippedPic(wcross_origin, wcross_size_x * ring_scale, ring_image, ring_value, ring_rgb, wcross_alpha * ring_alpha, DRAWFLAG_ADDITIVE);
+                               }
  
  #define CROSSHAIR_DO_BLUR(M,sz,wcross_name,wcross_alpha) \
-                       do \
-                       { \
-                               if(wcross_blur > 0) \
+                               do \
                                { \
-                                       for(i = -2; i <= 2; ++i) \
+                                       if(wcross_blur > 0) \
+                                       { \
+                                               for(i = -2; i <= 2; ++i) \
                                                for(j = -2; j <= 2; ++j) \
-                                                       M(i,j,sz,wcross_name,wcross_alpha*0.04); \
-                               } \
-                               else \
-                               { \
-                                       M(0,0,sz,wcross_name,wcross_alpha); \
+                                               M(i,j,sz,wcross_name,wcross_alpha*0.04); \
+                                       } \
+                                       else \
+                                       { \
+                                               M(0,0,sz,wcross_name,wcross_alpha); \
+                                       } \
                                } \
-                       } \
-                       while(0)
+                               while(0)
  
  #define CROSSHAIR_DRAW_SINGLE(i,j,sz,wcross_name,wcross_alpha) \
-                       drawpic(wcross_origin - ('0.5 0 0' * (sz * wcross_size_x + i * wcross_blur) + '0 0.5 0' * (sz * wcross_size_y + j * wcross_blur)), wcross_name, sz * wcross_size, wcross_color, wcross_alpha, DRAWFLAG_NORMAL)
+                               drawpic(wcross_origin - ('0.5 0 0' * (sz * wcross_size_x + i * wcross_blur) + '0 0.5 0' * (sz * wcross_size_y + j * wcross_blur)), wcross_name, sz * wcross_size, wcross_color, wcross_alpha, DRAWFLAG_NORMAL)
  
  #define CROSSHAIR_DRAW(sz,wcross_name,wcross_alpha) \
-                       CROSSHAIR_DO_BLUR(CROSSHAIR_DRAW_SINGLE,sz,wcross_name,wcross_alpha)
+                               CROSSHAIR_DO_BLUR(CROSSHAIR_DRAW_SINGLE,sz,wcross_name,wcross_alpha)
  
-                       if(time < wcross_name_changedonetime && wcross_name != wcross_name_goal_prev_prev && wcross_name_goal_prev_prev)
-                       {
-                               f = (wcross_name_changedonetime - time) / (wcross_name_changedonetime - wcross_name_changestarttime);
-                               wcross_size = drawgetimagesize(wcross_name_goal_prev_prev) * wcross_scale;
-                               CROSSHAIR_DRAW(wcross_resolution_goal_prev_prev, wcross_name_goal_prev_prev, wcross_alpha * f * wcross_name_alpha_goal_prev_prev);
-                               f = 1 - f;
-                       }
-                       else
-                       {
-                               f = 1;
-                       }
+                               if(time < wcross_name_changedonetime && wcross_name != wcross_name_goal_prev_prev && wcross_name_goal_prev_prev)
+                               {
+                                       f = (wcross_name_changedonetime - time) / (wcross_name_changedonetime - wcross_name_changestarttime);
+                                       wcross_size = drawgetimagesize(wcross_name_goal_prev_prev) * wcross_scale;
+                                       CROSSHAIR_DRAW(wcross_resolution_goal_prev_prev, wcross_name_goal_prev_prev, wcross_alpha * f * wcross_name_alpha_goal_prev_prev);
+                                       f = 1 - f;
+                               }
+                               else
+                               {
+                                       f = 1;
+                               }
+                               wcross_name_alpha_goal_prev = f;
  
-                       wcross_size = drawgetimagesize(wcross_name) * wcross_scale;
-                       CROSSHAIR_DRAW(wcross_resolution, wcross_name, wcross_alpha * f);
-                       if(autocvar_crosshair_dot)
-             {
-                 vector wcross_color_old;
-                 wcross_color_old = wcross_color;
-                 if(autocvar_crosshair_dot_color != "0")
-                     wcross_color = stov(autocvar_crosshair_dot_color);
-                               CROSSHAIR_DRAW(wcross_resolution * autocvar_crosshair_dot_size, "gfx/crosshairdot.tga", f * autocvar_crosshair_dot_alpha);
-                 wcross_color = wcross_color_old;
-             }
-                       wcross_name_alpha_goal_prev = f;
+                               wcross_size = drawgetimagesize(wcross_name) * wcross_scale;
+                               CROSSHAIR_DRAW(wcross_resolution, wcross_name, wcross_alpha * f);
+                               if(autocvar_crosshair_dot)
+                               {
+                                       vector wcross_color_old;
+                                       wcross_color_old = wcross_color;
+                                       if(autocvar_crosshair_dot_color != "0")
+                                               wcross_color = stov(autocvar_crosshair_dot_color);
+                                       CROSSHAIR_DRAW(wcross_resolution * autocvar_crosshair_dot_size, "gfx/crosshairdot.tga", f * autocvar_crosshair_dot_alpha);
+                                       // FIXME why don't we use wcross_alpha here?
+                                       wcross_color = wcross_color_old;
+                               }
+                       }
                }
                else
                {
  
        if(autocvar__hud_configure)
                HUD_Panel_Mouse();
+     
+     if(hud && !intermission)
+     {        
+         if(hud == HUD_SPIDERBOT)
+             CSQC_SPIDER_HUD();
+         else if(hud == HUD_WAKIZASHI)
+             CSQC_WAKIZASHI_HUD();
+         else if(hud == HUD_RAPTOR)
+             CSQC_RAPTOR_HUD();
+         else if(hud == HUD_BUMBLEBEE)
+             CSQC_BUMBLE_HUD();
+     }
        // let's reset the view back to normal for the end
        R_SetView(VF_MIN, '0 0 0');
        R_SetView(VF_SIZE, '1 0 0' * w + '0 1 0' * h);
  }
  
- #define spider_h "gfx/vehicles/hud_bg.tga"
- #define spider_b "gfx/vehicles/sbot.tga"
- #define spider_r "gfx/vehicles/sbot_rpods.tga"
- #define spider_g "gfx/vehicles/sbot_mguns.tga"
- #define spider_s "gfx/vehicles/shiled.tga"
- #define spider_a1 "gfx/hud/sb_rocket.tga"
- #define spider_a2 "gfx/sb_bullets.tga"
- void CSQC_SPIDER_HUD()
- {
-       float rockets, reload, heat, hp, shield;
-       vector picsize, hudloc;
-     // Fetch health & ammo stats
-     hp      = bound(0,getstatf(STAT_VEHICLESTAT_HEALTH), 1);
-       shield  = bound(0,getstatf(STAT_VEHICLESTAT_SHIELD), 1);
-       heat    = min(getstatf(STAT_VEHICLESTAT_RELOAD1), 2);
-       rockets =     getstati(STAT_VEHICLESTAT_AMMO2);
-       reload  = min(getstatf(STAT_VEHICLESTAT_RELOAD2), 1);
-     // Draw the crosshairs
-     picsize = drawgetimagesize(SPIDER_CROSS);
-     picsize_x *= autocvar_cl_vehicle_spiderbot_cross_size;
-     picsize_y *= autocvar_cl_vehicle_spiderbot_cross_size;
-     drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), SPIDER_CROSS, picsize, '1 1 1', autocvar_cl_vehicle_spiderbot_cross_alpha, DRAWFLAG_NORMAL);
-     hudloc_y =  4;
-     hudloc_x = 4;
-     picsize = drawgetimagesize(spider_h) * 0.5;
-     drawpic(hudloc, spider_h, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-     picsize = drawgetimagesize(spider_a2) * 0.5;
-     drawpic(hudloc + '120 96  0', spider_a2, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '145 19  0', strcat(ftos(rint(hp * 100)), "%"),'15 15 0','0 1 0', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '175 34  0', strcat(ftos(rint(shield * 100)), "%"),'15 15 0','0 0 1', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '136 102  0', strcat(ftos(100 - rint(heat * 100)), "%"),'14 14 0','1 1 0', 1, DRAWFLAG_NORMAL);
-     picsize = drawgetimagesize(spider_a1) * 0.85;
-     if(rockets == 9)
-     {
-         drawpic(hudloc + '132 54  0', spider_a1, picsize, '-1 -1 -1', 1, DRAWFLAG_NORMAL);
-         drawstring(hudloc + '179 69 0', strcat(ftos(rint(reload * 100)), "%"),'14 14 0','1 1 0', 1, DRAWFLAG_NORMAL);
-     }
-     else
-     {
-         drawpic(hudloc + '132 54  0', spider_a1, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-         drawstring(hudloc + '179 69  0', strcat(ftos(9 - rockets), "/8"),'14 14 0','1 1 0', 1, DRAWFLAG_NORMAL);
-     }
-     picsize = drawgetimagesize(spider_b) * 0.5;
-     hudloc_y = 10.5;
-     hudloc_x = 10.5;
-     drawpic(hudloc, spider_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
-     drawpic(hudloc, spider_b, picsize, '0 1 0' * hp + '1 0 0' * (1 - hp), 1, DRAWFLAG_NORMAL);
-     drawpic(hudloc, spider_r, picsize, '1 1 1' * reload + '1 0 0' * (1 - reload), 1, DRAWFLAG_NORMAL);
-     drawpic(hudloc, spider_g, picsize, '1 1 1' * (1 - heat) + '1 0 0' *  heat, 1, DRAWFLAG_NORMAL);
-       /*
-       // Draw health bar
-       p = '0.5 0 0' * (vid_conwidth - (rkt_size * 8));
-       p = p + '0 1 0' * vid_conheight - '0 32 0';
-       //pp = ('0 1 0' * hp) + ('1 0 0' * (1-hp));
-       drawfill(p, '256 0 0' * shield + '0 8 0' , '0.5 0.5 1', 0.75, DRAWFLAG_NORMAL);
-       p_y += 8;
-       drawfill(p, '256 0 0' * hp + '0 8 0' , '0 1 0', 0.75, DRAWFLAG_NORMAL);
-       p_x += 256 * hp;
-       drawfill(p, '256 0 0' * (1-hp) + '0 8 0' , '0 0 0', 0.75, DRAWFLAG_NORMAL);
-       // Draw minigun heat indicator
-       p = '0.5 0 0' * (vid_conwidth - 256);
-       p = p + '0 1 0' * vid_conheight - '0 34  0';
-       drawfill(p, '256 0 0' * (1-heat) + '0 2 0' ,'0 0 1', 0.5, DRAWFLAG_NORMAL);
-       p_x += 256 * (1-heat);
-       drawfill(p, '256 0 0' * heat  + '0 2 0' , '1 0 0', 0.5, DRAWFLAG_NORMAL);
-       // Draw rocket icons for loaded/empty tubes.
-       pp = '0.5 0 0' * (vid_conwidth - (rkt_size * 8));
-       pp += '0 1 0' * vid_conheight - '0 64 0';
-       for(i = 0; i < 8; ++i)
-       {
-               p = pp + '1 0 0' * (rkt_size * i);
-               if(rockets == 8)
-               {
-                       if(floor(reload * 8) == i)
-                       {
-                               drawpic(p, spider_rocket_icon, '1 1 0' * rkt_size, '1 0 0' + '0 1 0' * ((reload*8)-i), 0.75 , DRAWFLAG_NORMAL);
-                       }
-                       else if(i < reload * 8)
-                               drawpic(p, spider_rocket_icon, '1 1 0' * rkt_size, '1 1 0', 0.75 , DRAWFLAG_NORMAL);
-                       else
-                               drawpic(p, spider_rocket_icon, '1 1 0' * rkt_size, '0.5 0.5 0.5', 0.75, DRAWFLAG_NORMAL);
-               }
-               else
-               {
-                       if(i < rockets)
-                               drawpic(p, spider_rocket_icon, '1 1 0' * rkt_size, '0 0 0', 0.25, DRAWFLAG_NORMAL);
-                       else
-                               drawpic(p, spider_rocket_icon, '1 1 0' * rkt_size, '0 1 0' * reload, 0.75, DRAWFLAG_NORMAL);
-               }
-       }
-       */
-       if (scoreboard_showscores)
-       {
-               HUD_DrawScoreboard();
-       }
- }
- #define raptor_h "gfx/vehicles/hud_bg.tga"
- #define raptor_b "gfx/vehicles/raptor.tga"
- #define raptor_g1 "gfx/vehicles/raptor_guns.tga"
- #define raptor_g2 "gfx/vehicles/raptor_bombs.tga"
- #define raptor_s "gfx/vehicles/shiled.tga"
  
- void CSQC_RAPTOR_HUD()
+ void CSQC_common_hud(void)
  {
-       float reload, hp, shield, energy;
-       vector picsize, hudloc;
-     // Fetch health & ammo stats
-     hp      = bound(0,getstatf(STAT_VEHICLESTAT_HEALTH), 1);
-       shield  = bound(0,getstatf(STAT_VEHICLESTAT_SHIELD), 1);
-       reload  = min(getstatf(STAT_VEHICLESTAT_RELOAD1), 1);
-       energy  = min(getstatf(STAT_VEHICLESTAT_ENERGY),  1);
-     // Draw the crosshairs
-     picsize = drawgetimagesize(SPIDER_CROSS);
-     picsize_x *= autocvar_cl_vehicle_spiderbot_cross_size;
-     picsize_y *= autocvar_cl_vehicle_spiderbot_cross_size;
-     drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), SPIDER_CROSS, picsize, '1 1 1', autocvar_cl_vehicle_spiderbot_cross_alpha, DRAWFLAG_NORMAL);
-     hudloc_y =  4;
-     hudloc_x = 4;
-     picsize = drawgetimagesize(raptor_h) * 0.5;
-     drawpic(hudloc, raptor_h, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-     picsize = drawgetimagesize(spider_a2) * 0.5;
-     drawpic(hudloc + '120 96  0', spider_a2, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '145 19  0', strcat(ftos(rint(hp * 100)), "%"),'15 15 0','0 1 0', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '175 34  0', strcat(ftos(rint(shield * 100)), "%"),'15 15 0','0 0 1', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '136 102 0', strcat(ftos(rint(energy * 100)), "%"),'15 15 0','0.5 0.5 1', 1, DRAWFLAG_NORMAL);
-     picsize = drawgetimagesize(spider_a1) * 0.85;
-     if(reload == 1)
+     // do some accuracy var caching
+     float i;
+     if(!(gametype == GAME_RACE || gametype == GAME_CTS))
      {
-         drawpic(hudloc + '132 54  0', spider_a1, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-         drawstring(hudloc + '179 69  0', strcat(ftos(rint(reload * 100)), "%"),'14 14 0','0 1 0', 0.5, DRAWFLAG_NORMAL);
+         if(autocvar_accuracy_color_levels != acc_color_levels)
+         {
+             if(acc_color_levels)
+                 strunzone(acc_color_levels);
+             acc_color_levels = strzone(autocvar_accuracy_color_levels);
+             acc_levels = tokenize(acc_color_levels);
+             if (acc_levels > MAX_ACCURACY_LEVELS)
+                 acc_levels = MAX_ACCURACY_LEVELS;
+             for (i = 0; i < acc_levels; ++i)
+                 acc_lev[i] = stof(argv(i)) / 100.0;
+         }
+         // let know that acc_col[] needs to be loaded
+         acc_col_x[0] = -1;
      }
-     else
-     {
-         drawpic(hudloc + '132 54  0', spider_a1, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-         drawstring(hudloc + '179 69  0', strcat(ftos(rint(reload * 100)), "%"),'14 14 0','0 0 1', 1, DRAWFLAG_NORMAL);
-     }
-     picsize = drawgetimagesize(raptor_b) * 0.5;
-     hudloc_y = 10.5;
-     hudloc_x = 10.5;
  
-     drawpic(hudloc, raptor_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
-     drawpic(hudloc, raptor_b, picsize, '0 1 0' * hp + '1 0 0' * (1 - hp), 1, DRAWFLAG_NORMAL);
-     drawpic(hudloc, raptor_g1, picsize, '1 1 1' * energy + '1 0 0' * (1 - energy), 1, DRAWFLAG_NORMAL);
-     drawpic(hudloc, raptor_g2, picsize, '1 1 1' * reload + '1 0 0' *  (1 - reload), 1, DRAWFLAG_NORMAL);
-       if (scoreboard_showscores)
-       {
-               HUD_DrawScoreboard();
-       }
+     HUD_Main(); // always run these functions for alpha checks
+     HUD_DrawScoreboard();
  
- }
- #define waki_h "gfx/vehicles/hud_bg.tga"
- #define waki_b "gfx/vehicles/waki.tga"
- #define waki_e "gfx/vehicles/waki_e.tga"
- #define waki_g "gfx/vehicles/waki_guns.tga"
- #define waki_r "gfx/vehicles/waki_rockets.tga"
- #define waki_s "gfx/vehicles/shiled.tga"
- #define waki_a1 "gfx/hud/sb_rocket.tga"
- #define waki_a2 "gfx/sb_cells.tga"
- void CSQC_WAKIZASHI_HUD()
- {
-       // 0--1 floats. 1 = 100%, 0.6 = 50%.
-       float health, shield, energy, rockets;
-       vector picsize, hudloc;
-     picsize = drawgetimagesize(SPIDER_CROSS);
-     picsize_x *= autocvar_cl_vehicle_spiderbot_cross_size;
-     picsize_y *= autocvar_cl_vehicle_spiderbot_cross_size;
-     drawpic('0.5 0 0' * (vid_conwidth - picsize_x) + '0 0.5 0' * (vid_conheight - picsize_y), SPIDER_CROSS, picsize, '1 1 1', autocvar_cl_vehicle_spiderbot_cross_alpha, DRAWFLAG_NORMAL);
- /*
- const float STAT_VEHICLESTAT_HEALTH  = 60;
- const float STAT_VEHICLESTAT_SHIELD  = 61;
- const float STAT_VEHICLESTAT_ENERGY  = 62;
- const float STAT_VEHICLESTAT_AMMO1   = 63;
- const float STAT_VEHICLESTAT_RELAOD1 = 64;
- const float STAT_VEHICLESTAT_AMMO2   = 65;
- const float STAT_VEHICLESTAT_RELOAD2 = 66;
- */
-     health  = min(getstatf(STAT_VEHICLESTAT_HEALTH),  1);
-       shield  = min(getstatf(STAT_VEHICLESTAT_SHIELD),  1);
-       energy  = min(getstatf(STAT_VEHICLESTAT_ENERGY),  1);
-       rockets = bound(0,getstatf(STAT_VEHICLESTAT_RELOAD1), 1);
-     hudloc_y =  4;
-     hudloc_x = 4;
-     picsize = drawgetimagesize(waki_h) * 0.5;
-     drawpic(hudloc, waki_h, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-     picsize = drawgetimagesize(waki_a2) * 0.7;
-     drawpic(hudloc + '116 92  0', waki_a2, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '145 19  0', strcat(ftos(rint(health * 100)), "%"),'15 15 0','0 1 0', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '175 34  0', strcat(ftos(rint(shield * 100)), "%"),'15 15 0','0 0 1', 1, DRAWFLAG_NORMAL);
-     drawstring(hudloc + '136 102  0', strcat(ftos(rint(energy * 100)), "%"),'14 14 0','1 1 1', 1, DRAWFLAG_NORMAL);
-     picsize = drawgetimagesize(waki_a1) * 0.75;
-     if(rockets == 1)
+     if (scoreboard_active) // scoreboard/accuracy
 -    {
+         HUD_Reset();
 -        // HUD_DrawScoreboard takes care of centerprint_start
 -    }
+     else if (intermission == 2) // map voting screen
      {
-         drawpic(hudloc + '140 55  0', waki_a1, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
-         drawpic(hudloc + '144 59  0', waki_a1, picsize, '1 1 1', 1, DRAWFLAG_NORMAL);
+         HUD_FinaleOverlay();
+         HUD_Reset();
 -
 -        centerprint_start_x = 0;
 -        centerprint_start_y = autocvar_scr_centerpos * vid_conheight;
 -    }
 -    else // hud
 -    {
 -        centerprint_start_x = 0;
 -        centerprint_start_y = autocvar_scr_centerpos * vid_conheight;
      }
-     else
-     {
-         drawpic(hudloc + '140 55  0', waki_a1, picsize, '-1 -1 -1', 1, DRAWFLAG_NORMAL);
-         drawpic(hudloc + '144 59  0', waki_a1, picsize, '-1 -1 -1', 1, DRAWFLAG_NORMAL);
-         drawstring(hudloc + '165 69 0', strcat(ftos(rint(rockets * 100)), "%"),'14 14 0','1 1 0', 1, DRAWFLAG_NORMAL);
-     }
-     picsize = drawgetimagesize(waki_b) * 0.5;
-     hudloc_y = 10.5;
-     hudloc_x = 10.5;
-     drawpic(hudloc, waki_s, picsize, '1 1 1', shield, DRAWFLAG_NORMAL);
-     drawpic(hudloc, waki_b, picsize, '0 1 0' * health + '1 0 0' * (1 - health), 1, DRAWFLAG_NORMAL);
-     drawpic(hudloc, waki_r, picsize, '1 1 1' * rockets + '1 0 0' * (1 - rockets), 1, DRAWFLAG_NORMAL);
-     drawpic(hudloc, waki_e, picsize, '1 1 1' * energy + '1 0 0' *  (1 - energy), 1, DRAWFLAG_NORMAL);
--
        /*
-       p = '0.5 0 0' * (vid_conwidth - (rkt_size * 8));
-       p = p + '0 1 0' * vid_conheight - '0 32 0';
-       // Draw health bar
-       p_y += 8;
-       drawfill(p, '256 0 0' * health + '0 8 0' , '0 0.7 0', 0.75, DRAWFLAG_NORMAL);
-       p_x += 256 * health;
-       drawfill(p, '256 0 0' * (1 - health) + '0 8 0' , '0 0 0', 0.75, DRAWFLAG_NORMAL);
-       // Draw shiled bar
-       p_x -= 256 * health;
-       p_y += 4;
-       drawfill(p, '256 0 0' * shield + '0 4 0' , '0.25 0.25 1', 0.5, DRAWFLAG_NORMAL);
-       // Draw energy
-       //p_x -= 256 * health;
-       p_y -= 8;
-       drawfill(p, '256 0 0' * energy + '0 4 0' , '1 1 1', 0.75, DRAWFLAG_NORMAL);
-       // Draw rockets bar
-       p_y += 12;
-       drawfill(p, '256 0 0' * rockets + '0 4 0' , '1 0 0', 0.75, DRAWFLAG_NORMAL);
-       */
-       if (scoreboard_showscores)
-       {
-               HUD_DrawScoreboard();
-       }
- }
- void CSQC_common_hud(void)
- {
-       // HUD_SortFrags(); done in HUD_Draw
-       float hud;
-       hud = getstati(STAT_HUD);
-       //hud = 10;
        switch(hud)
        {
-               case HUD_NORMAL:
-                       // do some accuracy var caching
-                       float i;
-                       if(!(gametype == GAME_RACE || gametype == GAME_CTS))
-                       {
-                               if(autocvar_accuracy_color_levels != acc_color_levels)
-                               {
-                                       if(acc_color_levels)
-                                               strunzone(acc_color_levels);
-                                       acc_color_levels = strzone(autocvar_accuracy_color_levels);
-                                       acc_levels = tokenize(acc_color_levels);
-                                       if (acc_levels > MAX_ACCURACY_LEVELS)
-                                               acc_levels = MAX_ACCURACY_LEVELS;
-                                       for (i = 0; i < acc_levels; ++i)
-                                               acc_lev[i] = stof(argv(i)) / 100.0;
-                               }
-                               // let know that acc_col[] needs to be loaded
-                               acc_col_x[0] = -1;
-                       }
-                       HUD_Main(); // always run these functions for alpha checks
-                       HUD_DrawScoreboard();
-                       if (scoreboard_active) // scoreboard/accuracy
-                               HUD_Reset();
-                       else if (intermission == 2) // map voting screen
-                       {
-                               HUD_FinaleOverlay();
-                               HUD_Reset();
-                       }
-                       break;
                case HUD_SPIDERBOT:
                        CSQC_SPIDER_HUD();
                        break;
                case HUD_WAKIZASHI:
                        CSQC_WAKIZASHI_HUD();
                        break;
+         case HUD_BUMBLEBEE:
+             CSQC_BUMBLE_HUD();
+             break;
        }
 -      
 -    HUD_DrawCenterPrint();
 -    
+       */
  }
  
  
index ef2cbf6e3387a7d7fede771d6ecff8654db606df,4edfda3ad56149281c1c13cec32d2d7eeecdd946..a33f1f71aa7b4d7a2f771373ea7411119887f515
@@@ -122,6 -122,7 +122,7 @@@ float autocvar_g_balance_tuba_attenuati
  float autocvar_g_balance_tuba_fadetime;
  float autocvar_g_balance_tuba_volume;
  float autocvar_g_warmup_limit;
+ var float autocvar_g_waypointsprite_uppercase = 1;
  var float autocvar_g_waypointsprite_alpha = 1;
  var float autocvar_g_waypointsprite_crosshairfadealpha = 1;
  float autocvar_g_waypointsprite_crosshairfadedistance;
@@@ -137,6 -138,7 +138,7 @@@ float autocvar_g_waypointsprite_minalph
  float autocvar_g_waypointsprite_minscale;
  float autocvar_g_waypointsprite_normdistance;
  var float autocvar_g_waypointsprite_scale = 1;
+ var float autocvar_g_waypointsprite_fontsize = 12;
  float autocvar_g_waypointsprite_timealphaexponent;
  var float autocvar_hud_colorflash_alpha = 0.5;
  float autocvar_hud_configure_bg_minalpha;
@@@ -205,11 -207,6 +207,11 @@@ float autocvar_hud_panel_healtharmor_pr
  float autocvar_hud_panel_healtharmor_progressbar_gfx_lowhealth;
  float autocvar_hud_panel_healtharmor_progressbar_gfx_smooth;
  
 +float autocvar_hud_panel_centerprint;
 +float autocvar_hud_panel_centerprint_align;
 +float autocvar_hud_panel_centerprint_flip;
 +float autocvar_hud_panel_centerprint_fontscale;
 +float autocvar_hud_panel_centerprint_time;
  float autocvar_hud_panel_healtharmor_text;
  float autocvar_hud_panel_infomessages;
  float autocvar_hud_panel_infomessages_flip;
@@@ -324,6 -321,9 +326,6 @@@ var float autocvar_scoreboard_highlight
  var float autocvar_scoreboard_highlight_alpha_self = 0.25;
  float autocvar_scoreboard_offset_left;
  float autocvar_scoreboard_offset_right;
 -float autocvar_scr_centerpos;
 -float autocvar_scr_centersize;
 -float autocvar_scr_centertime;
  float autocvar_v_flipped;
  float autocvar_vid_conheight;
  float autocvar_vid_conwidth;
diff --combined qcsrc/client/hud.qc
index f02af57f66cc7857858302e9a271f90c9404b135,6b11719567d055e4234fd81ddb8344f3ba4316e8..5b73c5f96983c02d571d774588b6477c107d3ad5
@@@ -142,6 -142,183 +142,6 @@@ float stringwidth_nocolors(string s, ve
        return stringwidth(s, FALSE, theSize);
  }
  
 -#define CENTERPRINT_MAX_LINES 30
 -string centerprint_messages[CENTERPRINT_MAX_LINES];
 -float centerprint_width[CENTERPRINT_MAX_LINES];
 -float centerprint_time;
 -float centerprint_expire;
 -float centerprint_num;
 -float centerprint_offset_hint;
 -vector centerprint_fontsize;
 -
 -void centerprint(string strMessage)
 -{
 -      float i, j, n, hcount;
 -      string s;
 -
 -      centerprint_fontsize = HUD_GetFontsize("scr_centersize");
 -
 -      centerprint_expire = min(centerprint_expire, time); // if any of the returns happens, this message will fade out
 -
 -      if(autocvar_scr_centertime <= 0)
 -              return;
 -
 -      if(strMessage == "")
 -              return;
 -
 -      // strip trailing newlines
 -      j = strlen(strMessage) - 1;
 -      while(substring(strMessage, j, 1) == "\n" && j >= 0)
 -              j = j - 1;
 -      strMessage = substring(strMessage, 0, j + 1);
 -
 -      if(strMessage == "")
 -              return;
 -
 -      // strip leading newlines and remember them, they are a hint that the message should be lower on the screen
 -      j = 0;
 -      while(substring(strMessage, j, 1) == "\n" && j < strlen(strMessage))
 -              j = j + 1;
 -      strMessage = substring(strMessage, j, strlen(strMessage) - j);
 -      centerprint_offset_hint = j;
 -
 -      if(strMessage == "")
 -              return;
 -
 -      // if we get here, we have a message. Initialize its height.
 -      centerprint_num = 0;
 -
 -      n = tokenizebyseparator(strMessage, "\n");
 -      i = hcount = 0;
 -      for(j = 0; j < n; ++j)
 -      {
 -              getWrappedLine_remaining = argv(j);
 -              while(getWrappedLine_remaining)
 -              {
 -                      s = getWrappedLine(vid_conwidth * 0.75, centerprint_fontsize, stringwidth_colors);
 -                      if(centerprint_messages[i] != s) // don't fade the same message in, looks stupid
 -                              centerprint_time = time;
 -                      if(centerprint_messages[i])
 -                              strunzone(centerprint_messages[i]);
 -                      centerprint_messages[i] = strzone(s);
 -                      centerprint_width[i] = stringwidth(s, TRUE, centerprint_fontsize);
 -                      ++i;
 -
 -                      // half height for empty lines looks better
 -                      if(s == "")
 -                              hcount += 0.5;
 -                      else
 -                              hcount += 1;
 -
 -                      if(i >= CENTERPRINT_MAX_LINES)
 -                              break;
 -              }
 -      }
 -
 -      float h, havail;
 -      h = centerprint_fontsize_y*hcount;
 -
 -      havail = vid_conheight;
 -      if(autocvar_con_chatpos < 0)
 -              havail -= (-autocvar_con_chatpos + autocvar_con_chat) * autocvar_con_chatsize; // avoid overlapping chat
 -      if(havail > vid_conheight - 70)
 -              havail = vid_conheight - 70; // avoid overlapping HUD
 -
 -#if 0
 -      float forbiddenmin, forbiddenmax, allowedmin, allowedmax, preferred;
 -
 -      // here, the centerprint would cover the crosshair. REALLY BAD.
 -      forbiddenmin = vid_conheight * 0.5 - h - 16;
 -      forbiddenmax = vid_conheight * 0.5 + 16;
 -
 -      allowedmin = scoreboard_bottom;
 -      allowedmax = havail - h;
 -      preferred = (havail - h)/2;
 -
 -
 -      // possible orderings (total: 4! / 4 = 6)
 -      //  allowedmin allowedmax forbiddenmin forbiddenmax
 -      //  forbiddenmin forbiddenmax allowedmin allowedmax
 -      if(allowedmax < forbiddenmin || allowedmin > forbiddenmax)
 -      {
 -              // forbidden doesn't matter in this case
 -              centerprint_start_y = bound(allowedmin, preferred, allowedmax);
 -      }
 -      //  allowedmin forbiddenmin allowedmax forbiddenmax
 -      else if(allowedmin < forbiddenmin && allowedmax < forbiddenmax)
 -      {
 -              centerprint_start_y = bound(allowedmin, preferred, forbiddenmin);
 -      }
 -      //  allowedmin forbiddenmin forbiddenmax allowedmax
 -      else if(allowedmin < forbiddenmin)
 -      {
 -              // make sure the forbidden zone is not covered
 -              if(preferred > (forbiddenmin + forbiddenmax) * 0.5)
 -                      centerprint_start_y = bound(allowedmin, preferred, forbiddenmin);
 -              else
 -                      centerprint_start_y = bound(forbiddenmax, preferred, allowedmin);
 -      }
 -      //  forbiddenmin allowedmin allowedmax forbiddenmax
 -      else if(allowedmax < forbiddenmax)
 -      {
 -              // it's better to leave the allowed zone (overlap with scoreboard) than
 -              // to cover the forbidden zone (crosshair)
 -              if(preferred > (forbiddenmin + forbiddenmax) * 0.5)
 -                      centerprint_start_y = forbiddenmax;
 -              else
 -                      centerprint_start_y = forbiddenmin;
 -      }
 -      //  forbiddenmin allowedmin forbiddenmax allowedmax
 -      else
 -      {
 -              centerprint_start_y = bound(forbiddenmax, preferred, allowedmax);
 -      }
 -#else
 -#endif
 -
 -      centerprint_num = i;
 -
 -      centerprint_expire = time + autocvar_scr_centertime;
 -}
 -
 -void HUD_DrawCenterPrint (void)
 -{
 -      float i;
 -      vector pos;
 -      string ts;
 -      float a, sz;
 -
 -      if(time - centerprint_time < 0.25)
 -              a = (time - centerprint_time) / 0.25;
 -      else
 -              a = bound(0, 1 - 4 * (time - centerprint_expire), 1);
 -
 -      if(a <= 0)
 -              return;
 -
 -      sz = 0.8 + (a / 5);
 -
 -      if(centerprint_num * autocvar_scr_centersize > 24 && scoreboard_active) // 24 = height of Scoreboard text
 -              centerprint_start_y = scoreboard_bottom + centerprint_fontsize_y;
 -
 -      pos = centerprint_start;
 -      for (i=0; i<centerprint_num; i = i + 1)
 -      {
 -              ts = centerprint_messages[i];
 -              drawfontscale = sz * '1 1 0';
 -              pos_x = (vid_conwidth - stringwidth(ts, TRUE, centerprint_fontsize)) * 0.5;
 -              if (ts != "")
 -              {
 -                      drawcolorcodedstring(pos + '0 1 0' * (1 - sz) * 0.5 *centerprint_fontsize_y, ts, centerprint_fontsize, a, DRAWFLAG_NORMAL);
 -                      pos_y = pos_y + centerprint_fontsize_y;
 -              }
 -              else
 -                      // half height for empty lines looks better
 -                      pos_y = pos_y + sz * centerprint_fontsize_y * 0.5;
 -              drawfontscale = '1 1 0';
 -      }
 -}
 -
  void drawstringright(vector position, string text, vector scale, vector rgb, float alpha, float flag)
  {
        position_x -= 2 / 3 * strlen(text) * scale_x;
@@@ -437,7 -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;
        }
  
        HUD_Panel_UpdateCvars(weapons);
 +      HUD_Panel_ApplyFadeAlpha();
  
        if (timeout && time >= weapontime + timeout && !autocvar__hud_configure)
        {
@@@ -843,6 -1019,7 +843,7 @@@ void DrawAmmoItem(vector myPos, vector 
  
  void HUD_Ammo(void)
  {
+     if(hud != HUD_NORMAL) return;
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_ammo) return;
                hud_configure_active_panel = HUD_PANEL_AMMO;
  
        HUD_Panel_UpdateCvars(ammo);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -1038,7 -1214,6 +1039,7 @@@ void HUD_Powerups(void
        }
  
        HUD_Panel_UpdateCvars(powerups);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -1145,6 -1320,7 +1146,7 @@@ 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);
        }
  
        HUD_Panel_UpdateCvars(healtharmor);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -1582,7 -1757,7 +1584,7 @@@ void HUD_KillNotify(string s1, string 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));
                        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)
        }
  }
  
 -#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 ^7%s^1, 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 ^7%s^1, 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!")));
        }
  }
  
@@@ -1916,7 -2105,6 +1930,7 @@@ void HUD_Notify (void
                hud_configure_active_panel = HUD_PANEL_NOTIFY;
  
        HUD_Panel_UpdateCvars(notify);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2230,7 -2418,6 +2244,7 @@@ void HUD_Timer(void
                hud_configure_active_panel = HUD_PANEL_TIMER;
  
        HUD_Panel_UpdateCvars(timer);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2288,7 -2475,6 +2302,7 @@@ void HUD_Radar(void
                hud_configure_active_panel = HUD_PANEL_RADAR;
  
        HUD_Panel_UpdateCvars(radar);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2540,7 -2726,6 +2554,7 @@@ void HUD_Score(void
                hud_configure_active_panel = HUD_PANEL_SCORE;
  
        HUD_Panel_UpdateCvars(score);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2725,7 -2910,6 +2739,7 @@@ void HUD_RaceTimer (void
                hud_configure_active_panel = HUD_PANEL_RACETIMER;
  
        HUD_Panel_UpdateCvars(racetimer);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -2921,7 -3105,6 +2935,7 @@@ void HUD_VoteWindow(void
                return;
  
        HUD_Panel_UpdateCvars(vote);
 +      HUD_Panel_ApplyFadeAlpha();
  
        if(uid2name_dialog)
        {
@@@ -3677,7 -3860,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;
@@@ -3732,7 -3914,6 +3746,7 @@@ void HUD_DrawPressedKeys(void
  
  
        HUD_Panel_UpdateCvars(pressedkeys);
 +      HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
        mySize = panel_size;
@@@ -3797,7 -3978,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
        {
@@@ -3873,7 -4053,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;
@@@ -3936,7 -4115,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;
@@@ -4122,7 -4300,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)
                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 = 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])
 +              {
 +                      if(centerprint_messages[j])
 +                              strunzone(centerprint_messages[j]);
 +                      centerprint_messages[j] = strzone(strMessage);
 +
 +                      centerprint_time[j] = duration;
 +                      centerprint_expire_time[j] = time + duration;
 +                      centerprint_countdown_num[j] = countdown_num;
 +                      return;
 +              }
 +      }
 +
 +      --cpm_index;
 +      if (cpm_index == -1)
 +              cpm_index = CENTERPRINT_MAX_MSGS - 1;
 +      if(centerprint_messages[cpm_index])
 +              strunzone(centerprint_messages[cpm_index]);
 +      centerprint_messages[cpm_index] = strzone(strMessage);
 +      centerprint_msgID[cpm_index] = new_id;
 +      centerprint_time[cpm_index] = duration;
 +      centerprint_expire_time[cpm_index] = time + duration;
 +      centerprint_countdown_num[cpm_index] = countdown_num;
 +}
 +
 +void centerprint(string strMessage)
 +{
 +      centerprint_generic(0, strMessage, autocvar_hud_panel_centerprint_time, 0);
 +}
 +
 +// CenterPrint (#16)
 +//
 +void HUD_CenterPrint (void)
 +{
 +      if(!autocvar__hud_configure)
 +      {
 +              if(!autocvar_hud_panel_centerprint) return;
 +      }
 +      else
 +              hud_configure_active_panel = HUD_PANEL_CENTERPRINT;
 +
 +      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_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_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
@@@ -4579,8 -4559,6 +4593,8 @@@ switch (id) {
                 HUD_InfoMessages(); break;\
        case (HUD_PANEL_PHYSICS):\
                 HUD_Physics(); break;\
 +      case (HUD_PANEL_CENTERPRINT):\
 +               HUD_CenterPrint(); break;\
  } ENDS_WITH_CURLY_BRACE
  
  void HUD_Main (void)
        else if(autocvar__menu_alpha == 0 && scoreboard_fade_alpha == 0)
                hud_fade_alpha = 1;
  
 +      // panels that we want to be active together with the scoreboard
 +      // they must call HUD_Panel_ApplyFadeAlpha(); only when showing the menu
 +      if(scoreboard_fade_alpha == 1)
 +      {
 +              HUD_CenterPrint();
 +              return;
 +      }
 +
        if(!autocvar__hud_configure && !hud_fade_alpha)
                return;
  
diff --combined qcsrc/client/main.qh
index 689722a1f6a9207e62d613b08546865bf8b9af79,6788daad18d229f17499c3f7f38b425d839252d5..62475f9fb1f6bd33b8c01bd1fe7880344bd229a1
@@@ -144,7 -144,6 +144,7 @@@ float camera_roll
  vector camera_direction;
  
  void centerprint(string strMessage);
 +void centerprint_generic(float new_id, string strMessage, float duration, float countdown_num);
  
  #define ALPHA_MIN_VISIBLE 0.003
  
@@@ -165,3 -164,5 +165,5 @@@ float g_balance_electro_secondary_bounc
  float g_trueaim_minrange;
  
  entity entcs_receiver[255]; // 255 is the engine limit on maxclients
+ float hud;
index 8dc7a75464251216f3c455e46517f01334033437,fcce8a70bbfcfab6b76ad6b3be16a80f35634113..47f6c3a6a74be93179b674039f9731e66b603a9a
@@@ -64,6 -64,7 +64,7 @@@ const float TE_CSQC_WEAPONCOMPLAIN = 11
  const float TE_CSQC_NEX_SCOPE = 116;
  const float TE_CSQC_MINELAYER_MAXMINES = 117;
  const float TE_CSQC_HAGAR_MAXROCKETS = 118;
+ const float TE_CSQC_VEHICLESETUP = 119;
  
  const float RACE_NET_CHECKPOINT_HIT_QUALIFYING = 0; // byte checkpoint, short time, short recordtime, string recordholder
  const float RACE_NET_CHECKPOINT_CLEAR = 1;
@@@ -82,7 -83,6 +83,7 @@@ const float RANKINGS_CNT = 15
  
  const float CSQC_KILLNOTIFY = 0;
  const float CSQC_CENTERPRINT = 1;
 +const float CSQC_CENTERPRINT_GENERIC = 2;
  
  const float ENT_CLIENT = 0;
  const float ENT_CLIENT_DEAD = 1;
@@@ -119,10 -119,13 +120,13 @@@ const float ENT_CLIENT_SHOWNAMES = 31
  const float ENT_CLIENT_WARPZONE_TELEPORTED = 32;
  
  const float ENT_CLIENT_TURRET = 40;
+ const float ENT_CLIENT_AUXILIARYXHAIR = 50;
+ const float ENT_CLIENT_VEHICLE = 60;
  
  const float SPRITERULE_DEFAULT = 0;
  const float SPRITERULE_TEAMPLAY = 1;
  
+ const float RADARICON_NONE = 0;
  const float RADARICON_FLAG = 1;
  const float RADARICON_FLAGCARRIER = 1;
  const float RADARICON_HERE = 1; // TODO make these 3 and 4, and make images for them
@@@ -134,6 -137,7 +138,7 @@@ const float RADARICON_GENERATOR = 1
  const float RADARICON_OBJECTIVE = 1;
  const float RADARICON_DOMPOINT = 1;
  const float RADARICON_POWERUP = 1;
+ const float RADARICON_TAGGED = 1;
  
  ///////////////////////////
  // key constants
@@@ -334,9 -338,13 +339,13 @@@ const float CTF_STATE_DEFEND = 2
  const float CTF_STATE_COMMANDER = 3;
  
  const float HUD_NORMAL = 0;
- const float HUD_SPIDERBOT = 10;
- const float HUD_WAKIZASHI = 11;
- const float HUD_RAPTOR    = 12;
+ const float HUD_VEHICLE_FIRST   = 10;
+ const float HUD_SPIDERBOT       = 10;
+ const float HUD_WAKIZASHI       = 11;
+ const float HUD_RAPTOR          = 12;
+ const float HUD_BUMBLEBEE       = 13;
+ const float HUD_VEHICLE_LAST    = 13;
  const vector eX = '1 0 0';
  const vector eY = '0 1 0';
  const vector eZ = '0 0 1';
@@@ -359,6 -367,7 +368,7 @@@ const float STAT_PINKALIVE = 103
  const float STAT_FROZEN = 104;
  const float STAT_REVIVE_PROGRESS = 105;
  
  const float STAT_DOM_TOTAL_PPS = 100;
  const float STAT_DOM_PPS_RED = 101;
  const float STAT_DOM_PPS_BLUE = 102;
@@@ -368,9 -377,6 +378,6 @@@ const float STAT_DOM_PPS_YELLOW = 104
  //const float STAT_SPIDERBOT_AIM     53 // compressShotOrigin
  //const float STAT_SPIDERBOT_TARGET  54 // compressShotOrigin
  
  // moved that here so the client knows the max.
  // # of maps, I'll use arrays for them :P
  #define MAPVOTE_COUNT 10
@@@ -500,6 -506,13 +507,13 @@@ float PROJECTILE_FIREBALL = 21
  float PROJECTILE_FIREMINE = 22;
  float PROJECTILE_BULLET_GLOWING_TRACER = 23;
  
+ float PROJECTILE_RAPTORCANNON   = 24;
+ float PROJECTILE_RAPTORBOMB     = 25;
+ float PROJECTILE_RAPTORBOMBLET  = 26;
+ float PROJECTILE_SPIDERROCKET   = 27;
+ float PROJECTILE_WAKIROCKET     = 28;
+ float PROJECTILE_WAKICANNON     = 29;
  float SPECIES_HUMAN        =  0;
  float SPECIES_ROBOT_SOLID  =  1;
  float SPECIES_ALIEN        =  2;
@@@ -529,18 -542,23 +543,23 @@@ float DEATH_MIRRORDAMAGE = 10014
  float DEATH_TOUCHEXPLODE = 10015;
  float DEATH_CHEAT = 10016;
  float DEATH_FIRE = 10017;
- float DEATH_TURRET = 10020;
  float DEATH_QUIET = 10021;
  float DEATH_HEADSHOT = 10022;
  
- float DEATH_SBMINIGUN = 10030;
- float DEATH_SBROCKET  = 10031;
- float DEATH_SBCRUSH   = 10032;
- float DEATH_SBBLOWUP  = 10033;
- float DEATH_WAKIGUN    = 10040;
- float DEATH_WAKIROCKET = 10041;
- float DEATH_WAKIBLOWUP = 10042;
+ float  DEATH_VHFIRST       = 10030;
+ float  DEATH_VHCRUSH       = 10030;
+ float  DEATH_SBMINIGUN     = 10031;
+ float  DEATH_SBROCKET      = 10032;
+ float  DEATH_SBBLOWUP      = 10033;
+ float  DEATH_WAKIGUN       = 10034;
+ float  DEATH_WAKIROCKET    = 10035;
+ float  DEATH_WAKIBLOWUP    = 10036;
+ float  DEATH_RAPTOR_CANNON = 10037;
+ float  DEATH_RAPTOR_BOMB   = 10038;
+ float  DEATH_RAPTOR_BOMB_SPLIT = 10039;
+ float  DEATH_RAPTOR_DEATH  = 10040;
+ float  DEATH_VHLAST        = 10040;
+ #define DEATH_ISVEHICLE(t)  ((t) >= DEATH_VHFIRST && (t) <= DEATH_VHLAST)
  
  float DEATH_GENERIC = 10050;
  
@@@ -548,6 -566,20 +567,20 @@@ float DEATH_WEAPON = 10100
  
  float DEATH_CUSTOM = 10300;
  
+ float DEATH_TURRET                  = 10500;
+ float DEATH_TURRET_EWHEEL           = 10501;
+ float DEATH_TURRET_FLAC             = 10502;
+ float DEATH_TURRET_MACHINEGUN       = 10503;
+ float DEATH_TURRET_WALKER_GUN       = 10504;
+ float DEATH_TURRET_WALKER_MEELE     = 10505;
+ float DEATH_TURRET_WALKER_ROCKET    = 10506;
+ float DEATH_TURRET_HELLION          = 10507;
+ float DEATH_TURRET_HK               = 10508;
+ float DEATH_TURRET_MLRS             = 10509;
+ float DEATH_TURRET_PLASMA           = 10510;
+ float DEATH_TURRET_PHASER           = 10511;
+ float DEATH_TURRET_TESLA            = 10512;
+ float DEATH_TURRET_LAST            = 10512;
  
  float DEATH_WEAPONMASK = 0xFF;
  float DEATH_HITTYPEMASK = 0x1F00; // which is WAY below 10000 used for normal deaths
@@@ -558,6 -590,7 +591,7 @@@ float HITTYPE_HEADSHOT = 0x800
  float HITTYPE_RESERVED = 0x1000; // unused yet
  
  // macros to access these
+ #define DEATH_ISTURRET(t)            ((t) >= DEATH_TURRET && (t) <= DEATH_TURRET_LAST)
  #define DEATH_ISSPECIAL(t)            ((t) >= DEATH_SPECIAL_START)
  #define DEATH_WEAPONOFWEAPONDEATH(t)  ((t) & DEATH_WEAPONMASK)
  #define DEATH_ISWEAPON(t,w)           (!DEATH_ISSPECIAL(t) && DEATH_WEAPONOFWEAPONDEATH(t) == (w))
@@@ -581,18 -614,6 +615,18 @@@ float WATERLEVEL_SUBMERGED = 3
  
  float MAX_SHOT_DISTANCE = 32768;
  
 +//centerprint ID list
 +float CPID_TEAMCHANGE = 1;
 +float CPID_KILL = 2;
 +float CPID_MINSTA_FINDAMMO = 3;
 +float CPID_NIX_WPNCHANGE = 4;
 +float CPID_DISCONNECT_IDLING = 5;
 +float CPID_ROUND_STARTING = 6;
 +float CPID_GAME_STARTING = 7;
 +float CPID_TIMEOUT_COUNTDOWN = 8;
 +float CPID_MOTD = 9;
 +float CPID_KH_MSG = 10;
 +
  // CSQC centerprint/notify message types
  float MSG_SUICIDE = 0;
  float MSG_KILL = 1;
@@@ -667,8 -688,7 +701,8 @@@ float HUD_PANEL_CHAT               = 12
  float HUD_PANEL_ENGINEINFO    = 13;
  float HUD_PANEL_INFOMESSAGES  = 14;
  float HUD_PANEL_PHYSICS       = 15;
 -float HUD_PANEL_NUM           = 16; // always last panel id + 1, please increment when adding a new panel
 +float HUD_PANEL_CENTERPRINT   = 16;
 +float HUD_PANEL_NUM           = 17; // always last panel id + 1, please increment when adding a new panel
  
  string HUD_PANELNAME_WEAPONS          = "weapons";
  string HUD_PANELNAME_AMMO             = "ammo";
@@@ -686,7 -706,6 +720,7 @@@ string HUD_PANELNAME_CHAT          = "chat"
  string HUD_PANELNAME_ENGINEINFO               = "engineinfo";
  string HUD_PANELNAME_INFOMESSAGES     = "infomessages";
  string HUD_PANELNAME_PHYSICS  = "physics";
 +string HUD_PANELNAME_CENTERPRINT      = "centerprint";
  
  float HUD_MENU_ENABLE         = 0;
  
index 01f7459e73db43beb1ad13947afd0308b31d338c,1261e9d188ecc44f5f1e4b1973ea187760f65bf0..078828f58ae64fd9b6a32d737cbeaf4d557c539d
@@@ -596,7 -596,7 +596,7 @@@ void FixPlayermodel()
  void PutObserverInServer (void)
  {
        entity  spot;
+     self.hud = HUD_NORMAL;
        race_PreSpawnObserver();
  
        spot = SelectSpawnPoint (TRUE);
        DropAllRunes(self);
        MUTATOR_CALLHOOK(MakePlayerObserver);
  
 +      if (g_minstagib)
 +              minstagib_stop_countdown();
 +
        Portal_ClearAll(self);
  
        if(self.alivetime)
                self.alivetime = 0;
        }
  
+       if(self.vehicle)
+           vehicles_exit(VHEF_RELESE);
        if(self.flagcarried)
                DropFlag(self.flagcarried, world, world);
  
@@@ -1267,6 -1267,16 +1270,16 @@@ void ClientKill_Now_TeamChange(
  
  void ClientKill_Now()
  {
+       if(self.vehicle)
+       {
+           vehicles_exit(VHEF_RELESE);
+           if(!self.killindicator_teamchange)
+           {
+             self.vehicle_health = -1;
+             Damage(self, self, self, 1 , DEATH_KILL, self.origin, '0 0 0');           
+           }
+       }
+       
        remove(self.killindicator);
        self.killindicator = world;
  
@@@ -1306,6 -1316,17 +1319,6 @@@ void KillIndicator_Think(
                {
                        if(self.cnt <= 10)
                                AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
 -                      if(self.owner.killindicator_teamchange)
 -                      {
 -                              if(self.owner.killindicator_teamchange == -1)
 -                                      centerprint(self.owner, strcat("Changing team in ", ftos(self.cnt), " seconds"));
 -                              else if(self.owner.killindicator_teamchange == -2)
 -                                      centerprint(self.owner, strcat("Spectating in ", ftos(self.cnt), " seconds"));
 -                              else
 -                                      centerprint(self.owner, strcat("Changing to ", ColoredTeamName(self.owner.killindicator_teamchange), " in ", ftos(self.cnt), " seconds"));
 -                      }
 -                      else
 -                              centerprint(self.owner, strcat("^1Suicide in ", ftos(self.cnt), " seconds"));
                }
                self.nextthink = time + 1;
                self.cnt -= 1;
@@@ -1376,31 -1397,14 +1389,31 @@@ void ClientKill_TeamChange (float targe
        if(self.killindicator)
        {
                if(targetteam == 0) // just die
 +              {
                        self.killindicator.colormod = '0 0 0';
 +                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                              Send_CSQC_Centerprint_Generic(self, CPID_KILL, "^1Suicide in %d seconds", 1, self.killindicator.cnt);
 +              }
                else if(targetteam == -1) // auto
 +              {
                        self.killindicator.colormod = '0 1 0';
 +                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Changing team in %d seconds", 1, self.killindicator.cnt);
 +              }
                else if(targetteam == -2) // spectate
 +              {
                        self.killindicator.colormod = '0.5 0.5 0.5';
 +                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "Spectating in %d seconds", 1, self.killindicator.cnt);
 +              }
                else
 +              {
                        self.killindicator.colormod = TeamColor(targetteam);
 +                      if(clienttype(self) == CLIENTTYPE_REAL)
 +                              Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt);
 +              }
        }
 +
  }
  
  void ClientKill (void)
@@@ -1578,7 -1582,7 +1591,7 @@@ void ClientConnect (void
        playerdemo_init();
  
        anticheat_init();
-       
        race_PreSpawnObserver();
  
        //if(g_domination)
  
        bprint("\n");
  
 -      self.welcomemessage_time = 0;
 -
        stuffcmd(self, strcat(clientstuff, "\n"));
        stuffcmd(self, strcat("exec maps/", mapname, ".cfg\n"));
        stuffcmd(self, "cl_particles_reloadeffects\n");
                set_dom_state(self);
  
        CheatInitClient();
 +
 +      if(!autocvar_g_campaign)
 +              Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
  }
  
  /*
@@@ -1800,6 -1803,9 +1813,9 @@@ Called when a client disconnects from t
  void ReadyCount();
  void ClientDisconnect (void)
  {
+       if(self.vehicle)
+           vehicles_exit(VHEF_RELESE);
        if not(self.flags & FL_CLIENT)
        {
                print("Warning: ClientDisconnect without ClientConnect\n");
@@@ -1982,11 -1988,52 +1998,11 @@@ void play_countdown(float finished, str
                                sound (self, CHAN_AUTO, samp, VOL_BASE, ATTN_NORM);
  }
  
 -/**
 - * When sv_timeout is used this function returs strings like
 - * "Timeout begins in 2 seconds!\n" or "Timeout ends in 23 seconds!\n".
 - * Called by centerprint functions
 - * @param addOneSecond boolean, set to 1 if the welcome-message centerprint asks for the text
 - */
 -string getTimeoutText(float addOneSecond) {
 -      if (!autocvar_sv_timeout || !timeoutStatus)
 -              return "";
 -
 -      local string retStr;
 -      if (timeoutStatus == 1) {
 -              if (addOneSecond == 1) {
 -                      retStr = strcat("Timeout begins in ", ftos(remainingLeadTime + 1), " seconds!\n");
 -              }
 -              else {
 -                      retStr = strcat("Timeout begins in ", ftos(remainingLeadTime), " seconds!\n");
 -              }
 -              return retStr;
 -      }
 -      else if (timeoutStatus == 2) {
 -              if (addOneSecond) {
 -                      retStr = strcat("Timeout ends in ", ftos(remainingTimeoutTime + 1), " seconds!\n");
 -                      //don't show messages like "Timeout ends in 0 seconds"...
 -                      if ((remainingTimeoutTime + 1) > 0)
 -                              return retStr;
 -                      else
 -                              return "";
 -              }
 -              else {
 -                      retStr = strcat("Timeout ends in ", ftos(remainingTimeoutTime), " seconds!\n");
 -                      //don't show messages like "Timeout ends in 0 seconds"...
 -                      if (remainingTimeoutTime > 0)
 -                              return retStr;
 -                      else
 -                              return "";
 -              }
 -      }
 -      else return "";
 -}
 -
  void player_powerups (void)
  {
        // add a way to see what the items were BEFORE all of these checks for the mutator hook
        olditems = self.items;
-       
        if((self.items & IT_USING_JETPACK) && !self.deadflag)
        {
                SoundEntity_StartSound(self, CHAN_PLAYER, "misc/jetpack_fly.wav", VOL_BASE, autocvar_g_jetpack_attenuation);
  
        if(!self.modelindex || self.deadflag) // don't apply the flags if the player is gibbed
                return;
-       
        Fire_ApplyDamage(self);
        Fire_ApplyEffect(self);
  
                if (time < self.spawnshieldtime)
                        self.effects = self.effects | (EF_ADDITIVE | EF_FULLBRIGHT);
        }
-       
        MUTATOR_CALLHOOK(PlayerPowerups);
  }
  
@@@ -2323,17 -2370,40 +2339,40 @@@ void SpectateCopy(entity spectatee) 
        self.dmg_save = spectatee.dmg_save;
        self.dmg_inflictor = spectatee.dmg_inflictor;
        self.angles = spectatee.v_angle;
-       self.fixangle = TRUE;
+       //self.fixangle = TRUE;
        setorigin(self, spectatee.origin);
        setsize(self, spectatee.mins, spectatee.maxs);
        SetZoomState(spectatee.zoomstate);
  
        anticheat_spectatecopy(spectatee);
+       //self.vehicle = spectatee.vehicle;
+       self.hud = spectatee.hud;
+       if(spectatee.vehicle)
+     {
+         setorigin(self, spectatee.origin);
+         self.velocity = spectatee.vehicle.velocity;
+         //self.v_angle += spectatee.vehicle.angles;
+         //self.v_angle_x *= -1;
+         self.vehicle_health = spectatee.vehicle_health;
+         self.vehicle_shield = spectatee.vehicle_shield;
+         self.vehicle_energy = spectatee.vehicle_energy;
+         self.vehicle_ammo1 = spectatee.vehicle_ammo1;
+         self.vehicle_ammo2 = spectatee.vehicle_ammo2;
+         self.vehicle_reload1 = spectatee.vehicle_reload1;
+         self.vehicle_reload2 = spectatee.vehicle_reload2;
+         
+         msg_entity = self;
+         WriteByte (MSG_ONE, SVC_SETVIEWPORT);
+         WriteEntity(MSG_ONE, spectatee);
+         //self.tur_head = spectatee.vehicle.vehicle_viewport;
+     }
  }
  
  float SpectateUpdate() {
        if(!self.enemy)
-               return 0;
+           return 0;           
  
        if (self == self.enemy)
                return 0;
@@@ -2356,17 -2426,28 +2395,28 @@@ float SpectateNext() 
                self.enemy = other;
  
        if(self.enemy.classname == "player") {
-               msg_entity = self;
-               WriteByte(MSG_ONE, SVC_SETVIEW);
-               WriteEntity(MSG_ONE, self.enemy);
-               //stuffcmd(self, "set viewsize $tmpviewsize \n");
-               self.movetype = MOVETYPE_NONE;
-               accuracy_resend(self);
-               if(!SpectateUpdate())
-                       PutObserverInServer();
-               return 1;
+           if(self.enemy.vehicle)
+           {      
+             msg_entity = self;
+             WriteByte(MSG_ONE, SVC_SETVIEWPORT);
+             WriteEntity(MSG_ONE, self.enemy);
+             //stuffcmd(self, "set viewsize $tmpviewsize \n");
+             self.movetype = MOVETYPE_NONE;
+             accuracy_resend(self);
+           }
+           else 
+           {           
+             msg_entity = self;
+             WriteByte(MSG_ONE, SVC_SETVIEW);
+             WriteEntity(MSG_ONE, self.enemy);
+             //stuffcmd(self, "set viewsize $tmpviewsize \n");
+             self.movetype = MOVETYPE_NONE;
+             accuracy_resend(self);
+             if(!SpectateUpdate())
+                 PutObserverInServer();
+         }
+         return 1;
        } else {
                return 0;
        }
@@@ -2416,7 -2497,7 +2466,7 @@@ void LeaveSpectatorMode(
                                bprint ("^4", self.netname, "^4 is playing now\n");
  
                        if(!autocvar_g_campaign)
 -                              centerprint(self,""); // clear MOTD
 +                              Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); // clear MOTD
  
                        return;
                } else {
        }
        else {
                //player may not join because of g_maxplayers is set
 -              centerprint_atprio(self, CENTERPRIO_MAPVOTE, PREVENT_JOIN_TEXT);
 +              centerprint(self, PREVENT_JOIN_TEXT);
        }
  }
  
@@@ -2501,6 -2582,7 +2551,6 @@@ void ObserverThink(
                        }
                }
        }
 -      PrintWelcomeMessage(self);
  }
  
  void SpectatorThink()
                }
        }
  
 -      PrintWelcomeMessage(self);
        self.flags |= FL_CLIENT | FL_NOTARGET;
  }
  
@@@ -2549,6 -2632,12 +2599,12 @@@ void PlayerUseKey(
        if(self.classname != "player")
                return;
  
+       if(self.vehicle)
+       {
+         vehicles_exit(VHEF_NORMAL);
+         return;
+       }
+       
        // a use key was pressed; call handlers
        if(ctf_usekey())
                return;
@@@ -2569,7 -2658,6 +2625,7 @@@ Called every frame for each client befo
  void() ctf_setstatus;
  void() nexball_setstatus;
  .float items_added;
 +.float motd_actived_time; // used for both motd and campaign_message
  void PlayerPreThink (void)
  {
        WarpZone_PlayerPhysics_FixVAngle();
                PlayerUseKey();
        self.usekeypressed = self.BUTTON_USE;
  
 +      if (self.motd_actived_time == 0) {
 +              if (autocvar_g_campaign) {
 +                      if (self.classname == "player" && self.BUTTON_INFO) {
 +                              self.motd_actived_time = time;
 +                              Send_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, 999, 0);
 +                      }
 +              } else {
 +                      if ((self.classname == "player" || time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
 +                              self.motd_actived_time = time;
 +                              Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), 999, 0);
 +                      }
 +              }
 +      } else { // showing MOTD or campaign message
 +              if (autocvar_g_campaign) {
 +                      if (self.classname == "player") {
 +                              if (self.BUTTON_INFO)
 +                                      self.motd_actived_time = time;
 +                              else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
 +                                      self.motd_actived_time = 0;
 +                                      Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
 +                              }
 +                      }
 +              } else {
 +                      if (self.classname == "player" || (time - self.jointime) > autocvar_welcome_message_time) {
 +                              if (self.BUTTON_INFO)
 +                                      self.motd_actived_time = time;
 +                              else if (time - self.motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released
 +                                      self.motd_actived_time = 0;
 +                                      Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD);
 +                              }
 +                      }
 +              }
 +      }
 +
        if(self.classname == "player") {
  //            if(self.netname == "Wazat")
  //                    bprint(self.classname, "\n");
  
                CheckRules_Player();
  
 -              PrintWelcomeMessage(self);
 -
                if (intermission_running)
                {
                        IntermissionThink ();   // otherwise a button could be missed between
                        player_powerups();
                }
  
 +              if (g_minstagib)
 +                      minstagib_ammocheck();
 +
                if (self.deadflag != DEAD_NO)
                {
                        float button_pressed, force_respawn;
                        }
                        return;
                }
 +              // FIXME from now on self.deadflag is always 0 (and self.health is never < 1)
 +              // so (self.deadflag == DEAD_NO) is always true in the code below
  
                if(g_touchexplode)
                if(time > self.touchexplode_time)
                if(frametime)
                        player_anim();
  
 -              if (g_minstagib)
 -                      minstagib_ammocheck();
 -
                if(g_ctf)
                        ctf_setstatus();
  
@@@ -3032,21 -3086,7 +3088,21 @@@ void PlayerPostThink (void
        {
                // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero).
                float timeleft;
 +              if (time - self.parm_idlesince < 1) // instead of (time == self.parm_idlesince) to support sv_maxidle <= 10
 +              {
 +                      if(self.idlekick_lasttimeleft)
 +                      {
 +                              Send_CSQC_Centerprint_Generic_Expire(self, CPID_DISCONNECT_IDLING);
 +                              self.idlekick_lasttimeleft = 0;
 +                      }
 +                      return;
 +              }
                timeleft = ceil(sv_maxidle - (time - self.parm_idlesince));
 +              if(timeleft == min(10, sv_maxidle - 1)) // - 1 to support sv_maxidle <= 10
 +              {
 +                      if(!self.idlekick_lasttimeleft)
 +                              Send_CSQC_Centerprint_Generic(self, CPID_DISCONNECT_IDLING, "^3Stop idling!\n^3Disconnecting in %d seconds...", 1, timeleft);
 +              }
                if(timeleft <= 0)
                {
                        bprint("^3", self.netname, "^3 was kicked for idling.\n");
                else if(timeleft <= 10)
                {
                        if(timeleft != self.idlekick_lasttimeleft)
 -                      {
 -                              centerprint_atprio(self, CENTERPRIO_IDLEKICK, strcat("^3Stop idling!\n^3Disconnecting in ", ftos(timeleft), "..."));
 -                              AnnounceTo(self, strcat(ftos(timeleft), ""));
 -                      }
 -              }
 -              else
 -              {
 -                      centerprint_expire(self, CENTERPRIO_IDLEKICK);
 +                              AnnounceTo(self, ftos(timeleft));
 +                      self.idlekick_lasttimeleft = timeleft;
                }
 -              self.idlekick_lasttimeleft = timeleft;
        }
  
  #ifdef TETRIS
  
        if(self.waypointsprite_attachedforcarrier)
                WaypointSprite_UpdateHealth(self.waypointsprite_attachedforcarrier, '1 0 0' * healtharmor_maxdamage(self.health, self.armorvalue, autocvar_g_balance_armor_blockpercent));
-       
        if(self.classname == "player" && self.deadflag == DEAD_NO && autocvar_r_showbboxes)
        {
                if(!self.showheadshotbbox)
diff --combined qcsrc/server/ctf.qc
index d76eba938da2dc96af647ba9ca3d26ea0734b63a,7edfe9337185601a50019e2b9c6eab592eee2e92..df44f5d2e8ab2861ab1409f731512df0db2cd921
@@@ -49,7 -49,7 +49,7 @@@ float ctf_captureshield_shielded(entit
  
        // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
        // use this rule here
-       
        if(players_worseeq >= players_total * captureshield_max_ratio)
                return FALSE;
  
@@@ -66,12 -66,12 +66,12 @@@ void ctf_captureshield_update(entity p
                {
                        if(should)
                        {
 -                              centerprint_atprio(p, CENTERPRIO_SHIELDING, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.");
 +                              centerprint(p, "^3You are now ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Make some defensive scores before trying again.");
                                // TODO csqc notifier for this
                        }
                        else
                        {
 -                              centerprint_atprio(p, CENTERPRIO_SHIELDING, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.");
 +                              centerprint(p, "^3You are now free.\n\n^3Feel free to ^1try to capture^3 the flag again\n^3if you think you will succeed.");
                                // TODO csqc notifier for this
                        }
                        p.ctf_captureshielded = should;
@@@ -99,7 -99,7 +99,7 @@@ void ctf_captureshield_touch(
        mymid = (self.absmin + self.absmax) * 0.5;
        othermid = (other.absmin + other.absmax) * 0.5;
        Damage(other, self, self, 0, DEATH_HURTTRIGGER, mymid, normalize(othermid - mymid) * captureshield_force);
 -      centerprint_atprio(other, CENTERPRIO_SHIELDING, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.");
 +      centerprint(other, "^3You are ^4shielded^3 from the flag\n^3for ^1too many unsuccessful attempts^3 to capture.\n\n^3Get some defensive scores before trying again.");
  }
  
  void ctf_flag_spawnstuff()
        self.basewaypoint = self.nearestwaypoint;
  
        if(self.team == COLOR_TEAM1)
-       {
-               WaypointSprite_SpawnFixed("redbase", self.origin + '0 0 61', self, sprite);
-               WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_FLAG, colormapPaletteColor(COLOR_TEAM1 - 1, FALSE));
-       }
+               WaypointSprite_SpawnFixed("redbase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(COLOR_TEAM1 - 1, FALSE));
        else
-       {
-               WaypointSprite_SpawnFixed("bluebase", self.origin + '0 0 61', self, sprite);
-               WaypointSprite_UpdateTeamRadar(self.sprite, RADARICON_FLAG, colormapPaletteColor(COLOR_TEAM2 - 1, FALSE));
-       }
+               WaypointSprite_SpawnFixed("bluebase", self.origin + '0 0 61', self, sprite, RADARICON_FLAG, colormapPaletteColor(COLOR_TEAM2 - 1, FALSE));
  }
  
  float ctf_score_value(string parameter)
@@@ -296,11 -290,11 +290,11 @@@ void DropFlag(entity e, entity penalty_
        ctf_captureshield_update(p, 0); // shield only
        e.playerid = attacker.playerid;
        e.ctf_droptime = time;
-       WaypointSprite_Spawn("flagdropped", 0, 0, e, '0 0 1' * 61, world, COLOR_TEAM1 + COLOR_TEAM2 - e.team, e, waypointsprite_attachedforcarrier, FALSE);
+       WaypointSprite_Spawn("flagdropped", 0, 0, e, '0 0 1' * 61, world, COLOR_TEAM1 + COLOR_TEAM2 - e.team, e, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAG, '0 1 1');
+       WaypointSprite_Ping(e.waypointsprite_attachedforcarrier);
        
        if(p.waypointsprite_attachedforcarrier)
        {
-               WaypointSprite_Ping(p.waypointsprite_attachedforcarrier);
                WaypointSprite_DetachCarrier(p);
        }
        else
@@@ -515,10 -509,10 +509,10 @@@ void FlagTouch(
        {
                if (other.next_take_time > time)
                        return;
-                       
                if (autocvar_g_ctf_flag_pickup_effects) // pickup effect
                        pointparticles(particleeffectnum("smoke_ring"), 0.5 * (self.absmin + self.absmax), '0 0 0', 1);
-                       
                // pick up
                self.flagpickuptime = time; // used for timing runs
                self.speedrunning = other.speedrunning; // if speedrunning, flag will self-return and teleport the owner back after the record
                self.movetype = MOVETYPE_NONE;
                setorigin(self, FLAG_CARRY_POS);
                setattachment(self, other, "");
-               WaypointSprite_AttachCarrier("flagcarrier", other);
-               WaypointSprite_UpdateTeamRadar(other.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '1 1 0');
+               WaypointSprite_AttachCarrier("flagcarrier", other, RADARICON_FLAGCARRIER, '1 1 0');
                WaypointSprite_Ping(self.sprite);
  
                return;
  
                        if (autocvar_g_ctf_flag_pickup_effects) // field pickup effect
                                pointparticles(particleeffectnum("smoke_ring"), 0.5 * (self.absmin + self.absmax), '0 0 0', 1);
-                       
                        // pick up
                        self.solid = SOLID_NOT;
                        setorigin(self, self.origin); // relink
                        setattachment(self, other, "");
                        self.damageforcescale = 0;
                        self.takedamage = DAMAGE_NO;
-                       WaypointSprite_AttachCarrier("flagcarrier", other);
-                       WaypointSprite_UpdateTeamRadar(other.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '1 1 0');
+                       WaypointSprite_AttachCarrier("flagcarrier", other, RADARICON_FLAGCARRIER, '1 1 0');
                }
        }
  };
@@@ -742,7 -734,7 +734,7 @@@ void item_flag_postspawn(
                if(self.team == COLOR_TEAM2)
                        // Blue
                        self.glow_color = 210;
-                       
                self.glow_size = 25;
                self.glow_trail = 1;
        }
@@@ -1087,7 -1079,7 +1079,7 @@@ entity(float cteam) ctf_team_has_comman
        entity pl;
        if(cteam != COLOR_TEAM1 || cteam != COLOR_TEAM2)
                return world;
-       
        FOR_EACH_REALPLAYER(pl) {
                if(pl.team == cteam && pl.iscommander) {
                        return pl;
@@@ -1105,7 -1097,7 +1097,7 @@@ void(entity e, float st) ctf_setstate 
  void(float cteam) ctf_new_commander =
  {
        entity pl, plmax;
-       
        plmax = world;
        FOR_EACH_REALPLAYER(pl) {
                if(pl.team == cteam) {
  void() ctf_clientconnect =
  {
        self.iscommander = FALSE;
-       
        if(!self.team || self.classname != "player") {
                ctf_setstate(self, -1);
        } else
                ctf_setstate(self, 0);
  
        self.team_saved = self.team;
-       
        if(self.team != 0 && self.classname == "player" && !ctf_team_has_commander(self.team)) {
                ctf_new_commander(self.team);
        }
@@@ -1162,9 -1154,9 +1154,9 @@@ void() ctf_playerchanged 
                        ctf_setstate(self, -1);
                ctf_new_commander(self.team_saved);
        }
-       
        self.team_saved = self.team;
-       
        ctf_new_commander(self.team);
  };
  
diff --combined qcsrc/server/defs.qh
index 1eb9e70074dc79d6c58772c7e7870c85888e675b,cb88d354e4087a13d40ddf5473b50bb9ecef754a..4e0f1ad0c6a08a813b8cb854571e04555686351d
@@@ -231,7 -231,7 +231,7 @@@ void weapon_defaultspawnfunc(float wpn)
  
  string w_deathtypestring;
  
 -void(entity client, string s) centerprint_builtin = #73;
 +// void(entity client, string s) centerprint_builtin = #73;
  .vector dest1, dest2;
  
  float gameover;
@@@ -286,6 -286,7 +286,6 @@@ entity timeoutHandler; //responsible fo
  void timeoutHandler_Think();
  void evaluateTimeout();
  void evaluateTimein();
 -string getTimeoutText(float addOneSecond);
  
  .float spawnshieldtime;
  
@@@ -311,6 -312,7 +311,6 @@@ float default_weapon_alpha
  .float() customizeentityforclient;
  .float cvar_cl_handicap;
  .float cvar_cl_playerdetailreduction;
 -.float cvar_scr_centertime;
  .string cvar_g_xonoticversion;
  .string cvar_cl_weaponpriority;
  .string cvar_cl_weaponpriorities[10];
@@@ -366,6 -368,8 +366,6 @@@ void FixClientCvars(entity e)
  
  float weaponsInMap;
  
 -void centerprint_atprio(entity e, float prio, string s);
 -void centerprint_expire(entity e, float prio);
  void centerprint(entity e, string s);
  
  .float respawn_countdown; // next number to count
@@@ -558,10 -562,6 +558,6 @@@ void ClientData_Touch(entity e)
  
  vector debug_shotorg; // if non-zero, overrides the shot origin of all weapons
  
- // the QC VM sucks
- #define BITXOR(v,b)        ((v) + (b) - 2 * ((v) & (b)))
- #define BITXOR_ASSIGN(v,b) ((v) += ((b) - 2 * ((v) & (b))))
  .float wasplayer;
  
  float servertime, serverprevtime, serverframetime;
index 549ac70a6c13b39fd4d0f8dfa1071865a22fa108,c8d2af14368d49bd1aabe54840822db95e1499d8..aac959bd8bf65f917bcfb8b2c742abd5526f49f8
@@@ -668,6 -668,34 +668,34 @@@ void changematchtime(float delta, floa
        cvar_set("timelimit", ftos(new / 60));
  }
  
+ float g_clientmodel_genericsendentity (entity to, float sf);
+ void modelbug_make_svqc();
+ void modelbug_make_csqc()
+ {
+       Net_LinkEntity(self, TRUE, 0, g_clientmodel_genericsendentity);
+       self.think = modelbug_make_svqc;
+       self.nextthink = time + 1;
+       setorigin(self, self.origin - '0 0 8');
+ }
+ void modelbug_make_svqc()
+ {
+       self.SendEntity = func_null;
+       self.think = modelbug_make_csqc;
+       self.nextthink = time + 1;
+       setorigin(self, self.origin + '0 0 8');
+ }
+ void modelbug()
+ {
+       entity e;
+       e = spawn();
+       setorigin(e, nextent(world).origin);
+       precache_model("models_portal.md3");
+       setmodel(e, "models/portal.md3");
+       e.think = modelbug_make_svqc;
+       e.nextthink = time + 1;
+ }
  void GameCommand(string command)
  {
        float argc;
                                }
                                else
                                {
 -                                      centerprint_atprio(client, CENTERPRIO_ADMIN, strcat("^3", admin_name(), ":\n\n^7", argv(2)));
 +                                      centerprint(client, strcat("^3", admin_name(), ":\n\n^7", argv(2)));
                                        sprint(client, strcat("\{1}\{13}^3", admin_name(), "^7: ", argv(2), "\n"));
                                }
                                print("Message sent to ", client.netname, "\n");
                return;
        }
  
+       if(argv(0) == "modelbug")
+       {
+               modelbug();
+               return;
+       }
        print("Invalid command. For a list of supported commands, try sv_cmd help.\n");
  }
  
index 859b367830e44efc8efd3aee3b8f5fe2de35ea8e,8b7806e566e91968bf6cc1211fa759aa4d27ac02..ffbe00f0fe7d9a546cc619f4cb6111a4fd2ae844
@@@ -579,6 -579,7 +579,6 @@@ void GetCvars(float f
        MUTATOR_CALLHOOK(GetCvars);
        GetCvars_handleFloat(s, f, autoswitch, "cl_autoswitch");
        GetCvars_handleFloat(s, f, cvar_cl_playerdetailreduction, "cl_playerdetailreduction");
 -      GetCvars_handleFloat(s, f, cvar_scr_centertime, "scr_centertime");
        GetCvars_handleString(s, f, cvar_g_xonoticversion, "g_xonoticversion");
        GetCvars_handleFloat(s, f, cvar_cl_handicap, "cl_handicap");
        GetCvars_handleString_Fixup(s, f, cvar_cl_weaponpriority, "cl_weaponpriority", W_FixWeaponOrder_ForceComplete_AndBuildImpulseList);
@@@ -717,10 -718,44 +717,10 @@@ float NumberToTeamNumber(float number
        return -1;
  }
  
 -#define CENTERPRIO_POINT 1
 -#define CENTERPRIO_SPAM 2
 -#define CENTERPRIO_VOTE 4
 -#define CENTERPRIO_NORMAL 5
 -#define CENTERPRIO_SHIELDING 7
 -#define CENTERPRIO_MAPVOTE 9
 -#define CENTERPRIO_IDLEKICK 50
 -#define CENTERPRIO_ADMIN 99
 -.float centerprint_priority;
 -.float centerprint_expires;
 -void centerprint_atprio(entity e, float prio, string s)
 -{
 -    if (intermission_running)
 -        if (prio < CENTERPRIO_MAPVOTE)
 -            return;
 -    if (time > e.centerprint_expires)
 -        e.centerprint_priority = 0;
 -    if (prio >= e.centerprint_priority)
 -    {
 -        e.centerprint_priority = prio;
 -        if (timeoutStatus == 2)
 -            e.centerprint_expires = time + (e.cvar_scr_centertime * TIMEOUT_SLOWMO_VALUE);
 -        else
 -            e.centerprint_expires = time + e.cvar_scr_centertime;
 -        centerprint_builtin(e, s);
 -    }
 -}
 -void centerprint_expire(entity e, float prio)
 -{
 -    if (prio == e.centerprint_priority)
 -    {
 -        e.centerprint_priority = 0;
 -        centerprint_builtin(e, "");
 -    }
 -}
 +void Send_CSQC_Centerprint_Generic(entity e, float id, string s1, float duration, float countdown_num);
  void centerprint(entity e, string s)
  {
 -    centerprint_atprio(e, CENTERPRIO_NORMAL, s);
 +      Send_CSQC_Centerprint_Generic(e, 0, s, 0, 0);
  }
  
  // decolorizes and team colors the player name when needed
@@@ -1654,30 -1689,6 +1654,30 @@@ void precache(
  #define WRITESPECTATABLE_MSG_ONE(statement) WRITESPECTATABLE_MSG_ONE_VARNAME(oldmsg_entity, statement)
  #define WRITESPECTATABLE(msg,statement) if(msg == MSG_ONE) { WRITESPECTATABLE_MSG_ONE(statement); } else statement float WRITESPECTATABLE_workaround = 0
  
 +
 +void Send_CSQC_Centerprint_Generic(entity e, float id, string s1, float duration, float countdown_num)
 +{
 +      if (clienttype(e) == CLIENTTYPE_REAL)
 +      {
 +              msg_entity = e;
 +              WRITESPECTATABLE_MSG_ONE({
 +                      WriteByte(MSG_ONE, SVC_TEMPENTITY);
 +                      WriteByte(MSG_ONE, TE_CSQC_NOTIFY);
 +                      WriteByte(MSG_ONE, CSQC_CENTERPRINT_GENERIC);
 +                      WriteByte(MSG_ONE, id);
 +                      WriteString(MSG_ONE, s1);
 +                      if (id != 0)
 +                      {
 +                              WriteByte(MSG_ONE, duration);
 +                              WriteByte(MSG_ONE, countdown_num);
 +                      }
 +              });
 +      }
 +}
 +void Send_CSQC_Centerprint_Generic_Expire(entity e, float id)
 +{
 +      Send_CSQC_Centerprint_Generic(e, id, "", 1, 0);
 +}
  // WARNING: this kills the trace globals
  #define EXACTTRIGGER_TOUCH if(WarpZoneLib_ExactTrigger_Touch()) return
  #define EXACTTRIGGER_INIT  WarpZoneLib_ExactTrigger_Init()
@@@ -3075,3 -3086,40 +3075,40 @@@ void defer(float fdelay, void() func
      e.think     = defer_think;
      e.nextthink = time + fdelay;
  }
+ .string aiment_classname;
+ .float aiment_deadflag;
+ void SetMovetypeFollow(entity ent, entity e)
+ {
+       // FIXME this may not be warpzone aware
+       ent.movetype = MOVETYPE_FOLLOW; // make the hole follow
+       ent.solid = SOLID_NOT; // MOVETYPE_FOLLOW is always non-solid - this means this cannot be teleported by warpzones any more! Instead, we must notice when our owner gets teleported.
+       ent.aiment = e; // make the hole follow bmodel
+       ent.punchangle = e.angles; // the original angles of bmodel
+       ent.view_ofs = ent.origin - e.origin; // relative origin
+       ent.v_angle = ent.angles - e.angles; // relative angles
+       ent.aiment_classname = strzone(e.classname);
+       ent.aiment_deadflag = e.deadflag;
+ }
+ void UnsetMovetypeFollow(entity ent)
+ {
+       ent.movetype = MOVETYPE_FLY;
+       PROJECTILE_MAKETRIGGER(ent);
+       ent.aiment = world;
+ }
+ float LostMovetypeFollow(entity ent)
+ {
+ /*
+       if(ent.movetype != MOVETYPE_FOLLOW)
+               if(ent.aiment)
+                       error("???");
+ */
+       if(ent.aiment)
+       {
+               if(ent.aiment.classname != ent.aiment_classname)
+                       return 1;
+               if(ent.aiment.deadflag != ent.aiment_deadflag)
+                       return 1;
+       }
+       return 0;
+ }
index 4d67e1aa82b59df5e5bc26982e8d48a0d54d504a,e55f979960eab8c4ceb7f2acc0276e013bda7a64..f3828adc2dd54fa1bbdf96b2eb13c18904875b5e
@@@ -4,6 -4,8 +4,8 @@@ void ka_RespawnBall(void)
  void ka_DropEvent(entity);
  void ka_TimeScoring(void);
  
+ entity ka_ball;
  float ka_ballcarrier_waypointsprite_visible_for_player(entity);
  
  void ka_Initialize() // run at the start of a match, initiates game mode
@@@ -50,6 -52,7 +52,7 @@@ void ka_SpawnBall() // loads various va
        e.reset = ka_Reset;
        e.touch = ka_TouchEvent;
        e.owner = world;
+       ka_ball = e;
  
        InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So. 
  }
@@@ -72,8 -75,7 +75,7 @@@ void ka_RespawnBall() // runs whenever 
                pointparticles(particleeffectnum("electro_combo"), oldballorigin, '0 0 0', 1);
                pointparticles(particleeffectnum("electro_combo"), self.origin, '0 0 0', 1);
  
-               WaypointSprite_Spawn("ka-ball", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attachedforcarrier, FALSE);
-               WaypointSprite_UpdateTeamRadar(self.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '0 1 1');
+               WaypointSprite_Spawn("ka-ball", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAGCARRIER, '0 1 1');
                WaypointSprite_Ping(self.waypointsprite_attachedforcarrier);    
  
                sound(self, CHAN_AUTO, "keepaway/respawn.wav", VOL_BASE, ATTN_NONE); // ATTN_NONE (it's a sound intended to be heard anywhere) 
@@@ -132,10 -134,9 +134,9 @@@ void ka_TouchEvent() // runs any time t
        PlayerScore_Add(other, SP_KEEPAWAY_PICKUPS, 1);
  
        // waypoints
-       WaypointSprite_AttachCarrier("ka-ballcarrier", other);
+       WaypointSprite_AttachCarrier("ka-ballcarrier", other, RADARICON_FLAGCARRIER, '1 0 0');
        other.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = ka_ballcarrier_waypointsprite_visible_for_player;
        WaypointSprite_UpdateRule(other.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-       WaypointSprite_UpdateTeamRadar(other.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '1 0 0');
        WaypointSprite_Ping(other.waypointsprite_attachedforcarrier);   
        WaypointSprite_Kill(self.waypointsprite_attachedforcarrier);
  }
@@@ -175,9 -176,8 +176,8 @@@ void ka_DropEvent(entity plyr) // runs 
        // PlayerScore_Add(plyr, SP_KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
        
        // waypoints
-       WaypointSprite_Spawn("ka-ball", 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, FALSE);
+       WaypointSprite_Spawn("ka-ball", 0, 0, ball, '0 0 64', world, ball.team, ball, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAGCARRIER, '0 1 1');
        WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-       WaypointSprite_UpdateTeamRadar(ball.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, '0 1 1');
        WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);    
        WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
  }
@@@ -216,7 -216,7 +216,7 @@@ MUTATOR_HOOKFUNCTION(ka_Scoring
                }
                else if(!frag_attacker.ballcarried)
                        if(autocvar_g_keepaway_noncarrier_warn)
 -                              centerprint_atprio(frag_attacker, (CENTERPRIO_SPAM + 5), "Killing people while you don't have the ball gives no points!");
 +                              centerprint(frag_attacker, "Killing people while you don't have the ball gives no points!");
  
                if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier
                        PlayerScore_Add(frag_attacker, SP_SCORE, autocvar_g_keepaway_score_killac);
index 540530dd9869f8461789b225fc8b1350bc305815,32e4116aa1273e342491fc34a48288c0d901796a..8a8ed5bca470ce16bc2cc21395bc164177e9431a
@@@ -152,10 -152,9 +152,10 @@@ void kh_Controller_Think()  // called 
  
                        //dprint(s, "\n");
  
 +                      // TODO limit centerprint spam and set the appropriated duration for each centerprinted msg 
                        FOR_EACH_PLAYER(e)
                                if(clienttype(e) == CLIENTTYPE_REAL)
 -                                      centerprint_atprio(e, CENTERPRIO_SPAM, s);
 +                                      Send_CSQC_Centerprint_Generic(e, CPID_KH_MSG, s, 2, 0); // duration > 1 works with all the messages
                }
                self.cnt -= 1;
        }
@@@ -351,7 -350,7 +351,7 @@@ void kh_Key_AssignTo(entity key, entit
                if(key.kh_next == world)
                {
                        // player is now a key carrier
-                       WaypointSprite_AttachCarrier("", player);
+                       WaypointSprite_AttachCarrier("", player, RADARICON_FLAGCARRIER, colormapPaletteColor(player.team - 1, 0));
                        player.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_KeyCarrier_waypointsprite_visible_for_player;
                        WaypointSprite_UpdateRule(player.waypointsprite_attachedforcarrier, player.team, SPRITERULE_TEAMPLAY);
                        if(player.team == COLOR_TEAM1)
                                WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-yellow", "keycarrier-friend", "keycarrier-yellow");
                        else if(player.team == COLOR_TEAM4)
                                WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, "keycarrier-pink", "keycarrier-friend", "keycarrier-pink");
-                       WaypointSprite_UpdateTeamRadar(player.waypointsprite_attachedforcarrier, RADARICON_FLAGCARRIER, colormapPaletteColor(player.team - 1, 0));
                        if(!kh_no_radar_circles)
                                WaypointSprite_Ping(player.waypointsprite_attachedforcarrier);
                }
@@@ -687,11 -685,11 +686,11 @@@ void kh_Key_Think()  // runs all the ti
                {
                        if(head.team == kh_interferemsg_team)
                                if(head.kh_next)
 -                                      centerprint(head, "All keys are in your team's hands!\n\nMeet the other key carriers ^1NOW^7!");
 +                                      Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, "All keys are in your team's hands!\n\nMeet the other key carriers ^1NOW^7!", 0, 0);
                                else
 -                                      centerprint(head, "All keys are in your team's hands!\n\nHelp the key carriers to meet!");
 +                                      Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, "All keys are in your team's hands!\n\nHelp the key carriers to meet!", 0, 0);
                        else
 -                              centerprint(head, strcat("All keys are in the ", ColoredTeamName(kh_interferemsg_team), "^7's hands!\n\nInterfere ^1NOW^7!"));
 +                              Send_CSQC_Centerprint_Generic(head, CPID_KH_MSG, strcat("All keys are in the ", ColoredTeamName(kh_interferemsg_team), "^7's hands!\n\nInterfere ^1NOW^7!"), 0, 0);
                }
        }
  
@@@ -752,9 -750,8 +751,8 @@@ void kh_Key_Spawn(entity initial_owner
  
        centerprint(initial_owner, strcat("You are starting with the ", key.netname, "\n"));  // message to player at start of round
  
-       WaypointSprite_Spawn("key-dropped", 0, 0, key, '0 0 1' * KH_KEY_WP_ZSHIFT, world, key.team, key, waypointsprite_attachedforcarrier, FALSE);
+       WaypointSprite_Spawn("key-dropped", 0, 0, key, '0 0 1' * KH_KEY_WP_ZSHIFT, world, key.team, key, waypointsprite_attachedforcarrier, FALSE, RADARICON_FLAG, '0 1 1');
        key.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_Key_waypointsprite_visible_for_player;
-       WaypointSprite_UpdateTeamRadar(key.waypointsprite_attachedforcarrier, RADARICON_FLAG, '0 1 1');
  
        kh_Key_AssignTo(key, initial_owner);
  }
@@@ -882,7 -879,7 +880,7 @@@ void kh_EnableTrackingDevice()  // run
  
        FOR_EACH_PLAYER(player)
                if(clienttype(player) == CLIENTTYPE_REAL)
 -                      centerprint_expire(player, CENTERPRIO_SPAM);
 +                      Send_CSQC_Centerprint_Generic_Expire(player, CPID_KH_MSG);
  
        kh_tracking_enabled = TRUE;
  }
@@@ -908,7 -905,7 +906,7 @@@ void kh_StartRound()  // runs at the st
  
        FOR_EACH_PLAYER(player)
                if(clienttype(player) == CLIENTTYPE_REAL)
 -                      centerprint_expire(player, CENTERPRIO_SPAM);
 +                      Send_CSQC_Centerprint_Generic_Expire(player, CPID_KH_MSG);
  
        for(i = 0; i < kh_teams; ++i)
        {
diff --combined qcsrc/server/t_items.qc
index d6e232286343c608a16c38f6049e09201cb6d8d7,02660fc52a97c8f291f98d4728a92053ae9d563a..81c47529383e784de05b8a74a9fa491bf1d0d900
@@@ -198,13 -198,9 +198,9 @@@ void Item_RespawnCountdown (void
                        }
                        if(name)
                        {
-                               WaypointSprite_Spawn(name, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE);
+                               WaypointSprite_Spawn(name, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb);
                                if(self.waypointsprite_attached)
-                               {
-                                       WaypointSprite_UpdateTeamRadar(self.waypointsprite_attached, RADARICON_POWERUP, rgb);
-                                       //WaypointSprite_UpdateMaxHealth(self.waypointsprite_attached, ITEM_RESPAWN_TICKS + 1);
                                        WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
-                               }
                        }
                }
                sound (self, CHAN_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTN_NORM);       // play respawn sound
@@@ -283,6 -279,7 +279,6 @@@ float Item_GiveTo(entity item, entity p
                        {
                                pickedup = TRUE;
                                // play some cool sounds ;)
 -                              centerprint(player, "\n");
                                if (clienttype(player) == CLIENTTYPE_REAL)
                                {
                                        if(player.health <= 5)