X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fcl_client.qc;h=fe307fc01ac5872538b0ffd5aada4cdd964cab24;hp=28d9c6c1a04895bc264ace6bbcd99182e44f6f89;hb=87cbf00c7734cf2910502c217b5c5157511ba5ea;hpb=3220cab5a7b69ced4a641504a6a5f4eccf2d3bfc diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc index 28d9c6c1a0..fe307fc01a 100644 --- a/qcsrc/server/cl_client.qc +++ b/qcsrc/server/cl_client.qc @@ -55,21 +55,20 @@ STATIC_METHOD(Client, Add, void(Client this, int _team)) { - WITHSELF(this, ClientConnect()); + ClientConnect(this); TRANSMUTE(Player, this); this.frame = 12; // 7 this.team = _team; - WITHSELF(this, PutClientInServer()); + PutClientInServer(this); } void PutObserverInServer(entity this); -void ClientDisconnect(); STATIC_METHOD(Client, Remove, void(Client this)) { TRANSMUTE(Observer, this); - WITHSELF(this, PutClientInServer()); - WITHSELF(this, ClientDisconnect()); + PutClientInServer(this); + ClientDisconnect(this); } void send_CSQC_teamnagger() { @@ -270,7 +269,7 @@ void PutObserverInServer(entity this) this.health = FRAGS_SPECTATOR; this.takedamage = DAMAGE_NO; this.solid = SOLID_NOT; - this.movetype = MOVETYPE_FLY_WORLDONLY; // user preference is controlled by playerprethink + set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink this.flags = FL_CLIENT | FL_NOTARGET; this.armorvalue = 666; this.effects = 0; @@ -440,8 +439,8 @@ void FixPlayermodel(entity player) /** Called when a client spawns in the server */ -void PutClientInServer() -{ENGINE_EVENT(); +void PutClientInServer(entity this) +{ if (IS_BOT_CLIENT(this)) { TRANSMUTE(Player, this); } else if (IS_REAL_CLIENT(this)) { @@ -463,6 +462,8 @@ void PutClientInServer() if (IS_OBSERVER(this)) { PutObserverInServer(this); } else if (IS_PLAYER(this)) { + if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE); + PlayerState_attach(this); accuracy_resend(this); @@ -480,7 +481,7 @@ void PutClientInServer() this.iscreature = true; this.teleportable = TELEPORT_NORMAL; this.damagedbycontents = true; - this.movetype = MOVETYPE_WALK; + set_movetype(this, MOVETYPE_WALK); this.solid = SOLID_SLIDEBOX; this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID; if (autocvar_g_playerclip_collisions) @@ -731,8 +732,8 @@ void SetNewParms () SetChangeParms ============= */ -void SetChangeParms () -{ENGINE_EVENT(); +void SetChangeParms (entity this) +{ // save parms for level change parm1 = this.parm_idlesince - time; @@ -779,7 +780,7 @@ void ClientKill_Now_TeamChange(entity this) PutObserverInServer(this); } else - WITHSELF(this, SV_ChangeTeam(this.killindicator_teamchange - 1)); + SV_ChangeTeam(this, this.killindicator_teamchange - 1); this.killindicator_teamchange = 0; } @@ -803,7 +804,7 @@ void ClientKill_Now(entity this) if(this.killindicator_teamchange) ClientKill_Now_TeamChange(this); - if(IS_PLAYER(this)) + if(!IS_SPEC(this) && !IS_OBSERVER(this)) Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0'); // now I am sure the player IS dead @@ -853,7 +854,6 @@ void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change, { float killtime; float starttime; - entity e; if (gameover) return; @@ -896,20 +896,20 @@ void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change, this.killindicator.count = bound(0, ceil(killtime), 10); //sprint(this, strcat("^1You'll be dead in ", ftos(this.killindicator.cnt), " seconds\n")); - for(e = NULL; (e = find(e, classname, "body")) != NULL; ) + FOREACH_ENTITY_ENT(enemy, this, { - if(e.enemy != this) + if(it.classname != "body") continue; - e.killindicator = spawn(); - e.killindicator.owner = e; - e.killindicator.scale = 0.5; - setattachment(e.killindicator, e, ""); - setorigin(e.killindicator, '0 0 52'); - setthink(e.killindicator, KillIndicator_Think); - e.killindicator.nextthink = starttime + (e.lip) * 0.05; - clientkilltime = max(clientkilltime, e.killindicator.nextthink + 0.05); - e.killindicator.cnt = ceil(killtime); - } + it.killindicator = spawn(); + it.killindicator.owner = it; + it.killindicator.scale = 0.5; + setattachment(it.killindicator, it, ""); + setorigin(it.killindicator, '0 0 52'); + setthink(it.killindicator, KillIndicator_Think); + it.killindicator.nextthink = starttime + (it.lip) * 0.05; + //clientkilltime = max(clientkilltime, it.killindicator.nextthink + 0.05); + it.killindicator.cnt = ceil(killtime); + }); this.lip = 0; } } @@ -947,8 +947,8 @@ void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change, } -void ClientKill () -{ENGINE_EVENT(); +void ClientKill (entity this) +{ if(gameover) return; if(this.player_blocked) return; if(STAT(FROZEN, this)) return; @@ -1017,8 +1017,8 @@ ClientConnect Called when a client connects to the server ============= */ -void ClientConnect() -{ENGINE_EVENT(); +void ClientConnect(entity this) +{ if (Ban_MaybeEnforceBanOnce(this)) return; assert(!IS_CLIENT(this), return); this.flags |= FL_CLIENT; @@ -1147,7 +1147,7 @@ void ClientConnect() if (!sv_foginterval && world.fog != "") stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n")); - if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && (c3==-1 && c4==-1))) + if (autocvar_sv_teamnagger && !(autocvar_bot_vs_human && AvailableTeams() == 2)) if (!g_ca && !g_cts && !g_race) // teamnagger is currently bad for ca, race & cts send_CSQC_teamnagger(); @@ -1173,8 +1173,8 @@ Called when a client disconnects from the server */ .entity chatbubbleentity; void ReadyCount(); -void ClientDisconnect() -{ENGINE_EVENT(); +void ClientDisconnect(entity this) +{ assert(IS_CLIENT(this), return); PlayerStats_GameReport_FinalizePlayer(this); @@ -1289,7 +1289,7 @@ void respawn(entity this) { this.solid = SOLID_NOT; this.takedamage = DAMAGE_NO; - this.movetype = MOVETYPE_FLY; + set_movetype(this, MOVETYPE_FLY); this.velocity = '0 0 1' * autocvar_g_respawn_ghosts_speed; this.avelocity = randomvec() * autocvar_g_respawn_ghosts_speed * 3 - randomvec() * autocvar_g_respawn_ghosts_speed * 3; this.effects |= CSQCMODEL_EF_RESPAWNGHOST; @@ -1301,7 +1301,7 @@ void respawn(entity this) CopyBody(this, 1); this.effects |= EF_NODRAW; // prevent another CopyBody - WITHSELF(this, PutClientInServer()); + PutClientInServer(this); } void play_countdown(entity this, float finished, Sound samp) @@ -1615,7 +1615,7 @@ void SpectateCopy(entity this, entity spectatee) this.angles = spectatee.v_angle; STAT(FROZEN, this) = STAT(FROZEN, spectatee); this.revive_progress = spectatee.revive_progress; - if(!PHYS_INPUT_BUTTON_USE(this)) + if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2) this.fixangle = true; setorigin(this, spectatee.origin); setsize(this, spectatee.mins, spectatee.maxs); @@ -1625,7 +1625,9 @@ void SpectateCopy(entity this, entity spectatee) this.hud = spectatee.hud; if(spectatee.vehicle) { - this.fixangle = false; + this.angles = spectatee.v_angle; + + //this.fixangle = false; //this.velocity = spectatee.vehicle.velocity; this.vehicle_health = spectatee.vehicle_health; this.vehicle_shield = spectatee.vehicle_shield; @@ -1635,12 +1637,12 @@ void SpectateCopy(entity this, entity spectatee) this.vehicle_reload1 = spectatee.vehicle_reload1; this.vehicle_reload2 = spectatee.vehicle_reload2; - msg_entity = this; + //msg_entity = this; - WriteByte (MSG_ONE, SVC_SETVIEWANGLES); - WriteAngle(MSG_ONE, spectatee.v_angle.x); - WriteAngle(MSG_ONE, spectatee.v_angle.y); - WriteAngle(MSG_ONE, spectatee.v_angle.z); + // WriteByte (MSG_ONE, SVC_SETVIEWANGLES); + //WriteAngle(MSG_ONE, spectatee.v_angle.x); + // WriteAngle(MSG_ONE, spectatee.v_angle.y); + // WriteAngle(MSG_ONE, spectatee.v_angle.z); //WriteByte (MSG_ONE, SVC_SETVIEW); // WriteEntity(MSG_ONE, this); @@ -1673,7 +1675,7 @@ bool SpectateSet(entity this) msg_entity = this; WriteByte(MSG_ONE, SVC_SETVIEW); WriteEntity(MSG_ONE, this.enemy); - this.movetype = MOVETYPE_NONE; + set_movetype(this, MOVETYPE_NONE); accuracy_resend(this); if(!SpectateUpdate(this)) @@ -1706,14 +1708,14 @@ bool Spectate(entity this, entity pl) bool SpectateNext(entity this) { - other = find(this.enemy, classname, STR_PLAYER); + entity ent = find(this.enemy, classname, STR_PLAYER); - if (MUTATOR_CALLHOOK(SpectateNext, this, other)) - other = M_ARGV(1, entity); - else if (!other) - other = find(other, classname, STR_PLAYER); + if (MUTATOR_CALLHOOK(SpectateNext, this, ent)) + ent = M_ARGV(1, entity); + else if (!ent) + ent = find(ent, classname, STR_PLAYER); - if(other) { SetSpectatee(this, other); } + if(ent) { SetSpectatee(this, ent); } return SpectateSet(this); } @@ -1721,36 +1723,35 @@ bool SpectateNext(entity this) bool SpectatePrev(entity this) { // NOTE: chain order is from the highest to the lower entnum (unlike find) - other = findchain(classname, STR_PLAYER); - if (!other) // no player + entity ent = findchain(classname, STR_PLAYER); + if (!ent) // no player return false; - entity first = other; + entity first = ent; // skip players until current spectated player if(this.enemy) - while(other && other != this.enemy) - other = other.chain; + while(ent && ent != this.enemy) + ent = ent.chain; - switch (MUTATOR_CALLHOOK(SpectatePrev, this, other, first)) + switch (MUTATOR_CALLHOOK(SpectatePrev, this, ent, first)) { case MUT_SPECPREV_FOUND: - other = M_ARGV(1, entity); + ent = M_ARGV(1, entity); break; case MUT_SPECPREV_RETURN: - other = M_ARGV(1, entity); return true; case MUT_SPECPREV_CONTINUE: default: { - if(other.chain) - other = other.chain; + if(ent.chain) + ent = ent.chain; else - other = first; + ent = first; break; } } - SetSpectatee(this, other); + SetSpectatee(this, ent); return SpectateSet(this); } @@ -1798,7 +1799,7 @@ void LeaveSpectatorMode(entity this) Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN); - WITHSELF(this, PutClientInServer()); + PutClientInServer(this); if(IS_PLAYER(this)) { Send_Notification(NOTIF_ALL, NULL, MSG_INFO, ((teamplay && this.team != -1) ? APP_TEAM_ENT(this, INFO_JOIN_PLAY_TEAM) : INFO_JOIN_PLAY), this.netname); } } @@ -1924,7 +1925,6 @@ void ObserverThink(entity this) MinigameImpulse(this, this.impulse); this.impulse = 0; } - float prefered_movetype; if (this.flags & FL_JUMPRELEASED) { if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) { this.flags &= ~FL_JUMPRELEASED; @@ -1935,9 +1935,8 @@ void ObserverThink(entity this) TRANSMUTE(Spectator, this); } } else { - prefered_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP); - if (this.movetype != prefered_movetype) - this.movetype = prefered_movetype; + int preferred_movetype = ((!PHYS_INPUT_BUTTON_USE(this) ? this.cvar_cl_clippedspectating : !this.cvar_cl_clippedspectating) ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP); + set_movetype(this, preferred_movetype); } } else { if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this))) { @@ -1958,6 +1957,13 @@ void SpectatorThink(entity this) { if(MinigameImpulse(this, this.impulse)) this.impulse = 0; + + if (this.impulse == IMP_weapon_drop.impulse) + { + STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3; + this.impulse = 0; + return; + } } if (this.flags & FL_JUMPRELEASED) { if (PHYS_INPUT_BUTTON_JUMP(this) && !this.version_mismatch) { @@ -1969,7 +1975,7 @@ void SpectatorThink(entity this) TRANSMUTE(Spectator, this); } else { TRANSMUTE(Observer, this); - WITHSELF(this, PutClientInServer()); + PutClientInServer(this); } this.impulse = 0; } else if(this.impulse == 12 || this.impulse == 16 || this.impulse == 19 || (this.impulse >= 220 && this.impulse <= 229)) { @@ -1978,13 +1984,13 @@ void SpectatorThink(entity this) TRANSMUTE(Spectator, this); } else { TRANSMUTE(Observer, this); - WITHSELF(this, PutClientInServer()); + PutClientInServer(this); } this.impulse = 0; } else if (PHYS_INPUT_BUTTON_ATCK2(this)) { this.flags &= ~FL_JUMPRELEASED; TRANSMUTE(Observer, this); - WITHSELF(this, PutClientInServer()); + PutClientInServer(this); } else { if(!SpectateUpdate(this)) PutObserverInServer(this); @@ -2031,7 +2037,7 @@ void PlayerUseKey(entity this) while(head) // find the closest acceptable target to enter { - if(head.vehicle_flags & VHF_ISVEHICLE) + if(IS_VEHICLE(head)) if(!IS_DEAD(head)) if(!head.owner || ((head.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(head.owner, this))) if(head.takedamage != DAMAGE_NO) @@ -2066,8 +2072,8 @@ Called every frame for each client before the physics are run .float usekeypressed; .float last_vehiclecheck; .int items_added; -void PlayerPreThink () -{ENGINE_EVENT(); +void PlayerPreThink (entity this) +{ WarpZone_PlayerPhysics_FixVAngle(this); STAT(GAMESTARTTIME, this) = game_starttime; @@ -2155,26 +2161,24 @@ void PlayerPreThink () MUTATOR_CALLHOOK(PlayerPreThink, this); - if(autocvar_g_vehicles_enter) - if(time > this.last_vehiclecheck) - if(IS_PLAYER(this)) - if(!gameover) - if(!STAT(FROZEN, this)) - if(!this.vehicle) - if(!IS_DEAD(this)) + if(autocvar_g_vehicles_enter && (time > this.last_vehiclecheck) && !gameover && !this.vehicle) + if(IS_PLAYER(this) && !STAT(FROZEN, this) && !IS_DEAD(this)) { - entity veh; - for(veh = NULL; (veh = findflags(veh, vehicle_flags, VHF_ISVEHICLE)); ) - if(vdist(veh.origin - this.origin, <, autocvar_g_vehicles_enter_radius)) - if(!IS_DEAD(veh)) - if(veh.takedamage != DAMAGE_NO) - if((veh.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(veh.owner, this)) - Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER); - else if(!veh.owner) - if(!veh.team || SAME_TEAM(this, veh)) - Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER); - else if(autocvar_g_vehicles_steal) - Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL); + FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_vehicles_enter_radius, IS_VEHICLE(it), + { + if(!IS_DEAD(it) && it.takedamage != DAMAGE_NO) + if((it.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(it.owner, this)) + { + Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER); + } + else if(!it.owner) + { + if(!it.team || SAME_TEAM(this, it)) + Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER); + else if(autocvar_g_vehicles_steal) + Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL); + } + }); this.last_vehiclecheck = time + 1; } @@ -2218,27 +2222,39 @@ void PlayerPreThink () if (frametime) player_anim(this); bool button_pressed = (PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this)); - if (this.deadflag == DEAD_DYING) { - if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max)) { - this.deadflag = DEAD_RESPAWNING; - } else if (!button_pressed) { - this.deadflag = DEAD_DEAD; - } - } else if (this.deadflag == DEAD_DEAD) { - if (button_pressed) { - this.deadflag = DEAD_RESPAWNABLE; - } else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)) { - this.deadflag = DEAD_RESPAWNING; - } - } else if (this.deadflag == DEAD_RESPAWNABLE) { - if (!button_pressed) { - this.deadflag = DEAD_RESPAWNING; - } - } else if (this.deadflag == DEAD_RESPAWNING) { - if (time > this.respawn_time) { - this.respawn_time = time + 1; // only retry once a second - this.respawn_time_max = this.respawn_time; - respawn(this); + switch(this.deadflag) + { + case DEAD_DYING: + { + if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max)) + this.deadflag = DEAD_RESPAWNING; + else if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE)) + this.deadflag = DEAD_DEAD; + break; + } + case DEAD_DEAD: + { + if (button_pressed) + this.deadflag = DEAD_RESPAWNABLE; + else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)) + this.deadflag = DEAD_RESPAWNING; + break; + } + case DEAD_RESPAWNABLE: + { + if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE)) + this.deadflag = DEAD_RESPAWNING; + break; + } + case DEAD_RESPAWNING: + { + if (time > this.respawn_time) + { + this.respawn_time = time + 1; // only retry once a second + this.respawn_time_max = this.respawn_time; + respawn(this); + } + break; } } @@ -2270,12 +2286,15 @@ void PlayerPreThink () .entity weaponentity = weaponentities[0]; // TODO: unhardcode if (this.hook.state) { do_crouch = false; + } else if (this.waterlevel >= WATERLEVEL_SWIMMING) { + do_crouch = false; } else if (this.vehicle) { do_crouch = false; } else if (STAT(FROZEN, this)) { do_crouch = false; - } else if ((PS(this).m_weapon == WEP_SHOTGUN || PS(this).m_weapon == WEP_SHOCKWAVE) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) { - // WEAPONTODO: predict + } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_PRI) && this.(weaponentity).wframe == WFRAME_FIRE1 && time < this.(weaponentity).weapon_nextthink) { + do_crouch = false; + } else if ((PS(this).m_weapon.spawnflags & WEP_TYPE_MELEE_SEC) && this.(weaponentity).wframe == WFRAME_FIRE2 && time < this.(weaponentity).weapon_nextthink) { do_crouch = false; } @@ -2368,13 +2387,13 @@ void PlayerPreThink () entity e = this.teamkill_soundsource; entity oldpusher = e.pusher; e.pusher = this; - PlayerSound(e, playersound_teamshoot, CH_VOICE, VOICETYPE_LASTATTACKER_ONLY); + PlayerSound(e, playersound_teamshoot, CH_VOICE, VOL_BASEVOICE, VOICETYPE_LASTATTACKER_ONLY); e.pusher = oldpusher; } if (this.taunt_soundtime && time > this.taunt_soundtime) { this.taunt_soundtime = 0; - PlayerSound(this, playersound_taunt, CH_VOICE, VOICETYPE_AUTOTAUNT); + PlayerSound(this, playersound_taunt, CH_VOICE, VOL_BASEVOICE, VOICETYPE_AUTOTAUNT); } target_voicescript_next(this); @@ -2390,10 +2409,10 @@ void DrownPlayer(entity this) if(IS_DEAD(this)) return; - if (this.waterlevel != WATERLEVEL_SUBMERGED) + if (this.waterlevel != WATERLEVEL_SUBMERGED || this.vehicle) { if(this.air_finished < time) - PlayerSound(this, playersound_gasp, CH_PLAYER, VOICETYPE_PLAYERSOUND); + PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND); this.air_finished = time + autocvar_g_balance_contents_drowndelay; this.dmg = 2; } @@ -2407,6 +2426,30 @@ void DrownPlayer(entity this) } } +void Player_Physics(entity this) +{ + this.movetype = ((this.move_qcphysics) ? MOVETYPE_NONE : this.move_movetype); + + if(!this.move_qcphysics) + return; + + int mt = this.move_movetype; + + if(mt == MOVETYPE_PUSH || mt == MOVETYPE_FAKEPUSH || mt == MOVETYPE_PHYSICS) + { + this.move_qcphysics = false; + this.movetype = mt; + return; + } + + if(!frametime && !this.pm_frametime) + return; + + Movetype_Physics_NoMatchTicrate(this, this.pm_frametime, true); + + this.pm_frametime = 0; +} + /* ============= PlayerPostThink @@ -2415,14 +2458,27 @@ Called every frame for each client after the physics are run ============= */ .float idlekick_lasttimeleft; -void PlayerPostThink () -{ENGINE_EVENT(); +void PlayerPostThink (entity this) +{ + Player_Physics(this); + if (sv_maxidle > 0) if (frametime) // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero). if (IS_REAL_CLIENT(this)) if (IS_PLAYER(this) || sv_maxidle_spectatorsareidle) { - if (time - this.parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10 + int totalClients = 0; + if(sv_maxidle_slots > 0) + { + FOREACH_CLIENT(IS_REAL_CLIENT(it) || sv_maxidle_slots_countbots, + { + ++totalClients; + }); + } + + if (sv_maxidle_slots > 0 && (maxclients - totalClients) > sv_maxidle_slots) + { /* do nothing */ } + else if (time - this.parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10 { if (this.idlekick_lasttimeleft) {