Use Xonotic's system for selecting teams and spectating
authorMirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Mon, 11 Jul 2011 15:35:10 +0000 (18:35 +0300)
committerMirceaKitsune <sonichedgehog_hyperblast00@yahoo.com>
Mon, 11 Jul 2011 15:35:10 +0000 (18:35 +0300)
data/defaultVT.cfg
data/qcsrc/server/cl_client.qc
data/qcsrc/server/clientcommands.qc
data/qcsrc/server/race.qc

index 419ddd8..60e08cf 100644 (file)
@@ -487,6 +487,7 @@ set g_rc_respawn_delay 0
 set g_cts_respawn_waves 0\r
 set g_cts_respawn_delay 0\r
 set g_cts_selfdamage 1 "0 = disable all selfdamage and falldamage in cts"\r
+set g_cts_finish_kill_delay 10 "prevent cheating by running back to the start line, and starting out with more speed than otherwise possible"\r
 set g_rpg_respawn_waves 0\r
 set g_rpg_respawn_delay 0\r
 \r
@@ -1262,7 +1263,8 @@ sv_gameplayfix_q2airaccelerate 1
 sv_gameplayfix_stepmultipletimes 1\r
 \r
 // delay for "kill" to prevent abuse\r
-set g_balance_kill_delay 5\r
+set g_balance_kill_delay 2\r
+set g_balance_kill_antispam 5\r
 \r
 // this feature is currently buggy in the engine (it appears to PREVENT any dropping in lots of maps, leading to weirdly aligned entities, and in some cases even CAUSES them to drop through solid, like in facing worlds nex)\r
 sv_gameplayfix_droptofloorstartsolid 0\r
index 702125d..91d566f 100644 (file)
@@ -1119,6 +1119,7 @@ Called when a client types 'kill' in the console
 =============\r
 */\r
 \r
+.float clientkill_nexttime;\r
 void ClientKill_Now_TeamChange()\r
 {\r
        if(self.killindicator_teamchange == -1)\r
@@ -1126,24 +1127,32 @@ void ClientKill_Now_TeamChange()
                self.team = -1;\r
                JoinBestTeam( self, FALSE, FALSE );\r
        }\r
+       else if(self.killindicator_teamchange == -2)\r
+       {\r
+               if(g_ca)\r
+                       self.caplayer = 0;\r
+               if(blockSpectators)\r
+                       sprint(self, strcat("^7You have to become a player within the next ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));\r
+               PutObserverInServer();\r
+       }\r
        else\r
                SV_ChangeTeam(self.killindicator_teamchange - 1);\r
 }\r
 \r
 void ClientKill_Now()\r
-{\r
+{      \r
+       if(self.killindicator && !wasfreed(self.killindicator))\r
+        remove(self.killindicator);\r
+       \r
+       self.killindicator = world;\r
+\r
        if(self.killindicator_teamchange)\r
                ClientKill_Now_TeamChange();\r
 \r
        // in any case:\r
        Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');\r
 \r
-       if(self.killindicator)\r
-       {\r
-               dprint("Cleaned up after a leaked kill indicator.\n");\r
-               remove(self.killindicator);\r
-               self.killindicator = world;\r
-       }\r
+       // now I am sure the player IS dead\r
 }\r
 void KillIndicator_Think()\r
 {\r
@@ -1160,6 +1169,11 @@ void KillIndicator_Think()
                ClientKill_Now(); // no oldself needed\r
                return;\r
        }\r
+    else if(g_cts && self.health == 1) // health == 1 means that it's silent\r
+    {\r
+        self.nextthink = time + 1;\r
+        self.cnt -= 1;\r
+    }\r
        else\r
        {\r
                if(self.cnt <= 10)\r
@@ -1172,6 +1186,8 @@ void KillIndicator_Think()
                        {\r
                                if(self.owner.killindicator_teamchange == -1)\r
                                        centerprint(self.owner, strcat("Changing team in ", ftos(self.cnt), " seconds"));\r
+                               else if(self.owner.killindicator_teamchange == -2)\r
+                                       centerprint(self.owner, strcat("Spectating in ", ftos(self.cnt), " seconds"));\r
                                else\r
                                        centerprint(self.owner, strcat("Changing to ", ColoredTeamName(self.owner.killindicator_teamchange), " in ", ftos(self.cnt), " seconds"));\r
                        }\r
@@ -1183,19 +1199,34 @@ void KillIndicator_Think()
        }\r
 }\r
 \r
-void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto\r
+void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto, -2 = spec\r
 {\r
        float killtime;\r
        entity e;\r
        killtime = cvar("g_balance_kill_delay");\r
 \r
-       if(g_race_qualifying)\r
+       if(g_race_qualifying || g_cts)\r
                killtime = 0;\r
 \r
+    if(g_cts && self.killindicator && self.killindicator.health == 1) // self.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill\r
+    {\r
+               remove(self.killindicator);\r
+               self.killindicator = world;\r
+\r
+        ClientKill_Now(); // allow instant kill in this case\r
+        return;\r
+    }\r
+\r
        self.killindicator_teamchange = targetteam;\r
 \r
-       if(!self.killindicator)\r
+    if(!self.killindicator)\r
        {\r
+               if(self.modelindex && self.deadflag == DEAD_NO)\r
+               {\r
+                       killtime = max(killtime, self.clientkill_nexttime - time);\r
+                       self.clientkill_nexttime = time + killtime + cvar("g_balance_kill_antispam");\r
+               }\r
+\r
                if(killtime <= 0 || !self.modelindex || self.deadflag != DEAD_NO)\r
                {\r
                        ClientKill_Now();\r
@@ -1211,7 +1242,7 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto
                        self.killindicator.nextthink = time + (self.lip) * 0.05;\r
                        self.killindicator.cnt = ceil(killtime);\r
                        self.killindicator.count = bound(0, ceil(killtime), 10);\r
-                       sprint(self, strcat("^1You'll be dead in ", ftos(self.killindicator.cnt), " seconds\n"));\r
+                       //sprint(self, strcat("^1You'll be dead in ", ftos(self.killindicator.cnt), " seconds\n"));\r
 \r
                        for(e = world; (e = find(e, classname, "body")) != world; )\r
                        {\r
@@ -1231,22 +1262,42 @@ void ClientKill_TeamChange (float targetteam) // 0 = don't change, -1 = auto
        }\r
        if(self.killindicator)\r
        {\r
-               if(targetteam)\r
-                       self.killindicator.colormod = TeamColor(targetteam);\r
-               else\r
+               if(targetteam == 0) // just die\r
                        self.killindicator.colormod = '0 0 0';\r
+               else if(targetteam == -1) // auto\r
+                       self.killindicator.colormod = '0 1 0';\r
+               else if(targetteam == -2) // spectate\r
+                       self.killindicator.colormod = '0.5 0.5 0.5';\r
+               else\r
+                       self.killindicator.colormod = TeamColor(targetteam);\r
        }\r
 }\r
 \r
 void ClientKill (void)\r
 {\r
-       ClientKill_TeamChange(0);\r
+       if((g_arena || g_ca) && ((champion && champion.classname == "player" && player_count > 1) || player_count == 1)) // don't allow a kill in this case either\r
+       {\r
+               // do nothing\r
+       }\r
+       else\r
+               ClientKill_TeamChange(0);\r
+}\r
+\r
+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\r
+{\r
+    e.killindicator = spawn();\r
+    e.killindicator.owner = e;\r
+    e.killindicator.think = KillIndicator_Think;\r
+    e.killindicator.nextthink = time + (e.lip) * 0.05;\r
+    e.killindicator.cnt = ceil(cvar("g_cts_finish_kill_delay"));\r
+    e.killindicator.health = 1; // this is used to indicate that it should be silent\r
+    e.lip = 0;\r
 }\r
 \r
 void DoTeamChange(float destteam)\r
 {\r
        float t, c0;\r
-       if(!teams_matter)\r
+       if(!teamplay)\r
        {\r
                if(destteam >= 0)\r
                        SetPlayerColors(self, destteam);\r
index 369005a..3d52a01 100644 (file)
@@ -166,9 +166,8 @@ void SV_ParseClientCommand(string s) {
                }\r
                if(self.version != cvar("gameversion"))\r
                {\r
-                       self.classname = "observer";\r
                        self.version_mismatch = 1;\r
-                       PutClientInServer();\r
+                       ClientKill_TeamChange(-2); // observe\r
                } else if(cvar("g_campaign") || cvar("g_balance_teams") || cvar("g_balance_teams_force")) {\r
                        //JoinBestTeam(self, FALSE, TRUE);\r
                } else if(teams_matter && !cvar("sv_spectate")) {\r
@@ -221,16 +220,7 @@ void SV_ParseClientCommand(string s) {
                        }\r
                }\r
                if(self.classname == "player" && cvar("sv_spectate") == 1) {\r
-                       if(self.flagcarried)\r
-                               DropFlag(self.flagcarried, world, world);\r
-                       kh_Key_DropAll(self, TRUE);\r
-                       WaypointSprite_PlayerDead();\r
-                       self.classname = "observer";\r
-                       if(g_ca)\r
-                               self.caplayer = 0;\r
-                       if(blockSpectators)\r
-                               sprint(self, strcat("^7You have to become a player within the next ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));\r
-                       PutClientInServer();\r
+                       ClientKill_TeamChange(-2); // observe\r
                }\r
        } else if(cmd == "join") {\r
                if not(self.flags & FL_CLIENT)\r
@@ -264,15 +254,15 @@ void SV_ParseClientCommand(string s) {
                } else if(lockteams) {\r
                        sprint( self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");\r
                } else if( argv(1) == "red" ) {\r
-                       DoTeamChange(COLOR_TEAM1);\r
+                       ClientKill_TeamChange(COLOR_TEAM1);\r
                } else if( argv(1) == "blue" ) {\r
-                       DoTeamChange(COLOR_TEAM2);\r
+                       ClientKill_TeamChange(COLOR_TEAM2);\r
                } else if( argv(1) == "yellow" ) {\r
-                       DoTeamChange(COLOR_TEAM3);\r
+                       ClientKill_TeamChange(COLOR_TEAM3);\r
                } else if( argv(1) == "pink" ) {\r
-                       DoTeamChange(COLOR_TEAM4);\r
+                       ClientKill_TeamChange(COLOR_TEAM4);\r
                } else if( argv(1) == "auto" ) {\r
-                       DoTeamChange(-1);\r
+                       ClientKill_TeamChange(-1);\r
                } else {\r
                        sprint( self, strcat( "selectteam none/red/blue/yellow/pink/auto - \"", argv(1), "\" not recognised\n" ) );\r
                }\r
index e48d865..0f84c66 100644 (file)
@@ -485,7 +485,13 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
 \r
                        if(t != 0) {\r
                                if(cp == race_timed_checkpoint)\r
+                               {\r
                                        race_SetTime(e, t, recordtime);\r
+                                       if(g_cts && cvar("g_cts_finish_kill_delay"))\r
+                                       {\r
+                                               CTS_ClientKill(e);\r
+                                       }\r
+                               }\r
 \r
                                if(t < recordtime || recordtime == 0)\r
                                {\r