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

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Thu Jul 24 14:48:31 EDT 2008


Author: blub0
Date: 2008-07-24 14:48:31 -0400 (Thu, 24 Jul 2008)
New Revision: 3903

Modified:
   trunk/data/qcsrc/client/Defs.qc
   trunk/data/qcsrc/client/Main.qc
   trunk/data/qcsrc/client/View.qc
   trunk/data/qcsrc/client/main.qh
   trunk/data/qcsrc/client/mapvoting.qc
   trunk/data/qcsrc/client/miscfunctions.qc
   trunk/data/qcsrc/client/progs.src
   trunk/data/qcsrc/client/sbar.qc
   trunk/data/qcsrc/client/sortlist.qc
   trunk/data/qcsrc/client/teamplay.qc
   trunk/data/qcsrc/common/constants.qh
   trunk/data/qcsrc/server/cl_weapons.qc
   trunk/data/qcsrc/server/defs.qh
   trunk/data/qcsrc/server/ent_cs.qc
   trunk/data/qcsrc/server/g_damage.qc
   trunk/data/qcsrc/server/keyhunt.qc
   trunk/data/qcsrc/server/scores.qc
   trunk/data/qcsrc/server/scores.qh
Log:
CSQC part for the new score system (not really finished yet, needs cleaning)
Added a few calls to PlayerScore_Add for testing purposes...
Added default scoreboard layout for and KH, CTF
Lots of the old csqc code for the scoreboard can be removed
(parts of the sortlist code too)


Modified: trunk/data/qcsrc/client/Defs.qc
===================================================================
--- trunk/data/qcsrc/client/Defs.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/Defs.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -167,6 +167,9 @@
 // Basic variables
 .float enttype; // entity type sent from server
 .float sv_entnum; // entity number sent from server
+.float team;
+.float team_size;
+
 float vid_conwidth, vid_conheight;
 float caps_team1, caps_team2;
 float configdb;

Modified: trunk/data/qcsrc/client/Main.qc
===================================================================
--- trunk/data/qcsrc/client/Main.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/Main.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -56,7 +56,7 @@
 	menu_action = menu_sub_null;
 	using_gps = false;
 	//ctf_temp_1 = "";
-	localcmd("alias order \"cmd order $*\"");
+	// localcmd("alias order \"cmd order $*\""); enable if ctf-command thingy is used
 	//registercmd("ctf_menu");
 	registercmd("ons_map");
 	//registercmd("menu_action");
@@ -76,7 +76,10 @@
 
 	postinit = false;
 
-	Sbar_Init();
+	teams = Sort_Spawn();
+	players = Sort_Spawn();
+	
+	teamspec = AddTeam(COLOR_SPECTATOR); // add specs first
 }
 
 // CSQC_Shutdown : Called every time the CSQC code is shutdown (changing maps, quitting, etc)
@@ -88,6 +91,9 @@
 		return 0;
 #pragma TARGET fte
 #endif
+
+	remove(teams);
+	remove(players);
 	db_close(configdb);
 	buf_del(databuf);
 }
@@ -185,7 +191,7 @@
 
 // --------------------------------------------------------------------------
 // BEGIN OPTIONAL CSQC FUNCTIONS
-void ReadONS()
+void Ent_ReadONS()
 {
 	entity gps;
 	using_gps = true;
@@ -207,7 +213,7 @@
 	}
 }
 
-void RemoveONS()
+void Ent_RemoveONS()
 {
 	if(gps_start == self)
 		gps_start = self.chain;
@@ -223,6 +229,69 @@
 	}
 }
 
+void Ent_ReadScoresInfo()
+{
+	float i;
+	for(i = 0; i < MAX_SCORE; ++i)
+	{
+		scores_label[i] = strzone(ReadString());
+		scores_flags[i] = ReadByte();
+	}
+	for(i = 0; i < MAX_TEAMSCORE; ++i)
+	{
+		teamscores_label[i] = strzone(ReadString());
+		teamscores_flags[i] = ReadByte();
+	}
+	Sbar_InitScores();
+}
+
+void Ent_ReadPlayerScore(float isNew)
+{
+	float i, Team;
+	entity tm;
+
+	// damnit -.- don't want to go change every single .sv_entnum in sbar.qc AGAIN
+	// (no I've never heard of M-x replace-string, sed, or anything like that)
+	self.sv_entnum = ReadByte()-1;
+	Team = GetPlayerColor(self.sv_entnum);
+
+	if(isNew)
+		RegisterPlayer(self);
+
+	if(isNew || Team != self.team)
+	{
+		if(!isNew)
+		{
+			tm = GetTeam(self.team, false);
+			tm.team_size -= 1;
+		}
+		
+		self.team = Team;
+		tm = GetTeam(Team, true);
+		tm.team_size += 1;
+	}
+
+	for(i = 0; i < MAX_SCORE; ++i)
+		self.(scores[i]) = ReadShort();
+
+	Sbar_UpdatePlayerPos(self);
+}
+
+void Ent_ReadTeamScore(float isNew)
+{
+	float i;
+	
+	self.team = ReadByte();
+
+	if(isNew)
+		RegisterTeam(self);
+
+	for(i = 0; i < MAX_TEAMSCORE; ++i)
+		self.(teamscores[i]) = ReadShort();
+
+	Sbar_UpdateTeamPos(self);
+}
+
 // CSQC_Ent_Update : Called every frame that the server has indicated an update to the SSQC / CSQC entity has occured.
 // The only parameter reflects if the entity is "new" to the client, meaning it just came into the client's PVS.
 void(float bIsNewEntity) CSQC_Ent_Update =
@@ -237,13 +306,19 @@
 		{
 			switch(msg)
 			{
-			case ENTCS_MSG_ONS_GPS: ReadONS(); break;
-			case ENTCS_MSG_ONS_REMOVE: RemoveONS(); break;
+			case ENTCS_MSG_ONS_GPS: Ent_ReadONS(); break;
+			case ENTCS_MSG_ONS_REMOVE: Ent_RemoveONS(); break;
 			default:
 				error("unknown ENTCS_MSG type\n");
 			}
 		}
 	}
+	else if(self.enttype == ENT_CLIENT_SCORES_INFO)
+		Ent_ReadScoresInfo();
+	else if(self.enttype == ENT_CLIENT_SCORES)
+		Ent_ReadPlayerScore(bIsNewEntity);
+	else if(self.enttype == ENT_CLIENT_TEAMSCORES)
+		Ent_ReadTeamScore(bIsNewEntity);
 	else
 		error("unknown entity type in CSQC_Ent_Update\n");
 	
@@ -268,6 +343,21 @@
 					ent.chain = self.chain;
 			}
 		}
+	} else if(self.enttype == ENT_CLIENT_SCORES_INFO)
+	{
+		// OH NOES!! WE LOST DA SCORES INFO ENTITY
+		print("The world is going to explode.");
+		// kkthxbai
+	} else if(self.enttype == ENT_CLIENT_SCORES)
+	{
+		entity tm;
+		print("lost a client score\n");
+		tm = GetTeam(self.team, false);
+		tm.team_size -= 1;
+		RemovePlayer(self);
+	} else if(self.enttype == ENT_CLIENT_TEAMSCORES)
+	{
+		RemoveTeam(self);
 	}
 	remove(self);
 }
@@ -333,11 +423,6 @@
 void CSQC_Parse_StuffCmd(string strMessage)
 {
 	localcmd(strMessage);
-	// watch for gametype changes!
-	if(gametype != cvar("gametype"))
-	{
-		Gamemode_Init();
-	}
 }
 // CSQC_Parse_Print : Provides the print string in the first parameter that the server provided.  To execute standard behavior, simply execute print with the string.
 void CSQC_Parse_Print(string strMessage)

Modified: trunk/data/qcsrc/client/View.qc
===================================================================
--- trunk/data/qcsrc/client/View.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/View.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -7,6 +7,12 @@
 void PostInit(void);
 void CSQC_UpdateView(void)
 {
+	// watch for gametype changes here...
+	// in ParseStuffCMD the cmd isn't executed yet :/
+	// might even be better to add the gametype to TE_CSQC_INIT...?
+	if(gametype != cvar("gametype"))
+		Gamemode_Init();
+	
 	if(!postinit)
 		PostInit();
 	

Modified: trunk/data/qcsrc/client/main.qh
===================================================================
--- trunk/data/qcsrc/client/main.qh	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/main.qh	2008-07-24 18:48:31 UTC (rev 3903)
@@ -67,23 +67,32 @@
 
 #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 SP_END -1
 
-#define SBF_SEPARATOR 100
+#define SP_PING -2
+#define SP_NAME -3
+#define SP_KDRATIO -4
+#define SP_CLRATIO -5
 
+#define SP_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;
+
 float sbar_font;
 
+string scores_label[MAX_SCORE];
+float scores_flags[MAX_SCORE];
+string teamscores_label[MAX_SCORE];
+float teamscores_flags[MAX_SCORE];
+.float scores[MAX_SCORE];
+.float teamscores[MAX_TEAMSCORE];
+
+#define IS_INCREASING(x) ( (x)&SFL_DECREASING )
+#define IS_DECREASING(x) ( !((x)&SFL_DECREASING) )
+
 float csqc_flags;
 #define CSQC_FLAG_READPICTURE 1
 

Modified: trunk/data/qcsrc/client/mapvoting.qc
===================================================================
--- trunk/data/qcsrc/client/mapvoting.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/mapvoting.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -105,7 +105,6 @@
 	vector pos;
 	float isize;
 	float center;
-	float margin;
 	
 	center = (vid_conwidth - 1)/2;
 	xmin = vid_conwidth*0.2;

Modified: trunk/data/qcsrc/client/miscfunctions.qc
===================================================================
--- trunk/data/qcsrc/client/miscfunctions.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/miscfunctions.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -1,6 +1,111 @@
 float databuf;
 var float(string text, float handleColors) stringwidth;
 
+entity players;
+entity teams;
+
+float RegisterPlayer(entity player)
+{
+	entity pl;
+	for(pl = players.sort_next; pl; pl = pl.sort_next)
+		if(pl == player)
+			return false;
+	player.sort_next = players.sort_next;
+	player.sort_prev = players;
+	if(players.sort_next)
+		players.sort_next.sort_prev = player;
+	players.sort_next = player;
+	return true;
+}
+
+void RemovePlayer(entity player)
+{
+	entity pl, parent;
+	parent = players;
+	for(pl = players.sort_next; pl && pl != player; pl = pl.sort_next)
+		parent = pl;
+
+	if(!pl)
+	{
+		print("Trying to remove a player which is not in the playerlist!");
+		return;
+	}
+	parent.sort_next = player.sort_next;
+	if(player.sort_next)
+		player.sort_next.sort_prev = parent;
+}
+
+entity AddTeam(float num)
+{
+	entity tm;
+	tm = spawn();
+	tm.team = num;
+	tm.sort_next = teams.sort_next;
+	tm.sort_prev = teams;
+	if(teams.sort_next)
+		teams.sort_next.sort_prev = tm;
+	teams.sort_next = tm;
+	return tm;
+}
+
+void MoveToLast(entity e)
+{
+	other = e.sort_next;
+	while(other)
+	{
+		SORT_SWAP(other, e);
+		other = e.sort_next;
+	}
+}
+
+// warning: Local "team" defined with name of a global
+// FU FTEQCC, .float team is a ENTVAR shitty piece of crap!!!
+float RegisterTeam(entity Team)
+{
+	entity tm;
+	for(tm = teams.sort_next; tm; tm = tm.sort_next)
+		if(tm == Team)
+			return false;
+	Team.sort_next = teams.sort_next;
+	Team.sort_prev = teams;
+	if(teams.sort_next)
+		teams.sort_next.sort_prev = Team;
+	teams.sort_next = Team;
+	return true;
+}
+
+void RemoveTeam(entity Team)
+{
+	entity tm, parent;
+	parent = teams;
+	for(tm = teams.sort_next; tm && tm != Team; tm = tm.sort_next)
+		parent = tm;
+
+	if(!tm)
+	{
+		print("Trying to remove a team which is not in the teamlist!");
+		return;
+	}
+	parent.sort_next = Team.sort_next;
+	if(Team.sort_next)
+		Team.sort_next.sort_prev = parent;
+}
+
+entity GetTeam(float num, float add)
+{
+	entity tm;
+	for(tm = teams.sort_next; tm; tm = tm.sort_next)
+	{
+		if(tm.team == num)
+			return tm;
+	}
+	
+	if(add)
+		return AddTeam(num);
+	
+	return NULL;
+}
+
 float stringwidth_oldfont(string text, float handleColors)
 {
 	float i, len, ch, width;

Modified: trunk/data/qcsrc/client/progs.src
===================================================================
--- trunk/data/qcsrc/client/progs.src	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/progs.src	2008-07-24 18:48:31 UTC (rev 3903)
@@ -11,8 +11,8 @@
 
 main.qh
 
+sortlist.qc
 miscfunctions.qc
-sortlist.qc
 teamplay.qc
 
 ons.qc

Modified: trunk/data/qcsrc/client/sbar.qc
===================================================================
--- trunk/data/qcsrc/client/sbar.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/sbar.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -9,7 +9,7 @@
 vector sbar_fontsize;
 float sbar_alpha_fg;
 float sbar_hudselector;
-
+/*
 entity sortedPlayers;
 entity sortedTeams;
 
@@ -17,6 +17,9 @@
 .float sb_team;
 .float sb_player;
 .float sb_caps;
+*/
+float ps_primary, ps_secondary;
+float ts_primary, ts_secondary;
 
 entity team1, team2, team3, team4, teamspec;
 
@@ -128,447 +131,282 @@
 	}
 }
 
-float Sbar_PlayerCmp(entity l, entity r)
+void Cmd_Sbar_SetFields(float argc);
+void Sbar_InitScores()
 {
-	if(teamplay)
+	float i, f, primary_prio, secondary_prio;
+
+	primary_prio = secondary_prio = -1;
+	for(i = 0; i < MAX_SCORE; ++i)
 	{
-		if(l.sb_team > r.sb_team)
-			return true;
-		else if(l.sb_team > r.sb_team)
-			return false;
-		if(gametype == GAME_CTF)
-		{
-			if(l.sb_caps > r.sb_caps)
-				return true;
-			else if(l.sb_caps < r.sb_caps)
-				return false;
-		}
+		f = (scores_flags[i] & SFL_SORT_PRIO_MASK);
+		if(f > primary_prio) {
+			ps_secondary = ps_primary;
+			ps_primary = i;
+		} else if(f > secondary_prio)
+			ps_secondary = i;
 	}
-	if(l.sb_frags > r.sb_frags)
-		return true;
-	else if(l.sb_frags < r.sb_frags)
-		return false;
-	return (l.sb_player > r.sb_player);
-}
-float Sbar_TeamCmp(entity l, entity r)
-{
-	if(gametype == GAME_CTF)
+	
+	primary_prio = secondary_prio = -1;
+	for(i = 0; i < MAX_TEAMSCORE; ++i)
 	{
-		if(l.sb_caps > r.sb_caps)
-			return true;
-		else if(l.sb_caps < r.sb_caps)
-			return false;
+		f = (teamscores_flags[i] & SFL_SORT_PRIO_MASK);
+		if(f > primary_prio) {
+			ts_secondary = ts_primary;
+			ts_primary = i;
+		} else if(f > secondary_prio)
+			ts_secondary = i;
 	}
-	if(l.sb_frags > r.sb_frags)
-		return true;
-	else if(l.sb_frags < r.sb_frags)
-		return false;
-	return (l.sb_player > r.sb_player);
-}
 
-void Sbar_Init()
-{
-	sortedPlayers = Sort_New(Sbar_PlayerCmp);
-	sortedTeams = Sort_New(Sbar_TeamCmp);
-	team1 = Sort_Next(sortedTeams);
-	team1.sb_team = COLOR_TEAM1;
-	team2 = Sort_Next(sortedTeams);
-	team2.sb_team = COLOR_TEAM2;
-	team3 = Sort_Next(sortedTeams);
-	team3.sb_team = COLOR_TEAM3;
-	team4 = Sort_Next(sortedTeams);
-	team4.sb_team = COLOR_TEAM4;
-	teamspec = Sort_Next(sortedTeams);
-	teamspec.sb_team = COLOR_SPECTATOR;
+	Cmd_Sbar_SetFields(0);
 }
 
-void Sbar_UpdatePosFrags(entity player)
+void Sbar_UpdatePlayerPos(entity pl);
+void Sbar_UpdatePlayerTeams()
 {
-	other = player.sort_prev;
-	while(other != sortedPlayers && player.sb_frags > other.sb_frags)
-	{
-		SORT_SWAP(other, player);
-		other = player.sort_prev;
-	}
+	float Team;
+	entity pl, tmp;
+	float num;
 
-	other = player.sort_next;
-	while(other && player.sb_frags < other.sb_frags)
+	num = 0;
+	for(pl = players.sort_next; pl; pl = pl.sort_next)
 	{
-		SORT_SWAP(player, other);
-		other = player.sort_next;
+		num += 1;
+		Team = GetPlayerColor(pl.sv_entnum);
+		if(pl.team != Team)
+		{
+			tmp = GetTeam(pl.team, false);
+			tmp.team_size -= 1;
+			tmp = GetTeam(Team, true);
+			tmp.team_size += 1;
+			
+			pl.team = Team;
+
+			tmp = pl.sort_prev;
+			Sbar_UpdatePlayerPos(pl);
+			if(tmp)
+				pl = tmp;
+			else
+				pl = players.sort_next;
+		}
 	}
+	//print(strcat("PNUM: ", ftos(num), "\n"));
 }
-void Sbar_UpdatePosFragsCTF(entity player)
+
+float Sbar_ComparePlayerScores(entity left, entity right)
 {
-	other = player.sort_prev;
-	while(other != sortedPlayers && player.sb_frags > other.sb_frags && player.sb_caps == other.sb_caps)
-	{
-		SORT_SWAP(other, player);
-		other = player.sort_prev;
-	}
+	float vl, vr;
+	vl = GetPlayerColor(left.sv_entnum);
+	vr = GetPlayerColor(right.sv_entnum);
+	
+	if(vl > vr)
+		return true;
+	if(vl < vr)
+		return false;
 
-	other = player.sort_next;
-	while(other && player.sb_frags < other.sb_frags && player.sb_caps == other.sb_caps)
-	{
-		SORT_SWAP(player, other);
-		other = player.sort_next;
-	}
+	vl = left.scores[ps_primary];
+	vr = right.scores[ps_primary];
+	if(vl > vr)
+		return IS_INCREASING(scores_flags[ps_primary]);
+	if(vl < vr)
+		return IS_DECREASING(scores_flags[ps_primary]);
+	
+	vl = left.scores[ps_secondary];
+	vr = right.scores[ps_secondary];
+	if(vl > vr)
+		return IS_INCREASING(scores_flags[ps_secondary]);
+	if(vl < vr)
+		return IS_DECREASING(scores_flags[ps_secondary]);
+	
+	return false;
 }
-void Sbar_UpdatePosCaps(entity player)
+
+void Sbar_UpdatePlayerPos(entity player)
 {
-	other = player.sort_prev;
-	while(other != sortedPlayers && player.sb_caps > other.sb_caps)
+	for(other = player.sort_next; other && Sbar_ComparePlayerScores(player, other); other = player.sort_next)
 	{
-		SORT_SWAP(other, player);
-		other = player.sort_prev;
-	}
-	other = player.sort_next;
-	while(other && player.sb_caps < other.sb_caps)
-	{
 		SORT_SWAP(player, other);
-		other = player.sort_next;
 	}
-	// let it update the frags now too, so if we have more frags then the next guy with the same caps
-	// we beat his ass :)
-	player.sb_frags -= 1;
-}
-
-void Sbar_UpdatePosTeam(entity player)
-{
-	player.sb_caps -= 1; // team change needs a full update
-	other = player.sort_prev;
-	while(other != sortedPlayers && player.sb_team > other.sb_team)
+	for(other = player.sort_prev; other != players && Sbar_ComparePlayerScores(other, player); other = player.sort_prev)
 	{
 		SORT_SWAP(other, player);
-		other = player.sort_prev;
 	}
-
-	other = player.sort_next;
-	while(other && player.sb_team < other.sb_team)
-	{
-		SORT_SWAP(player, other);
-		other = player.sort_next;
-	}
 }
 
-void Sbar_UpdatePlayer(entity player)
+float Sbar_CompareTeamScores(entity left, entity right)
 {
-	float i;
-
-	if(player.sb_frags == -666)
-		i = COLOR_SPECTATOR;
-	else
-		i = GetPlayerColor(player.sb_player);
+	float vl, vr;
 	
-	if(player.sb_team != i)
-	{
-		player.sb_team = i;
-		Sbar_UpdatePosTeam(player);
-	}
+	vl = left.teamscores[ts_primary];
+	vr = right.teamscores[ts_primary];
+	if(vl > vr)
+		return IS_INCREASING(teamscores_flags[ts_primary]);
+	if(vl < vr)
+		return IS_DECREASING(teamscores_flags[ts_primary]);
 	
-	if(gametype == GAME_CTF)
-	{
-		i = stof(bufstr_get(databuf, DATABUF_CAPTURES + player.sb_player));
-		if(player.sb_caps != i)
-		{
-			player.sb_caps = i;
-			Sbar_UpdatePosCaps(player);
-		}
-		i = stof(getplayerkey(player.sb_player, "frags"));
-		if(player.sb_frags != i)
-		{
-			player.sb_frags = i;
-			Sbar_UpdatePosFragsCTF(player);
-		}
-	} else {
-		i = stof(getplayerkey(player.sb_player, "frags"));
-		if(player.sb_frags != i)
-		{
-			player.sb_frags = i;
-			Sbar_UpdatePosFrags(player);
-		}
-	}
+	vl = left.teamscores[ts_secondary];
+	vr = right.teamscores[ts_secondary];
+	if(vl > vr)
+		return IS_INCREASING(teamscores_flags[ts_secondary]);
+	if(vl < vr)
+		return IS_DECREASING(teamscores_flags[ts_secondary]);
+
+	return false;
 }
 
-void Sbar_UpdateTeamPosCaps(entity tm)
+void Sbar_UpdateTeamPos(entity Team)
 {
-	other = tm.sort_prev;
-	while(other != sortedTeams && tm.sb_caps > other.sb_caps)
+	for(other = Team.sort_next; other && Sbar_ComparePlayerScores(Team, other); other = Team.sort_next)
 	{
-		SORT_SWAP(other, tm);
-		other = tm.sort_prev;
+		if(other.team == COLOR_SPECTATOR)
+			break;
+		SORT_SWAP(Team, other);
 	}
-
-	other = tm.sort_next;
-	while(other && tm.sb_caps < tm.sb_caps)
+	for(other = Team.sort_prev; other != teams && Sbar_ComparePlayerScores(other, Team); other = Team.sort_prev)
 	{
-		SORT_SWAP(tm, other);
-		other = tm.sort_next;
+		SORT_SWAP(other, Team);
 	}
 }
-void Sbar_UpdateTeamPosFrags(entity tm)
-{
-	other = tm.sort_prev;
-	while(other != sortedTeams && tm.sb_caps == other.sb_caps && tm.sb_frags > other.sb_frags)
-	{
-		SORT_SWAP(other, tm);
-		other = tm.sort_prev;
-	}
 
-	other = tm.sort_next;
-	while(other && tm.sb_caps == other.sb_caps && tm.sb_frags < other.sb_frags)
-	{
-		SORT_SWAP(tm, other);
-		other = tm.sort_next;
-	}
-}
-
-void Sbar_SortFrags()
-{
-	float i;
-	entity tmp;
-	float t1f, t2f, t3f, t4f;
-	
-	Sort_Reset(sortedPlayers);
-
-	numteams = 0;
-	if(teamplay)
-	{
-		Sort_Reset(sortedTeams);
-		tmp = Sort_Next(sortedTeams);
-
-		team1.sb_player = 0;
-		team2.sb_player = 0;
-		team3.sb_player = 0;
-		team4.sb_player = 0;
-		teamspec.sb_player = 0;
-		
-		t1f = team1.sb_frags;
-		t2f = team2.sb_frags;
-		t3f = team3.sb_frags;
-		t4f = team4.sb_frags;
-
-		team1.sb_frags = 0;
-		team2.sb_frags = 0;
-		team3.sb_frags = 0;
-		team4.sb_frags = 0;
-		
-		for(i = 0; i < maxclients; ++i)
-		{
-			if(strlen(getplayerkey(i, "name")) <= 0)
-				continue;
-
-			Sort_Reset(sortedPlayers);
-
-			tmp = NULL;
-			while(Sort_HasNext(sortedPlayers))
-			{
-				tmp = Sort_Next(sortedPlayers);
-				if(tmp.sb_player == i)
-					break;
-			}
-			if(!tmp || tmp.sb_player != i)
-				tmp = Sort_Next(sortedPlayers);
-			
-			tmp.sb_player = i;
-			tmp.frame = time;
-			Sbar_UpdatePlayer(tmp);
-			
-			switch(tmp.sb_team)
-			{
-			case COLOR_TEAM1: team1.sb_frags += tmp.sb_frags; team1.sb_player++; break;
-			case COLOR_TEAM2: team2.sb_frags += tmp.sb_frags; team2.sb_player++; break;
-			case COLOR_TEAM3: team3.sb_frags += tmp.sb_frags; team3.sb_player++; break;
-			case COLOR_TEAM4: team4.sb_frags += tmp.sb_frags; team4.sb_player++; break;
-			case COLOR_SPECTATOR: teamspec.sb_frags += tmp.sb_frags; teamspec.sb_player++; break;
-			}
-
-			if(i == player_localentnum-1)
-				myteam = tmp.sb_team;
-		}
-		if(team1.sb_player) ++numteams;
-		if(team2.sb_player) ++numteams;
-		if(team3.sb_player) ++numteams;
-		if(team4.sb_player) ++numteams;
-
-		if(team1.sb_caps != caps_team1)
-		{
-			team1.sb_caps = caps_team1;
-			Sbar_UpdateTeamPosCaps(team1);
-		}
-		if(team2.sb_caps != caps_team2)
-		{
-			team2.sb_caps = caps_team2;
-			Sbar_UpdateTeamPosCaps(team2);
-		}
-		if(team1.sb_frags != t1f) Sbar_UpdateTeamPosFrags(team1);
-		if(team2.sb_frags != t2f) Sbar_UpdateTeamPosFrags(team2);
-		if(team3.sb_frags != t3f) Sbar_UpdateTeamPosFrags(team3);
-		if(team4.sb_frags != t4f) Sbar_UpdateTeamPosFrags(team4);
-	} else {
-		for(i = 0; i < maxclients; ++i)
-		{
-			if(strlen(getplayerkey(i, "name")) <= 0)
-				continue;
-		
-			Sort_Reset(sortedPlayers);
-			tmp = NULL;
-			while(Sort_HasNext(sortedPlayers))
-			{
-				tmp = Sort_Next(sortedPlayers);
-				if(tmp.sb_player == i)
-					break;
-			}
-			if(!tmp || tmp.sb_player != i)
-				tmp = Sort_Next(sortedPlayers);
-			
-			tmp.sb_player = i;
-			tmp.frame = time;
-			Sbar_UpdatePlayer(tmp);
-		}
-	}
-	Sort_RemoveOld(sortedPlayers);
-}
-
 void Cmd_Sbar_Help(float argc)
 {
 	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("^1 TO BE DONE\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("You can use a ^3|^7 to start the right-aligned fields.\n");
+	
 	print("^3name^7 or ^3nick^7             Name of a player\n");
+	print("^3ping^7                     Ping time\n\n");
+	print("^3kd^7 or ^3kdr^7 or ^3kdratio^7 or ^3k/d\n");
+	print("                         The kill-death ratio\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");
-
+	*/
+	local float i;
+	print("Additional columns:\n");
+	for(i = 0; i < MAX_SCORE; ++i)
+	{
+		if(scores_label[i])
+			print(strcat(scores_label[i], "\n"));
+	}
 }
 
 #define MIN_NAMELEN 24
 #define MAX_NAMELEN 24
 
+string Sbar_DefaultColumnLayout()
+{
+	switch(gametype)
+	{
+		case GAME_CTF: return "ping name | caps frags";
+		case GAME_KEYHUNT: return "ping name | score caps kills";
+		default: return "ping name | frags";
+			// TODO: add other gametypes
+	}
+}
+
 void Cmd_Sbar_SetFields(float argc)
 {
-	float i;
+	float i, j;
 	string str;
 	float digit;
 
-	if(argc < 2)
+	// TODO: re enable with gametype dependant cvars?
+	if(argc < 2) // no arguments provided
 		argc = tokenize(strcat("x ", cvar_string("sbar_columns")));
+
+	if(argc < 2)
+		argc = tokenize(strcat("x ", Sbar_DefaultColumnLayout()));
 	
 	argc = min(MAX_SBAR_FIELDS, argc);
 	sbar_num_fields = 0;
+
 	drawfont = sbar_font;
 	digit = stringwidth("0123456789", FALSE) / 10;
-	for(i = 0; i < argc-1; ++i)
+
+	argc = min(argc-1, MAX_SBAR_FIELDS-1);
+	for(i = 0; i < argc; ++i)
 	{
 		str = argv(i+1);
 		strunzone(sbar_title[i]);
 		sbar_title[i] = strzone(str);
 		sbar_size[i] = stringwidth(str, FALSE);
 		str = strtolower(str);
+
+		
+
 		if(str == "ping") {
-			sbar_field[i] = SBF_PING;
+			sbar_field[i] = SP_PING;
 		} else if(str == "name" || str == "nick") {
-			sbar_field[i] = SBF_NAME;
+			sbar_field[i] = SP_NAME;
 			sbar_size[i] = MIN_NAMELEN; // minimum size? any use?
-		} else if(str == "caps" || str == "captures") {
-			if(sbar_size[i] < 3*digit)
-				sbar_size[i] = 3*digit;
-			sbar_field[i] = SBF_CAPS;
-		} else if(str == "rets" || str == "returns") {
-			if(sbar_size[i] < 3*digit)
-				sbar_size[i] = 3*digit;
-			sbar_field[i] = SBF_RETS;
-		} else if(str == "frags" || str == "kills") {
-			if(sbar_size[i] < 5*digit)
-				sbar_size[i] = 5*digit;
-			sbar_field[i] = SBF_FRAGS;
-		} else if(str == "deaths" || str == "dths") {
-			if(sbar_size[i] < 5*digit)
-				sbar_size[i] = 5*digit;
-			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;
+			sbar_field[i] = SP_SEPARATOR;
 		} else {
-			print(strcat("^1Error:^7 Unknown score field: '", str, "'\n"));
-			--sbar_num_fields;
+			for(j = 0; j < MAX_SCORE; ++j)
+			{
+				if(str == strtolower(scores_label[j]))
+					break;
+			}
+			if(j == MAX_SCORE) {
+				print(strcat("^1Error:^7 Unknown score field: '", str, "'\n"));
+				--sbar_num_fields;
+			} else
+				sbar_field[i] = j;
 		}
 		++sbar_num_fields;
 	}
-	sbar_field[i] = SBF_END;
+	sbar_field[i] = SP_END;
 }
 
+// MOVEUP::
 vector sbar_field_rgb;
 string Sbar_GetField(entity pl, float field)
 {
-	float tmp;
+	float tmp, num, denom;
 	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);
+		case SP_PING:
+			str = bufstr_get(databuf, DATABUF_PING + pl.sv_entnum);
+			tmp = max(0, min(220, stof(str)-80)) / 220;
+			sbar_field_rgb = '1 1 1' - '0 1 1'*tmp;
+			return str;
 		
-		tmp = strstrofs(str, ".", 0);
-		if(tmp > 0)
-			str = substring(str, 0, tmp+2);
-		return str;
+		case SP_NAME:
+			return getplayerkey(pl.sv_entnum, "name");
+
+		case SP_KDRATIO:
+			num = pl.(scores[SP_KILLS]);
+			denom = pl.(scores[SP_DEATHS]);
+
+			if(denom == 0) {
+				sbar_field_rgb = '0 1 0';
+				str = ftos(num);
+			} else if(num <= 0) {
+				sbar_field_rgb = '1 0 0';
+				str = ftos(num/denom);
+			} else
+				str = ftos(num/denom);
+		
+			tmp = strstrofs(str, ".", 0);
+			if(tmp > 0)
+				str = substring(str, 0, tmp+2);
+			return str;
+			
+		default:
+			return ftos(pl.(scores[field]));
 	}
+	return "error";
 }
-#define SBAR_DEFAULT_MASK 0
-#define SBAR_MASK_SPECTATORS 1
-float Sbar_IsFieldMasked(float field, float mask)
-{
-	if(mask&1) // spectator
-		return (field != SBF_NAME && field != SBF_PING);
-	if(gametype != GAME_CTF)
-	{
-		if(field == SBF_CAPS || field == SBF_RETS)
-			return true;
-	}
-	return false;
-}
 
 // shamelessly stolen from menu QC :P <- as if I would steal YOUR code pfft ;)
 float textLengthUpToWidth(string theText, float maxWidth, float handleColors)
@@ -612,11 +450,14 @@
 }
 
 float xmin, xmax, ymin, ymax, sbwidth, sbheight;
-void Sbar_PrintScoreboardItem(vector pos, entity pl, float is_self, float mask)
+
+void Sbar_PrintScoreboardItem(vector pos, entity pl, float is_self)
 {
 	vector tmp;
 	string str;
 	float i, field, len;
+	float is_spec;
+	is_spec = (GetPlayerColor(pl.sv_entnum) == COLOR_SPECTATOR);
 
 	// Layout:
 	tmp_z = 0;
@@ -631,23 +472,25 @@
 	for(i = 0; i < sbar_num_fields; ++i)
 	{
 		field = sbar_field[i];
-		if(field == SBF_SEPARATOR)
+		if(field == SP_SEPARATOR)
 			break;
-		if(Sbar_IsFieldMasked(field, mask))
-			continue;
 
+		if(is_spec && field != SP_NAME && field != SP_PING) {
+			pos_x += sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
+			continue;
+		}
 		str = Sbar_GetField(pl, field);
 
-		if(field == SBF_NAME)
+		if(field == SP_NAME)
 		{
 			float realsize;
 			float j;
 			realsize = sbar_size[i];
 			if(i+1 < sbar_num_fields)
-				if(sbar_field[i+1] == SBF_SEPARATOR)
+				if(sbar_field[i+1] == SP_SEPARATOR)
 				{
 					realsize = (xmax - xmin) / sbar_fontsize_x;
-					for(j = 0; j < sbar_num_fields; ++j) if(j != i) if(sbar_field[j] != SBF_SEPARATOR)
+					for(j = 0; j < sbar_num_fields; ++j) if(j != i) if(sbar_field[j] != SP_SEPARATOR)
 						realsize -= sbar_size[j] + 1;
 					realsize += 1;
 				}
@@ -659,7 +502,8 @@
 			sbar_size[i] = len;
 
 		pos_x += sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
-		if(field == SBF_NAME) {
+
+		if(field == SP_NAME) {
 			tmp_x = sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
 			drawcolorcodedstring(pos - tmp, str, sbar_fontsize, 1, DRAWFLAG_NORMAL);
 		} else {
@@ -668,27 +512,30 @@
 		}
 	}
 	
-	if(sbar_field[i] == SBF_SEPARATOR)
+	if(sbar_field[i] == SP_SEPARATOR)
 	{
 		pos_x = xmax;
 		for(i = sbar_num_fields-1; i > 0; --i)
 		{
 			field = sbar_field[i];
-			if(field == SBF_SEPARATOR)
+			if(field == SP_SEPARATOR)
 				break;
-			if(Sbar_IsFieldMasked(field, mask))
+			
+			if(is_spec && field != SP_NAME && field != SP_PING) {
+				pos_x -= sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
 				continue;
+			}
 			
 			str = Sbar_GetField(pl, field);
 
-			if(field == SBF_NAME)
+			if(field == SP_NAME)
 				str = textShortenToWidth(str, sbar_size[i], TRUE);
 			len = stringwidth(str, TRUE);
 
 			if(sbar_size[i] < len)
 				sbar_size[i] = len;
-			
-			if(field == SBF_NAME) {
+
+			if(field == SP_NAME) {
 				tmp_x = sbar_fontsize_x*len; // left or right aligned? let's put it right...
 				drawcolorcodedstring(pos - tmp, str, sbar_fontsize, 1, DRAWFLAG_NORMAL);
 			} else {
@@ -746,23 +593,19 @@
 	
 	for(i = 0; i < sbar_num_fields; ++i)
 	{
-		if(Sbar_IsFieldMasked(sbar_field[i], SBAR_DEFAULT_MASK))
-			continue;
-		if(sbar_field[i] == SBF_SEPARATOR)
+		if(sbar_field[i] == SP_SEPARATOR)
 			break;
 		drawstring(pos, sbar_title[i], sbar_fontsize, '1 1 1', 1, DRAWFLAG_NORMAL);
 		pos_x += sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
 	}
 	
-	if(sbar_field[i] == SBF_SEPARATOR)
+	if(sbar_field[i] == SP_SEPARATOR)
 	{
 		pos_x = xmax + sbar_fontsize_x;
 		tmp_y = tmp_z = 0;
 		for(i = sbar_num_fields-1; i > 0; --i)
 		{
-			if(Sbar_IsFieldMasked(sbar_field[i], SBAR_DEFAULT_MASK))
-				continue;
-			if(sbar_field[i] == SBF_SEPARATOR)
+			if(sbar_field[i] == SP_SEPARATOR)
 				break;
 			
 			pos_x -= sbar_fontsize_x*sbar_size[i] + sbar_fontsize_x;
@@ -786,49 +629,33 @@
 	
 	if(teamplay)
 	{
-		for(tm = sortedTeams.sort_next; tm; tm = tm.sort_next)
+		//for(tm = sortedTeams.sort_next; tm; tm = tm.sort_next)
+		for(tm = teams.sort_next; tm; tm = tm.sort_next)
 		{
-			if(!tm.sb_player || tm.sb_team == COLOR_SPECTATOR) // no players in it?
+			if(!tm.team_size || tm.team == COLOR_SPECTATOR)
 				continue;
 
-			rgb = GetTeamRGB(tm.sb_team);
+			rgb = GetTeamRGB(tm.team);
 
 			pos_x = xmin - 4*24;
-			if(gametype == GAME_CTF)
-			{
-				if(tm.sb_team == COLOR_TEAM1)
-					Sbar_DrawXNum(pos, caps_team1, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
-				else if(tm.sb_team == COLOR_TEAM2)
-					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, tm.sb_frags, 4, 24, rgb, 1, DRAWFLAG_NORMAL);
+			// TODO: Print primary and secondary scores!
+			
 			pos_x = xmin;
 
-			// abuse specs as playerounter
-			specs = 0;
-			for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
-			{
-				if(pl.sb_team == tm.sb_team)
-					++specs;
-			}
+			specs = tm.team_size;
 
 			if(specs < 2)
 				specs = 2;
-			if(gametype == GAME_CTF && specs < 4)
-				specs = 4;
 			
 			tmp_x = sbwidth;
 			tmp_y = 1.25 * sbar_fontsize_y * specs;
 			drawfill(pos - '1 1', tmp + '2 0', rgb, 0.2, DRAWFLAG_NORMAL);
 			
-			for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
+			for(pl = players.sort_next; pl; pl = pl.sort_next)
 			{
-				if(pl.sb_team != tm.sb_team)
+				if(pl.team != tm.team)
 					continue;
-				Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), SBAR_DEFAULT_MASK);
+				Sbar_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localentnum - 1));
 				pos_y += 1.25 * sbar_fontsize_y;
 				tmp_y -= 1.25 * sbar_fontsize_y;
 			}
@@ -838,12 +665,12 @@
 		rgb = pos + '0 1.5 0' * sbar_fontsize_y;
 		pos_y += 3 * sbar_fontsize_y;
 		specs = 0;
-		for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
+		for(pl = players.sort_next; pl; pl = pl.sort_next)
 		{
-			if(pl.sb_team != COLOR_SPECTATOR)
+			if(pl.team != COLOR_SPECTATOR)
 				continue;
 			//drawcolorcodedstring(pos, getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
-			Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), SBAR_MASK_SPECTATORS);
+			Sbar_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localentnum - 1));
 			pos += '0 1.25 0' * sbar_fontsize_y;
 			++specs;
 		}
@@ -852,11 +679,11 @@
 			drawstring(rgb, "Spectators", sbar_fontsize, '1 1 1', 1, 0);
 	} else {
 		pos_x = xmin;
-		for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
+		for(pl = players.sort_next; pl; pl = pl.sort_next)
 		{
-			if(pl.sb_team == COLOR_SPECTATOR)
+			if(pl.team == COLOR_SPECTATOR)
 				continue;
-			Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), SBAR_DEFAULT_MASK);
+			Sbar_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localentnum - 1));
 			pos_y += 1.25 * sbar_fontsize_y;
 			tmp_y -= 1.25 * sbar_fontsize_y;
 		}
@@ -865,12 +692,11 @@
 		rgb = pos + '0 1.5 0' * sbar_fontsize_y;
 		pos_y += 3 * sbar_fontsize_y;
 		specs = 0;
-		for(pl = sortedPlayers.sort_next; pl; pl = pl.sort_next)
+		for(pl = players.sort_next; pl; pl = pl.sort_next)
 		{
-			if(pl.sb_team != COLOR_SPECTATOR)
+			if(pl.team != COLOR_SPECTATOR)
 				continue;
-			//drawcolorcodedstring(pos, getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
-			Sbar_PrintScoreboardItem(pos, pl, (pl.sb_player == player_localentnum - 1), SBAR_MASK_SPECTATORS);
+			Sbar_PrintScoreboardItem(pos, pl, (pl.sv_entnum == player_localentnum - 1));
 			pos += '0 1.25 0' * sbar_fontsize_y;
 			++specs;
 		}
@@ -883,7 +709,7 @@
 
 void Sbar_Score(float margin)
 {
-	float timelimit, timeleft, minutes, seconds, distribution, myplace;
+	float timelimit, timeleft, minutes, seconds, distribution, myplace, score;
 	vector sbar_save, place;
 	entity tm, pl, me;
 	sbar_save = sbar;
@@ -900,38 +726,36 @@
 		//
 		//         TEAM2
 		//for(i = 0; i < 4; ++i)
-		for(tm = sortedTeams.sort_next; tm; tm = tm.sort_next)
+		for(tm = teams.sort_next; tm; tm = tm.sort_next)
 		{
-			if(tm.sb_team == COLOR_SPECTATOR || !tm.sb_player) // no players? don't display
+			if(tm.team == COLOR_SPECTATOR || !tm.team_size) // no players? don't display
 				continue;
 			// -32*4 = -128
-			if(tm.sb_team == myteam)
-				Sbar_DrawXNum('-128 0', tm.sb_frags, 4, 32, GetTeamRGB(tm.sb_team), 1, DRAWFLAG_NORMAL);
+			score = tm.(teamscores[ts_primary]);
+			if(tm.team == myteam)
+				Sbar_DrawXNum('-128 0', score, 4, 32, GetTeamRGB(tm.team), 1, DRAWFLAG_NORMAL);
 			else
 			{
-				Sbar_DrawXNum(place, tm.sb_frags, 4, 12, GetTeamRGB(tm.sb_team), 1, DRAWFLAG_NORMAL);
+				Sbar_DrawXNum(place, score, 4, 12, GetTeamRGB(tm.team), 1, DRAWFLAG_NORMAL);
 				place_x -= 4*12;
 			}
 		}
 	} else {
 		// me vector := [team/connected frags id]
 		myplace = 0;
-		for(me = sortedPlayers.sort_next; me; me = me.sort_next)
+		for(me = players.sort_next; me; me = me.sort_next)
 		{
-			if(me.sb_team != COLOR_SPECTATOR)
+			if(me.team != COLOR_SPECTATOR)
 				++myplace;
-			if(me.sb_player == player_localentnum - 1)
+			if(me.sv_entnum == player_localentnum - 1)
 				break;
 		}
-		pl = sortedPlayers.sort_next;
+		pl = players;
 		if(pl == me)
 			pl = pl.sort_next;
 		
-		if(pl && myplace != 1)
-		{
-			distribution = me.sb_frags - pl.sb_frags;
-		} else if(pl) {
-			distribution = me.sb_frags - pl.sb_frags;
+		if(pl) {
+			distribution = me.(scores[ps_primary]) - pl.(scores[ps_primary]);
 		} else
 			distribution = 0;
 		
@@ -942,17 +766,18 @@
 		else
 			Sbar_DrawXNum('-36 -12', myplace, 3, 12, '1 0 0', 1, DRAWFLAG_NORMAL);
 
+		score = me.(scores[ps_primary]);
 		if(distribution >= 0)
 		{
 			Sbar_DrawXNum('-84 -12', distribution, 4, 12, ' 1 1 1', 1, DRAWFLAG_NORMAL);
-			Sbar_DrawXNum('-128 0', me.sb_frags, 4, 32, '1 1 1', 1, DRAWFLAG_NORMAL);
+			Sbar_DrawXNum('-128 0', score, 4, 32, '1 1 1', 1, DRAWFLAG_NORMAL);
 		} else if(distribution >= -5)
 		{
 			Sbar_DrawXNum('-84 -12', distribution, 4, 12, ' 1 1 0', 1, DRAWFLAG_NORMAL);
-			Sbar_DrawXNum('-128 0', me.sb_frags, 4, 32, '1 1 0', 1, DRAWFLAG_NORMAL);
+			Sbar_DrawXNum('-128 0', score, 4, 32, '1 1 0', 1, DRAWFLAG_NORMAL);
 		} else {
 			Sbar_DrawXNum('-84 -12', distribution, 4, 12, ' 1 0 0', 1, DRAWFLAG_NORMAL);
-			Sbar_DrawXNum('-128 0', me.sb_frags, 4, 32, '1 0 0', 1, DRAWFLAG_NORMAL);
+			Sbar_DrawXNum('-128 0', score, 4, 32, '1 0 0', 1, DRAWFLAG_NORMAL);
 		}
 	}
 	timelimit = getstatf(STAT_TIMELIMIT);
@@ -986,17 +811,18 @@
 
 void Sbar_MiniscoreItem(vector pos, entity pl, float is_self)
 {
-	float x;
+	float x, score;
 	pos_x += 72;
 	
 	if(teamplay)
-		drawfill(pos + '0 1 0', '40 6 0', GetTeamRGB(pl.sb_team)*0.5, 1, DRAWFLAG_NORMAL);
+		drawfill(pos + '0 1 0', '40 6 0', GetTeamRGB(pl.team)*0.5, 1, DRAWFLAG_NORMAL);
 	else
 		drawfill(pos + '0 1 0', '40 6 0', '0.5 0.5 0.5', 0.5, DRAWFLAG_NORMAL);
 	x = pos_x;
 	pos_x += 5*8;
-	pos_x -= stringwidth(ftos(pl.sb_frags), FALSE)*8;
-	drawstring(pos, ftos(pl.sb_frags), '8 8 0', '1 1 1', 1, DRAWFLAG_NORMAL);
+	score = pl.(scores[ps_primary]);
+	pos_x -= stringwidth(ftos(score), FALSE)*8;
+	drawstring(pos, ftos(score), '8 8 0', '1 1 1', 1, DRAWFLAG_NORMAL);
 	pos_x = x;
 	if(is_self)
 	{
@@ -1005,7 +831,7 @@
 		pos_x += 8;
 	} else
 		pos_x += 56;
-	drawcolorcodedstring(pos, getplayerkey(pl.sb_player, "name"), '8 8 0', 1, 0);
+	drawcolorcodedstring(pos, getplayerkey(pl.sv_entnum, "name"), '8 8 0', 1, 0);
 }
 
 void Sbar_MiniscoreTeamItem(vector pos, float color, float frags, float is_self)
@@ -1034,7 +860,7 @@
 
 void Sbar_MiniDeathmatchOverlay(vector pos)
 {
-	float numlines, up, down;
+	float numlines, up, down, score;
 	entity me, tm, pl;
 	float miniscoreboard_size;
 	miniscoreboard_size = cvar("sbar_miniscoreboard_size");
@@ -1053,9 +879,9 @@
 		return;
 
 	// me vector := [team/connected frags id]
-	for(me = sortedPlayers.sort_next; me; me = me.sort_next)
+	for(me = players.sort_next; me; me = me.sort_next)
 	{
-		if(me.sb_player == player_localentnum - 1)
+		if(me.sv_entnum == player_localentnum - 1)
 			break;
 	}
 
@@ -1071,7 +897,7 @@
 	// render bottom-up
 	for(pl = me.sort_next; pl && down > 0; pl = pl.sort_next)
 	{
-		if(pl.sb_team == COLOR_SPECTATOR)
+		if(pl.team == COLOR_SPECTATOR)
 			continue;
 		Sbar_MiniscoreItem(pos, pl, false);
 		pos_y -= 9;
@@ -1080,9 +906,9 @@
 	Sbar_MiniscoreItem(pos, me, true);
 	pos_y -= 9;
 	up += down; // if there weren't enough lines below... add them
-	for(pl = me.sort_prev; pl != sortedPlayers && up > 0; pl = pl.sort_prev)
+	for(pl = me.sort_prev; pl && up > 0; pl = pl.sort_prev)
 	{
-		if(pl.sb_team == COLOR_SPECTATOR)
+		if(pl.team == COLOR_SPECTATOR)
 			continue;
 		Sbar_MiniscoreItem(pos, pl, false);
 		pos_y -= 9;
@@ -1091,12 +917,13 @@
 
 	if(teamplay)
 	{
-		for(tm = sortedTeams.sort_next; tm.sort_next; tm = tm.sort_next);
-		for(; tm != sortedTeams; tm = tm.sort_prev)
+		for(tm = teams.sort_next; tm.sort_next; tm = tm.sort_next);
+		for(; tm; tm = tm.sort_prev)
 		{
-			if(!tm.sb_player || tm.sb_team == COLOR_SPECTATOR) // no players?
+			if(!tm.team_size || tm.team == COLOR_SPECTATOR)
 				continue;
-			Sbar_MiniscoreTeamItem(pos, tm.sb_team, tm.sb_frags, (tm.sb_team == me.sb_team));
+			score = tm.(teamscores[ts_primary]);
+			Sbar_MiniscoreTeamItem(pos, tm.team, score, (tm.team == me.team));
 			pos_y -= 9;
 		}
 	}
@@ -1108,7 +935,8 @@
 	float x, fade;
 	float stat_items;
 
-	Sbar_SortFrags();
+	//Sbar_SortFrags();
+	Sbar_UpdatePlayerTeams();
 
 	sb_lines = 24;
 	

Modified: trunk/data/qcsrc/client/sortlist.qc
===================================================================
--- trunk/data/qcsrc/client/sortlist.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/sortlist.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -1,6 +1,15 @@
 .float(entity,entity) sort_cmp;
 .entity sort_next, sort_prev;
 
+entity Sort_Spawn()
+{
+	entity sort;
+	sort = spawn();
+	sort.sort_next = NULL;
+	sort.chain = sort;
+	return sort;
+}
+
 entity Sort_New(float(entity,entity) cmp)
 {
 	entity sort;
@@ -88,12 +97,17 @@
 	return sort;
 }
 
-#define SORT_SWAP(a,b) \
-	b.sort_prev = a.sort_prev;			\
-	a.sort_next = b.sort_next;			\
+/**
+ * Swap two neighbours in a sortlist.
+ * @param a FIRST entity
+ * @param b entity after a
+ */
+#define SORT_SWAP(a,b)									\
+	b.sort_prev = a.sort_prev;							\
+	a.sort_next = b.sort_next;							\
 	if(b.sort_next) b.sort_next.sort_prev = a;			\
-	a.sort_prev.sort_next = b;			\
-	a.sort_prev = b;				\
+	if(a.sort_prev) a.sort_prev.sort_next = b;			\
+	a.sort_prev = b;									\
 	b.sort_next = a
 
 void Sort_Erase(entity ent)

Modified: trunk/data/qcsrc/client/teamplay.qc
===================================================================
--- trunk/data/qcsrc/client/teamplay.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/client/teamplay.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -16,6 +16,8 @@
 
 float GetPlayerColor(float i)
 {
+	if(getplayerkey(i, "frags") == "-666")
+		return COLOR_SPECTATOR;
 	return stof(getplayerkey(i, "colors")) & 15;
 }
 

Modified: trunk/data/qcsrc/common/constants.qh
===================================================================
--- trunk/data/qcsrc/common/constants.qh	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/common/constants.qh	2008-07-24 18:48:31 UTC (rev 3903)
@@ -169,6 +169,7 @@
 const float ENTCS_MSG_END = 0;
 const float ENTCS_MSG_ONS_GPS = 1;
 const float ENTCS_MSG_ONS_REMOVE = 2;
+const float ENTCS_MSG_INIT = 3;
 
 const float TE_CSQC_INIT = 100;
 const float TE_CSQC_PING = 101;
@@ -192,3 +193,41 @@
 const float MAPVOTE_NET_UPDATE = 1;
 const float MAPVOTE_NET_PIC = 2;
 const float MAPVOTE_NET_OWNVOTE = 3;
+
+/**
+ * Lower scores are better (e.g. deaths)
+ */
+#define SFL_DECREASING         1
+
+/**
+ * Scoring priority (NOTE: PRIMARY is used for fraglimit)
+ */
+#define SFL_SORT_PRIO_LOW      2
+#define SFL_SORT_PRIO_MED      4
+#define SFL_SORT_PRIO_HIGH     8
+#define SFL_SORT_PRIO_PRIMARY 14
+#define SFL_SORT_PRIO_MASK    14
+
+/**
+ * Score indices
+ */
+#define MAX_SCORE 10
+#define MAX_TEAMSCORE 2
+
+#define SP_KILLS 0
+#define SP_DEATHS 1
+#define SP_SUICIDES 2
+#define SP_SCORE 3 // personal score, game modes can set it their own way
+#define ST_SCORE 0
+
+#define SP_CTF_CAPS 4
+#define SP_CTF_RETURNS 5
+#define ST_CTF_CAPS 1
+
+#define SP_KH_COLLECT 4
+#define SP_KH_LOSEKEY 5
+#define SP_KH_CAPS 6
+#define SP_KH_PUSH 7
+#define SP_KH_DESTROYED 8
+#define SP_KH_KCFRAG 9
+#define ST_KH_CAPS 1

Modified: trunk/data/qcsrc/server/cl_weapons.qc
===================================================================
--- trunk/data/qcsrc/server/cl_weapons.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/server/cl_weapons.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -35,6 +35,7 @@
 	if(weaponid == WEP_HAGAR)             return "Hagar";
 	if(weaponid == WEP_ROCKET_LAUNCHER)   return "Rocket Launcher";
 	if(weaponid == WEP_CRYLINK)           return "Crylink";
+	if(weaponid == WEP_ANTINEX)	      return "Antinex";
 	return "@!#%'n Tuba";
 }
 
@@ -67,6 +68,7 @@
 		case WEP_NEX:              return IT_CELLS;
 		case WEP_HAGAR:            return IT_ROCKETS;
 		case WEP_ROCKET_LAUNCHER:  return IT_ROCKETS;
+		case WEP_ANTINEX:	   return IT_ROCKETS;
 		default:                   return 0;
 	}
 }

Modified: trunk/data/qcsrc/server/defs.qh
===================================================================
--- trunk/data/qcsrc/server/defs.qh	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/server/defs.qh	2008-07-24 18:48:31 UTC (rev 3903)
@@ -208,11 +208,11 @@
 float WEP_NEX				= 7; // float	IT_NEX					= 32;
 float WEP_HAGAR				= 8; // float	IT_HAGAR				= 64;
 float WEP_ROCKET_LAUNCHER	= 9; // float	IT_ROCKET_LAUNCHER		= 128;
-
+float WEP_ANTINEX			= 10;
 // For weapon cycling commands
 float WEP_FIRST				= 1;
-float WEP_LAST				= 9;
-float WEP_COUNT             = 10;
+float WEP_LAST				= 10;
+float WEP_COUNT             = 11;
 
 void(entity client, string s) centerprint_builtin = #73;
 .vector dest1, dest2;
@@ -442,6 +442,9 @@
 
 float next_pingtime;
 
+.float Version;
+.float(entity to) SendEntity;
+
 .float captures;
 .float returns;
 float caps_team1, caps_team2;

Modified: trunk/data/qcsrc/server/ent_cs.qc
===================================================================
--- trunk/data/qcsrc/server/ent_cs.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/server/ent_cs.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -13,9 +13,6 @@
 // it did when I added this) But you have to use .Version
 // Capital V
 
-.float(entity to) SendEntity;
-.float Version;
-
 entity entcs_start;
 
 void entcs_init()
@@ -26,7 +23,7 @@
 	entcs_start.chain = world;
 };
 
-entity get_entcs_ent(float num)
+entity get_entcs_ent()
 {
 	entity entcs;
 	entcs = spawn();
@@ -104,7 +101,7 @@
 	print("Attaching ENTCS entity\n");
 
 	num = num_for_edict(self);
-	ent = get_entcs_ent(num);
+	ent = get_entcs_ent();
 
 	ent.classname = "entcs_sender";
 	ent.health = num;

Modified: trunk/data/qcsrc/server/g_damage.qc
===================================================================
--- trunk/data/qcsrc/server/g_damage.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/server/g_damage.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -193,6 +193,7 @@
 				if(deathtype != DEATH_TEAMCHANGE)
 				{
 					LogDeath("suicide", deathtype, targ, targ);
+					PlayerScore_Add(attacker, SP_SUICIDES, 1);
 					GiveFrags(attacker, targ, -1);
 				}
 				if (targ.killcount > 2)
@@ -224,6 +225,7 @@
 				if(deathtype != DEATH_TEAMCHANGE)
 				{
 					LogDeath("suicide", deathtype, targ, targ);
+					PlayerScore_Add(attacker, SP_SUICIDES, 1);
 					GiveFrags(attacker, targ, -1);
 				}
 				if (targ.killcount > 2)
@@ -242,6 +244,7 @@
 					bprint ("^1", a, "^1 mows down a teammate\n");
 				}
 				GiveFrags(attacker, targ, -1);
+				PlayerScore_Add(attacker, -1); // teamkills DO cound as -1 kill right?
 				if (targ.killcount > 2) {
 					if(sv_gentle)
 						bprint ("^1",s,"'s ^1",ftos(targ.killcount)," scoring spree was ended by a teammate!\n");
@@ -444,6 +447,7 @@
 				else
 					bprint ("^1",s, "^1 died\n");
 			GiveFrags(targ, targ, -1);
+			PlayerScore_Add(targ, SP_DEATHS, 1);
 			if(targ.frags == -5) {
 				announce(targ, "announcer/male/botlike.ogg");
 			}

Modified: trunk/data/qcsrc/server/keyhunt.qc
===================================================================
--- trunk/data/qcsrc/server/keyhunt.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/server/keyhunt.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -473,7 +473,8 @@
 		while((key = player.kh_next))
 		{
 			kh_Scores_Event(player, key, "losekey", 0, 0);
-			PlayerScore_Add(player, SP_KH_LOSEKEY, 1);
+			if(PlayerScore_IsValid(player))
+				PlayerScore_Add(player, SP_KH_LOSEKEY, 1);
 			bprint(player.netname, "^7 died and lost the ", key.netname, "\n");
 			kh_Key_AssignTo(key, world);
 			makevectors('-1 0 0' * (45 + 45 * random()) + '0 360 0' * random());

Modified: trunk/data/qcsrc/server/scores.qc
===================================================================
--- trunk/data/qcsrc/server/scores.qc	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/server/scores.qc	2008-07-24 18:48:31 UTC (rev 3903)
@@ -12,8 +12,12 @@
 var .float teamscores_primary;
 float scores_initialized;
 
-.float Version;
-.float(entity to) SendEntity;
+void Net_LinkEntity(entity e)
+{
+	e.model = "net_entity";
+	e.modelindex = 1;
+	e.effects = EF_NODEPTHTEST | EF_LOWPRECISION;
+}
 
 vector ScoreField_Compare(entity t1, entity t2, .float field, float fieldflags, vector previous) // returns: cmp value, best prio
 {
@@ -38,7 +42,7 @@
  * teamscore entities
  */
 
-void TeamScore_SendEntity(entity to)
+float TeamScore_SendEntity(entity to)
 {
 	float i;
 
@@ -46,6 +50,8 @@
 	WriteByte(MSG_ENTITY, self.team);
 	for(i = 0; i < MAX_TEAMSCORE; ++i)
 		WriteShort(MSG_ENTITY, self.teamscores[i]);
+
+	return TRUE;
 }
 
 void TeamScore_Spawn(float t, string name)
@@ -57,6 +63,7 @@
 	ts.netname = name; // not used yet, FIXME
 	ts.Version = 1; // immediately send, so csqc knows about the team
 	ts.team = t;
+	Net_LinkEntity(ts);
 	teamscorekeepers[t] = ts;
 	++teamscores_entities_count;
 }
@@ -103,7 +110,7 @@
 		teamscores_primary = teamscores[i];
 }
 
-void ScoreInfo_SendEntity(entity to)
+float ScoreInfo_SendEntity(entity to)
 {
 	WriteByte(MSG_ENTITY, ENT_CLIENT_SCORES_INFO);
 	float i;
@@ -117,6 +124,7 @@
 		WriteString(MSG_ENTITY, teamscores_label[i]);
 		WriteByte(MSG_ENTITY, teamscores_flags[i]);
 	}
+	return TRUE;
 }
 
 void ScoreInfo_Init(float teams)
@@ -132,6 +140,7 @@
 		TeamScore_Spawn(COLOR_TEAM4, "Pink");
 	entity si;
 	si = spawn();
+	Net_LinkEntity(si);
 	si.classname = "csqc_score_info";
 	si.SendEntity = ScoreInfo_SendEntity;
 	si.Version = 1;
@@ -141,7 +150,7 @@
  * per-player score entities
  */
 
-void PlayerScore_SendEntity()
+float PlayerScore_SendEntity()
 {
 	float i;
 
@@ -149,6 +158,8 @@
 	WriteByte(MSG_ENTITY, num_for_edict(self.owner));
 	for(i = 0; i < MAX_SCORE; ++i)
 		WriteShort(MSG_ENTITY, self.scores[i]);
+
+	return TRUE;
 }
 
 void PlayerScore_Clear(entity player)
@@ -189,6 +200,14 @@
 	}
 }
 
+float PlayerScore_IsValid(entity player)
+{
+	if(!player.scorekeeper)
+		return FALSE;
+
+	return TRUE;
+}
+
 void PlayerScore_Attach(entity player)
 {
 	entity sk;
@@ -196,7 +215,9 @@
 		error("player already has a scorekeeper");
 	sk = spawn();
 	sk.owner = player;
+	sk.Version = 1;
 	sk.SendEntity = PlayerScore_SendEntity;
+	Net_LinkEntity(sk);
 	player.scorekeeper = sk;
 }
 

Modified: trunk/data/qcsrc/server/scores.qh
===================================================================
--- trunk/data/qcsrc/server/scores.qh	2008-07-24 14:05:46 UTC (rev 3902)
+++ trunk/data/qcsrc/server/scores.qh	2008-07-24 18:48:31 UTC (rev 3903)
@@ -1,6 +1,3 @@
-#define MAX_SCORE 10
-#define MAX_TEAMSCORE 2
-
 /**
  * Attaches a PlayerScore entity to a player. Use that in ClientConnect.
  * Remember to detach it in ClientDisconnect!
@@ -20,6 +17,15 @@
 void PlayerScore_Add(entity player, float scorefield, float score);
 
 /**
+ * Check if the player can have scores.
+ * This is needed for example in keyhunt, when the carrier disconnects.
+ * The key-losing happens too late... which should probably be fixed
+ * but I'm just not in the mood to do that now as I'm busy making the
+ * csqc part work <.<
+ */
+float PlayerScore_IsValid(entity player);
+
+/**
  * Initialize the score of this player if needed.
  * Does nothing in teamplay.
  * Use that when a spectator becomes a player.
@@ -69,20 +75,6 @@
 void Score_DebugPrint();
 
 /**
- * Lower scores are better (e.g. deaths)
- */
-#define SFL_DECREASING         1
-
-/**
- * Scoring priority (NOTE: PRIMARY is used for fraglimit)
- */
-#define SFL_SORT_PRIO_LOW      2
-#define SFL_SORT_PRIO_MED      4
-#define SFL_SORT_PRIO_HIGH     8
-#define SFL_SORT_PRIO_PRIMARY 14
-#define SFL_SORT_PRIO_MASK    14
-
-/**
  * Sets the following results for the current scores entities.
  */
 void WinningConditionHelper();
@@ -90,21 +82,3 @@
 float WinningConditionHelper_equality;   ///< 1 if and only if the top two have equal scores
 float WinningConditionHelper_winnerteam; ///< the color of the winning team, or -1 if none
 entity WinningConditionHelper_winner;    ///< the winning player, or world if none
-
-#define SP_KILLS 0
-#define SP_DEATHS 1
-#define SP_SUICIDES 2
-#define SP_SCORE 3 // personal score, game modes can set it their own way
-#define ST_SCORE 0
-
-#define SP_CTF_CAPS 4
-#define SP_CTF_RETURNS 5
-#define ST_CTF_CAPS 1
-
-#define SP_KH_COLLECT 4
-#define SP_KH_LOSEKEY 5
-#define SP_KH_CAPS 6
-#define SP_KH_PUSH 7
-#define SP_KH_DESTROYED 8
-#define SP_KH_KCFRAG 9
-#define ST_KH_CAPS 1




More information about the nexuiz-commits mailing list