r4086 - in trunk/data: . qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sun Aug 10 06:07:09 EDT 2008


Author: div0
Date: 2008-08-10 06:07:06 -0400 (Sun, 10 Aug 2008)
New Revision: 4086

Modified:
   trunk/data/defaultNexuiz.cfg
   trunk/data/qcsrc/server/arena.qc
   trunk/data/qcsrc/server/cl_client.qc
   trunk/data/qcsrc/server/cl_weaponsystem.qc
   trunk/data/qcsrc/server/defs.qh
   trunk/data/qcsrc/server/g_subs.qc
   trunk/data/qcsrc/server/havocbot.qc
   trunk/data/qcsrc/server/miscfunctions.qc
   trunk/data/qcsrc/server/race.qc
   trunk/data/qcsrc/server/race.qh
   trunk/data/qcsrc/server/scores.qc
   trunk/data/qcsrc/server/scores.qh
   trunk/data/qcsrc/server/scores_rules.qc
Log:
race: "g_race_qualifying 2" makes qualifying-then-race mode (using new special entities). Race still displays stuff wrong, though - it shows lap times, it SHOULD show times to the next enemy in race (not qualifying) mode.


Modified: trunk/data/defaultNexuiz.cfg
===================================================================
--- trunk/data/defaultNexuiz.cfg	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/defaultNexuiz.cfg	2008-08-10 10:07:06 UTC (rev 4086)
@@ -486,9 +486,11 @@
 
 // race
 set g_race 0
-set g_race_qualifying 0
+set g_race_qualifying 1
 // Qualifying uses timelimit, and the one with the best time wins. Fraglimit is nonfunctional then.
 // Normal race uses fraglimit as a limit for the laps.
+// Special mode: g_race_qualifying 2. First runs a qualifying, after
+// ready-restart it turns into a race. TODO not done yet (e.g. timing display)
 set g_race_teams 0 // when 2, 3, or 4, the race is played as a team game (the team members can add up their laps)
 
 // server game balance settings

Modified: trunk/data/qcsrc/server/arena.qc
===================================================================
--- trunk/data/qcsrc/server/arena.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/arena.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -28,10 +28,12 @@
 	if(g_arena)
 	if(cvar("g_arena_warmup"))
 		warmup = time + cvar("g_arena_warmup");
-	
+
 	lms_lowest_lives = 999;
 	lms_next_place = player_count;
 
+	race_ReadyRestart();
+	
 	self = nextent(world);
 	while(self)
 	{
@@ -108,8 +110,6 @@
 	FOR_EACH_CLIENT(self) {
 		if(self.flags & FL_CLIENT)				// reset all players
 		{
-			if(g_race)
-				race_PreparePlayer();
 			if(g_arena)
 			{
 				if(self.spawned)

Modified: trunk/data/qcsrc/server/cl_client.qc
===================================================================
--- trunk/data/qcsrc/server/cl_client.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/cl_client.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -50,29 +50,39 @@
 	// filter out spots for assault
 	if(spot.target != "") {
 		local entity ent;
+		float good;
 		ent = find(world, targetname, spot.target);
-		if(!ent)
-		{
-			return -1;
-		}
 		while(ent) {
 			if(ent.classname == "target_objective")
 			{
 				if(ent.health < 0 || ent.health >= ASSAULT_VALUE_INACTIVE)
 					return -1;
+				good = 1;
 			}
 			else if(ent.classname == "trigger_race_checkpoint")
 			{
 				if(self.classname == "player") // spectators may spawn everywhere
-				if(ent.cnt != race_PreviousCheckpoint(self.race_checkpoint))
-					// checkpoint -1 players (freshly spawned) spawn close to finish!
-					return -1;
+				{
+					if(ent.race_checkpoint != race_PreviousCheckpoint(self.race_checkpoint))
+						return -1;
+					print(ftos(race_place_valid), ": ");
+					print(ftos(self.race_place), " <-> ");
+					print(ftos(spot.race_place), "\n");
+					if(race_place_valid && (spot.race_place != self.race_place))
+						return -1;
+					if(!race_place_valid && (spot.race_place != 0))
+						return -1;
+				}
+				good = 1;
 			}
 			else
 			{
 			}
 			ent = find(ent, targetname, spot.target);
 		}
+
+		if(!good)
+			return -1;
 	}
 
 	player = playerlist;
@@ -374,6 +384,9 @@
 void PutObserverInServer (void)
 {
 	entity	spot;
+
+	race_PreSpawnObserver();
+
 	spot = SelectSpawnPoint (TRUE);
 	if(!spot)
 		error("No spawnpoints for observers?!?\n");
@@ -464,9 +477,6 @@
 	self.viewzoom = 1;
 	self.wantswelcomemessage = 1;
 
-	if(g_race)
-		race_PreparePlayer();
-
 	if(g_arena)
 	{
 		if(self.version_mismatch)
@@ -590,9 +600,7 @@
 	if(self.classname == "player") {
 		entity	spot;
 
-		if(g_race)
-			if(self.killcount == -666)
-				race_PreparePlayer();
+		race_PreSpawn();
 
 		spot = SelectSpawnPoint (FALSE);
 		if(!spot)
@@ -703,16 +711,6 @@
 		self.statdraintime = time + 5;
 		self.BUTTON_ATCK = self.BUTTON_JUMP = self.BUTTON_ATCK2 = 0;
 
-		if(g_race)
-			if(self.killcount != -666)
-			{
-				if(spot.target == "")
-					// let the player run without timing, if he did not spawn at a targetting spawnpoint
-					race_PreparePlayer();
-				else
-					race_RetractPlayer();
-			}
-
 		if(self.killcount == -666) {
 			PlayerScore_Clear(self);
 			self.killcount = 0;
@@ -731,6 +729,8 @@
 		self.lms_traveled_distance = 0;
 		self.speedrunning = FALSE;
 
+		race_PostSpawn(spot);
+
 		if(cvar("spawn_debug"))
 		{
 			sprint(self, strcat("spawnpoint origin:  ", vtos(spot.origin), "\n"));
@@ -1061,6 +1061,8 @@
 
 	bot_clientconnect();
 
+	race_PreSpawnObserver();
+
 	//if(g_domination)
 	//	dom_player_join_team(self);
 
@@ -2195,6 +2197,8 @@
 =============
 */
 .float idlekick_lasttimeleft;
+.float race_penalty;
+.float race_penalty_nagged;
 void PlayerPostThink (void)
 {
 	// Savage: Check for nameless players
@@ -2246,12 +2250,35 @@
 			if(time < restart_countdown) {
 				if (!cvar("sv_ready_restart_after_countdown"))
 				{
+					if(self.movement != '0 0 0' && g_race && !g_race_qualifying)
+					{
+						if(time < restart_countdown - 2)
+						{
+							if(!self.race_penalty_nagged)
+							{
+								centerprint_atprio(self, CENTERPRIO_IDLEKICK, "^1DO NOT MOVE DURING THE COUNTDOWN.");
+								self.race_penalty_nagged = 1;
+							}
+						}
+						else if(!self.race_penalty)
+						{
+							centerprint_atprio(self, CENTERPRIO_IDLEKICK, "^1FIVE SECONDS PENALTY.");
+							self.race_penalty = time + 5;
+						}
+					}
 					self.movetype = MOVETYPE_NONE;		
 					self.velocity = '0 0 0';
 					self.avelocity = '0 0 0';
 					self.movement = '0 0 0';
 				}
 			}
+			else if (time < self.race_penalty)
+			{
+				self.movetype = MOVETYPE_NONE;		
+				self.velocity = '0 0 0';
+				self.avelocity = '0 0 0';
+				self.movement = '0 0 0';
+			}
 			else
 			{
 				//allow the player to move again if sv_ready_restart_after_countdown is not used and countdown is over
@@ -2261,6 +2288,8 @@
 					{
 						self.movetype = MOVETYPE_WALK;
 					}
+					self.race_penalty = 0;
+					self.race_penalty_nagged = 0;
 				}
 			}
 		}

Modified: trunk/data/qcsrc/server/cl_weaponsystem.qc
===================================================================
--- trunk/data/qcsrc/server/cl_weaponsystem.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/cl_weaponsystem.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -422,12 +422,13 @@
 };
 
 // perform weapon to attack (weaponstate and attack_finished check is here)
+.float race_penalty;
 float weapon_prepareattack(float secondary, float attacktime)
 {
 	//if sv_ready_restart_after_countdown is set, don't allow the player to shoot
 	//if all players readied up and the countdown is running
 	if (cvar("sv_ready_restart_after_countdown"))
-		if(time < restart_countdown) {
+		if(time < restart_countdown || time < self.race_penalty) {
 			return FALSE;
 		}
 	

Modified: trunk/data/qcsrc/server/defs.qh
===================================================================
--- trunk/data/qcsrc/server/defs.qh	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/defs.qh	2008-08-10 10:07:06 UTC (rev 4086)
@@ -19,6 +19,7 @@
 float g_cloaked, g_footsteps, g_jump_grunt, g_grappling_hook, g_instagib, g_laserguided_missile, g_midair, g_minstagib, g_nixnex, g_nixnex_with_laser, g_norecoil, g_rocketarena, g_vampire, g_minstagib_invis_alpha;
 float g_tourney;
 float g_ctf_win_mode;
+float g_race_qualifying;
 float tourneyInMatchStage;
 
 float sv_cheats;

Modified: trunk/data/qcsrc/server/g_subs.qc
===================================================================
--- trunk/data/qcsrc/server/g_subs.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/g_subs.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -386,6 +386,7 @@
 		// force relinking
 		setorigin(self, self.origin);
 		setsize (self, self.mins, self.maxs);
+		print("size: ", vtos(self.maxs), "\n");
 	}
 	self.movetype = MOVETYPE_NONE;
 	self.modelindex = 0;

Modified: trunk/data/qcsrc/server/havocbot.qc
===================================================================
--- trunk/data/qcsrc/server/havocbot.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/havocbot.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -258,7 +258,7 @@
 	local entity head, best;
 	local float rating, bestrating;
 	local vector eye, v;
-	if (cvar("bot_nofire"))
+	if (cvar("bot_nofire") || independent_players)
 	{
 		self.enemy = world;
 		return;
@@ -457,7 +457,7 @@
 	if (self.bot_aimtarg)
 	{
 		weapon_action(self.weapon, WR_AIM);
-		if (cvar("bot_nofire"))
+		if (cvar("bot_nofire") || independent_players)
 		{
 			self.BUTTON_ATCK = FALSE;
 			self.BUTTON_ATCK2 = FALSE;

Modified: trunk/data/qcsrc/server/miscfunctions.qc
===================================================================
--- trunk/data/qcsrc/server/miscfunctions.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/miscfunctions.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -260,6 +260,18 @@
 	if(g_ctf || g_assault || g_onslaught || g_domination)
 	if(self.team)
 		have_team_spawns = 1;
+
+	if(cvar("r_showbboxes"))
+	{
+		// show where spawnpoints point at too
+		makevectors(self.angles);
+		entity e;
+		e = spawn();
+		e.classname = "info_player_foo";
+		setorigin(e, self.origin + v_forward * 24);
+		setsize(e, '-8 -8 -8', '8 8 8');
+		e.solid = SOLID_TRIGGER;
+	}
 }
 
 #define strstr strstrofs
@@ -719,6 +731,7 @@
 	sv_pogostick = cvar("sv_pogostick");
 	sv_doublejump = cvar("sv_doublejump");
 	g_ctf_win_mode = cvar("g_ctf_win_mode");
+	g_race_qualifying = cvar("g_race_qualifying");
 
 	g_pickup_shells                    = cvar("g_pickup_shells");
 	g_pickup_shells_max                = cvar("g_pickup_shells_max");

Modified: trunk/data/qcsrc/server/race.qc
===================================================================
--- trunk/data/qcsrc/server/race.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/race.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -1,3 +1,5 @@
+#define MAX_CHECKPOINTS 255
+
 .float race_checkpoint; // player: next checkpoint that has to be reached
 .float race_laptime;
 
@@ -3,8 +5,9 @@
 .entity sprite;
 
-float race_checkpoint_records[256];
-string race_checkpoint_recordholders[256];
+float race_checkpoint_records[MAX_CHECKPOINTS];
+string race_checkpoint_recordholders[MAX_CHECKPOINTS];
 
 float race_highest_checkpoint;
+float race_highest_place_spawn;
 
 float race_NextCheckpoint(float f)
@@ -165,18 +168,18 @@
 	if(other.classname != "player")
 		return;
 
-	if(other.race_checkpoint == -1 || other.race_checkpoint == self.cnt)
+	if(other.race_checkpoint == -1 || other.race_checkpoint == self.race_checkpoint)
 	{
-		other.race_checkpoint = race_NextCheckpoint(self.cnt);
+		other.race_checkpoint = race_NextCheckpoint(self.race_checkpoint);
 
-		race_SendTime(other, self.cnt, time - other.race_laptime, !!other.race_laptime);
+		race_SendTime(other, self.race_checkpoint, time - other.race_laptime, !!other.race_laptime);
 
-		if(!self.cnt) // finish line
+		if(!self.race_checkpoint) // finish line
 			other.race_laptime = time;
 
 		race_SendNextCheckpoint(other);
 	}
-	else if(other.race_checkpoint == race_NextCheckpoint(self.cnt))
+	else if(other.race_checkpoint == race_NextCheckpoint(self.race_checkpoint))
 	{
 		// ignored
 	}
@@ -197,7 +200,7 @@
 {
 	if(e.race_checkpoint == -1)
 		return self.modelindex;
-	else if(e.race_checkpoint == self.owner.cnt)
+	else if(e.race_checkpoint == self.owner.race_checkpoint)
 		return self.modelindex;
 	else
 		return FALSE;
@@ -223,11 +226,13 @@
 
 	if(!self.message)
 		self.message = "went backwards";
+	
+	self.race_checkpoint = self.cnt;
 
-	if(self.cnt > race_highest_checkpoint)
-		race_highest_checkpoint = self.cnt;
+	if(self.race_checkpoint > race_highest_checkpoint)
+		race_highest_checkpoint = self.race_checkpoint;
 
-	if(self.cnt)
+	if(self.race_checkpoint)
 	{
 		precache_model("models/sprites/race-checkpoint.sp2");
 		WaypointSprite_SpawnFixed("race-checkpoint", o, self, sprite);
@@ -242,9 +247,8 @@
 
 void race_PreparePlayer()
 {
-	if(!g_race)
-		return;
 	race_ClearTime(self);
+	self.race_place = 0;
 }
 
 void race_RetractPlayer()
@@ -253,9 +257,46 @@
 		return;
 	self.race_checkpoint = race_PreviousCheckpoint(self.race_checkpoint);
 	if(self.race_checkpoint == 0)
+	{
 		race_ClearTime(self);
+		self.race_checkpoint = 0;
+	}
 }
 
+void race_PreSpawn()
+{
+	if(!g_race)
+		return;
+	if(self.killcount == -666 || g_race_qualifying)
+		race_PreparePlayer();
+}
+
+void race_PostSpawn(entity spot)
+{
+	if(!g_race)
+		return;
+	if(self.killcount != -666 && !g_race_qualifying)
+	{
+		if(spot.target == "")
+			// let the player run without timing, if he did not spawn at a targetting spawnpoint
+			race_PreparePlayer();
+		else
+			race_RetractPlayer();
+	}
+
+	if(spot.target != "" && self.race_checkpoint == -1)
+		self.race_checkpoint = 0;
+
+	self.race_place = 0;
+}
+
+void race_PreSpawnObserver()
+{
+	if(!g_race)
+		return;
+	race_PreparePlayer();
+}
+
 void spawnfunc_info_player_race (void)
 {
 	if(!g_race)
@@ -265,4 +306,42 @@
 	}
 	++race_spawns;
 	spawnfunc_info_player_deathmatch();
+
+	if(self.race_place > race_highest_place_spawn)
+		race_highest_place_spawn = self.race_place;
 }
+
+void race_ClearRecords()
+{
+	float i;
+	entity e;
+
+	for(i = 0; i < MAX_CHECKPOINTS; ++i)
+	{
+		race_checkpoint_records[i] = 0;
+		if(race_checkpoint_recordholders[i])
+			strunzone(race_checkpoint_recordholders[i]);
+		race_checkpoint_recordholders[i] = string_null;
+	}
+
+	FOR_EACH_CLIENT(e)
+		race_ClearTime(e);
+}
+
+void race_ReadyRestart()
+{
+	race_ClearRecords();
+
+	if(g_race_qualifying == 2)
+	{
+		g_race_qualifying = 0;
+		independent_players = 0;
+		ScoreRules_race();
+	}
+
+	if(PlayerScore_Sort(race_place) <= race_highest_place_spawn)
+		race_place_valid = 1;
+	else
+		race_place_valid = 0;
+	print("VALID: ", ftos(race_place_valid), "\n");
+}

Modified: trunk/data/qcsrc/server/race.qh
===================================================================
--- trunk/data/qcsrc/server/race.qh	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/race.qh	2008-08-10 10:07:06 UTC (rev 4086)
@@ -1,6 +1,10 @@
-void race_PreparePlayer();
-void race_RetractPlayer(); // go back by one checkpoint
+void race_PreSpawnObserver();
+void race_PreSpawn();
+void race_PostSpawn(entity spot);
+void race_ReadyRestart();
 float race_teams;
 float race_spawns;
 float race_PreviousCheckpoint(float f);
 float race_NextCheckpoint(float f);
+float race_place_valid;
+.float race_place;

Modified: trunk/data/qcsrc/server/scores.qc
===================================================================
--- trunk/data/qcsrc/server/scores.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/scores.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -564,3 +564,61 @@
 	}
 	return out;
 }
+
+float PlayerTeamScore_Compare(entity p1, entity p2)
+{
+	if(teamscores_entities_count)
+		if(p1.team != p2.team)
+		{
+			entity t1, t2;
+			t1 = teamscorekeepers[p1.team];
+			t2 = teamscorekeepers[p2.team];
+			return TeamScore_Compare(t1, t2);
+		}
+	
+	return PlayerScore_Compare(p1.scorekeeper, p2.scorekeeper);
+}
+
+float PlayerScore_Sort(.float field)
+{
+	entity p, plist, pprev, pbest, pbestprev;
+	float i;
+	plist = world;
+
+	FOR_EACH_CLIENT(p)
+		p.field = 0;
+
+	FOR_EACH_PLAYER(p) if(p.scorekeeper)
+	{
+		p.chain = plist;
+		plist = p;
+	}
+	// Now plist points to the whole list.
+
+	i = 0;
+	while(plist)
+	{
+		pprev = pbestprev = world;
+		pbest = plist;
+		for(p = plist; (p = p.chain); )
+		{
+			if(PlayerTeamScore_Compare(p, pbest) > 0)
+			{
+				pbest = p;
+				pbestprev = pprev;
+			}
+			pprev = p;
+		}
+
+		// remove pbest out of the chain
+		if(pbestprev == world)
+			plist = pbest.chain;
+		else
+			pbestprev.chain = pbest.chain;
+		pbest.chain = world;
+
+		pbest.field = ++i;
+	}
+
+	return i;
+}

Modified: trunk/data/qcsrc/server/scores.qh
===================================================================
--- trunk/data/qcsrc/server/scores.qh	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/scores.qh	2008-08-10 10:07:06 UTC (rev 4086)
@@ -105,3 +105,9 @@
  */
 string GetPlayerScoreString(entity pl, float shortString);
 string GetTeamScoreString(float tm, float shortString);
+
+/**
+ * Sorts the players and stores their place in the given field, starting with
+ * 1. Non-players get 0 written into that field.
+ */
+float PlayerScore_Sort(.float field);

Modified: trunk/data/qcsrc/server/scores_rules.qc
===================================================================
--- trunk/data/qcsrc/server/scores_rules.qc	2008-08-09 23:24:29 UTC (rev 4085)
+++ trunk/data/qcsrc/server/scores_rules.qc	2008-08-10 10:07:06 UTC (rev 4086)
@@ -133,13 +133,15 @@
 		ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS,    "laps",      SFL_SORT_PRIO_PRIMARY);
 		ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
 	}
-	else if(cvar("g_race_qualifying"))
+	else if(g_race_qualifying)
 	{
+		ScoreInfo_SetLabel_TeamScore(  ST_RACE_LAPS,    "laps",      0);
 		ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS,    "laps",      0);
 		ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
 	}
 	else
 	{
+		ScoreInfo_SetLabel_TeamScore(  ST_RACE_LAPS,    "laps",      0);
 		ScoreInfo_SetLabel_PlayerScore(SP_RACE_LAPS,    "laps",      SFL_SORT_PRIO_PRIMARY);
 		ScoreInfo_SetLabel_PlayerScore(SP_RACE_FASTEST, "fastest",   SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
 	}




More information about the nexuiz-commits mailing list