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