]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/cl_client.qc
adjust for fteqcc changes (these are safe, hope the new fteqcc still works)
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / cl_client.qc
index a497f8c34e336a4508296ebafb80e769ab401c52..52b1e375321e45d196c3a33132b814a47f7853c9 100644 (file)
@@ -614,6 +614,9 @@ void PutObserverInServer (void)
        DropAllRunes(self);
        MUTATOR_CALLHOOK(MakePlayerObserver);
 
+       if (g_minstagib)
+               minstagib_stop_countdown();
+
        Portal_ClearAll(self);
 
        if(self.alivetime)
@@ -656,13 +659,13 @@ void PutObserverInServer (void)
        accuracy_resend(self);
 
        self.spectatortime = time;
-
+       
        self.classname = "observer";
        self.iscreature = FALSE;
        self.health = -666;
        self.takedamage = DAMAGE_NO;
        self.solid = SOLID_NOT;
-       self.movetype = MOVETYPE_NOCLIP;
+       self.movetype = MOVETYPE_FLY_WORLDONLY; //(self.cvar_cl_clippedspectating ? MOVETYPE_NOCLIP : MOVETYPE_FLY); // it's too early for this anyway, lets just set it in playerprethink
        self.flags = FL_CLIENT | FL_NOTARGET;
        self.armorvalue = 666;
        self.effects = 0;
@@ -691,9 +694,9 @@ void PutObserverInServer (void)
        self.fixangle = TRUE;
        self.crouch = FALSE;
 
-       self.view_ofs = PL_VIEW_OFS;
+       self.view_ofs = '0 0 0'; // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
        setorigin (self, spot.origin);
-       setsize (self, '0 0 0', '0 0 0');
+       setsize (self, PL_CROUCH_MIN, PL_CROUCH_MAX); // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
        self.prevorigin = self.origin;
        self.items = 0;
        self.weapons = 0;
@@ -702,6 +705,8 @@ void PutObserverInServer (void)
        self.model = "";
        self.modelindex = 0;
        self.weapon = 0;
+       self.weaponname = "";
+       self.switchingweapon = 0;
        self.weaponmodel = "";
        self.weaponentity = world;
        self.exteriorweaponentity = world;
@@ -736,6 +741,13 @@ void PutObserverInServer (void)
                else
                        self.frags = FRAGS_LMS_LOSER;
        }
+       else if(g_ca)
+       {
+               if(self.caplayer)
+                       self.frags = FRAGS_LMS_LOSER;
+               else
+                       self.frags = FRAGS_SPECTATOR;
+       }
        else
                self.frags = FRAGS_SPECTATOR;
 }
@@ -895,7 +907,7 @@ void PutClientInServer (void)
                if(clienttype(self) == CLIENTTYPE_BOT && autocvar_g_botclip_collisions)
                        self.dphitcontentsmask |= DPCONTENTS_BOTCLIP;
                self.frags = FRAGS_PLAYER;
-               if(independent_players)
+               if(INDEPENDENT_PLAYERS)
                        MAKE_INDEPENDENT_PLAYER(self);
                self.flags = FL_CLIENT;
                self.takedamage = DAMAGE_AIM;
@@ -1038,8 +1050,6 @@ void PutClientInServer (void)
                        self.killcount = 0;
                }
 
-               self.cnt = WEP_LASER;
-
                CL_SpawnWeaponentity();
                self.alpha = default_player_alpha;
                self.colormod = '1 1 1' * autocvar_g_player_brightness;
@@ -1081,9 +1091,8 @@ void PutClientInServer (void)
                        entity e;
                        e = get_weaponinfo(j);
                        if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
-                               self.weapon_load[j] = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
+                               self.(weapon_load[j]) = cvar(strcat("g_balance_", e.netname, "_reload_ammo"));
                }
-               self.weapon_forbidchange = FALSE;
 
                oldself = self;
                self = spot;
@@ -1099,8 +1108,10 @@ void PutClientInServer (void)
                MUTATOR_CALLHOOK(PlayerSpawn);
 
                self.switchweapon = w_getbestweapon(self);
-               self.cnt = self.switchweapon;
+               self.cnt = -1; // W_LastWeapon will not complain
                self.weapon = 0;
+               self.weaponname = "";
+               self.switchingweapon = 0;
 
                if(!self.alivetime)
                        self.alivetime = time;
@@ -1326,26 +1337,17 @@ 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;
        }
 }
 
+float clientkilltime;
 void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2 = spec
 {
        float killtime;
+       float starttime;
        entity e;
 
        if (gameover)
@@ -1381,13 +1383,16 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2
                }
                else
                {
+                       starttime = max(time, clientkilltime);
+
                        self.killindicator = spawn();
                        self.killindicator.owner = self;
                        self.killindicator.scale = 0.5;
                        setattachment(self.killindicator, self, "");
                        setorigin(self.killindicator, '0 0 52');
                        self.killindicator.think = KillIndicator_Think;
-                       self.killindicator.nextthink = time + (self.lip) * 0.05;
+                       self.killindicator.nextthink = starttime + (self.lip) * 0.05;
+                       clientkilltime = max(clientkilltime, self.killindicator.nextthink + 0.05);
                        self.killindicator.cnt = ceil(killtime);
                        self.killindicator.count = bound(0, ceil(killtime), 10);
                        //sprint(self, strcat("^1You'll be dead in ", ftos(self.killindicator.cnt), " seconds\n"));
@@ -1402,7 +1407,8 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2
                                setattachment(e.killindicator, e, "");
                                setorigin(e.killindicator, '0 0 52');
                                e.killindicator.think = KillIndicator_Think;
-                               e.killindicator.nextthink = time + (e.lip) * 0.05;
+                               e.killindicator.nextthink = starttime + (e.lip) * 0.05;
+                               clientkilltime = max(clientkilltime, e.killindicator.nextthink + 0.05);
                                e.killindicator.cnt = ceil(killtime);
                        }
                        self.lip = 0;
@@ -1411,14 +1417,35 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2
        if(self.killindicator)
        {
                if(targetteam == 0) // just die
+               {
                        self.killindicator.colormod = '0 0 0';
+                       if(clienttype(self) == CLIENTTYPE_REAL)
+                       if(self.killindicator.cnt > 0)
+                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, "^1Suicide in %d seconds", 1, self.killindicator.cnt);
+               }
                else if(targetteam == -1) // auto
+               {
                        self.killindicator.colormod = '0 1 0';
+                       if(clienttype(self) == CLIENTTYPE_REAL)
+                       if(self.killindicator.cnt > 0)
+                               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)
+                       if(self.killindicator.cnt > 0)
+                               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)
+                       if(self.killindicator.cnt > 0)
+                               Send_CSQC_Centerprint_Generic(self, CPID_TEAMCHANGE, strcat("Changing to ", ColoredTeamName(targetteam), " in %d seconds"), 1, self.killindicator.cnt);
+               }
        }
+
 }
 
 void ClientKill (void)
@@ -1624,6 +1651,8 @@ void ClientConnect (void)
 
        self.playerid = (playerid_last = playerid_last + 1);
 
+       PlayerStats_AddEvent(sprintf("kills-%d", self.playerid));
+
     if(clienttype(self) == CLIENTTYPE_BOT)
         PlayerStats_AddPlayer(self);
 
@@ -1643,11 +1672,8 @@ void ClientConnect (void)
 
        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");
+       stuffcmd(self, "cl_particles_reloadeffects\n"); // TODO do we still need this?
 
        FixClientCvars(self);
 
@@ -1758,6 +1784,9 @@ void ClientConnect (void)
                set_dom_state(self);
 
        CheatInitClient();
+
+       if(!autocvar_g_campaign)
+               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), autocvar_welcome_message_time, 0);
 }
 
 /*
@@ -1956,47 +1985,6 @@ void play_countdown(float finished, string samp)
                                sound (self, CH_INFO, 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
@@ -2325,6 +2313,7 @@ void SpectateCopy(entity spectatee) {
        self.pressedkeys = spectatee.pressedkeys;
        self.weapons = spectatee.weapons;
        self.switchweapon = spectatee.switchweapon;
+       self.switchingweapon = spectatee.switchingweapon;
        self.weapon = spectatee.weapon;
        self.nex_charge = spectatee.nex_charge;
        self.nex_chargepool_ammo = spectatee.nex_chargepool_ammo;
@@ -2338,7 +2327,8 @@ void SpectateCopy(entity spectatee) {
        self.dmg_save = spectatee.dmg_save;
        self.dmg_inflictor = spectatee.dmg_inflictor;
        self.angles = spectatee.v_angle;
-       self.fixangle = TRUE;
+       if(!self.BUTTON_USE)
+               self.fixangle = TRUE;
        setorigin(self, spectatee.origin);
        setsize(self, spectatee.mins, spectatee.maxs);
        SetZoomState(spectatee.zoomstate);
@@ -2384,12 +2374,41 @@ float SpectateUpdate() {
        return 1;
 }
 
-float SpectateNext() {
-       other = find(self.enemy, classname, "player");
 
-       if (!other)
+// Returns next available player to spectate if g_ca_spectate_enemies == 0
+entity CA_SpectateNext(entity start) {
+       if (start.team == self.team) {
+               return start;
+       }
+       
+       other = start;
+       // continue from current player
+       while(other && other.team != self.team) {
                other = find(other, classname, "player");
+       }
+       
+       if (!other) {
+               // restart from begining
+               other = find(other, classname, "player");
+               while(other && other.team != self.team) {
+                       other = find(other, classname, "player");
+               }
+       }
+       
+       return other;
+}
 
+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);
+       } else {
+               // other modes and ca spectators or spectating enemies is allowed
+               if (!other)
+                       other = find(other, classname, "player");
+       }
+       
        if (other)
                self.enemy = other;
 
@@ -2447,6 +2466,7 @@ void ShowRespawnCountdown()
        }
 }
 
+.float prevent_join_msgtime;
 void LeaveSpectatorMode()
 {
        if(nJoinAllowed(1)) {
@@ -2465,7 +2485,14 @@ void LeaveSpectatorMode()
                                bprint ("^4", self.netname, "^4 is playing now\n");
 
                        if(!autocvar_g_campaign)
-                               centerprint(self,""); // clear MOTD
+                       if (time < self.jointime + autocvar_welcome_message_time)
+                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_MOTD); // clear MOTD
+
+                       if (self.prevent_join_msgtime)
+                       {
+                               Send_CSQC_Centerprint_Generic_Expire(self, CPID_PREVENT_JOIN);
+                               self.prevent_join_msgtime = 0;
+                       }
 
                        return;
                } else {
@@ -2478,7 +2505,11 @@ void LeaveSpectatorMode()
        }
        else {
                //player may not join because of g_maxplayers is set
-               centerprint_atprio(self, CENTERPRIO_MAPVOTE, PREVENT_JOIN_TEXT);
+               if (time - self.prevent_join_msgtime > 2)
+               {
+                       Send_CSQC_Centerprint_Generic(self, CPID_PREVENT_JOIN, PREVENT_JOIN_TEXT, 0, 0);
+                       self.prevent_join_msgtime = time;
+               }
        }
 }
 
@@ -2525,19 +2556,58 @@ 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 (autocvar_g_campaign) {
+                       if ((self.classname == "player" && self.BUTTON_INFO) || (self.classname != "player")) {
+                               self.motd_actived_time = time;
+                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, campaign_message, -1, 0);
+                       }
+               } else {
+                       if ((time - self.jointime > autocvar_welcome_message_time) && self.BUTTON_INFO) {
+                               self.motd_actived_time = time;
+                               Send_CSQC_Centerprint_Generic(self, CPID_MOTD, getwelcomemessage(), -1, 0);
+                       }
+               }
+       } else { // showing MOTD or campaign message
+               if (autocvar_g_campaign) {
+                       if (self.BUTTON_INFO)
+                               self.motd_actived_time = time;
+                       else if ((time - self.motd_actived_time > 2) && self.classname == "player") { // 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 ((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);
+                               }
+                       }
+               }
+       }
+}
+
 void ObserverThink()
 {
+       float prefered_movetype;
        if (self.flags & FL_JUMPRELEASED) {
                if (self.BUTTON_JUMP && !self.version_mismatch) {
-                       self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        self.flags |= FL_SPAWNING;
                } else if(self.BUTTON_ATCK && !self.version_mismatch) {
-                       self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        if(SpectateNext() == 1) {
                                self.classname = "spectator";
                        }
+               } else {
+                       prefered_movetype = ((!self.BUTTON_USE ? self.cvar_cl_clippedspectating : !self.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
+                       if (self.movetype != prefered_movetype)
+                               self.movetype = prefered_movetype;
                }
        } else {
                if (!(self.BUTTON_ATCK || self.BUTTON_JUMP)) {
@@ -2550,18 +2620,17 @@ void ObserverThink()
                        }
                }
        }
-       PrintWelcomeMessage(self);
+
+       PrintWelcomeMessage();
 }
 
 void SpectatorThink()
 {
        if (self.flags & FL_JUMPRELEASED) {
                if (self.BUTTON_JUMP && !self.version_mismatch) {
-                       self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        self.flags |= FL_SPAWNING;
                } else if(self.BUTTON_ATCK) {
-                       self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        if(SpectateNext() == 1) {
                                self.classname = "spectator";
@@ -2570,7 +2639,6 @@ void SpectatorThink()
                                PutClientInServer();
                        }
                } else if (self.BUTTON_ATCK2) {
-                       self.welcomemessage_time = 0;
                        self.flags &~= FL_JUMPRELEASED;
                        self.classname = "observer";
                        PutClientInServer();
@@ -2592,7 +2660,7 @@ void SpectatorThink()
                        PutObserverInServer();
        }
 
-       PrintWelcomeMessage(self);
+       PrintWelcomeMessage();
        self.flags |= FL_CLIENT | FL_NOTARGET;
 }
 
@@ -2662,10 +2730,12 @@ void PlayerPreThink (void)
                if(self.cvar_g_xonoticversion)
                        if(time > self.version_nagtime)
                        {
-                               if(strstr(self.cvar_g_xonoticversion, "git", 0) < 0)
+                               // don't notify git users
+                               if(strstr(self.cvar_g_xonoticversion, "git", 0) < 0 && strstr(self.cvar_g_xonoticversion, "autobuild", 0) < 0)
                                {
-                                       if(strstr(autocvar_g_xonoticversion, "git", 0) >= 0)
+                                       if(strstr(autocvar_g_xonoticversion, "git", 0) >= 0 || strstr(autocvar_g_xonoticversion, "autobuild", 0) >= 0)
                                        {
+                                               // notify release users if connecting to git
                                                dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
                                                sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, " (beta)^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
                                        }
@@ -2675,12 +2745,14 @@ void PlayerPreThink (void)
                                                r = vercmp(self.cvar_g_xonoticversion, autocvar_g_xonoticversion);
                                                if(r < 0)
                                                {
-                                                       dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.com/^1!\n");
-                                                       sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.com/^1!\n"));
+                                                       // give users new version
+                                                       dprint("^1NOTE^7 to ", self.netname, "^7 - ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n");
+                                                       sprint(self, strcat("\{1}^1NOTE: ^3Xonotic ", autocvar_g_xonoticversion, "^7 is out, and you still have ^3Xonotic ", self.cvar_g_xonoticversion, "^1 - get the update from ^4http://www.xonotic.org/^1!\n"));
                                                }
                                                else if(r > 0)
                                                {
-                                                       dprint("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
+                                                       // notify users about old server version
+                                                       print("^1NOTE^7 to ", self.netname, "^7 - the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n");
                                                        sprint(self, strcat("\{1}^1NOTE: ^7the server is running ^3Xonotic ", autocvar_g_xonoticversion, "^7, you have ^3Xonotic ", self.cvar_g_xonoticversion, "^1\n"));
                                                }
                                        }
@@ -2706,14 +2778,14 @@ void PlayerPreThink (void)
                PlayerUseKey();
        self.usekeypressed = self.BUTTON_USE;
 
+       PrintWelcomeMessage();
+
        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
@@ -2769,6 +2841,9 @@ void PlayerPreThink (void)
                        player_powerups();
                }
 
+               if (g_minstagib)
+                       minstagib_ammocheck();
+
                if (self.deadflag != DEAD_NO)
                {
                        float button_pressed, force_respawn;
@@ -2816,6 +2891,8 @@ void PlayerPreThink (void)
                        }
                        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)
@@ -2927,9 +3004,6 @@ void PlayerPreThink (void)
                if(frametime)
                        player_anim();
 
-               if (g_minstagib)
-                       minstagib_ammocheck();
-
                if(g_ctf)
                        ctf_setstatus();
 
@@ -3056,7 +3130,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");
@@ -3067,16 +3155,9 @@ void PlayerPostThink (void)
                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), ""));
-                       }
+                               AnnounceTo(self, ftos(timeleft));
+                       self.idlekick_lasttimeleft = timeleft;
                }
-               else
-               {
-                       centerprint_expire(self, CENTERPRIO_IDLEKICK);
-               }
-               self.idlekick_lasttimeleft = timeleft;
        }
 
 #ifdef TETRIS
@@ -3088,6 +3169,8 @@ void PlayerPostThink (void)
 
        CheatFrame();
 
+       //CheckPlayerJump();
+
        if(self.classname == "player") {
                CheckRules_Player();
                UpdateChatBubble();