Merge remote-tracking branch 'origin/master' into terencehill/spectate_prev
authorSamual Lenks <samual@xonotic.org>
Wed, 8 May 2013 01:10:59 +0000 (21:10 -0400)
committerSamual Lenks <samual@xonotic.org>
Wed, 8 May 2013 01:10:59 +0000 (21:10 -0400)
1  2 
qcsrc/client/hud.qc
qcsrc/server/cl_client.qc
qcsrc/server/mutators/mutator_superspec.qc

diff --combined qcsrc/client/hud.qc
index 90dac2e096aa333f8029410e5149bb046d1428bb,ee44db91a8f0e6013c027574b975b6fde3f5392b..469fe67fa27d1524e8f541adaf86602b46f3be90
@@@ -487,11 -487,9 +487,9 @@@ void HUD_Weapons(void
                        return;
                }
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_WEAPONS;
  
        // update generic hud functions
-       HUD_Panel_UpdateCvars(weapons);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        draw_beginBoldFont();
@@@ -950,10 -948,8 +948,8 @@@ void HUD_Ammo(void
                if(!autocvar_hud_panel_ammo) return;
                if(spectatee_status == -1) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_AMMO;
  
-       HUD_Panel_UpdateCvars(ammo);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        draw_beginBoldFont();
@@@ -1154,14 -1150,12 +1150,12 @@@ void HUD_Powerups(void
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_POWERUPS;
                strength_time = 15;
                shield_time = 27;
                superweapons_time = 13;
        }
  
-       HUD_Panel_UpdateCvars(powerups);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        draw_beginBoldFont();
@@@ -1397,14 -1391,12 +1391,12 @@@ void HUD_HealthArmor(void
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_HEALTHARMOR;
                health = 150;
                armor = 75;
                fuel = 20;
        }
  
-       HUD_Panel_UpdateCvars(healtharmor);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
@@@ -1656,10 -1648,8 +1648,8 @@@ void HUD_Notify(void
        {
                if(!autocvar_hud_panel_notify) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_NOTIFY;
  
-       HUD_Panel_UpdateCvars(notify);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
@@@ -1795,10 -1785,8 +1785,8 @@@ void HUD_Timer(void
        {
                if(!autocvar_hud_panel_timer) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_TIMER;
  
-       HUD_Panel_UpdateCvars(timer);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        draw_beginBoldFont();
@@@ -1865,12 -1853,10 +1853,10 @@@ void HUD_Radar(void
                        if (autocvar_hud_panel_radar != 2 && !teamplay) return;
                }
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_RADAR;
  
-       HUD_Panel_UpdateCvars(radar);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
-       
        float f = 0;
  
        if (hud_panel_radar_maximized && !autocvar__hud_configure)
@@@ -2159,10 -2145,8 +2145,8 @@@ void HUD_Score(void
                if(!autocvar_hud_panel_score) return;
                if(spectatee_status == -1 && (gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_SCORE;
  
-       HUD_Panel_UpdateCvars(score);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
@@@ -2356,10 -2340,8 +2340,8 @@@ void HUD_RaceTimer (void
                if(!(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
                if(spectatee_status == -1) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_RACETIMER;
  
-       HUD_Panel_UpdateCvars(racetimer);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        draw_beginBoldFont();
@@@ -2508,7 -2490,7 +2490,7 @@@ float vote_prev; // previous state of v
  float vote_alpha;
  float vote_change; // "time" when vote_active changed
  
- void HUD_VoteWindow(void) 
+ void HUD_Vote(void)
  {
        if(autocvar_cl_allow_uid2name == -1 && (gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (serverflags & SERVERFLAG_PLAYERSTATS)))
        {
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_VOTE;
                vote_yescount = 3;
                vote_nocount = 2;
                vote_needed = 4;
        if(!vote_alpha)
                return;
  
-       HUD_Panel_UpdateCvars(vote);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        if(uid2name_dialog)
  
  float mod_active; // is there any active mod icon?
  
- // Clan Arena HUD modicons
- void HUD_Mod_CA(vector pos, vector mySize)
+ void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, float i)
  {
-       mod_active = 1; // CA should never hide the mod icons panel
-       float redalive, bluealive;
-       redalive = getstati(STAT_REDALIVE);
-       bluealive = getstati(STAT_BLUEALIVE);
+       float stat;
+       string pic;
+       vector color;
+ #ifdef GMQCC
+       stat = -1;
+       pic = "";
+       color = '0 0 0';
+ #endif
+       switch(i)
+       {
+               case 0:
+                       stat = getstati(STAT_REDALIVE);
+                       pic = "player_red.tga";
+                       color = '1 0 0';
+                       break;
+               case 1:
+                       stat = getstati(STAT_BLUEALIVE);
+                       pic = "player_blue.tga";
+                       color = '0 0 1';
+                       break;
+               case 2:
+                       stat = getstati(STAT_YELLOWALIVE);
+                       pic = "player_yellow.tga";
+                       color = '1 1 0';
+                       break;
+               default:
+               case 3:
+                       stat = getstati(STAT_PINKALIVE);
+                       pic = "player_pink.tga";
+                       color = '1 0 1';
+                       break;
+       }
  
-       vector redpos, bluepos;
-       if(mySize_x > mySize_y)
+       if(mySize_x/mySize_y > aspect_ratio)
        {
-               redpos = pos;
-               bluepos = pos + eY * 0.5 * mySize_y;
-               drawpic_aspect_skin(redpos, "player_red.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(redpos + eX * 0.5 * mySize_x, ftos(redalive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawpic_aspect_skin(bluepos, "player_blue.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(bluepos + eX * 0.5 * mySize_x, ftos(bluealive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               i = aspect_ratio * mySize_y;
+               myPos_x = myPos_x + (mySize_x - i) / 2;
+               mySize_x = i;
        }
        else
        {
-               redpos = pos;
-               bluepos = pos + eY * 0.5 * mySize_y;
-               drawpic_aspect_skin(redpos, "player_red.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(redpos + eY * 0.3 * mySize_y, ftos(redalive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawpic_aspect_skin(bluepos, "player_blue.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(bluepos + eY * 0.3 * mySize_y, ftos(bluealive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               i = 1/aspect_ratio * mySize_x;
+               myPos_y = myPos_y + (mySize_y - i) / 2;
+               mySize_y = i;
+       }
+       if(layout)
+       {
+               drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(myPos + eX * 0.7 * mySize_x, ftos(stat), eX * 0.3 * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+       else
+               drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ // Clan Arena and Freeze Tag HUD modicons
+ void HUD_Mod_CA(vector myPos, vector mySize)
+ {
+       mod_active = 1; // required in each mod function that always shows something
+       entity tm;
+       float teams_count = 0;
+       for(tm = teams.sort_next; tm; tm = tm.sort_next)
+               if(tm.team != NUM_SPECTATOR)
+                       ++teams_count;
+       float layout;
+       if(gametype == MAPINFO_TYPE_CA)
+               layout = autocvar_hud_panel_modicons_ca_layout;
+       else //if(gametype == MAPINFO_TYPE_FREEZETAG)
+               layout = autocvar_hud_panel_modicons_freezetag_layout;
+       float rows, columns, aspect_ratio;
+       rows = mySize_y/mySize_x;
+       aspect_ratio = (layout) ? 2 : 1;
+       rows = bound(1, floor((sqrt((4 * aspect_ratio * teams_count + rows) * rows) + rows + 0.5) / 2), teams_count);
+       columns = ceil(teams_count/rows);
+       int i;
+       float row = 0, column = 0;
+       vector pos, itemSize;
+       itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+       for(i=0; i<teams_count; ++i)
+       {
+               pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
+               DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
+               ++row;
+               if(row >= rows)
+               {
+                       row = 0;
+                       ++column;
+               }
        }
  }
  
@@@ -3292,11 -3340,11 +3340,11 @@@ void HUD_Mod_Dom(vector myPos, vector m
  
        int i;
        float row = 0, column = 0;
+       vector pos, itemSize;
+       itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
        for(i=0; i<teams_count; ++i)
        {
-               vector pos, itemSize;
-               pos = myPos + eX * column * mySize_x*(1/columns) + eY * row * mySize_y*(1/rows);
-               itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+               pos = myPos + eX * column * itemSize_x + eY * row * itemSize_y;
  
                DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
  
@@@ -3320,10 -3368,8 +3368,8 @@@ void HUD_ModIcons(void
                if(!autocvar_hud_panel_modicons) return;
                if (gametype != MAPINFO_TYPE_CTF && gametype != MAPINFO_TYPE_KEYHUNT && gametype != MAPINFO_TYPE_NEXBALL && gametype != MAPINFO_TYPE_CTS && gametype != MAPINFO_TYPE_RACE && gametype != MAPINFO_TYPE_CA && gametype != MAPINFO_TYPE_FREEZETAG && gametype != MAPINFO_TYPE_KEEPAWAY && gametype != MAPINFO_TYPE_DOMINATION) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_MODICONS;
  
-       HUD_Panel_UpdateCvars(modicons);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        draw_beginBoldFont();
  
  // Draw pressed keys (#11)
  //
- void HUD_DrawPressedKeys(void)
+ void HUD_PressedKeys(void)
  {
        if(!autocvar__hud_configure)
        {
                if(!autocvar_hud_panel_pressedkeys) return;
                if(spectatee_status <= 0 && autocvar_hud_panel_pressedkeys < 2) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_PRESSEDKEYS;
  
-       HUD_Panel_UpdateCvars(pressedkeys);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
@@@ -3454,10 -3497,8 +3497,8 @@@ void HUD_Chat(void
                if(autocvar__con_chat_maximized)
                        if(!hud_draw_maximized) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_CHAT;
  
-       HUD_Panel_UpdateCvars(chat);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        if(autocvar__con_chat_maximized && !autocvar__hud_configure) // draw at full screen height if maximized
@@@ -3530,10 -3571,8 +3571,8 @@@ void HUD_EngineInfo(void
        {
                if(!autocvar_hud_panel_engineinfo) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_ENGINEINFO;
  
-       HUD_Panel_UpdateCvars(engineinfo);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
@@@ -3593,10 -3632,8 +3632,8 @@@ void HUD_InfoMessages(void
        {
                if(!autocvar_hud_panel_infomessages) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_INFOMESSAGES;
  
-       HUD_Panel_UpdateCvars(infomessages);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
        vector pos, mySize;
        pos = panel_pos;
                        if(spectatee_status == -1)
                                s = sprintf(_("^1Press ^3%s^1 to spectate"), getcommandkey("primary fire", "+fire"));
                        else
 -                              s = sprintf(_("^1Press ^3%s^1 for another player"), getcommandkey("primary fire", "+fire"));
 +                              s = sprintf(_("^1Press ^3%s^1 or ^3%s^1 for next or previous player"), getcommandkey("next weapon", "weapnext"), getcommandkey("previous weapon", "weapprev"));
                        drawInfoMessage(s)
  
                        if(spectatee_status == -1)
@@@ -3784,10 -3821,8 +3821,8 @@@ void HUD_Physics(void
                if(spectatee_status == -1 && (autocvar_hud_panel_physics == 1 || autocvar_hud_panel_physics == 3)) return;
                if(autocvar_hud_panel_physics == 3 && !(gametype == MAPINFO_TYPE_RACE || gametype == MAPINFO_TYPE_CTS)) return;
        }
-       else
-               hud_configure_active_panel = HUD_PANEL_PHYSICS;
  
-       HUD_Panel_UpdateCvars(physics);
+       HUD_Panel_UpdateCvars();
        HUD_Panel_ApplyFadeAlpha();
  
        draw_beginBoldFont();
@@@ -4167,8 -4202,6 +4202,6 @@@ void HUD_CenterPrint (void
        }
        else
        {
-               hud_configure_active_panel = HUD_PANEL_CENTERPRINT;
                if (!hud_configure_prev)
                        reset_centerprint_messages();
                if (time > hud_configure_cp_generation_time)
                }
        }
  
-       HUD_Panel_UpdateCvars(centerprint);
+       HUD_Panel_UpdateCvars();
  
        // this panel doesn't fade when showing the scoreboard
        if(autocvar__menu_alpha)
@@@ -4373,44 -4406,6 +4406,6 @@@ void HUD_Reset (void
                HUD_Mod_CTF_Reset();
  }
  
- #define HUD_DrawPanel(id)\
- switch (id) {\
-       case (HUD_PANEL_RADAR):\
-               HUD_Radar(); break;\
-       case (HUD_PANEL_WEAPONS):\
-               HUD_Weapons(); break;\
-       case (HUD_PANEL_AMMO):\
-               HUD_Ammo(); break;\
-       case (HUD_PANEL_POWERUPS):\
-               HUD_Powerups(); break;\
-       case (HUD_PANEL_HEALTHARMOR):\
-               HUD_HealthArmor(); break;\
-       case (HUD_PANEL_NOTIFY):\
-               HUD_Notify(); break;\
-       case (HUD_PANEL_TIMER):\
-               HUD_Timer(); break;\
-       case (HUD_PANEL_SCORE):\
-               HUD_Score(); break;\
-       case (HUD_PANEL_RACETIMER):\
-               HUD_RaceTimer(); break;\
-       case (HUD_PANEL_VOTE):\
-               HUD_VoteWindow(); break;\
-       case (HUD_PANEL_MODICONS):\
-               HUD_ModIcons(); break;\
-       case (HUD_PANEL_PRESSEDKEYS):\
-               HUD_DrawPressedKeys(); break;\
-       case (HUD_PANEL_CHAT):\
-               HUD_Chat(); break;\
-       case (HUD_PANEL_ENGINEINFO):\
-               HUD_EngineInfo(); break;\
-       case (HUD_PANEL_INFOMESSAGES):\
-               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)
  {
        float i;
        // they must call HUD_Panel_ApplyFadeAlpha(); only when showing the menu
        if(scoreboard_fade_alpha == 1)
        {
-               HUD_CenterPrint();
+               (panel = HUD_PANEL(CENTERPRINT)).panel_draw();
                return;
        }
  
                vector color;
                float hud_dock_color_team = autocvar_hud_dock_color_team;
                if((teamplay) && hud_dock_color_team) {
-                       color = colormapPaletteColor(myteam, 1) * hud_dock_color_team;
+                       if(autocvar__hud_configure && myteam == NUM_SPECTATOR)
+                               color = '1 0 0' * hud_dock_color_team;
+                       else
+                               color = myteamcolors * hud_dock_color_team;
                }
                else if(autocvar_hud_configure_teamcolorforced && autocvar__hud_configure && hud_dock_color_team) {
                        color = '1 0 0' * hud_dock_color_team;
        hud_draw_maximized = 0;
        // draw panels in order specified by panel_order array
        for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
-               HUD_DrawPanel(panel_order[i]);
+               (panel = hud_panel[panel_order[i]]).panel_draw();
  
        hud_draw_maximized = 1; // panels that may be maximized must check this var
        // draw maximized panels on top
        if(hud_panel_radar_maximized)
-               HUD_Radar();
+               (panel = HUD_PANEL(RADAR)).panel_draw();
        if(autocvar__con_chat_maximized)
-               HUD_Chat();
+               (panel = HUD_PANEL(CHAT)).panel_draw();
  
        if(autocvar__hud_configure)
        {
-               if(tab_panel != -1)
+               if(tab_panel)
                {
-                       HUD_Panel_UpdatePosSizeForId(tab_panel)
+                       panel = tab_panel;
+                       HUD_Panel_UpdatePosSize()
                        drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
                }
-               if(highlightedPanel != -1)
+               if(highlightedPanel)
                {
-                       HUD_Panel_UpdatePosSizeForId(highlightedPanel);
+                       panel = highlightedPanel;
+                       HUD_Panel_UpdatePosSize()
                        HUD_Panel_HlBorder(panel_bg_border + 1.5 * hlBorderSize, '0 0.5 1', 0.25 * (1 - autocvar__menu_alpha));
                }
                if(!hud_configure_prev || hud_configure_prev == -1)
                {
                        if(autocvar_hud_cursormode) { setcursormode(1); }
                        hudShiftState = 0;
+                       for(i = HUD_PANEL_NUM - 1; i >= 0; --i)
+                               hud_panel[panel_order[i]].update_time = time;
                }
        }
        else if (hud_configure_prev && autocvar_hud_cursormode)
index 3f6006838e7665bc31933aa8b5742ce7d5c5cfac,075280c264e2094c8ecd40785ad946c00736dec2..ca19ed7464b67307740805031f7b626ae8ea5c54
@@@ -6,22 -6,6 +6,6 @@@ void send_CSQC_teamnagger() 
        WriteByte(MSG_BROADCAST, TE_CSQC_TEAMNAGGER);
  }
  
- void Announce(string snd) {
-       WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-       WriteByte(MSG_BROADCAST, TE_CSQC_ANNOUNCE);
-       WriteString(MSG_BROADCAST, snd);
- }
- void AnnounceTo(entity e, string snd) {
-       if (clienttype(e) == CLIENTTYPE_REAL)
-       {
-               msg_entity = e;
-               WriteByte(MSG_ONE, SVC_TEMPENTITY);
-               WriteByte(MSG_ONE, TE_CSQC_ANNOUNCE);
-               WriteString(MSG_ONE, snd);
-       }
- }
  float ClientData_Send(entity to, float sf)
  {
        if(to != self.owner)
@@@ -293,7 -277,7 +277,7 @@@ entity SelectSpawnPoint (float anypoint
        else
        {
                float mindist;
-               if (arena_roundbased && !g_ca)
+               if (g_arena && arena_roundbased)
                        mindist = 800;
                else
                        mindist = 100;
@@@ -401,6 -385,24 +385,24 @@@ void PutObserverInServer (void
                WriteEntity(MSG_ONE, self);
        }
  
+       if(g_lms)
+       {
+               // Only if the player cannot play at all
+               if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
+                       self.frags = FRAGS_SPECTATOR;
+               else
+                       self.frags = FRAGS_LMS_LOSER;
+       }
+       else if((g_race && g_race_qualifying) || g_cts)
+       {
+               if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
+                       self.frags = FRAGS_LMS_LOSER;
+               else
+                       self.frags = FRAGS_SPECTATOR;
+       }
+       else
+               self.frags = FRAGS_SPECTATOR;
        MUTATOR_CALLHOOK(MakePlayerObserver);
  
        minstagib_stop_countdown(self);
        if not(g_ca)  // don't reset teams when moving a ca player to the spectators
                self.team = -1;  // move this as it is needed to log the player spectating in eventlog
  
-       if(self.killcount != -666) {
-               if(g_lms) {
-                       if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0 && self.lms_spectate_warning != 2)
-                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_NOLIVES, self.netname);
-                       else
-                               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_LMS_FORFEIT, self.netname);
-               } else { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname); }
+       if(self.killcount != -666)
+       {
+               Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_QUIT_SPECTATE, self.netname);
  
                if(self.just_joined == FALSE) {
                        LogTeamchange(self.playerid, -1, 4);
        self.pauseregen_finished = 0;
        self.damageforcescale = 0;
        self.death_time = 0;
+       self.respawn_flags = 0;
        self.respawn_time = 0;
+       self.stat_respawn_time = 0;
        self.alpha = 0;
        self.scale = 0;
        self.fade_time = 0;
        self.punchvector = '0 0 0';
        self.oldvelocity = self.velocity;
        self.fire_endtime = -1;
-       if(g_arena)
-       {
-               if(self.version_mismatch)
-               {
-                       self.frags = FRAGS_SPECTATOR;
-                       Spawnqueue_Unmark(self);
-                       Spawnqueue_Remove(self);
-               }
-               else
-               {
-                       self.frags = FRAGS_LMS_LOSER;
-                       Spawnqueue_Insert(self);
-               }
-       }
-       else if(g_lms)
-       {
-               // Only if the player cannot play at all
-               if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
-                       self.frags = FRAGS_SPECTATOR;
-               else
-                       self.frags = FRAGS_LMS_LOSER;
-       }
-       else if(g_ca)
-       {
-               if(self.caplayer)
-                       self.frags = FRAGS_LMS_LOSER;
-               else
-                       self.frags = FRAGS_SPECTATOR;
-       }
-       else if((g_race && g_race_qualifying) || g_cts)
-       {
-               if(PlayerScore_Add(self, SP_RACE_FASTEST, 0))
-                       self.frags = FRAGS_LMS_LOSER;
-               else
-                       self.frags = FRAGS_SPECTATOR;
-       }
-       else
-               self.frags = FRAGS_SPECTATOR;
  }
  
  .float model_randomizer;
@@@ -627,21 -588,6 +588,6 @@@ void FixPlayermodel(
                                setcolor(self, stof(autocvar_sv_defaultplayercolors));
  }
  
- void PlayerTouchExplode(entity p1, entity p2)
- {
-       vector org;
-       org = (p1.origin + p2.origin) * 0.5;
-       org_z += (p1.mins_z + p2.mins_z) * 0.5;
-       te_explosion(org);
-       entity e;
-       e = spawn();
-       setorigin(e, org);
-       RadiusDamage(e, world, g_touchexplode_damage, g_touchexplode_edgedamage, g_touchexplode_radius, world, g_touchexplode_force, DEATH_TOUCHEXPLODE, world);
-       remove(e);
- }
  /*
  =============
  PutClientInServer
@@@ -653,11 -599,7 +599,7 @@@ Called when a client spawns in the serv
  void PutClientInServer (void)
  {
        if(clienttype(self) == CLIENTTYPE_BOT)
-       {
                self.classname = "player";
-               if(g_ca)
-                       self.caplayer = 1;
-       }
        else if(clienttype(self) == CLIENTTYPE_REAL)
        {
                msg_entity = self;
                        self.classname = "observer";
        }
  
-       if((g_arena && !self.spawned) || (g_ca && !allowed_to_spawn))
-               self.classname = "observer";
+       MUTATOR_CALLHOOK(PutClientInServer);
  
        if(gameover)
                self.classname = "observer";
  
-       if(self.classname == "player" && (!g_ca || (g_ca && allowed_to_spawn))) {
+       if(self.classname == "player") {
                entity spot, oldself;
                float j;
  
                }
                self.damageforcescale = 2;
                self.death_time = 0;
+               self.respawn_flags = 0;
                self.respawn_time = 0;
+               self.stat_respawn_time = 0;
                self.scale = 0;
                self.fade_time = 0;
                self.pain_frame = 0;
                self.lastteleporttime = time; // prevent insane speeds due to changing origin
          self.hud = HUD_NORMAL;
  
-               if(g_arena)
-               {
-                       Spawnqueue_Remove(self);
-                       Spawnqueue_Mark(self);
-               }
-               else if(g_ca)
-                       self.caplayer = 1;
                self.event_damage = PlayerDamage;
  
                self.bot_attack = TRUE;
  
                //stuffcmd(self, "chase_active 0");
                //stuffcmd(self, "set viewsize $tmpviewsize \n");
-               if(g_assault) {
-                       if(self.team == assault_attacker_team)
-                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
-                       else
-                               Send_Notification(NOTIF_TEAM, self, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
-               }
+               
                target_voicescript_clear(self);
  
                // reset fields the weapons may use
@@@ -1078,14 -1006,13 +1006,13 @@@ void ClientKill_Now_TeamChange(
        }
        else if(self.killindicator_teamchange == -2)
        {
-               if(g_ca)
-                       self.caplayer = 0;
                if(blockSpectators)
                        Send_Notification(NOTIF_ONE_ONLY, self, MSG_INFO, INFO_SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
                PutObserverInServer();
        }
        else
                SV_ChangeTeam(self.killindicator_teamchange - 1);
+       self.killindicator_teamchange = 0;
  }
  
  void ClientKill_Now()
@@@ -1147,7 -1074,7 +1074,7 @@@ void KillIndicator_Think(
                if(clienttype(self.owner) == CLIENTTYPE_REAL)
                {
                        if(self.cnt <= 10)
-                               AnnounceTo(self.owner, strcat(ftos(self.cnt), ""));
+                               { Send_Notification(NOTIF_ONE, self.owner, MSG_ANNCE, Announcer_PickNumber(self.cnt)); }
                }
                self.nextthink = time + 1;
                self.cnt -= 1;
@@@ -1261,19 -1188,11 +1188,11 @@@ void ClientKill_TeamChange (float targe
  
  void ClientKill (void)
  {
-       if (gameover)
-               return;
+       if(gameover) return;
+       if(self.player_blocked) return;
+       if(self.freezetag_frozen) return;
  
-       if((g_arena || g_ca) && ((champion && champion.classname == "player" && player_count > 1) || player_count == 1)) // don't allow a kill in this case either
-       {
-               // do nothing
-       }
-     else if(self.freezetag_frozen)
-     {
-         // do nothing
-     }
-       else
-               ClientKill_TeamChange(0);
+       ClientKill_TeamChange(0);
  }
  
  void CTS_ClientKill (entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
@@@ -1433,7 -1352,7 +1352,7 @@@ void ClientConnect (void
  
        JoinBestTeam(self, FALSE, FALSE); // if the team number is valid, keep it
  
-       if((autocvar_sv_spectate == 1 && !g_lms) || autocvar_g_campaign || self.team_forced < 0) {
+       if((autocvar_sv_spectate == 1) || autocvar_g_campaign || self.team_forced < 0) {
                self.classname = "observer";
        } else {
                if(teamplay)
        else
                stuffcmd(self, "set _teams_available 0\n");
  
-       if(g_arena || g_ca)
-       {
-               self.classname = "observer";
-               if(g_arena)
-                       Spawnqueue_Insert(self);
-       }
        attach_entcs();
  
        bot_relinkplayerlist();
  
        if(clienttype(self) == CLIENTTYPE_REAL)
        {
-               if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA))
-                       stuffcmd(self, "cl_cmd settemp chase_active 1\n");
-       }
-       if(g_lms)
-       {
-               if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+               if(!autocvar_g_campaign)
                {
-                       PlayerScore_Add(self, SP_LMS_RANK, 666);
-                       self.frags = FRAGS_SPECTATOR;
+                       self.motd_actived_time = -1;
+                       Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
                }
+               if(autocvar_g_bugrigs || WEPSET_EQ_AW(g_weaponarena_weapons, WEP_TUBA))
+                       stuffcmd(self, "cl_cmd settemp chase_active 1\n");
        }
  
        if(!sv_foginterval && world.fog != "")
  
        CheatInitClient();
  
-       if(!autocvar_g_campaign)
-               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
        CSQCMODEL_AUTOINIT();
  
        self.model_randomizer = random();
-     
-     if(clienttype(self) != CLIENTTYPE_REAL)
-         return;
-         
-     sv_notice_join();
-     
-     MUTATOR_CALLHOOK(ClientConnect);
+       if(clienttype(self) == CLIENTTYPE_REAL)
+               sv_notice_join();
+       MUTATOR_CALLHOOK(ClientConnect);
  }
  /*
  =============
@@@ -1653,12 -1557,6 +1557,6 @@@ void ClientDisconnect (void
  
        bot_relinkplayerlist();
  
-       if(g_arena)
-       {
-               Spawnqueue_Unmark(self);
-               Spawnqueue_Remove(self);
-       }
        accuracy_free(self);
        ClientData_Detach();
        PlayerScore_Detach(self);
@@@ -2016,7 -1914,7 +1914,7 @@@ void player_regen (void
        limita = limita * limit_mod;
        //limitf = limitf * limit_mod;
  
-       if(g_lms && g_ca)
+       if(g_ca)
                rot_mod = 0;
  
        if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
@@@ -2141,7 -2039,6 +2039,6 @@@ void SpectateCopy(entity spectatee) 
        self.dmg_inflictor = spectatee.dmg_inflictor;
        self.v_angle = spectatee.v_angle;
        self.angles = spectatee.v_angle;
-       self.stat_respawn_time = spectatee.stat_respawn_time;
        if(!self.BUTTON_USE)
                self.fixangle = TRUE;
        setorigin(self, spectatee.origin);
@@@ -2192,46 -2089,6 +2089,46 @@@ float SpectateUpdate() 
  }
  
  
 +float setSpectator()
 +{
 +      if(self.enemy.classname != "player")
 +              return FALSE;
 +      /*if(self.enemy.vehicle)
 +      {
 +
 +              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);
 +      }
 +      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 TRUE;
 +}
 +
 +float Spectate(entity pl)
 +{
 +      if(g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer)
 +      if(pl.team != self.team)
 +              return 0;
 +
 +      self.enemy = pl;
 +      return setSpectator();
 +}
 +
  // Returns next available player to spectate if g_ca_spectate_enemies == 0
  entity CA_SpectateNext(entity start) {
        if (start.team == self.team) {
        return other;
  }
  
 -float SpectateNext(entity _prefer) {
 -      
 -      if(_prefer)
 -              other = _prefer;        
 -      else
 -              other = find(self.enemy, classname, "player");
 -      
 +float SpectateNext()
 +{
 +      other = find(self.enemy, classname, "player");
 +
        if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer) {
                // CA and ca players when spectating enemies is forbidden
                other = CA_SpectateNext(other);
                if (!other)
                        other = find(other, classname, "player");
        }
 -      
 +
        if (other)
                self.enemy = other;
  
 -      if(self.enemy.classname == "player") {
 -          /*if(self.enemy.vehicle)
 -          {      
 -            
 -            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);
 -          }
 -          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;
 +      return setSpectator();
 +}
 +
 +float SpectatePrev()
 +{
 +      // NOTE: chain order is from the highest to the lower entnum (unlike find)
 +      other = findchain(classname, "player");
 +      if not(other) // no player
 +              return FALSE;
 +
 +      entity first = other;
 +      // skip players until current spectated player
 +      if(self.enemy)
 +      while(other && other != self.enemy)
 +              other = other.chain;
 +
 +      if (g_ca && !autocvar_g_ca_spectate_enemies && self.caplayer)
 +      {
 +              do { other = other.chain; }
 +              while(other && other.team != self.team);
 +
 +              if not(other)
 +              {
 +                      other = first;
 +                      while(other.team != self.team)
 +                              other = other.chain;
 +                      if(other == self.enemy)
 +                              return TRUE;
 +              }
 +      }
 +      else
 +      {
 +              if(other.chain)
 +                      other = other.chain;
 +              else
 +                      other = first;
        }
 +      self.enemy = other;
 +      return setSpectator();
  }
  
  /*
@@@ -2333,13 -2182,15 +2230,15 @@@ void ShowRespawnCountdown(
                {
                        self.respawn_countdown = number - 1;
                        if(ceil(self.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
-                               AnnounceTo(self, strcat(ftos(number), ""));
+                               Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(number)); 
                }
        }
  }
  
  void LeaveSpectatorMode()
  {
+       if(self.caplayer)
+               return;
        if(nJoinAllowed(self))
        {
                if(!teamplay || autocvar_g_campaign || autocvar_g_balance_teams || (self.wasplayer && autocvar_g_changeteam_banned) || self.team_forced > 0)
  
                        if(autocvar_g_campaign)
                                { campaign_bots_may_start = 1; }
-                       else
-                               { Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD); }
  
                        Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
-                       
                        PutClientInServer();
  
                        if(IS_PLAYER(self)) { Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_JOIN_PLAY, self.netname); }
                }
-               else if not(g_ca && self.caplayer) { stuffcmd(self, "menu_showteamselect\n"); }
+               else
+                       stuffcmd(self, "menu_showteamselect\n");
        }
        else
        {
                // Player may not join because g_maxplayers is set
-               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_PREVENT_JOIN);
+               Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_JOIN_PREVENT);
        }
  }
  
@@@ -2400,8 -2250,9 +2298,9 @@@ float nJoinAllowed(entity ignore) 
                return maxclients - totalClients;
  
        float currentlyPlaying = 0;
-       FOR_EACH_REALPLAYER(e)
-               currentlyPlaying += 1;
+       FOR_EACH_REALCLIENT(e)
+               if(e.classname == "player" || e.caplayer == 1)
+                       currentlyPlaying += 1;
  
        if(currentlyPlaying < autocvar_g_maxplayers)
                return min(maxclients - totalClients, autocvar_g_maxplayers - currentlyPlaying);
@@@ -2422,22 -2273,24 +2321,24 @@@ void checkSpectatorBlock() 
        }
  }
  
- .float motd_actived_time; // used for both motd and campaign_message
  void PrintWelcomeMessage()
  {
-       if (self.motd_actived_time == 0) { // is there already a message showing?
+       if(self.motd_actived_time == 0)
+       {
                if (autocvar_g_campaign) {
                        if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
                                self.motd_actived_time = time;
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, campaign_message);
                        }
                } else {
-                       if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
+                       if (self.BUTTON_INFO) {
                                self.motd_actived_time = time;
                                Send_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER, CENTER_MOTD, getwelcomemessage());
                        }
                }
-       } else { // showing MOTD or campaign message
+       }
+       else if(self.motd_actived_time > 0) // showing MOTD or campaign message
+       {
                if (autocvar_g_campaign) {
                        if (self.BUTTON_INFO)
                                self.motd_actived_time = time;
                                Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                } else {
-                       if ((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;
-                                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
-                               }
+                       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;
+                               Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
                        }
                }
        }
+       else //if(self.motd_actived_time < 0) // just connected, motd is active
+       {
+               if(self.BUTTON_INFO) // BUTTON_INFO hides initial MOTD
+                       self.motd_actived_time = -2; // wait until BUTTON_INFO gets released
+               else if(self.motd_actived_time == -2 || IS_PLAYER(self) || time - self.jointime > autocvar_welcome_message_time)
+               {
+                       // instanctly hide MOTD
+                       self.motd_actived_time = 0;
+                       Kill_Notification(NOTIF_ONE_ONLY, self, MSG_CENTER_CPID, CPID_MOTD);
+               }
+       }
  }
  
  void ObserverThink()
                        self.flags |= FL_SPAWNING;
                } else if(self.BUTTON_ATCK && !self.version_mismatch) {
                        self.flags &~= FL_JUMPRELEASED;
 -                      if(SpectateNext(world) == 1) {
 +                      if(SpectateNext()) {
                                self.classname = "spectator";
                        }
                } else {
                        }
                }
        }
-       PrintWelcomeMessage();
  }
  
  void SpectatorThink()
                if (self.BUTTON_JUMP && !self.version_mismatch) {
                        self.flags &~= FL_JUMPRELEASED;
                        self.flags |= FL_SPAWNING;
 -              } else if(self.BUTTON_ATCK) {
 +              } else if(self.BUTTON_ATCK || self.impulse == 10 || self.impulse == 15 || self.impulse == 18 || self.impulse >= 200 && self.impulse <= 209) {
 +                      self.flags &~= FL_JUMPRELEASED;
 +                      if(SpectateNext()) {
 +                              self.classname = "spectator";
 +                      } else {
 +                              self.classname = "observer";
 +                              PutClientInServer();
 +                      }
 +                      self.impulse = 0;
 +              } else if(self.impulse == 12 || self.impulse == 16  || self.impulse == 19 || self.impulse >= 220 && self.impulse <= 229) {
                        self.flags &~= FL_JUMPRELEASED;
 -                      if(SpectateNext(world) == 1) {
 +                      if(SpectatePrev()) {
                                self.classname = "spectator";
                        } else {
                                self.classname = "observer";
                                PutClientInServer();
                        }
 +                      self.impulse = 0;
                } else if (self.BUTTON_ATCK2) {
                        self.flags &~= FL_JUMPRELEASED;
                        self.classname = "observer";
                        PutObserverInServer();
        }
  
-       PrintWelcomeMessage();
        self.flags |= FL_CLIENT | FL_NOTARGET;
  }
  
@@@ -2555,8 -2404,6 +2462,6 @@@ void PlayerUseKey(
        MUTATOR_CALLHOOK(PlayerUseKey);
  }
  
- .float touchexplode_time;
  /*
  =============
  PlayerPreThink
@@@ -2572,14 -2419,10 +2477,10 @@@ void PlayerPreThink (void
        WarpZone_PlayerPhysics_FixVAngle();
  
        self.stat_game_starttime = game_starttime;
+       self.stat_round_starttime = round_starttime;
        self.stat_allow_oldnexbeam = autocvar_g_allow_oldnexbeam;
        self.stat_leadlimit = autocvar_leadlimit;
  
-       if(g_arena || (g_ca && !allowed_to_spawn))
-               self.stat_respawn_time = 0;
-       else
-               self.stat_respawn_time = self.respawn_time;
        if(frametime)
        {
                // physics frames: update anticheat stuff
                self.usekeypressed = self.BUTTON_USE;
        }
  
-       PrintWelcomeMessage();
+       if(clienttype(self) == CLIENTTYPE_REAL)
+               PrintWelcomeMessage();
  
        if(self.classname == "player") {
- //            if(self.netname == "Wazat")
- //                    bprint(self.classname, "\n");
  
                CheckRules_Player();
  
  
                if (self.deadflag != DEAD_NO)
                {
-                       float button_pressed, force_respawn;
                        if(self.personal && g_race_qualifying)
                        {
                                if(time > self.respawn_time)
                                {
                                        self.respawn_time = time + 1; // only retry once a second
+                                       self.stat_respawn_time = self.respawn_time;
                                        respawn();
                                        self.impulse = 141;
                                }
                        }
                        else
                        {
+                               float button_pressed;
                                if(frametime)
                                        player_anim();
                                button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE);
-                               force_respawn = (g_lms || g_ca || g_cts || autocvar_g_forced_respawn);
+                               
                                if (self.deadflag == DEAD_DYING)
                                {
-                                       if(force_respawn)
+                                       if(self.respawn_flags & RESPAWN_FORCE)
                                                self.deadflag = DEAD_RESPAWNING;
                                        else if(!button_pressed)
                                                self.deadflag = DEAD_DEAD;
                                                respawn();
                                        }
                                }
                                ShowRespawnCountdown();
+                               if(self.respawn_flags & RESPAWN_SILENT)
+                                       self.stat_respawn_time = 0;
+                               else
+                                       self.stat_respawn_time = self.respawn_time;
                        }
  
                        // if respawning, invert stat_respawn_time to indicate this, the client translates it
  
                        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(self.classname == "player")
-               if(self.deadflag == DEAD_NO)
-               if not(IS_INDEPENDENT_PLAYER(self))
-               FOR_EACH_PLAYER(other) if(self != other)
-               {
-                       if(time > other.touchexplode_time)
-                       if(other.deadflag == DEAD_NO)
-                       if not(IS_INDEPENDENT_PLAYER(other))
-                       if(boxesoverlap(self.absmin, self.absmax, other.absmin, other.absmax))
-                       {
-                               PlayerTouchExplode(self, other);
-                               self.touchexplode_time = other.touchexplode_time = time + 0.2;
-                       }
-               }
-               if(g_lms && !self.deadflag && autocvar_g_lms_campcheck_interval)
-               {
-                       vector dist;
-                       // calculate player movement (in 2 dimensions only, so jumping on one spot doesn't count as movement)
-                       dist = self.prevorigin - self.origin;
-                       dist_z = 0;
-                       self.lms_traveled_distance += fabs(vlen(dist));
-                       if((autocvar_g_campaign && !campaign_bots_may_start) || (time < game_starttime))
-                       {
-                               self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval*2;
-                               self.lms_traveled_distance = 0;
-                       }
-                       if(time > self.lms_nextcheck)
-                       {
-                               //sprint(self, "distance: ", ftos(self.lms_traveled_distance), "\n");
-                               if(self.lms_traveled_distance < autocvar_g_lms_campcheck_distance)
-                               {
-                                       Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_LMS_CAMPCHECK);
-                                       // FIXME KadaverJack: gibbing player here causes playermodel to bounce around, instead of eye.md3
-                                       // I wasn't able to find out WHY that happens, so I put a workaround in place that shall prevent players from being gibbed :(
-                                       Damage(self, self, self, bound(0, autocvar_g_lms_campcheck_damage, self.health + self.armorvalue * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP, self.origin, '0 0 0');
-                               }
-                               self.lms_nextcheck = time + autocvar_g_lms_campcheck_interval;
-                               self.lms_traveled_distance = 0;
-                       }
-               }
  
                self.prevorigin = self.origin;
  
@@@ -3014,7 -2814,7 +2872,7 @@@ void PlayerPostThink (void
                        else if(timeleft <= 10)
                        {
                                if(timeleft != self.idlekick_lasttimeleft)
-                                       AnnounceTo(self, ftos(timeleft));
+                                       Send_Notification(NOTIF_ONE, self, MSG_ANNCE, Announcer_PickNumber(timeleft));
                                self.idlekick_lasttimeleft = timeleft;
                        }
                }
index 16aa80cabcf2c3e08f2e7aef7f695f855b8d081c,5a050356de617f251898f27648ca1736a91065f8..8f289e5c3b5e0f5821b0df4bc5b99ecbb3c7da2e
@@@ -21,7 -21,7 +21,7 @@@
  
  float _spectate(entity _player)
  {
 -      if(SpectateNext(_player) == 1)
 +      if(Spectate(_player) == 1)
        {
                PutObserverInServer();
                self.classname = "spectator";
@@@ -443,6 -443,9 +443,9 @@@ void superspec_hello(
  
  MUTATOR_HOOKFUNCTION(superspec_ClientConnect)
  {
+       if(clienttype(self) != CLIENTTYPE_REAL)
+               return FALSE;
        string fn = "superspec-local.options";
        float fh;