r3629 - in trunk/data: . qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sat May 17 16:21:38 EDT 2008


Author: greenmarine
Date: 2008-05-17 16:21:36 -0400 (Sat, 17 May 2008)
New Revision: 3629

Modified:
   trunk/data/default.cfg
   trunk/data/qcsrc/server/arena.qc
   trunk/data/qcsrc/server/cl_client.qc
   trunk/data/qcsrc/server/cl_weapons.qc
   trunk/data/qcsrc/server/cl_weaponsystem.qc
   trunk/data/qcsrc/server/clientcommands.qc
   trunk/data/qcsrc/server/defs.qh
   trunk/data/qcsrc/server/miscfunctions.qc
   trunk/data/qcsrc/server/teamplay.qc
Log:
extension of the ready-restart feature:
- bugfix: extend the pause for rotting health when map is being reset, otherwise health will start to rot after the 10 second countdown is over, because the rot is set to 10 seconds
- new feature: sv_ready_restart_after_countdown: allows player to walk around during countdown (and prevents that a player knows where he spawns as he gets spawned after the countdown is over)
- new feature: sv_ready_restart_repeatable: players can restart the map more often (more than once)
- new feature: sv_ready_restart_nag: nags other real players who haven't readied up yet to do so, interval and duration can also be setup

Modified: trunk/data/default.cfg
===================================================================
--- trunk/data/default.cfg	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/default.cfg	2008-05-17 20:21:36 UTC (rev 3629)
@@ -112,6 +112,11 @@
 
 // restart server if all players hit "ready"-button
 set sv_ready_restart 0
+set sv_ready_restart_after_countdown 0 //if set to 1 the players and map items are reset after the countdown ended, otherwise they're reset already at the beginning of the countdown
+set sv_ready_restart_repeatable 0 //allows the players to restart the game as often as needed
+set sv_ready_restart_nag 0 //whether to nag players who are not ready yet, the message is shown in intervals
+set sv_ready_restart_nag_duration 6 //how long to show the ready-nag, in seconds
+set sv_ready_restart_nag_interval 10 //how long the pause between the ready-nags is, in seconds
 
 // use default physics
 exec physicsQBR.cfg

Modified: trunk/data/qcsrc/server/arena.qc
===================================================================
--- trunk/data/qcsrc/server/arena.qc	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/arena.qc	2008-05-17 20:21:36 UTC (rev 3629)
@@ -19,6 +19,10 @@
 void onslaught_generator_reset();
 void onslaught_controlpoint_reset();
 
+/**
+ * Resets the state of all clients, items, flags, runes, keys, weapons, waypoints, ... of the map.
+ * Sets the 'warmup' global variable.
+ */
 void reset_map()
 {
 	if(g_arena)
@@ -105,21 +109,36 @@
 	FOR_EACH_CLIENT(self) {
 		if(self.flags & FL_CLIENT)				// reset all players
 		{
-			if(time < restart_countdown)
+			if(g_arena)
 			{
-				self.frags = (g_lms)?LMS_NewPlayerLives():0;
-				self.deaths = 0;
-				self.killcount = 0;
-				self.classname = "player";
-				PutClientInServer();
-			}
-			else if(g_arena)
-			{
 				if(self.spawned)
 					PutClientInServer();
 				else
 					PutObserverInServer();
 			}
+			else
+			{
+				/*
+				only reset players if a restart countdown is active
+				this can either be due to cvar sv_ready_restart_after_countdown having set
+				restart_mapalreadyrestarted to 1 after the countdown ended or when
+				sv_ready_restart_after_countdown is not used and countdown is still running
+				*/
+				if (restart_mapalreadyrestarted || (time < restart_countdown))
+				{
+					//NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
+					if (self.classname == "player") {
+						self.frags = (g_lms)?LMS_NewPlayerLives():0;
+						self.deaths = 0;
+						self.killcount = 0;
+						//stop the player from moving so that he stands still once he gets respawned
+						self.velocity = '0 0 0';
+						self.avelocity = '0 0 0';
+						self.movement = '0 0 0';
+						PutClientInServer();
+					}
+				}
+			}
 		}
 	}
 
@@ -180,6 +199,14 @@
 	numspawned = numspawned + 1;
 }
 
+/**
+ * If roundbased arena game mode is active, it centerprints the texts for the
+ * player when player is waiting for the countdown to finish.
+ * Blocks the players movement while countdown is active.
+ * Unblocks the player once the countdown is over.
+ * 
+ * Called in PlayerPostThink()
+ */
 void Arena_Warmup()
 {
 	float f;
@@ -223,11 +250,20 @@
 }
 
 float next_round;
+
+/**
+ * This function finds out whether an arena round is over 1 player is left.
+ * It determines the last player who's still alive and saves it's entity reference
+ * in the global variable 'champion'. Then the new enemy/enemies are put into the server.
+ * 
+ * Gets called in StartFrame()
+ */
 void Spawnqueue_Check()
 {
 	if(time < warmup + 1)
 		return;
 
+	//extend next_round if it isn't set yet and only 1 player is spawned
 	if(!next_round)
 	if(numspawned < 2)
 		next_round = time + 3;

Modified: trunk/data/qcsrc/server/cl_client.qc
===================================================================
--- trunk/data/qcsrc/server/cl_client.qc	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/cl_client.qc	2008-05-17 20:21:36 UTC (rev 3629)
@@ -555,6 +555,13 @@
 		self.pauserotarmor_finished = time + cvar("g_balance_pause_armor_rot_spawn");
 		self.pauserothealth_finished = time + cvar("g_balance_pause_health_rot_spawn");
 		self.pauseregen_finished = time + cvar("g_balance_pause_health_regen_spawn");
+		//extend the pause of rotting if client was reset at the beginning of the countdown
+		if(!cvar("sv_ready_restart_after_countdown") && time < restart_countdown) {
+			self.spawnshieldtime += RESTART_COUNTDOWN;
+			self.pauserotarmor_finished += RESTART_COUNTDOWN;
+			self.pauserothealth_finished += RESTART_COUNTDOWN;
+			self.pauseregen_finished += RESTART_COUNTDOWN;
+		}
 		self.damageforcescale = 2;
 		self.death_time = 0;
 		self.dead_frame = 0;
@@ -1780,24 +1787,29 @@
 		//if (TetrisPostFrame()) return;
 
 		// restart countdown
-		if(time < restart_countdown)
-		{
-			string s;
-			float sec;
-
-			sec = ceil(restart_countdown-time);
-			s = strcat(NEWLINES, "^1Game starts in ", ftos(sec), " seconds");
-			centerprint(self, s);
-			self.movetype = MOVETYPE_NONE;
-			self.velocity = '0 0 0';
-			self.avelocity = '0 0 0';
-			self.movement = '0 0 0';
+		if (restart_countdown) {
+			if(time < restart_countdown) {
+				if (!cvar("sv_ready_restart_after_countdown"))
+				{
+					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
+				if (!cvar("sv_ready_restart_after_countdown"))
+				{
+					if(self.movetype == MOVETYPE_NONE)
+					{
+						self.movetype = MOVETYPE_WALK;
+					}
+				}
+			}
 		}
-		else if(self.movetype == MOVETYPE_NONE)
-		{
-			self.movetype = MOVETYPE_WALK;
-			centerprint(self, "\n");
-		}
+		
 	} else if (self.classname == "observer") {
 		//do nothing
 	} else if (self.classname == "spectator") {

Modified: trunk/data/qcsrc/server/cl_weapons.qc
===================================================================
--- trunk/data/qcsrc/server/cl_weapons.qc	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/cl_weapons.qc	2008-05-17 20:21:36 UTC (rev 3629)
@@ -220,7 +220,7 @@
 // Bringed back weapon frame
 void() W_WeaponFrame =
 {
-	if((arena_roundbased && time < warmup) || (time < restart_countdown))
+	if((arena_roundbased && time < warmup) || ((time < restart_countdown) && !cvar("sv_ready_restart_after_countdown")))
 		return;
 
 	if (!self.weaponentity || self.health < 1)

Modified: trunk/data/qcsrc/server/cl_weaponsystem.qc
===================================================================
--- trunk/data/qcsrc/server/cl_weaponsystem.qc	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/cl_weaponsystem.qc	2008-05-17 20:21:36 UTC (rev 3629)
@@ -423,6 +423,13 @@
 // perform weapon to attack (weaponstate and attack_finished check is here)
 float(float secondary, float attacktime) weapon_prepareattack =
 {
+	//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) {
+			return FALSE;
+		}
+	
 	if (!weapon_action(self.weapon, WR_CHECKAMMO1 + secondary))
 	{
 		self.switchweapon = w_getbestweapon(self);

Modified: trunk/data/qcsrc/server/clientcommands.qc
===================================================================
--- trunk/data/qcsrc/server/clientcommands.qc	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/clientcommands.qc	2008-05-17 20:21:36 UTC (rev 3629)
@@ -483,7 +483,7 @@
 	} else if(argv(0) == "ready") {
 		if(cvar("sv_ready_restart"))
 		{
-			if(!restart_countdown)
+			if(!restart_countdown || cvar("sv_ready_restart_repeatable"))
 			{
 				self.ready = TRUE;
 				bprint(self.netname, "^2 is ready\n");
@@ -812,6 +812,15 @@
 
 float timelimit_orig;
 
+/**
+ * Counts how many players are ready. If not enough players are ready, the function
+ * does nothing. If all players are ready, the timelimit will be extended and the
+ * restart_countdown variable is set to allow other functions like PlayerPostThink
+ * to detect that the countdown is now active. If the cvar sv_ready_restart_after_countdown
+ * is not set the map will be resetted.
+ * 
+ * Function is called after the server receives a 'ready' sign from a player.
+ */
 void ReadyCount()
 {
 	local entity e;
@@ -824,6 +833,16 @@
 			r += 1;
 	}
 
+	if(cvar("sv_ready_restart_nag")) {
+		if(!readyNagActive) {
+			readyNagger = spawn();
+			readyNagger.think = readyNagger_Think;
+			readyNagger.cnt = cvar("sv_ready_restart_nag_duration");
+			readyNagger.nextthink = time;
+			readyNagActive = 1;
+		}
+	}
+
 	if(!p || r < p)
 		return;
 
@@ -833,7 +852,18 @@
 	if(g_arena | g_assault | gameover | intermission_running)
 		localcmd("restart\n");
 
+	if(readyNagActive) { //if every player is ready, remove the ready-nagger again
+		readyNagActive = 0;
+		remove(readyNagger);
+	}
+
 	restart_countdown = time + RESTART_COUNTDOWN;
+	restart_mapalreadyrestarted = 0; //reset this var, needed when cvar sv_ready_restart_repeatable is in use
+	//reset the .ready status of all players (also spectators)
+	FOR_EACH_CLIENT(e)
+	{
+		e.ready = 0;
+	}
 	if(0<cvar("timelimit"))
 	{
 		// remember original timelimit on first restart
@@ -842,8 +872,95 @@
 		cvar_set("timelimit", ftos(timelimit_orig + ceil(restart_countdown)/60));
 	}
 
-	reset_map();
+	//initiate the restart-countdown-announcer entity
+	restartAnnouncer = spawn();
+	restartAnnouncer.think = restartAnnouncer_Think;
+	restartAnnouncer.nextthink = time;
+	restartAnnouncer.cnt = RESTART_COUNTDOWN;
 
+	//play the prepareforbattle sound to everyone
+	sound(world, CHAN_AUTO, "announcer/robotic/prepareforbattle.wav", 1, ATTN_NONE);
+
+	//reset map immediately if this cvar is not set
+	if (!cvar("sv_ready_restart_after_countdown"))
+		reset_map();
+	
 	if(cvar("sv_eventlog"))
 		GameLogEcho(":restart", FALSE);
 }
+
+/**
+ * Centerprints the information to all players who didn't ready up yet to do so.
+ */
+void readyNagger_Think() {
+	local entity plr;
+	if(self.cnt <= 0) { //have a break showing the ready nag
+		//make sure that the old ready-nag-centerprint isn't shown too long:
+		FOR_EACH_REALCLIENT(plr) {
+			if(plr.classname == "player") {
+				if (!plr.ready)
+					centerprint_atprio(plr, CENTERPRIO_SPAM, "");
+			}
+		}
+		self.cnt = cvar("sv_ready_restart_nag_duration");
+		self.nextthink = time + cvar("sv_ready_restart_nag_interval");
+	}
+	else {
+		//show the ready nagging to all players who aren't ready yet
+		FOR_EACH_REALCLIENT(plr) {
+			if(plr.classname == "player") {
+				if (!plr.ready) {
+					centerprint_atprio(plr, CENTERPRIO_SPAM, "^2Please ready up (F4 by default)!");
+					//play reminder sound once the centerprint appears for the first time after the pause:
+					if (self.cnt == cvar("sv_ready_restart_nag_duration"))
+						play2(plr, "misc/talk2.wav");
+				}
+			}
+		}
+
+		self.nextthink = time + 1;
+		self.cnt -= 1;
+	}
+}
+
+/**
+ * Shows the restart countdown for all players.
+ * Plays the countdown sounds for the seconds 3, 2 1, begin for everyone.
+ * Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown
+ * is set to 1).
+ */
+void restartAnnouncer_Think() {
+	local entity plr;
+	local string s;
+	if(self.cnt <= 0) { //show the "Begin" message and
+		if (cvar("sv_ready_restart_after_countdown")) {
+			restart_mapalreadyrestarted = 1;
+			reset_map();
+		}
+
+		FOR_EACH_REALCLIENT(plr) {
+			if(plr.classname == "player") {
+				s = strcat(NEWLINES, "^1Begin!");
+				centerprint(plr, s);
+			}
+		}
+		sound(world, CHAN_AUTO, "announcer/robotic/begin.wav", 1, ATTN_NONE);
+
+		remove(self);
+		return;
+	}
+	else {
+		FOR_EACH_REALCLIENT(plr) {
+			if(plr.classname == "player") {
+				s = strcat(NEWLINES, "^1Game starts in ", ftos(self.cnt), " seconds");
+				centerprint(plr, s);
+			}
+		}
+
+		if(self.cnt <= 3) {
+			sound(world, CHAN_AUTO, strcat("announcer/robotic/", ftos(self.cnt), ".ogg"), 1, ATTN_NONE);
+		}
+		self.nextthink = time + 1;
+		self.cnt -= 1;
+	}
+}

Modified: trunk/data/qcsrc/server/defs.qh
===================================================================
--- trunk/data/qcsrc/server/defs.qh	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/defs.qh	2008-05-17 20:21:36 UTC (rev 3629)
@@ -272,7 +272,13 @@
 
 .float ready;
 #define RESTART_COUNTDOWN 10
-float restart_countdown;
+float restart_countdown; //point in time when the countdown is over
+float restart_mapalreadyrestarted; //bool, indicates whether reset_map() was already executed
+entity restartAnnouncer; //a temporary entity which will play the countdown sounds 3, 2, 1 for all clients, will also reset the map after the countdown
+void restartAnnouncer_Think();
+entity readyNagger; //manages printing the ready-nag to active players who are not ready yet
+void readyNagger_Think();
+float readyNagActive; //if set to 1, the readyNagger entity was already spawned (boolean)
 
 .float winning;
 .float deaths;

Modified: trunk/data/qcsrc/server/miscfunctions.qc
===================================================================
--- trunk/data/qcsrc/server/miscfunctions.qc	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/miscfunctions.qc	2008-05-17 20:21:36 UTC (rev 3629)
@@ -1029,6 +1029,8 @@
 	precache_sound ("announcer/male/yoda.wav");
 
 	// announcer sounds - robotic
+	precache_sound ("announcer/robotic/begin.wav");
+	precache_sound ("announcer/robotic/prepareforbattle.wav");
 	precache_sound ("announcer/robotic/1fragleft.wav");
 	precache_sound ("announcer/robotic/1minuteremains.wav");
 	precache_sound ("announcer/robotic/2fragsleft.wav");

Modified: trunk/data/qcsrc/server/teamplay.qc
===================================================================
--- trunk/data/qcsrc/server/teamplay.qc	2008-05-17 19:39:13 UTC (rev 3628)
+++ trunk/data/qcsrc/server/teamplay.qc	2008-05-17 20:21:36 UTC (rev 3629)
@@ -354,8 +354,10 @@
 	self.welcomemessage_time = time + 0.8; */
 
 	if(self.cvar_scr_centertime == 0) return;
-	if(self.welcomemessage_time > time) return;
-	self.welcomemessage_time = time + self.cvar_scr_centertime * 0.6;
+	if( !(time < restart_countdown) ) { //really print the WelcomeMessage to the player every frame when the game is restarted, to make sure that the shown number is accurate
+		if(self.welcomemessage_time > time) return;
+		self.welcomemessage_time = time + self.cvar_scr_centertime * 0.6;
+	}
 
 	if(cvar("g_campaign"))
 	{
@@ -377,7 +379,14 @@
 			if ((g_lms && self.frags < 1) || g_arena)
 				return centerprint_atprio(self, CENTERPRIO_SPAM, strcat(NEWLINES, "spectating ", self.enemy.netname, "\n\n\n^7press attack for next player\npress attack2 for free fly mode"));
 			else
-				return centerprint_atprio(self, CENTERPRIO_SPAM, strcat(NEWLINES, "spectating ", self.enemy.netname, "\n\n\n^7press jump to play\n^7press attack for next player\npress attack2 for free fly mode"));
+			{
+				local string spectatorText;
+				spectatorText = strcat(NEWLINES, "spectating ", self.enemy.netname, "\n\n\n^7press jump to play\n^7press attack for next player\npress attack2 for free fly mode");
+
+				if(time < restart_countdown) //also show the countdown when being a spectator
+					spectatorText = strcat(spectatorText, "\n\n^1Game starts in ", ftos(restartAnnouncer.cnt + 1), " seconds^7");
+				return centerprint_atprio(self, CENTERPRIO_SPAM, spectatorText);
+			}
 		}
 	}
 
@@ -420,7 +429,7 @@
 		s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
 
 	if(time < restart_countdown)
-		s = strcat(s, "\n^1Game starts in ", ftos(ceil(restart_countdown-time)), " seconds^7");
+		s = strcat(s, "\n^1Game starts in ", ftos(restartAnnouncer.cnt + 1), " seconds^7");
 
 	s = strzone(s);
 




More information about the nexuiz-commits mailing list