]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/cl_client.qc
Merge remote-tracking branch 'origin/master' into terencehill/spectate_prev
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / cl_client.qc
index 5bc0178f560fc491adb64bb3d7cb706e002bbd34..ca19ed7464b67307740805031f7b626ae8ea5c54 100644 (file)
@@ -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;
@@ -385,6 +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);
@@ -406,13 +424,9 @@ void PutObserverInServer (void)
        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);
@@ -443,7 +457,9 @@ void PutObserverInServer (void)
        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;
@@ -488,45 +504,6 @@ void PutObserverInServer (void)
        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;
@@ -611,21 +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
@@ -637,11 +599,7 @@ Called when a client spawns in the server
 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;
@@ -660,13 +618,12 @@ void PutClientInServer (void)
                        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;
 
@@ -772,7 +729,9 @@ void PutClientInServer (void)
                }
                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;
@@ -824,14 +783,6 @@ void PutClientInServer (void)
                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;
@@ -857,14 +808,7 @@ void PutClientInServer (void)
 
                //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
@@ -1062,14 +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()
@@ -1245,19 +1188,11 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2
 
 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
@@ -1417,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)
@@ -1487,13 +1422,6 @@ void ClientConnect (void)
        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();
@@ -1519,15 +1447,6 @@ void ClientConnect (void)
                        stuffcmd(self, "cl_cmd settemp chase_active 1\n");
        }
 
-       if(g_lms)
-       {
-               if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
-               {
-                       PlayerScore_Add(self, SP_LMS_RANK, 666);
-                       self.frags = FRAGS_SPECTATOR;
-               }
-       }
-
        if(!sv_foginterval && world.fog != "")
                stuffcmd(self, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
 
@@ -1567,13 +1486,11 @@ void ClientConnect (void)
        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);
 }
 /*
 =============
@@ -1640,12 +1557,6 @@ void ClientDisconnect (void)
 
        bot_relinkplayerlist();
 
-       if(g_arena)
-       {
-               Spawnqueue_Unmark(self);
-               Spawnqueue_Remove(self);
-       }
-
        accuracy_free(self);
        ClientData_Detach();
        PlayerScore_Detach(self);
@@ -2003,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))
@@ -2128,7 +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);
@@ -2179,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) {
@@ -2202,13 +2152,10 @@ entity CA_SpectateNext(entity start) {
        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);
@@ -2217,38 +2164,49 @@ float SpectateNext(entity _prefer) {
                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();
 }
 
 /*
@@ -2279,6 +2237,8 @@ void ShowRespawnCountdown()
 
 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)
@@ -2297,7 +2257,8 @@ void LeaveSpectatorMode()
 
                        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
        {
@@ -2337,8 +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);
@@ -2415,7 +2377,7 @@ 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 {
@@ -2442,14 +2404,24 @@ 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(world) == 1) {
+                       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(SpectatePrev()) {
+                               self.classname = "spectator";
+                       } else {
+                               self.classname = "observer";
+                               PutClientInServer();
+                       }
+                       self.impulse = 0;
                } else if (self.BUTTON_ATCK2) {
                        self.flags &~= FL_JUMPRELEASED;
                        self.classname = "observer";
@@ -2490,8 +2462,6 @@ void PlayerUseKey()
        MUTATOR_CALLHOOK(PlayerUseKey);
 }
 
-.float touchexplode_time;
-
 /*
 =============
 PlayerPreThink
@@ -2507,14 +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
@@ -2639,25 +2605,26 @@ void PlayerPreThink (void)
 
                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;
@@ -2680,7 +2647,13 @@ void PlayerPreThink (void)
                                                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
@@ -2689,58 +2662,6 @@ 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)
-               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 :(
-                                       if(self.vehicle)
-                                               Damage(self.vehicle, self, self, autocvar_g_lms_campcheck_damage * 2, DEATH_CAMP, self.vehicle.origin, '0 0 0');
-                                       else
-                                               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;