From: Mario <mario@smbclan.net>
Date: Thu, 12 Jan 2017 15:18:11 +0000 (+1000)
Subject: Add an option to show CTS-style capture time rankings in the CTF scoreboard
X-Git-Tag: xonotic-v0.8.2~259^2~2
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=d80c5b9c3e8e3c9495201565991afc571f14a0e5;p=xonotic%2Fxonotic-data.pk3dir.git

Add an option to show CTS-style capture time rankings in the CTF scoreboard
---

diff --git a/gamemodes.cfg b/gamemodes.cfg
index 9c70adca3c..5e941f1c11 100644
--- a/gamemodes.cfg
+++ b/gamemodes.cfg
@@ -256,6 +256,7 @@ set g_ca_teams 0
 set g_ctf 0 "Capture The Flag: take the enemy flag and bring it to yours at your base to score"
 set g_ctf_oneflag 0 "Allow oneflag CTF mode on maps that support it"
 set g_ctf_oneflag_reverse 0 "apply reverse mode to oneflag CTF (take flag to enemy bases to cap), overrides g_ctf_reverse only in oneflag, g_ctf_reverse still affects oneflag"
+set g_ctf_leaderboard 0 "show top capture times in the scoreboard"
 set g_ctf_flag_return 1 "auto return the flag to base when touched by a teammate"
 set g_ctf_flag_return_carrying 0 "(manual return mode) auto return the flag to base if touched by a flag carrier"
 set g_ctf_flag_return_carried_radius 100 "allow flags to be returned by carrier if base is within this radius"
diff --git a/qcsrc/client/hud/panel/scoreboard.qc b/qcsrc/client/hud/panel/scoreboard.qc
index 35de2196b9..6e2400ee69 100644
--- a/qcsrc/client/hud/panel/scoreboard.qc
+++ b/qcsrc/client/hud/panel/scoreboard.qc
@@ -1565,7 +1565,12 @@ void Scoreboard_Draw()
 		pos = Scoreboard_MakeTable(pos, tm, panel_bg_color, bg_size);
 	}
 
-	if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE) {
+	bool show_accuracy = (gametype != MAPINFO_TYPE_CTS && gametype != MAPINFO_TYPE_RACE && gametype != MAPINFO_TYPE_NEXBALL);
+
+	if (show_accuracy && autocvar_hud_panel_scoreboard_accuracy && !warmup_stage)
+		pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size);
+
+	if(gametype == MAPINFO_TYPE_CTS || gametype == MAPINFO_TYPE_RACE || (gametype == MAPINFO_TYPE_CTF && STAT(CTF_SHOWLEADERBOARD))) {
 		if(race_speedaward) {
 			drawcolorcodedstring(pos, sprintf(_("Speed award: %d%s ^7(%s^7)"), race_speedaward, race_speedaward_unit, race_speedaward_holder), hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 			pos.y += 1.25 * hud_fontsize.y;
@@ -1576,8 +1581,6 @@ void Scoreboard_Draw()
 		}
 		pos = Scoreboard_Rankings_Draw(pos, playerslots[player_localnum], panel_bg_color, bg_size);
 	}
-	else if (autocvar_hud_panel_scoreboard_accuracy && !warmup_stage && gametype != MAPINFO_TYPE_NEXBALL)
-		pos = Scoreboard_AccuracyStats_Draw(pos, panel_bg_color, bg_size);
 
 	pos = Scoreboard_MapStats_Draw(pos, panel_bg_color, bg_size);
 
diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh
index 3d21280e08..f14c9e7170 100644
--- a/qcsrc/common/stats.qh
+++ b/qcsrc/common/stats.qh
@@ -119,6 +119,11 @@ REGISTER_STAT(ENTRAP_ORB, float)
 REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
 REGISTER_STAT(ITEMSTIME, int, autocvar_sv_itemstime)
 
+#ifdef SVQC
+bool autocvar_g_ctf_leaderboard;
+#endif
+REGISTER_STAT(CTF_SHOWLEADERBOARD, bool, autocvar_g_ctf_leaderboard)
+
 #ifdef SVQC
 int autocvar_g_multijump;
 float autocvar_g_multijump_add;
diff --git a/qcsrc/common/util.qh b/qcsrc/common/util.qh
index 05e4a4ea27..5211c7588f 100644
--- a/qcsrc/common/util.qh
+++ b/qcsrc/common/util.qh
@@ -59,6 +59,7 @@ const float TIME_FACTOR = 100;
 #define TIME_ENCODED_TOSTRING(n) mmssss(n)
 #define RACE_RECORD "/race100record/"
 #define CTS_RECORD "/cts100record/"
+#define CTF_RECORD "/ctf100record/"
 #define TIME_ENCODE(t) TIME_TO_NTHS(t, TIME_FACTOR)
 #define TIME_DECODE(n) ((n) / TIME_FACTOR)
 
diff --git a/qcsrc/server/mutators/mutator/gamemode_ctf.qc b/qcsrc/server/mutators/mutator/gamemode_ctf.qc
index 5ee07992fc..147f16c4bf 100644
--- a/qcsrc/server/mutators/mutator/gamemode_ctf.qc
+++ b/qcsrc/server/mutators/mutator/gamemode_ctf.qc
@@ -153,6 +153,9 @@ void ctf_CaptureRecord(entity flag, entity player)
 		db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname);
 		write_recordmarker(player, (time - cap_time), cap_time);
 	}
+
+	if(autocvar_g_ctf_leaderboard && !ctf_oneflag)
+		race_setTime(GetMapname(), TIME_ENCODE(cap_time), player.crypto_idfp, player.netname, player, false);
 }
 
 bool ctf_Immediate_Return_Allowed(entity flag, entity toucher)
@@ -2170,6 +2173,22 @@ MUTATOR_HOOKFUNCTION(ctf, ClientDisconnect)
 	ctf_RemovePlayer(player);
 }
 
+MUTATOR_HOOKFUNCTION(ctf, ClientConnect)
+{
+	if(!autocvar_g_ctf_leaderboard)
+		return;
+
+	entity player = M_ARGV(0, entity);
+
+	if(IS_REAL_CLIENT(player))
+	{
+		for(int i = 1; i <= RANKINGS_CNT; ++i)
+		{
+			race_SendRankings(i, 0, 0, MSG_ONE);
+		}
+	}
+}
+
 MUTATOR_HOOKFUNCTION(ctf, PortalTeleport)
 {
 	entity player = M_ARGV(0, entity);
diff --git a/qcsrc/server/race.qc b/qcsrc/server/race.qc
index a3cbc685f2..48c8e32ae2 100644
--- a/qcsrc/server/race.qc
+++ b/qcsrc/server/race.qc
@@ -26,31 +26,33 @@ void W_Porto_Fail(entity this, float failhard);
 
 float race_readTime(string map, float pos)
 {
-	string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+	string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD));
 
 	return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos))));
 }
 
 string race_readUID(string map, float pos)
 {
-	string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+	string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD));
 
 	return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)));
 }
 
 float race_readPos(string map, float t)
 {
-	float i;
-	for (i = 1; i <= RANKINGS_CNT; ++i)
-	if (race_readTime(map, i) == 0 || race_readTime(map, i) > t)
-		return i;
+	for(int i = 1; i <= RANKINGS_CNT; ++i)
+	{
+		int mytime = race_readTime(map, i);
+		if(!mytime || mytime > t)
+			return i;
+	}
 
 	return 0; // pos is zero if unranked
 }
 
 void race_writeTime(string map, float t, string myuid)
 {
-	string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+	string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD));
 
 	float newpos;
 	newpos = race_readPos(map, t);
@@ -87,7 +89,7 @@ void race_writeTime(string map, float t, string myuid)
 
 string race_readName(string map, float pos)
 {
-	string rr = (g_cts) ? CTS_RECORD : RACE_RECORD;
+	string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD));
 
 	return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))));
 }
@@ -244,15 +246,13 @@ void race_SendStatus(float id, entity e)
 	});
 }
 
-void race_setTime(string map, float t, string myuid, string mynetname, entity e)
+void race_setTime(string map, float t, string myuid, string mynetname, entity e, bool showmessage)
 {
 	// netname only used TEMPORARILY for printing
-	float newpos, player_prevpos;
-	newpos = race_readPos(map, t);
+	int newpos = race_readPos(map, t);
 
-	float i;
-	player_prevpos = 0;
-	for(i = 1; i <= RANKINGS_CNT; ++i)
+	int player_prevpos = 0;
+	for(int i = 1; i <= RANKINGS_CNT; ++i)
 	{
 		if(race_readUID(map, i) == myuid)
 			player_prevpos = i;
@@ -264,7 +264,8 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e)
 	{
 		oldrec = race_readTime(GetMapname(), player_prevpos);
 		race_SendStatus(0, e); // "fail"
-		Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_FAIL_RANKED, mynetname, player_prevpos, t, oldrec);
+		if(showmessage)
+			Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_FAIL_RANKED, mynetname, player_prevpos, t, oldrec);
 		return;
 	}
 	else if (!newpos)
@@ -272,7 +273,8 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e)
 		// no ranking, time worse than the worst ranked
 		oldrec = race_readTime(GetMapname(), RANKINGS_CNT);
 		race_SendStatus(0, e); // "fail"
-		Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_FAIL_UNRANKED, mynetname, RANKINGS_CNT, t, oldrec);
+		if(showmessage)
+			Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_FAIL_UNRANKED, mynetname, RANKINGS_CNT, t, oldrec);
 		return;
 	}
 
@@ -281,7 +283,8 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e)
 	// if the player does not have a UID we can unfortunately not store the record, as the rankings system relies on UIDs
 	if(myuid == "")
 	{
-		Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_MISSING_UID, mynetname, t);
+		if(showmessage)
+			Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_MISSING_UID, mynetname, t);
 		return;
 	}
 
@@ -291,7 +294,7 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e)
 	// store new ranking
 	race_writeTime(GetMapname(), t, myuid);
 
-	if (newpos == 1)
+	if (newpos == 1 && showmessage)
 	{
 		write_recordmarker(e, time - TIME_DECODE(t), TIME_DECODE(t));
 		race_send_recordtime(MSG_ALL);
@@ -304,19 +307,22 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e)
 
 	if(newpos == player_prevpos)
 	{
-		Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_IMPROVED, mynetname, newpos, t, oldrec);
+		if(showmessage)
+			Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_IMPROVED, mynetname, newpos, t, oldrec);
 		if(newpos == 1) { race_SendStatus(3, e); } // "new server record"
 		else { race_SendStatus(1, e); } // "new time"
 	}
 	else if(oldrec == 0)
 	{
-		Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_SET, mynetname, newpos, t);
+		if(showmessage)
+			Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_SET, mynetname, newpos, t);
 		if(newpos == 1) { race_SendStatus(3, e); } // "new server record"
 		else { race_SendStatus(2, e); } // "new rank"
 	}
 	else
 	{
-		Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_BROKEN, mynetname, oldrec_holder, newpos, t, oldrec);
+		if(showmessage)
+			Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_NEW_BROKEN, mynetname, oldrec_holder, newpos, t, oldrec);
 		if(newpos == 1) { race_SendStatus(3, e); } // "new server record"
 		else { race_SendStatus(2, e); } // "new rank"
 	}
@@ -324,24 +330,20 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e)
 
 void race_deleteTime(string map, float pos)
 {
-	string rr;
-	if(g_cts)
-		rr = CTS_RECORD;
-	else
-		rr = RACE_RECORD;
+	string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD));
 
-	float i;
-	for (i = pos; i <= RANKINGS_CNT; ++i)
+	for(int i = pos; i <= RANKINGS_CNT; ++i)
 	{
+		string therank = ftos(i);
 		if (i == RANKINGS_CNT)
 		{
-			db_remove(ServerProgsDB, strcat(map, rr, "time", ftos(i)));
-			db_remove(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)));
+			db_remove(ServerProgsDB, strcat(map, rr, "time", therank));
+			db_remove(ServerProgsDB, strcat(map, rr, "crypto_idfp", therank));
 		}
 		else
 		{
-			db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(GetMapname(), i+1)));
-			db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(GetMapname(), i+1));
+			db_put(ServerProgsDB, strcat(map, rr, "time", therank), ftos(race_readTime(GetMapname(), i+1)));
+			db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", therank), race_readUID(GetMapname(), i+1));
 		}
 	}
 
@@ -415,7 +417,7 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
 			{
 				if(cp == race_timed_checkpoint)
 				{
-					race_setTime(GetMapname(), t, e.crypto_idfp, e.netname, e);
+					race_setTime(GetMapname(), t, e.crypto_idfp, e.netname, e, true);
 					MUTATOR_CALLHOOK(Race_FinalCheckpoint, e);
 				}
 				if(t < recordtime || recordtime == 0)