r3795 - in trunk/data/qcsrc: client common server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Tue Jul 8 14:41:40 EDT 2008


Author: blub0
Date: 2008-07-08 14:41:39 -0400 (Tue, 08 Jul 2008)
New Revision: 3795

Modified:
   trunk/data/qcsrc/client/Main.qc
   trunk/data/qcsrc/client/main.qh
   trunk/data/qcsrc/client/sbar.qc
   trunk/data/qcsrc/common/constants.qh
   trunk/data/qcsrc/server/cl_client.qc
   trunk/data/qcsrc/server/cl_player.qc
   trunk/data/qcsrc/server/clientcommands.qc
   trunk/data/qcsrc/server/ctf.qc
   trunk/data/qcsrc/server/defs.qh
Log:
Keep track of CSQC compatibility.
Count flag returns now.
Send flag returns and deaths over the net.
Dynamically create scoreboard columns.
Store sbar columns in sbar_columns, update the layout with the cmd sbar_columns_set.
sbar_columns_help for information about it.


Modified: trunk/data/qcsrc/client/Main.qc
===================================================================
--- trunk/data/qcsrc/client/Main.qc	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/client/Main.qc	2008-07-08 18:41:39 UTC (rev 3795)
@@ -20,6 +20,7 @@
 
 void CSQC_Init(void)
 {
+	float i;
 	drawfont = 0;
 	menu_visible = FALSE;
 	menu_show = menu_show_error;
@@ -30,27 +31,37 @@
 	//registercmd("ctf_menu");
 	registercmd("ons_map");
 	//registercmd("menu_action");
+	registercmd("sbar_columns_set");
+	registercmd("sbar_columns_help");
 
 	registercvar("sbar_usecsqc", "1");
+	registercvar("sbar_columns", "ping name | caps returns frags deaths");
 
 	gametype = 0;
 
 	gps_start = world;
 
+	// sbar_fields uses strunzone on the titles!
+	for(i = 0; i < MAX_SBAR_FIELDS; ++i)
+		sbar_title[i] = strzone("(null)");
+
+	localcmd(strcat("\nsbar_columns_set ", cvar_string("sbar_columns"), ";\n"));
+
 	postinit = false;
 }
 
 void PostInit(void)
 {
 	float i;
-	entity pl;
 
 	print(strcat("PostInit\n    maxclients = ", ftos(maxclients), "\n"));
 	databuf = buf_create();
 	for(i = 0; i < maxclients; ++i)
 	{
 		bufstr_set(databuf, DATABUF_PING + i, "N/A");
+		bufstr_set(databuf, DATABUF_DEATHS + i, "0");
 		bufstr_set(databuf, DATABUF_CAPTURES + i, "0");
+		bufstr_set(databuf, DATABUF_RETURNS + i, "0");
 	}
 
 	postinit = true;
@@ -63,13 +74,13 @@
 
 // CSQC_ConsoleCommand : Used to parse commands in the console that have been registered with the "registercmd" function
 // Return value should be 1 if CSQC handled the command, otherwise return 0 to have the engine handle it.
+void Cmd_Sbar_SetFields(float);
+void Cmd_Sbar_Help(float);
 float CSQC_ConsoleCommand(string strMessage)
 {
-	local float nReturn;
-		nReturn = FALSE;
-		
+	float argc;
 	// Tokenize String
-	tokenize(strMessage);
+	argc = tokenize(strMessage);
 	
 	// Acquire Command
 	local string strCmd;
@@ -77,14 +88,20 @@
 
 	/*if(strCmd == "ctf_menu") {
 		ctf_menu_show();
-		nReturn = TRUE;
+		nReturn = true;
 		} else*/
 	if(strCmd == "ons_map") {
 		Cmd_ons_map();
-		nReturn = TRUE;
+		return true;
+	} else if(strCmd == "sbar_columns_set") {
+		Cmd_Sbar_SetFields(argc);
+		return true;
+	} else if(strCmd == "sbar_columns_help") {
+		Cmd_Sbar_Help(argc);
+		return true;
 	}
 	
-	return nReturn;
+	return false;
 }
 // CSQC_InputEvent : Used to perform actions based on any key pressed, key released and mouse on the client.
 // Return value should be 1 if CSQC handled the input, otherwise return 0 to have the input passed to the engine.
@@ -274,9 +291,13 @@
 	cprint(strMessage);
 }
 
+void CSQC_CheckRevision();
 void ReadInit()
 {
+	csqc_revision = ReadShort();
 	maxclients = ReadByte();
+
+	CSQC_CheckRevision();
 }
 
 void ReadPings()
@@ -291,19 +312,27 @@
 
 void ReadCaptures()
 {
-	float plnum, caps;
-	entity pl;
+	float plnum, caps, mode;
+	mode = ReadByte();
 	caps_team1 = ReadByte();
 	caps_team2 = ReadByte();
 	for(plnum = ReadByte(); plnum != 0; plnum = ReadByte())
 	{
 		caps = ReadByte();
-		//print(strcat("Cap update: ", ftos(plnum), " has ", ftos(caps), " caps\n"));
-		//print(strcat("Index: ", ftos(DATABUF_CAPTURES + plnum-1), " -- I AM: ", ftos(player_localentnum), "\n"));
 		bufstr_set(databuf, DATABUF_CAPTURES + plnum-1, ftos(caps));
 	}
 }
 
+void ReadDatabuf(float ofs)
+{
+	float plnum, data;
+	for(plnum = ReadByte(); plnum != 0; plnum = ReadByte())
+	{
+		data = ReadByte();
+		bufstr_set(databuf, ofs + plnum-1, ftos(data));
+	}
+}
+
 // CSQC_Parse_TempEntity : Handles all temporary entity network data in the CSQC layer.
 // You must ALWAYS first acquire the temporary ID, which is sent as a byte.
 // Return value should be 1 if CSQC handled the temporary entity, otherwise return 0 to have the engine process the event.
@@ -329,6 +358,14 @@
 			ReadCaptures();
 			bHandled = true;
 			break;
+		case TE_CSQC_RETURNS:
+			ReadDatabuf(DATABUF_RETURNS);
+			bHandled = true;
+			break;
+		case TE_CSQC_DEATHS:
+			ReadDatabuf(DATABUF_DEATHS);
+			bHandled = true;
+			break;
 		default:
 			// No special logic for this temporary entity; return 0 so the engine can handle it
 			bHandled = false;
@@ -340,3 +377,26 @@
 		
 	return bHandled;
 }
+
+// COMMIT-TODO: Update if necessare, before committing
+float csqc_svn_map[CSQC_REVISION] =
+{
+	3795,
+};
+
+// COMMIT-TODO: Update if necessare, before committing
+void CSQC_CheckRevision()
+{
+	if(csqc_revision == CSQC_REVISION)
+	{
+		print("^2SVQC and CSQC revisions are compatible.\n");
+	} else if(csqc_revision < CSQC_REVISION) {
+		print("^1Your csprogs.dat (CSQC) version is newer than the one on the server.\n");
+		print("^1The last known svn revision for the server's CSQC is: ^7");
+		print(ftos(csqc_svn_map[csqc_revision])); // don't use strcat, fteqcc loves screwing up arrays...
+		print("\n");
+	} else if(csqc_revision > CSQC_REVISION) {
+		print("^1Your csprogs.dat (CSQC) is too old for this server.\n");
+		print("^1Please update to a newer version.\n");
+	}
+}

Modified: trunk/data/qcsrc/client/main.qh
===================================================================
--- trunk/data/qcsrc/client/main.qh	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/client/main.qh	2008-07-08 18:41:39 UTC (rev 3795)
@@ -3,8 +3,11 @@
 
 #define DATABUF_PING 0
 #define DATABUF_CAPTURES (1*maxclients)
-#define DATABUF_NEXT (2*maxclients)
+#define DATABUF_DEATHS (2*maxclients)
+#define DATABUF_RETURNS (3*maxclients)
 
+#define DATABUF_NEXT (5*maxclients)
+
 void() menu_show_error;
 void() menu_sub_null;
 
@@ -32,6 +35,8 @@
 // --------------------------------------------------------------------------
 // General stuff
 
+float csqc_revision;
+
 float drawfont;
 float postinit;
 float gametype;
@@ -57,3 +62,24 @@
 
 #define FONT_DEFAULT 0
 #define FONT_USER 8
+
+// --------------------------------------------------------------------------
+// Scoreboard stuff
+
+#define MAX_SBAR_FIELDS 16
+
+#define SBF_END 0
+#define SBF_PING 1
+#define SBF_NAME 2
+#define SBF_CAPS 3
+#define SBF_RETS 4
+#define SBF_FRAGS 5
+#define SBF_DEATHS 6
+#define SBF_KDRATIO 7
+
+#define SBF_SEPARATOR 100
+
+float sbar_field[MAX_SBAR_FIELDS + 1];
+float sbar_size[MAX_SBAR_FIELDS + 1];
+string sbar_title[MAX_SBAR_FIELDS + 1];
+float sbar_num_fields;

Modified: trunk/data/qcsrc/client/sbar.qc
===================================================================
--- trunk/data/qcsrc/client/sbar.qc	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/client/sbar.qc	2008-07-08 18:41:39 UTC (rev 3795)
@@ -239,142 +239,364 @@
 		}
 	}
 }
-float xmin, xmax, ymin, ymax;
-void Sbar_PrintScoreboardItem(vector pos, entity pl, float is_self, float mask)
+
+void Cmd_Sbar_Help(float argc)
 {
-	vector tmp;
+	print("You can modify the scoreboard using the\n");
+	print("^3|---------------------------------------------------------------|\n");
+	print("^2sbar_columns^7 cvar and the ^2sbar_columns_set command.\n");
+	print("^2sbar_columns^7             specifies the default layout and\n");
+	print("^2sbar_columns_set^7         actually changes the layout.\n");
+	print("You can call ^2sbar_columns_set^7 with the new layout\n");
+	print("as parameters, or eithout parameters it will read the cvar.\n\n");
+	print("Usage:\n");
+	print("^2sbar_columns_set ^7filed1 field2 ...\n");
+	print("Fields which are not relevant to the current gametype\n");
+	print("won't be displayed\n\n");
+	print("The following field names are recognized (case INsensitive):\n");
+	print("^3name^7 or ^3nick^7             Name of a player\n");
+	print("^3caps^7 or ^3captures^7         Number of flags captured\n");
+	print("^3rets^7 or ^3returns^7          Number of flags returned\n");
+	print("^3frags^7 or ^3kills^7           Frags\n");
+	print("^3deaths^7 or ^3dths^7           Number of deaths\n");
+	print("^3kd^7 or ^3kdr^7 or ^3kdratio^7 or ^3k/d\n");
+	print("                         The kill-death ratio\n");
+	print("^3ping^7                     Ping time\n\n");
+	print("You can use a ^3|^7 to start the right-aligned fields.\n");
+	print("Example: ping name | caps rets frags k/d\n");
+	print("This will put the ping and the name on the left side.\n");
+	print("The captures, returns, frags and kill-death ratio will be\n");
+	print("rendered beginning on the right side.\n");
+
+}
+
+void Cmd_Sbar_SetFields(float argc)
+{
+	float i;
 	string str;
-	entity player;
+
+	if(argc < 2)
+		argc = tokenize(strcat("x ", cvar_string("sbar_columns")));
 	
-	tmp_y = tmp_z = 0;
-	pos_x += 56;
-
-	str = bufstr_get(databuf, DATABUF_PING + pl.sb_player);
-	tmp_x = 4*8 - strlen(str) * 8 - 56;
-	drawstring(pos + tmp, str, '8 8 0', '0.8 0.8 0.8', 0.8, 0);
-
-	if(!(mask & 1)) // not a spectator:
+	argc = min(MAX_SBAR_FIELDS, argc);
+	sbar_num_fields = 0;
+	for(i = 0; i < argc-1; ++i)
 	{
-		if(gametype == GAME_CTF)
-		{
-			str = bufstr_get(databuf, DATABUF_CAPTURES + pl.sb_player);
-			tmp_x = xmax - strlen(str)*8 - pos_x;
-			drawstring(pos + tmp, str, '8 8 0', '1 1 1', 1, 0);
+		str = argv(i+1);
+		strunzone(sbar_title[i]);
+		sbar_title[i] = strzone(str);
+		sbar_size[i] = strlen(str)*8;
+		str = strtolower(str);
+		if(str == "ping") {
+			sbar_field[i] = SBF_PING;
+		} else if(str == "name" || str == "nick") {
+			sbar_field[i] = SBF_NAME;
+			sbar_size[i] = 24*8; // minimum size? any use?
+		} else if(str == "caps" || str == "captures") {
+			sbar_field[i] = SBF_CAPS;
+		} else if(str == "rets" || str == "returns") {
+			sbar_field[i] = SBF_RETS;
+		} else if(str == "frags" || str == "kills") {
+			sbar_field[i] = SBF_FRAGS;
+		} else if(str == "deaths" || str == "dths") {
+			sbar_field[i] = SBF_DEATHS;
+		} else if(str == "kdratio") {
+			sbar_field[i] = SBF_KDRATIO;
+		} else if(str == "kdr" || str == "k/d") {
+			sbar_field[i] = SBF_KDRATIO;
+		} else if(str == "kd") {
+			sbar_field[i] = SBF_KDRATIO;
+		} else if(str == "|") {
+			sbar_field[i] = SBF_SEPARATOR;
+		} else {
+			print(strcat("^1Error:^7 Unknown score field: '", str, "'\n"));
+			--sbar_num_fields;
 		}
-	
-		str = ftos(pl.sb_frags);
-		tmp_x = 4*8 - strlen(str) * 8;
-		drawstring(pos + tmp, str, '8 8 0', '1 1 1', 1, 0);
+		++sbar_num_fields;
 	}
+	sbar_field[i] = SBF_END;
+}
 
-	if(is_self)
-		drawstring(pos + '40 0 0', "\x0D", '8 8 0', '1 1 1', 1, 0);
-	str = getplayerkey(pl.sb_player, "name");
-	tmp_x = 5*8 - strlen(str) * 8 + 56;
-	drawcolorcodedstring(pos + '48 0 0', str, '8 8 0', 1, 0);
+vector sbar_field_rgb;
+string Sbar_GetField(entity pl, float field)
+{
+	float tmp;
+	string str;
+	sbar_field_rgb = '1 1 1';
+	switch(field)
+	{
+	case SBF_PING:
+		str = bufstr_get(databuf, DATABUF_PING + pl.sb_player);
+		tmp = max(0, min(220, stof(str)-80)) / 220;
+		sbar_field_rgb = '1 1 1' - '0 1 1'*tmp;
+		return str;
+	case SBF_NAME: return getplayerkey(pl.sb_player, "name");
+	case SBF_CAPS: return ftos(pl.sb_caps);
+	case SBF_RETS: return bufstr_get(databuf, DATABUF_RETURNS + pl.sb_player);
+	case SBF_FRAGS: return ftos(pl.sb_frags);
+	case SBF_DEATHS: return bufstr_get(databuf, DATABUF_DEATHS + pl.sb_player);
+	case SBF_KDRATIO:
+		tmp = stof(bufstr_get(databuf, DATABUF_DEATHS + pl.sb_player));
+		if(tmp == 0) {
+			sbar_field_rgb = '0 1 0';
+			str = ftos(pl.sb_frags);
+		} else if(pl.sb_frags <= 0) {
+			sbar_field_rgb = '1 0 0';
+			str = ftos(pl.sb_frags / tmp);
+		} else
+			str = ftos(pl.sb_frags / tmp);
+		
+		tmp = strstrofs(str, ".", 0);
+		if(tmp > 0)
+			str = substring(str, 0, tmp+2);
+		return str;
+	}
 }
-void Sbar_PrintScoreboardTeamItem(vector pos, entity tm, vector rgb, string name)
+
+float Sbar_IsFieldMasked(float field, float mask)
 {
+	if(mask&1) // spectator
+		return (field != SBF_NAME && field != SBF_PING);
+	if(gametype != GAME_CTF)
+		return (field == SBF_CAPS || field == SBF_RETS);
+	return false;
+}
+
+#define MAX_NAMELEN 24
+
+float xmin, xmax, ymin, ymax, sbwidth, sbheight;
+void Sbar_PrintScoreboardItem(vector pos, entity pl, float is_self, float mask)
+{
 	vector tmp;
-	string str;
+	string str, tempstr;
+	float i, field, len;
+
+	// Layout:
+	tmp_z = 0;
+	if(is_self)
+	{
+		tmp_x = sbwidth;
+		tmp_y = 8;
+		drawfill(pos - '1 1', tmp + '2 2', '1 1 1', 0.3, DRAWFLAG_NORMAL);
+	}	
+	tmp_y = 0;
 	
-	tmp_y = tmp_z = 0;
-	pos_x += 56;
+	for(i = 0; i < sbar_num_fields; ++i)
+	{
+		field = sbar_field[i];
+		if(field == SBF_SEPARATOR)
+			break;
+		if(Sbar_IsFieldMasked(field, mask))
+			continue;
 
-	str = ftos(tm.sb_frags);
-	tmp_x = 4*8 - strlen(str) * 8;
-	drawstring(pos + tmp, str, '8 8 0', '1 1 1', 1, 0);
+		str = Sbar_GetField(pl, field);
 
-	rgb += '0.3 0.3 0.3';
-	rgb = normalize(rgb * 5);
-	drawstring(pos + '48 0 0', name, '8 8 0', rgb, 1, 0);
+		if(field == SBF_NAME) {
+			len = strlen(strdecolorize(str));
+			if(len > MAX_NAMELEN)
+			{
+				while(len > MAX_NAMELEN)
+				{
+					// this way should be the fastest with 100% safety :P
+					// worst case: decolored length maxnamelen+1, and then only color codes =)
+					// cutting of reallength - (decolored-length - maxnamelen) characters
+					str = substring(str, 0, strlen(str) - (len-MAX_NAMELEN));
+					len = strlen(strdecolorize(str));
+				}
+				str = strcat(str, "^7...");
+				len += 3;
+			}
+			len *= 8;
+		} else
+			len = 8*strlen(str);
+		
+		if(sbar_size[i] < len)
+			sbar_size[i] = len;
+
+		pos_x += sbar_size[i] + 8;
+		if(field == SBF_NAME) {
+			tmp_x = sbar_size[i] + 8;
+			drawcolorcodedstring(pos - tmp, str, '8 8', 1, DRAWFLAG_NORMAL);
+		} else {
+			tmp_x = 8*strlen(str) + 8;
+			drawstring(pos - tmp, str, '8 8', sbar_field_rgb, 1, DRAWFLAG_NORMAL);
+		}
+	}
+	
+	if(sbar_field[i] == SBF_SEPARATOR)
+	{
+		pos_x = xmax;
+		for(i = sbar_num_fields-1; i > 0; --i)
+		{
+			field = sbar_field[i];
+			if(field == SBF_SEPARATOR)
+				break;
+			if(Sbar_IsFieldMasked(field, mask))
+				continue;
+			
+			str = Sbar_GetField(pl, field);
+
+			if(field == SBF_NAME) {
+				len = strlen(strdecolorize(str));
+				if(len > MAX_NAMELEN)
+				{
+					while(len > MAX_NAMELEN)
+					{
+						str = substring(str, 0, strlen(str) - (len-MAX_NAMELEN));
+						len = strlen(strdecolorize(str));
+					}
+					str = strcat(str, "^7...");
+					len += 3;
+				}
+				len *= 8;
+			} else
+				len = 8*strlen(str);
+			//len = 8*strlen(str);
+			if(sbar_size[i] < len)
+				sbar_size[i] = len;
+			
+			if(field == SBF_NAME) {
+				tmp_x = len; // left or right aligned? let's put it right...
+				drawcolorcodedstring(pos - tmp, str, '8 8', 1, DRAWFLAG_NORMAL);
+			} else {
+				tmp_x = len; //strlen(str);
+				drawstring(pos - tmp, str, '8 8', sbar_field_rgb, 1, DRAWFLAG_NORMAL);
+			}
+			pos_x -= sbar_size[i] + 8;
+		}
+	}
 }
 
 void Sbar_DrawScoreboard()
 {
-	// Assume: frags are already sorted
-	//float xmin, xmax, ymin, ymax, plcount;
-	float plcount;
-	vector pos, teammin, teammax, rgb;
+	//float xmin, ymin, xmax, ymax;
+	vector rgb, pos, tmp, sbar_save;
 	entity pl, tm;
-	float specs, minoffset;
-	specs = false;
+	float specs, i;
+	float center_x;
+	string str;
+	
+	xmin = vid_conwidth / 5;
+	ymin = 20;
 
-	xmin = vid_conwidth / 4;
 	xmax = vid_conwidth - xmin;
-	ymin = 48 - 26;
-	ymax = vid_conheight - 50;
+	ymax = vid_conheight - 0.2*vid_conheight;
 
+	sbwidth = xmax - xmin;
+	sbheight = ymax - ymin;
+
+	center_x = xmin + 0.5*sbwidth;
+
+	//Sbar_UpdateFields();
+
+	// Initializes position
+	//pos_x = xmin;
 	pos_y = ymin;
 	pos_z = 0;
 
-	teammin = teammax = '0 0 0';
-	teammin_x = xmin - 2;
-	teammax_x = xmax + 2;
-
-	pos_x = 0.5 * (xmin + xmax) - (24*5);
+	// Heading
 	drawfont = FONT_USER+0;
-	drawstring(pos, "Scoreboard", '24 24 0', '1 1 1', 1, DRAWFLAG_NORMAL);
-	drawfont = 0;
+	pos_x = center_x - 4*24;
+	drawstring(pos, "Scoreboard", '24 24', '1 1 1', 1, DRAWFLAG_NORMAL);
 	pos_x = xmin;
-	pos_y += 26;
+	pos_y += 24 + 4;
+	drawfont = FONT_DEFAULT;
 
-	drawstring(pos, "ping", '8 8 0', '1 1 1', 1, 0);
-	drawstring(pos + '48 0 0', "frags", '8 8 0', '1 1 1', 1, 0);
-	drawstring(pos + '104 0 0', "name", '8 8 0', '1 1 1', 1, 0);
-	if(gametype == GAME_CTF)
+	// Titlebar background:
+	tmp_x = sbwidth;
+	tmp_y = 8;
+	drawfill(pos - '1 1', tmp + '2 2', '0.5 0.5 0.5', 0.5, DRAWFLAG_NORMAL);
+	
+	for(i = 0; i < sbar_num_fields; ++i)
 	{
-		pos_x = xmax - 4*8;
-		drawstring(pos, "caps", '8 8 0', '1 1 1', 1, 0);
-		pos_x = xmin;
+		if(sbar_field[i] == SBF_SEPARATOR)
+			break;
+		drawstring(pos, sbar_title[i], '8 8', '1 1 1', 1, DRAWFLAG_NORMAL);
+		pos_x += sbar_size[i] + 8;
 	}
 	
-	pos_y += 16;
+	if(sbar_field[i] == SBF_SEPARATOR)
+	{
+		pos_x = xmax + 8;
+		tmp_y = tmp_z = 0;
+		for(i = sbar_num_fields-1; i > 0; --i)
+		{
+			if(sbar_field[i] == SBF_SEPARATOR)
+				break;
+			
+			pos_x -= sbar_size[i] + 8;
+			/**
+			 * FTEQCC BUG!
+			 * Using the following line will fuck it all up:
+			 **
+			 * tmp_x = sbar_size[i] - strlen(sbar_title[i])*8;
+			 */
+			tmp_x = sbar_size[i];
+			tmp_x -= strlen(sbar_title[i])*8;
+			drawstring(pos + tmp, sbar_title[i], '8 8', '1 1 1', 1, DRAWFLAG_NORMAL);
+		}
+	}
+		
+	pos_x = xmin;
+	pos_y += 12;
+
+	sbar_save = sbar;
+	sbar = '0 0 0';
 	
 	if(teamplay)
 	{
 		for(tm = sortedTeams.sort_next; tm; tm = tm.sort_next)
 		{
-			minoffset = pos_y + 24;
 			if(!tm.sb_player || tm.sb_team == COLOR_SPECTATOR) // no players in it?
 				continue;
 
 			rgb = GetTeamRGB(tm.sb_team);
+
+			pos_x = xmin - 4*24;
 			if(gametype == GAME_CTF)
 			{
-				minoffset = pos_y + 24 + 12;
 				if(tm.sb_team == COLOR_TEAM1)
-					Sbar_DrawXNum(pos-'106 0 0'-sbar, caps_team1, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
+					Sbar_DrawXNum(pos, caps_team1, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
 				else if(tm.sb_team == COLOR_TEAM2)
-					Sbar_DrawXNum(pos-'106 0 0'-sbar, caps_team2, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
-				Sbar_DrawXNum(pos-'44 -24 0'-sbar, tm.sb_frags, 4, 10, rgb, 1, DRAWFLAG_NORMAL);
+					Sbar_DrawXNum(pos, caps_team2, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
+				pos_x = xmin - 4*10;
+				Sbar_DrawXNum(pos + '0 24', tm.sb_frags, 4, 10, rgb, 1, DRAWFLAG_NORMAL);
+				pos_x = xmin;
 			} else
-				Sbar_DrawXNum(pos-'106 0 0'-sbar, tm.sb_frags, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
+				Sbar_DrawXNum(pos, tm.sb_frags, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
+			pos_x = xmin;
 
-			teammin_y = pos_y - 2;
-			teammax_y = pos_y + 2 + 10 * (tm.sb_player);
-			drawfill(teammin, teammax - teammin, rgb, 0.2, DRAWFLAG_NORMAL);
+			// abuse specs as playerounter
+			specs = 0;
+			for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
+			{
+				if(pl.sb_team == tm.sb_team)
+					++specs;
+			}
+
+			if(specs < 2)
+				specs = 2;
+			if(gametype == GAME_CTF && specs < 4)
+				specs = 4;
 			
-			plcount = 0;
+			tmp_x = sbwidth;
+			tmp_y = 10 * specs;
+			drawfill(pos - '1 1', tmp + '2 0', rgb, 0.2, DRAWFLAG_NORMAL);
+			
 			for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
 			{
 				if(pl.sb_team != tm.sb_team)
 					continue;
 				Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), 0);
 				pos_y += 10;
-				++plcount;
+				tmp_y -= 10;
 			}
-
-			pos_y += 12;
-			if(pos_y < minoffset)
-				pos_y = minoffset;
+			pos_y += tmp_y + 12;
 		}
-
 		// rgb := tempvector :)
 		rgb = pos + '0 12 0';
-		//pos += '64 24 0';
 		pos_y += 24;
-		//for(i = 0; i < maxclients; ++i)
+		specs = 0;
 		for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
 		{
 			if(pl.sb_team != COLOR_SPECTATOR)
@@ -382,40 +604,15 @@
 			//drawcolorcodedstring(pos, getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
 			Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), 1);
 			pos += '0 10 0';
-			specs = true;
+			++specs;
 		}
 			
 		if(specs)
 			drawstring(rgb, "Spectators", '8 8 0', '1 1 1', 1, 0);
-	} else {
-		//for(i = 0; i < maxclients; ++i)
-		for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
-		{
-			if(pl.sb_team != COLOR_TEAM1)
-				continue;
-			//drawstring(pos, ftos(pl.sb_frags), '8 8 0', '1 1 1', 1, 0);
-			//drawcolorcodedstring(pos + '64 0 0', getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
-			Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), 0);
-			pos += '0 12 0';
-		}
-		rgb = pos + '0 12 0';
-		//pos += '64 24 0';
-		pos_y += 24;
-		for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
-		{
-			if(pl.sb_team != COLOR_SPECTATOR)
-				continue;
-			specs = true;
-			//drawcolorcodedstring(pos, getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
-			Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), 1);
-			pos += '0 12 0';
-		}
-		if(specs)
-			drawstring(rgb, "Spectators", '8 8 0', '1 1 1', 1, 0);
 	}
+	sbar = sbar_save;
 }
 
-
 void Sbar_Score(float margin)
 {
 	float timelimit, timeleft, minutes, seconds, distribution, myplace;
@@ -865,7 +1062,22 @@
 	redflag = (stat_items/32768) & 3;
 	blueflag = (stat_items/131072) & 3;
 
-	pos_x = (cvar("sbar_flagstatus_right")) ? vid_conwidth - 10 - sbar_x - 64 : 10 - sbar_x;
+	/**
+	 * FTEQCC BUG!
+	 * For some reason now not even THAT works there...
+	 * Maybe the minus' precedence screws it up? The last one there, maybe I should use brackets
+	 **
+	 * pos_x = (cvar("sbar_flagstatus_right")) ? vid_conwidth - 10 - sbar_x - 64 : 10 - sbar_x;
+	 ** Should try those later:
+	 * pos_x = (cvar("sbar_flagstatus_right")) ? (vid_conwidth - 10 - sbar_x - 64) : (10 - sbar_x);
+	 * pos_x = ( (cvar("sbar_flagstatus_right")) ? vid_conwidth - 10 - 64 : 10 ) - sbar_x;
+	 */
+	
+	if(cvar("sbar_flagstatus_right"))
+		pos_x = vid_conwidth - 10 - sbar_x - 64;
+	else
+		pos_x = 10 - sbar_x;
+	
 	pos_z = 0;
 
 	if(sbar_hudselector == 1)

Modified: trunk/data/qcsrc/common/constants.qh
===================================================================
--- trunk/data/qcsrc/common/constants.qh	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/common/constants.qh	2008-07-08 18:41:39 UTC (rev 3795)
@@ -1,3 +1,6 @@
+// COMMIT-TODO: Update if necessary before committing
+#define CSQC_REVISION 1
+
 // probably put these in common/
 // so server/ and client/ can be synced better
 const float GAME_DEATHMATCH		= 1;
@@ -154,13 +157,13 @@
 const float TE_CSQC_INIT = 100;
 const float TE_CSQC_PING = 101;
 const float TE_CSQC_CAPTURES = 102;
+const float TE_CSQC_RETURNS = 103;
+const float TE_CSQC_DEATHS = 104;
 
-const float TE_CSQC_END = 101;
+const float TE_CSQC_END = 105;
 
 const float STAT_KH_KEYS = 32;
-const float STAT_CTF_CAPTURES = 33;
-
-const float STAT_CTF_STATE = 34;
+const float STAT_CTF_STATE = 33;
 const float CTF_STATE_ATTACK = 1;
 const float CTF_STATE_DEFEND = 2;
 const float CTF_STATE_COMMANDER = 3;

Modified: trunk/data/qcsrc/server/cl_client.qc
===================================================================
--- trunk/data/qcsrc/server/cl_client.qc	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/server/cl_client.qc	2008-07-08 18:41:39 UTC (rev 3795)
@@ -348,7 +348,8 @@
 putting a client as observer in the server
 =============
 */
-void ctf_UpdateCaptures();
+void ctf_UpdateCaptures(float);
+void ctf_UpdateReturns(float);
 void PutObserverInServer (void)
 {
 	entity	spot;
@@ -376,7 +377,7 @@
 	if(g_ctf)
 	{
 		self.captures = 0;
-		ctf_UpdateCaptures();
+		ctf_UpdateCaptures(MSG_BROADCAST);
 	}
 
 	if(self.frags <= 0 && self.frags > -666 && g_lms && self.killcount != -666)
@@ -402,6 +403,8 @@
 	self.death_time = 0;
 	self.dead_frame = 0;
 	self.deaths = 0;
+	self.captures = 0;
+	self.returns = 0;
 	self.alpha = 0;
 	self.scale = 0;
 	self.fade_time = 0;
@@ -454,6 +457,8 @@
 	}
 	else if(!g_lms)
 		self.frags = -666;
+	
+	net_UpdateDeaths(MSG_BROADCAST);
 }
 
 float RestrictSkin(float s)
@@ -662,6 +667,15 @@
 			if(!g_arena)
 			if(!g_lms)
 				self.frags = 0;
+			if(g_ctf)
+			{
+				self.captures = 0;
+				self.returns = 0;
+				ctf_UpdateCaptures(MSG_BROADCAST);
+				ctf_UpdateReturns(MSG_BROADCAST);
+			}
+			self.deaths = 0;
+			net_UpdateDeaths(MSG_BROADCAST);
 		}
 
 		self.cnt = WEP_LASER;
@@ -717,6 +731,7 @@
 	msg_entity = self;
 	WriteByte(MSG_ONE, SVC_TEMPENTITY);
 	WriteByte(MSG_ONE, TE_CSQC_INIT);
+	WriteShort(MSG_ONE, CSQC_REVISION);
 	WriteByte(MSG_ONE, maxclients-1);
 }
 
@@ -768,8 +783,12 @@
 	if(g_ctf)
 	{
 		self.captures = 0;
-		ctf_UpdateCaptures();
+		self.returns = 0;
+		ctf_UpdateCaptures(MSG_BROADCAST);
+		ctf_UpdateReturns(MSG_BROADCAST);
 	}
+	self.deaths = 0;
+	net_UpdateDeaths(MSG_BROADCAST);
 	if(self.killindicator_teamchange == -1)
 	{
 		self.team = -1;
@@ -966,7 +985,6 @@
 //void ctf_clientconnect();
 string ColoredTeamName(float t);
 void DecodeLevelParms (void);
-void ctf_SendCaptures(entity);
 //void dom_player_join_team(entity pl);
 void ClientConnect (void)
 {
@@ -1121,8 +1139,15 @@
 	self.jointime = time;
 	self.allowedTimeouts = cvar("sv_timeout_number");
 
-	SendCSQCInfo();
-	ctf_SendCaptures(self);
+	if(clienttype(self) == CLIENTTYPE_REAL)
+	{
+		sprint(self, strcat("nexuiz-csqc protocol ", ftos(CSQC_REVISION), "\n"));
+		SendCSQCInfo();
+		msg_entity = self;
+		ctf_UpdateCaptures(MSG_ONE);
+		ctf_UpdateReturns(MSG_ONE);
+		net_UpdateDeaths(MSG_ONE);
+	}
 }
 
 /*
@@ -1178,7 +1203,7 @@
 	if(g_ctf)
 	{
 		self.captures = 0;
-		ctf_UpdateCaptures();
+		ctf_UpdateCaptures(MSG_BROADCAST);
 	}
 
 	save = self.flags;

Modified: trunk/data/qcsrc/server/cl_player.qc
===================================================================
--- trunk/data/qcsrc/server/cl_player.qc	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/server/cl_player.qc	2008-07-08 18:41:39 UTC (rev 3795)
@@ -351,6 +351,19 @@
 
 void ClientKill_Now_TeamChange();
 
+void net_UpdateDeaths(float msg_target)
+{
+	entity p;
+	WriteByte(msg_target, SVC_TEMPENTITY);
+	WriteByte(msg_target, TE_CSQC_DEATHS);
+	FOR_EACH_PLAYER(p)
+	{
+		WriteByte(msg_target, num_for_edict(p));
+		WriteByte(msg_target, p.deaths);
+	}
+	WriteByte(msg_target, 0);
+}
+
 void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 {
 	local float take, save, waves, sdelay;
@@ -447,6 +460,7 @@
 		defer_ClientKill_Now_TeamChange = FALSE;
 
 		self.deaths += 1;
+		net_UpdateDeaths(MSG_BROADCAST);
 
 		// get rid of kill indicator
 		if(self.killindicator)

Modified: trunk/data/qcsrc/server/clientcommands.qc
===================================================================
--- trunk/data/qcsrc/server/clientcommands.qc	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/server/clientcommands.qc	2008-07-08 18:41:39 UTC (rev 3795)
@@ -214,8 +214,6 @@
 			kh_Key_DropAll(self, TRUE);
 			WaypointSprite_PlayerDead();
 			DistributeFragsAmongTeam(self, self.team, 1.0);
-			self.captures = 0;
-			ctf_UpdateCaptures();
 			self.classname = "observer";
 			if(blockSpectators)
 				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"));
@@ -228,8 +226,6 @@
 			if(isJoinAllowed()) {
 				self.classname = "player";
 				self.frags = 0;
-				self.captures = 0;
-				ctf_UpdateCaptures();
 				bprint ("^4", self.netname, "^4 is playing now\n");
 				PutClientInServer();
 			}

Modified: trunk/data/qcsrc/server/ctf.qc
===================================================================
--- trunk/data/qcsrc/server/ctf.qc	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/server/ctf.qc	2008-07-08 18:41:39 UTC (rev 3795)
@@ -230,37 +230,32 @@
 	}
 };
 
-void ctf_SendCaptures(entity player)
+void ctf_UpdateCaptures(float msg_target)
 {
 	entity p;
-	if(clienttype(player) != CLIENTTYPE_REAL)
-		return;
-	msg_entity = player;
-	WriteByte(MSG_ONE, SVC_TEMPENTITY);
-	WriteByte(MSG_ONE, TE_CSQC_CAPTURES);
-	WriteByte(MSG_ONE, caps_team1);
-	WriteByte(MSG_ONE, caps_team2);
-	FOR_EACH_CLIENT(p)
+	WriteByte(msg_target, SVC_TEMPENTITY);
+	WriteByte(msg_target, TE_CSQC_CAPTURES);
+	WriteByte(msg_target, cvar("g_ctf_win_mode"));
+	WriteByte(msg_target, caps_team1);
+	WriteByte(msg_target, caps_team2);
+	FOR_EACH_PLAYER(p)
 	{
-		WriteByte(MSG_ONE, num_for_edict(p));
-		WriteByte(MSG_ONE, p.captures);
+		WriteByte(msg_target, num_for_edict(p));
+		WriteByte(msg_target, p.captures);
 	}
-	WriteByte(MSG_ONE, 0);
+	WriteByte(msg_target, 0);
 }
-
-void ctf_UpdateCaptures()
+void ctf_UpdateReturns(float msg_target)
 {
 	entity p;
-	WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
-	WriteByte(MSG_BROADCAST, TE_CSQC_CAPTURES);
-	WriteByte(MSG_BROADCAST, caps_team1);
-	WriteByte(MSG_BROADCAST, caps_team2);
-	FOR_EACH_REALCLIENT(p)
+	WriteByte(msg_target, SVC_TEMPENTITY);
+	WriteByte(msg_target, TE_CSQC_RETURNS);
+	FOR_EACH_PLAYER(p)
 	{
-		WriteByte(MSG_BROADCAST, num_for_edict(p));
-		WriteByte(MSG_BROADCAST, p.captures);
+		WriteByte(msg_target, num_for_edict(p));
+		WriteByte(msg_target, p.returns);
 	}
-	WriteByte(MSG_BROADCAST, 0);
+	WriteByte(msg_target, 0);
 }
 
 void FlagTouch()
@@ -323,7 +318,7 @@
 			caps_team2++;
 		else
 			print("Unknown team captured the flag!\n");
-		ctf_UpdateCaptures();
+		ctf_UpdateCaptures(MSG_BROADCAST);
 		// FIXME: When counting captures, should the score be updated?
 
 		LogCTF("capture", other.flagcarried.team, other);
@@ -387,10 +382,15 @@
 		{
 			// return flag
 			bprint(other.netname, "^7 returned the ", self.netname, "\n");
-			if (other.team == COLOR_TEAM1 || other.team == COLOR_TEAM2)
-				UpdateFrags(other, cvar("g_ctf_flagscore_return"));
-			else
-				UpdateFrags(other, cvar("g_ctf_flagscore_return_rogue"));
+			if(cvar("g_ctf_win_mode") == 2)
+			{
+				if (other.team == COLOR_TEAM1 || other.team == COLOR_TEAM2)
+					UpdateFrags(other, cvar("g_ctf_flagscore_return"));
+				else
+					UpdateFrags(other, cvar("g_ctf_flagscore_return_rogue"));
+			}
+			other.returns++;
+			ctf_UpdateReturns(MSG_BROADCAST);
 			LogCTF("return", self.team, other);
 			sound (self, CHAN_AUTO, self.noise1, 1, ATTN_NONE);
 			ReturnFlag(self);

Modified: trunk/data/qcsrc/server/defs.qh
===================================================================
--- trunk/data/qcsrc/server/defs.qh	2008-07-08 18:03:39 UTC (rev 3794)
+++ trunk/data/qcsrc/server/defs.qh	2008-07-08 18:41:39 UTC (rev 3795)
@@ -438,4 +438,5 @@
 float next_pingtime;
 
 .float captures;
+.float returns;
 float caps_team1, caps_team2;




More information about the nexuiz-commits mailing list