From: Samual <samual@xonotic.org>
Date: Tue, 27 Dec 2011 19:24:47 +0000 (-0500)
Subject: Finish up work on timeout system, now has much cleaner functionality (though it still... 
X-Git-Tag: xonotic-v0.6.0~188^2~28^2~56
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=29b55dfa978a11a987d1f4ea1ec586272115ddab;p=xonotic%2Fxonotic-data.pk3dir.git

Finish up work on timeout system, now has much cleaner functionality (though it still works on the same fundamental slowmo hack) and will be easier to maintain
---

diff --git a/qcsrc/server/cl_client.qc b/qcsrc/server/cl_client.qc
index 9ddcaabac3..92e2687cb8 100644
--- a/qcsrc/server/cl_client.qc
+++ b/qcsrc/server/cl_client.qc
@@ -1528,7 +1528,7 @@ void ClientConnect (void)
 	}
 
 	self.jointime = time;
-	self.allowedTimeouts = autocvar_sv_timeout_number;
+	self.allowed_timeouts = autocvar_sv_timeout_number;
 
 	if(clienttype(self) == CLIENTTYPE_REAL)
 	{
@@ -2603,7 +2603,7 @@ void PlayerPreThink (void)
 		}
 
 		//don't allow the player to turn around while game is paused!
-		if(timeoutStatus == 2) {
+		if(timeout_status == TIMEOUT_ACTIVE) {
 			// FIXME turn this into CSQC stuff
 			self.v_angle = self.lastV_angle;
 			self.angles = self.lastV_angle;
diff --git a/qcsrc/server/cl_impulse.qc b/qcsrc/server/cl_impulse.qc
index 9e662bb848..524e796af2 100644
--- a/qcsrc/server/cl_impulse.qc
+++ b/qcsrc/server/cl_impulse.qc
@@ -46,7 +46,7 @@ void ImpulseCommands (void)
 		return;
 	self.impulse = 0;
 
-	if (timeoutStatus == 2) //don't allow any impulses while the game is paused
+	if (timeout_status == TIMEOUT_ACTIVE) //don't allow any impulses while the game is paused
 		return;
 
 	if(CheatImpulse(imp))
diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc
index 5b369c27c5..f67ac1be93 100644
--- a/qcsrc/server/cl_player.qc
+++ b/qcsrc/server/cl_player.qc
@@ -962,7 +962,7 @@ float Say(entity source, float teamsay, entity privatesay, string msgin, float f
 				flood = 1;
 		}
 
-		if (timeoutStatus == 2) //when game is paused, no flood protection
+		if (timeout_status == TIMEOUT_ACTIVE) // when game is paused, no flood protection
 			source.flood_field = flood = 0;
 	}
 
diff --git a/qcsrc/server/cl_weaponsystem.qc b/qcsrc/server/cl_weaponsystem.qc
index 2062f446fd..e049ef8588 100644
--- a/qcsrc/server/cl_weaponsystem.qc
+++ b/qcsrc/server/cl_weaponsystem.qc
@@ -913,7 +913,7 @@ float weapon_prepareattack_check(float secondary, float attacktime)
 		return FALSE;
 	}
 
-	if (timeoutStatus == 2) //don't allow the player to shoot while game is paused
+	if (timeout_status == TIMEOUT_ACTIVE) //don't allow the player to shoot while game is paused
 		return FALSE;
 
 	// do not even think about shooting if switching
diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc
index f218a4e670..521db1a0ab 100644
--- a/qcsrc/server/command/cmd.qc
+++ b/qcsrc/server/command/cmd.qc
@@ -5,7 +5,7 @@
 
 float SV_ParseClientCommand_floodcheck()
 {
-	if (timeoutStatus != 2) // if the game is not paused... but wait, doesn't that mean it could be dos'd by pausing it? eh? (old code)
+	if not(timeout_status) // not while paused
 	{
 		if(time <= (self.cmd_floodtime + autocvar_sv_clientcommand_antispam_time))
 		{
@@ -192,7 +192,7 @@ void ClientCommand_ready(float request) // todo: anti-spam for toggling readynes
 						}
 
 						// cannot reset the game while a timeout is active!
-						if(!timeoutStatus)
+						if not(timeout_status)
 							ReadyCount();
 					} else {
 						sprint(self, "^1Game has already been restarted\n");
diff --git a/qcsrc/server/command/common.qc b/qcsrc/server/command/common.qc
index 2e40340206..c333910ec6 100644
--- a/qcsrc/server/command/common.qc
+++ b/qcsrc/server/command/common.qc
@@ -104,6 +104,99 @@ void print_to(entity to, string input)
 //  Supporting functions for common commands
 // ==========================================
 
+// used by CommonCommand_timeout() and CommonCommand_timein() to handle game pausing and messaging and such.
+void timeout_handler_reset()
+{
+	entity tmp_player;
+	
+	timeout_caller = world;
+	timeout_time = 0;
+	timeout_leadtime = 0;
+	
+	FOR_EACH_REALPLAYER(tmp_player)
+		Send_CSQC_Centerprint_Generic_Expire(tmp_player, CPID_TIMEOUT_COUNTDOWN);
+				
+	remove(self);
+}
+
+void timeout_handler_think() 
+{
+	entity tmp_player;
+	
+	switch(timeout_status)
+	{
+		case TIMEOUT_ACTIVE:
+		{
+			if(timeout_time > 0) // countdown is still going
+			{
+				FOR_EACH_REALPLAYER(tmp_player)
+					Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout ends in %d seconds!", 1, timeout_time);
+
+				if(timeout_time == autocvar_sv_timeout_resumetime) // play a warning sound when only <sv_timeout_resumetime> seconds are left
+					Announce("prepareforbattle");
+
+				self.nextthink = time + TIMEOUT_SLOWMO_VALUE; // think again in one second
+				timeout_time -= 1; // decrease the time counter
+			}
+			else // time to end the timeout
+			{
+				timeout_status = TIMEOUT_INACTIVE;
+				
+				// reset the slowmo value back to normal
+				cvar_set("slowmo", ftos(orig_slowmo));
+				
+				// unlock the view for players so they can move around again
+				FOR_EACH_REALPLAYER(tmp_player) 
+					tmp_player.fixangle = FALSE;
+					
+				timeout_handler_reset();
+			}
+			
+			return;
+		}
+		
+		case TIMEOUT_LEADTIME:
+		{
+			if (timeout_leadtime > 0) // countdown is still going
+			{
+				// centerprint the information to every player
+				FOR_EACH_REALPLAYER(tmp_player) 
+					Send_CSQC_Centerprint_Generic(tmp_player, CPID_TIMEOUT_COUNTDOWN, "Timeout begins in %d seconds!", 1, timeout_leadtime);
+				
+				self.nextthink = time + 1; // think again in one second
+				timeout_leadtime -= 1; // decrease the time counter
+			}
+			else // time to begin the timeout
+			{
+				timeout_status = TIMEOUT_ACTIVE;
+				
+				// set the slowmo value to the timeout default slowmo value
+				cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
+				
+				// reset all the flood variables
+				FOR_EACH_CLIENT(tmp_player)
+					tmp_player.nickspamcount = tmp_player.nickspamtime = tmp_player.floodcontrol_chat =
+					tmp_player.floodcontrol_chatteam = tmp_player.floodcontrol_chattell = 
+					tmp_player.floodcontrol_voice = tmp_player.floodcontrol_voiceteam = 0;
+					
+				// copy .v_angle to .lastV_angle for every player in order to fix their view during pause (see PlayerPreThink)
+				FOR_EACH_REALPLAYER(tmp_player) 
+					tmp_player.lastV_angle = tmp_player.v_angle;
+				
+				self.nextthink = time; // think again next frame to handle it under TIMEOUT_ACTIVE code
+			}
+		}
+		
+		
+		case TIMEOUT_INACTIVE:
+		default:
+		{
+			timeout_handler_reset();
+			return;
+		}
+	}
+}
+
 
 
 // ===================================================
@@ -399,7 +492,7 @@ void CommonCommand_timein(float request, entity caller)
 						case TIMEOUT_ACTIVE:
 						{
 							timeout_time = autocvar_sv_timeout_resumetime;
-							timeoutHandler.nextthink = time; // timeout_handler has to take care of it immediately
+							timeout_handler.nextthink = time; // timeout_handler has to take care of it immediately
 							bprint(strcat("^1Attention: ^7", caller.netname, " resumed the game! Prepare for battle!\n"));
 							return;
 						}
@@ -443,7 +536,7 @@ void CommonCommand_timeout(float request, entity caller) // DEAR GOD THIS COMMAN
 				{					
 					if(caller) { caller.allowed_timeouts -= 1; }
 					
-					bprint(GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(caller.allowedTimeouts), " timeouts left)") : string_null), "!\n"); // write a bprint who started the timeout (and how many they have left)
+					bprint(GetCallerName(caller), " ^7called a timeout", (caller ? strcat(" (", ftos(caller.allowed_timeouts), " timeouts left)") : string_null), "!\n"); // write a bprint who started the timeout (and how many they have left)
 					
 					timeout_status = TIMEOUT_LEADTIME;
 					timeout_caller = caller;
diff --git a/qcsrc/server/command/vote.qc b/qcsrc/server/command/vote.qc
index 1c7b170220..bf636a3877 100644
--- a/qcsrc/server/command/vote.qc
+++ b/qcsrc/server/command/vote.qc
@@ -367,7 +367,7 @@ void ReadyRestart_force()
 	}
 
 	// after a restart every players number of allowed timeouts gets reset, too
-	if(autocvar_sv_timeout) { FOR_EACH_REALPLAYER(tmp_player) { tmp_player.allowedTimeouts = autocvar_sv_timeout_number; } }
+	if(autocvar_sv_timeout) { FOR_EACH_REALPLAYER(tmp_player) { tmp_player.allowed_timeouts = autocvar_sv_timeout_number; } }
 
 	//reset map immediately if this cvar is not set
 	if not(autocvar_sv_ready_restart_after_countdown) { reset_map(TRUE); }
@@ -625,7 +625,7 @@ void VoteCommand_call(float request, entity caller, float argc, string vote_comm
 			if not(autocvar_sv_vote_call || !caller) { print_to(caller, "^1Vote calling is not allowed."); }
 			else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
 			else if(!spectators_allowed && (caller && (caller.classname != "player"))) { print_to(caller, "^1Only players can call a vote."); }
-			else if(timeoutStatus) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
+			else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
 			else if(caller && (time < caller.vote_waittime)) { print_to(caller, strcat("^1You have to wait ^2", ftos(ceil(caller.vote_waittime - time)), "^1 seconds before you can again call a vote.")); }
 			else if not(VoteCommand_checknasty(vote_command)) { print_to(caller, "^1Syntax error in command, see 'vhelp' for more info."); }
 			else if not(VoteCommand_parse(caller, vote_command, autocvar_sv_vote_commands, 2, argc)) { print_to(caller, "^1This command is not acceptable, see 'vhelp' for more info."); }
@@ -719,6 +719,7 @@ void VoteCommand_master(float request, entity caller, float argc, string vote_co
 					{
 						if not(autocvar_sv_vote_master_callable) { print_to(caller, "^1Vote to become vote master is not allowed."); }
 						else if(vote_called) { print_to(caller, "^1There is already a vote called."); }
+						else if(timeout_status) { print_to(caller, "^1You can not call a vote while a timeout is active."); }
 						
 						else // everything went okay, continue with creating vote
 						{
diff --git a/qcsrc/server/g_hook.qc b/qcsrc/server/g_hook.qc
index 84ea021018..370f2fb987 100644
--- a/qcsrc/server/g_hook.qc
+++ b/qcsrc/server/g_hook.qc
@@ -382,7 +382,7 @@ void FireGrapplingHook (void)
 
 void GrapplingHookFrame()
 {
-	if(g_grappling_hook && timeoutStatus != 2 && self.weapon != WEP_HOOK)
+	if(g_grappling_hook && timeout_status != TIMEOUT_ACTIVE && self.weapon != WEP_HOOK)
 	{
 		// offhand hook controls
 		if(self.BUTTON_HOOK)
diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc
index 41288a8086..80a34a0e69 100644
--- a/qcsrc/server/g_world.qc
+++ b/qcsrc/server/g_world.qc
@@ -95,83 +95,6 @@ void fteqcc_testbugs()
 	world.cnt = 0;
 }
 
-/**
- * Takes care of pausing and unpausing the game.
- * Centerprints the information about an upcoming or active timeout to all active
- * players. Also plays reminder sounds.
- */
-void timeoutHandler_Think() {
-	entity plr;
-	if (timeoutStatus == 1) {
-		if (remainingLeadTime > 0) {
-			//centerprint the information to every player
-			FOR_EACH_REALCLIENT(plr) {
-				if(plr.classname == "player") {
-					Send_CSQC_Centerprint_Generic(plr, CPID_TIMEOUT_COUNTDOWN, "Timeout begins in %d seconds!", 1, remainingLeadTime);
-				}
-			}
-			remainingLeadTime -= 1;
-			//think again in 1 second:
-			self.nextthink = time + 1;
-		}
-		else {
-			//now pause the game:
-			timeoutStatus = 2;
-			//reset all the flood variables
-			FOR_EACH_CLIENT(plr) {
-				plr.nickspamcount = plr.nickspamtime = plr.floodcontrol_chat = plr.floodcontrol_chatteam = plr.floodcontrol_chattell = plr.floodcontrol_voice = plr.floodcontrol_voiceteam = 0;
-			}
-			cvar_set("slowmo", ftos(TIMEOUT_SLOWMO_VALUE));
-			//copy .v_angle to .lastV_angle for every player in order to fix their view during pause (see PlayerPreThink)
-			FOR_EACH_REALPLAYER(plr) {
-				plr.lastV_angle = plr.v_angle;
-			}
-			self.nextthink = time;
-		}
-	}
-	else if (timeoutStatus == 2) {
-		if (remainingTimeoutTime > 0) {
-			FOR_EACH_REALCLIENT(plr) {
-				if(plr.classname == "player") {
-					Send_CSQC_Centerprint_Generic(plr, CPID_TIMEOUT_COUNTDOWN, "Timeout ends in %d seconds!", 1, remainingTimeoutTime);
-				}
-			}
-			if(remainingTimeoutTime == autocvar_sv_timeout_resumetime) { //play a warning sound when only <sv_timeout_resumetime> seconds are left
-				Announce("prepareforbattle");
-			}
-			remainingTimeoutTime -= 1;
-			self.nextthink = time + TIMEOUT_SLOWMO_VALUE;
-		}
-		else {
-			//unpause the game again
-			remainingTimeoutTime = timeoutStatus = 0;
-			cvar_set("slowmo", ftos(orig_slowmo));
-			//and unlock the fixed view again once there is no timeout active anymore
-			FOR_EACH_REALPLAYER(plr) {
-				plr.fixangle = FALSE;
-			}
-			//get rid of the countdown message
-			FOR_EACH_REALCLIENT(plr) {
-				if(plr.classname == "player") {
-					Send_CSQC_Centerprint_Generic_Expire(plr, CPID_TIMEOUT_COUNTDOWN);
-				}
-			}
-			remove(self);
-			return;
-		}
-
-	}
-	else if (timeoutStatus == 0) { //if a player called the resumegame command (which set timeoutStatus to 0 already)
-		FOR_EACH_REALCLIENT(plr) {
-			if(plr.classname == "player") {
-				Send_CSQC_Centerprint_Generic_Expire(plr, CPID_TIMEOUT_COUNTDOWN);
-			}
-		}
-		remove(self);
-		return;
-	}
-}
-
 void GotoFirstMap()
 {
 	float n;
diff --git a/qcsrc/server/sv_main.qc b/qcsrc/server/sv_main.qc
index 7ec4b49d67..d9a0ad460e 100644
--- a/qcsrc/server/sv_main.qc
+++ b/qcsrc/server/sv_main.qc
@@ -196,7 +196,7 @@ void StartFrame (void)
 	if(sys_frametime <= 0)
 		sys_frametime = 1.0 / 60.0; // somewhat safe fallback
 
-	if (timeoutStatus == 1) // just before the timeout (when timeoutStatus will be 2)
+	if (timeout_status == TIMEOUT_LEADTIME) // just before the timeout (when timeout_status will be TIMEOUT_ACTIVE)
 		orig_slowmo = autocvar_slowmo; // slowmo will be restored after the timeout
 
 	skill = autocvar_skill;