r2253 - in trunk/data: . qcsrc/server

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Mon Mar 26 06:50:09 EDT 2007


Author: div0
Date: 2007-03-26 06:50:09 -0400 (Mon, 26 Mar 2007)
New Revision: 2253

Modified:
   trunk/data/default.cfg
   trunk/data/qcsrc/server/cl_client.qc
   trunk/data/qcsrc/server/clientcommands.qc
   trunk/data/qcsrc/server/defs.qh
   trunk/data/qcsrc/server/g_world.qc
Log:
- projectile style is now 2 (Newtonian with aimfix), fixes RL when movingh fast
- g_maplist_putfirst
- voting on end of level (PLEASE TEST), default might better be 0, but when I enable it here, people will test it


Modified: trunk/data/default.cfg
===================================================================
--- trunk/data/default.cfg	2007-03-26 10:42:30 UTC (rev 2252)
+++ trunk/data/default.cfg	2007-03-26 10:50:09 UTC (rev 2253)
@@ -221,6 +221,7 @@
 alias g_maplist_shufflenow "set _g_maplist_shufflenow 1"
 alias g_maplist_add "set _g_maplist_add $1"
 alias g_maplist_remove "set _g_maplist_remove $1"
+alias g_maplist_putfirst "set _g_maplist_putfirst $1"
 // timeout for kill credit when your damage knocks someone into a death trap
 set g_maxpushtime 8.0
 
@@ -794,10 +795,16 @@
 
 set g_waypoints_for_items 1 // make waypoints out of items; values: 0 = never, 1 = unless the mapper prevents it by worldspawn.spawnflags & 1, 2 = always
 
-set g_projectiles_newton_style 0
+set g_projectiles_newton_style 2
 // possible values:
 //   0: absolute velocity projectiles (like Quake)
 //   1: relative velocity projectiles, "Newtonian" (like Tribes 2)
 //   2: relative velocity projectiles, but aim is precorrected so projectiles hit the crosshair (note: strafe rockets then are SLOWER than ones shot while standing; happens in 1 too when aiming correctly which is hard)
 //   3: absolute velocity + player velocity component in shot direction (note: does NOT yield the right relative velocity, but may be good enough; but it is somewhat prone to sniper rockets)
 //   4: just add the player velocity length to the absolute velocity (tZork's sniper rockets)
+
+set g_maplist_votable 5
+set g_maplist_votable_keeptwotime 15
+set g_maplist_votable_timeout 30 // note: must be below 50 seconds!
+set g_maplist_votable_suggestions 2
+alias suggestmap "cmd suggestmap $1"

Modified: trunk/data/qcsrc/server/cl_client.qc
===================================================================
--- trunk/data/qcsrc/server/cl_client.qc	2007-03-26 10:42:30 UTC (rev 2252)
+++ trunk/data/qcsrc/server/cl_client.qc	2007-03-26 10:50:09 UTC (rev 2253)
@@ -653,6 +653,25 @@
 	Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
 }
 
+void FixClientCvars(entity e)
+{
+	// send prediction settings to the client
+	stuffcmd(e, "\nin_bindmap 0 0\n");
+	stuffcmd(e, strcat("cl_gravity ", ftos(cvar("sv_gravity")), "\n"));
+	stuffcmd(e, strcat("cl_movement_accelerate ", ftos(cvar("sv_accelerate")), "\n"));
+	stuffcmd(e, strcat("cl_movement_friction ", ftos(cvar("sv_friction")), "\n"));
+	stuffcmd(e, strcat("cl_movement_maxspeed ", ftos(cvar("sv_maxspeed")), "\n"));
+	stuffcmd(e, strcat("cl_movement_airaccelerate ", ftos(cvar("sv_airaccelerate")), "\n"));
+	stuffcmd(e, strcat("cl_movement_maxairspeed ", ftos(cvar("sv_maxairspeed")), "\n"));
+	stuffcmd(e, strcat("cl_movement_stopspeed ", ftos(cvar("sv_stopspeed")), "\n"));
+	stuffcmd(e, strcat("cl_movement_jumpvelocity ", ftos(cvar("g_balance_jumpheight")), "\n"));
+	stuffcmd(e, strcat("cl_movement_stepheight ", ftos(cvar("sv_stepheight")), "\n"));
+	stuffcmd(e, strcat("set cl_movement_friction_on_land ", ftos(cvar("sv_friction_on_land")), "\n"));
+	stuffcmd(e, strcat("set cl_movement_airaccel_qw ", ftos(cvar("sv_airaccel_qw")), "\n"));
+	stuffcmd(e, strcat("set cl_movement_airaccel_sideways_friction ", ftos(cvar("sv_airaccel_sideways_friction")), "\n"));
+	stuffcmd(e, strcat("cl_movement_edgefriction 0\n"));
+}
+
 /*
 =============
 ClientConnect
@@ -722,19 +741,8 @@
 	// TODO: is this being used for anything else than cd tracks?
 	// Remember: SVC_CDTRACK exists. Maybe it should be used.
 	
-	// send prediction settings to the client
-	stuffcmd(self, strcat("cl_movement_accelerate ", ftos(cvar("sv_accelerate")), "\n"));
-	stuffcmd(self, strcat("cl_movement_friction ", ftos(cvar("sv_friction")), "\n"));
-	stuffcmd(self, strcat("cl_movement_maxspeed ", ftos(cvar("sv_maxspeed")), "\n"));
-	stuffcmd(self, strcat("cl_movement_airaccelerate ", ftos(cvar("sv_airaccelerate")), "\n"));
-	stuffcmd(self, strcat("cl_movement_maxairspeed ", ftos(cvar("sv_maxairspeed")), "\n"));
-	stuffcmd(self, strcat("cl_movement_stopspeed ", ftos(cvar("sv_stopspeed")), "\n"));
-	stuffcmd(self, strcat("cl_movement_jumpvelocity ", ftos(cvar("g_balance_jumpheight")), "\n"));
-	stuffcmd(self, strcat("cl_movement_stepheight ", ftos(cvar("sv_stepheight")), "\n"));
-	stuffcmd(self, strcat("set cl_movement_friction_on_land ", ftos(cvar("sv_friction_on_land")), "\n"));
-	stuffcmd(self, strcat("set cl_movement_airaccel_qw ", ftos(cvar("sv_airaccel_qw")), "\n"));
-	stuffcmd(self, strcat("set cl_movement_airaccel_sideways_friction ", ftos(cvar("sv_airaccel_sideways_friction")), "\n"));
-	stuffcmd(self, strcat("cl_movement_edgefriction 0\n"));
+	FixClientCvars(self);
+
 	// Wazat's grappling hook
 	SetGrappleHookBindings();
 
@@ -1545,10 +1553,12 @@
 
 		if (self.flags & FL_JUMPRELEASED) {
 			if (self.button2 && self.version == cvar("gameversion")) {
+				self.welcomemessage_time = 0;
 				self.flags = self.flags - FL_JUMPRELEASED;
 				LeaveSpectatorMode();
 				return;
 			} else if(self.button0 && self.version == cvar("gameversion")) {
+				self.welcomemessage_time = 0;
 				self.flags = self.flags - FL_JUMPRELEASED;
 				if(SpectateNext() == 1) {
 					self.classname = "spectator";
@@ -1563,10 +1573,12 @@
 	} else if(self.classname == "spectator") {
 		if (self.flags & FL_JUMPRELEASED) {
 			if (self.button2 && self.version == cvar("gameversion")) {
+				self.welcomemessage_time = 0;
 				self.flags = self.flags - FL_JUMPRELEASED;
 				LeaveSpectatorMode();
 				return;
 			} else if(self.button0) {
+				self.welcomemessage_time = 0;
 				self.flags = self.flags - FL_JUMPRELEASED;
 				if(SpectateNext() == 1) {
 					self.classname = "spectator";
@@ -1575,6 +1587,7 @@
 					PutClientInServer();
 				}
 			} else if (self.button3) {
+				self.welcomemessage_time = 0;
 				self.flags = self.flags - FL_JUMPRELEASED;
 				self.classname = "observer";
 				PutClientInServer();

Modified: trunk/data/qcsrc/server/clientcommands.qc
===================================================================
--- trunk/data/qcsrc/server/clientcommands.qc	2007-03-26 10:42:30 UTC (rev 2252)
+++ trunk/data/qcsrc/server/clientcommands.qc	2007-03-26 10:50:09 UTC (rev 2253)
@@ -1,6 +1,7 @@
 void ReadyCount();
 float ValidateMap(string vote);
 void(entity e) DropFlag;
+string MapVote_Suggest(string m);
 
 void Say(entity source, float teamsay, string msgin)
 {
@@ -17,6 +18,9 @@
 	if(!teams_matter)
 		teamsay = FALSE;
 
+	if(intermission_running)
+		teamsay = FALSE;
+
 	if(source.classname != "player") // observers can't
 		teamsay = FALSE;
 
@@ -330,6 +334,8 @@
 			sprint(self, strcat(col, argv(i), " "));
 		}
 		sprint(self, "\n");
+	} else if(argv(0) == "teamstatus") {
+		PrintScoreboard(self);
 	} else if(argv(0) == "say") {
 		Say(self, FALSE, substring(s, 4, strlen(s) - 4));
 		//clientcommand(self, formatmessage(s));
@@ -342,6 +348,8 @@
 			sprint(self, "ERROR: unsupported info command\n");
 		else
 			wordwrap_sprint(cmd, 1111);
+	} else if(argv(0) == "suggestmap") {
+		sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));
 	} else {
 		cmd = argv(0);
 		/* checks not needed any more since DP has separated clientcommands and regular commands

Modified: trunk/data/qcsrc/server/defs.qh
===================================================================
--- trunk/data/qcsrc/server/defs.qh	2007-03-26 10:42:30 UTC (rev 2252)
+++ trunk/data/qcsrc/server/defs.qh	2007-03-26 10:50:09 UTC (rev 2253)
@@ -301,6 +301,9 @@
 .float selected_player_display_needs_update; // are regular updates necessary? (health)
 .float selected_player_display_timeout; // when the selection will time out
 
+void FixIntermissionClient(entity e);
+void FixClientCvars(entity e);
+
 void centerprint_atprio(entity e, float prio, string s);
 void centerprint_expire(entity e, float prio);
 void centerprint(entity e, string s);

Modified: trunk/data/qcsrc/server/g_world.qc
===================================================================
--- trunk/data/qcsrc/server/g_world.qc	2007-03-26 10:42:30 UTC (rev 2252)
+++ trunk/data/qcsrc/server/g_world.qc	2007-03-26 10:50:09 UTC (rev 2253)
@@ -3,6 +3,7 @@
 string GetMapname();
 void GotoNextMap();
 void HandleMaplistShuffleCommands();
+float() DoNextMapOverride;
 
 void SetDefaultAlpha()
 {
@@ -61,7 +62,8 @@
 		if(argv(0) != GetMapname())
 		{
 			cvar_set("nextmap", argv(0));
-			GotoNextMap();
+			if(!DoNextMapOverride())
+				GotoNextMap();
 		}
 	}
 }
@@ -343,6 +345,9 @@
 
 	registercvar("_g_maplist_shufflenow", "0");
 	registercvar("_g_maplist_have_shuffled", "0");
+	registercvar("_g_maplist_add", "");
+	registercvar("_g_maplist_remove", "");
+	registercvar("_g_maplist_putfirst", "");
 
 	player_count = 0;
 	lms_lowest_lives = 0;
@@ -452,9 +457,12 @@
 	return "dm";
 }
 
+string getmapname_stored;
 string GetMapname()
 {
-	return strcat(GetGametype(), "_", mapname);
+	if(getmapname_stored == "")
+		getmapname_stored = strzone(strcat(GetGametype(), "_", mapname));
+	return getmapname_stored;
 }
 
 float Map_Count, Map_Current;
@@ -514,6 +522,7 @@
 
 string Map_Filename(float position)
 {
+	// FIXME unused
 	return strcat("maps/", argv(position), ".mapcfg");
 }
 
@@ -540,12 +549,39 @@
 	return 0;
 }
 
-void(float position) Map_Goto =
+void(string nextmapname) Map_Goto_SetStr =
 {
+	if(getmapname_stored != "")
+		strunzone(getmapname_stored);
+	if(nextmapname == "")
+		getmapname_stored = "";
+	else
+		getmapname_stored = strzone(nextmapname);
+}
+
+void(float position) Map_Goto_SetFloat =
+{
 	cvar_set("g_maplist_index", ftos(position));
-	localcmd(strcat("exec \"", Map_Filename(position) ,"\"\n"));
+	Map_Goto_SetStr(argv(position));
 }
 
+void() GameResetCfg =
+{
+	// if an exit cfg is defined by exiting map, exec it.
+	string exit_cfg;
+	exit_cfg = cvar_string("exit_cfg");
+	if(exit_cfg != "")
+		localcmd(strcat("exec \"", exit_cfg, "\"\n"));
+
+	localcmd("exec game_reset.cfg\n");
+};
+
+void() Map_Goto =
+{
+	GameResetCfg();
+	localcmd(strcat("exec \"maps/", getmapname_stored ,".mapcfg\"\n"));
+}
+
 // return codes of map selectors:
 //   -1 = temporary failure (that is, try some method that is guaranteed to succeed)
 //   -2 = permanent failure
@@ -648,31 +684,51 @@
 	// isn't chosen in the first pass that should have been
 }
 
-void() GotoNextMap =
+string() GetNextMap =
 {
-	//local string nextmap;
-	//local float n, nummaps;
-	//local string s;
-	string exit_cfg;
-	if (alreadychangedlevel)
-		return;
-	alreadychangedlevel = TRUE;
+	float nextMap;
 
+	Maplist_Init();
+	nextMap = -1;
+
+	if(nextMap == -1)
+		if(cvar("g_maplist_shuffle") > 0)
+			nextMap = MaplistMethod_Shuffle(cvar("g_maplist_shuffle") + 1);
+
+	if(nextMap == -1)
+		if(cvar("g_maplist_selectrandom"))
+			nextMap = MaplistMethod_Random();
+
+	if(nextMap == -1)
+		nextMap = MaplistMethod_Iterate();
+
+	if(nextMap == -1)
+		nextMap = MaplistMethod_Repeat();
+
+	if(nextMap >= 0)
+	{
+		Map_Goto_SetFloat(nextMap);
+		return getmapname_stored;
+	}
+
+	return "";
+};
+
+float() DoNextMapOverride =
+{
 	if(cvar("g_campaign"))
 	{
 		CampaignPostIntermission();
-		return;
+		return TRUE;
 	}
-
 	if(cvar("quit_when_empty"))
 	{
 		if(player_count <= currentbots)
 		{
 			localcmd("quit\n");
-			return;
+			return TRUE;
 		}
 	}
-
 	if (cvar("samelevel")) // if samelevel is set, stay on same level
 	{
 		// this does not work because it tries to exec maps/nexdm01.mapcfg (which doesn't exist, it should be trying maps/dm_nexdm01.mapcfg for example)
@@ -680,72 +736,55 @@
 		// so instead just restart the current map using the restart command (DOES NOT WORK PROPERLY WITH exit_cfg STUFF)
 		localcmd("restart\n");
 		//changelevel (mapname);
-		return;
+		return TRUE;
 	}
-
-	// if an exit cfg is defined by exiting map, exec it.
-	exit_cfg = cvar_string("exit_cfg");
-	if(exit_cfg != "")
-		localcmd(strcat("exec \"", exit_cfg, "\"\n"));
-
-	localcmd("exec game_reset.cfg\n");
-
-
-	if (cvar("lastlevel"))
+	if(cvar_string("nextmap") != "")
+		if(TryFile(strcat("maps/", cvar_string("nextmap"), ".mapcfg")))
+		{
+			Map_Goto_SetStr(cvar_string("nextmap"));
+			Map_Goto();
+			return TRUE;
+		}
+	if(cvar("lastlevel"))
 	{
+		GameResetCfg();
 		localcmd(strcat("set lastlevel 0\n"));
 		localcmd(strcat("togglemenu\n"));
+		return TRUE;
 	}
-	else
+	return FALSE;
+};
+
+void() GotoNextMap =
+{
+	//local string nextmap;
+	//local float n, nummaps;
+	//local string s;
+	if (alreadychangedlevel)
+		return;
+	alreadychangedlevel = TRUE;
+
 	{
-		float nextMap;
+		string nextMap;
 		float allowReset;
 
-		// cvar "nextmap" always gets priority
-		if(cvar_string("nextmap") != "")
-		if(TryFile(strcat("maps/", cvar_string("nextmap"), ".mapcfg")))
-		{
-			localcmd(strcat("exec \"maps/", cvar_string("nextmap"), ".mapcfg\"\n"));
-			return;
-		}
-
 		for(allowReset = 1; allowReset >= 0; --allowReset)
 		{
-			Maplist_Init();
-			nextMap = -1;
+			nextMap = GetNextMap();
+			if(nextMap != "")
+				break;
 
-			if(nextMap == -1)
-				if(cvar("g_maplist_shuffle") > 0)
-					nextMap = MaplistMethod_Shuffle(cvar("g_maplist_shuffle") + 1);
-
-			if(nextMap == -1)
-				if(cvar("g_maplist_selectrandom"))
-					nextMap = MaplistMethod_Random();
-
-			if(nextMap == -1)
-				nextMap = MaplistMethod_Iterate();
-
-			if(nextMap == -1)
-				nextMap = MaplistMethod_Repeat();
-
-			if(nextMap >= 0)
+			if(allowReset)
 			{
-				Map_Goto(nextMap);
-				break;
+				bprint( "Maplist contains no single playable map!  Resetting it to default map list.\n" );
+				cvar_set("g_maplist", cvar_string("g_maplist_defaultlist"));
 			}
-			else // PERMANENT FAILURE
+			else
 			{
-				if(allowReset)
-				{
-					bprint( "Maplist contains no single playable map!  Resetting it to default map list.\n" );
-					cvar_set("g_maplist", cvar_string("g_maplist_defaultlist"));
-				}
-				else
-				{
-					error("Everything is broken - not even the default map list works. Please report this to the developers.");
-				}
+				error("Everything is broken - not even the default map list works. Please report this to the developers.");
 			}
 		}
+		Map_Goto();
 	}
 };
 
@@ -758,8 +797,12 @@
 ============
 */
 .float autoscreenshot;
+void() MapVote_Think;
+float mapvote_initialized;
 void() IntermissionThink =
 {
+	FixIntermissionClient(self);
+
 	if(cvar("sv_autoscreenshot"))
 	if(self.autoscreenshot)
 	if(time > self.autoscreenshot)
@@ -773,10 +816,12 @@
 	if (time < intermission_exittime)
 		return;
 
-	if (time < intermission_exittime + 10 && !self.button0 && !self.button2 && !self.button3 && !self.button6 && !self.buttonuse)
-		return;
+	if(!mapvote_initialized)
+		if (time < intermission_exittime + 10 && !self.button0 && !self.button2 && !self.button3 && !self.button6 && !self.buttonuse)
+			return;
 
-	GotoNextMap ();
+	if(intermission_exittime >= 0)
+		MapVote_Think();
 };
 
 /*
@@ -893,7 +938,29 @@
 	}
 }
 
+void FixIntermissionClient(entity e)
+{
+	if(!e.autoscreenshot) // initial call
+	{
+		e.angles = e.v_angle;
+		e.autoscreenshot = time + 0.8;	// used for autoscreenshot
+		e.armorvalue = 0;
+		e.health = -42; // show scoreboard
+		e.solid = SOLID_NOT;
+		e.movetype = MOVETYPE_NONE;
+		e.takedamage = DAMAGE_NO;
+		if(e.weaponentity)
+			e.weaponentity.effects = EF_NODRAW;
+		stuffcmd(e, "\ncl_gravity 0\ncl_movement_maxspeed 0\ncl_movement_jumpvelocity 0\ncl_movement_maxairspeed 0\n");
+	}
 
+	e.velocity = '0 0 0';
+	e.fixangle = TRUE; // (e.health <= 0);
+
+	// TODO halt weapon animation
+}
+
+
 /*
 go to the next level for deathmatch
 only called if a time or frag limit has expired
@@ -941,13 +1008,7 @@
 
 	for(other = world; (other = findflags(other, flags, FL_CLIENT)); )
 	{
-		//other.nextthink = time + 0.5;
-		other.takedamage = DAMAGE_NO;
-		other.solid = SOLID_NOT;
-		other.movetype = MOVETYPE_NONE;
-		other.angles = other.v_angle;
-		other.angles_x = other.angles_x * -1;
-		other.autoscreenshot = time + 0.8;	// used for autoscreenshot
+		FixIntermissionClient(other);
 
 		self = other;
 
@@ -965,7 +1026,7 @@
 	if(cvar("g_campaign"))
 		CampaignPreIntermission();
 
-	WriteByte (MSG_ALL, SVC_INTERMISSION);
+	// WriteByte (MSG_ALL, SVC_INTERMISSION);
 };
 
 /*
@@ -1316,8 +1377,16 @@
 	return WinningConditionBase_Teamplay(fraglimit);
 }
 
-void PrintScoreboardFor(string name, string colorcode, float whichteam)
+void print_to(entity e, string s)
 {
+	if(e)
+		sprint(e, strcat(s, "\n"));
+	else
+		ServerConsoleEcho(s, TRUE);
+}
+
+void PrintScoreboardFor(entity e, string name, string colorcode, float whichteam)
+{
 	entity head;
 	float v;
 	float teamvalue;
@@ -1333,7 +1402,7 @@
 		{
 			if(name != "")
 				if(!found)
-					ServerConsoleEcho(strcat(" ", colorcode, name, ":"), FALSE);
+					print_to(e, strcat(" ", colorcode, name, ":"));
 			found = TRUE;
 			fragtotal = fragtotal + head.frags;
 			s = ftos(head.frags);
@@ -1346,7 +1415,7 @@
 			v = PlayerValue(head);
 			teamvalue += v;
 			s = strcat(s, " / ", ftos(v));
-			ServerConsoleEcho(strcat("  ", colorcode, head.netname, colorcode, " (", s, ")"), TRUE);
+			print_to(e, strcat("  ", colorcode, head.netname, colorcode, " (", s, ")"));
 		}
 		head = find(head, classname, "player");
 	}
@@ -1354,25 +1423,28 @@
 	{
 		s = ftos(fragtotal);
 		s = strcat(s, " / ", ftos(teamvalue));
-		ServerConsoleEcho(strcat(colorcode, "  (total: ", s, ")"), FALSE);
+		print_to(e, strcat(colorcode, "  (total: ", s, ")"));
 	}
 }
 
-void PrintScoreboard()
+void PrintScoreboard(entity e)
 {
-	ServerConsoleEcho("Scoreboard:", FALSE);
+	print_to(e, strcat("Time:      ", ftos(time / 60)));
+	print_to(e, strcat("Timelimit: ", ftos(cvar("timelimit"))));
+	print_to(e, strcat("Fraglimit: ", ftos(cvar("fraglimit"))));
+	print_to(e, "Scoreboard:");
 	if(teams_matter)
 	{
-		PrintScoreboardFor("Red", "^1", COLOR_TEAM1);
-		PrintScoreboardFor("Blue", "^4", COLOR_TEAM2);
-		PrintScoreboardFor("Pink", "^6", COLOR_TEAM3);
-		PrintScoreboardFor("Yellow", "^3", COLOR_TEAM4);
+		PrintScoreboardFor(e, "Red", "^1", COLOR_TEAM1);
+		PrintScoreboardFor(e, "Blue", "^4", COLOR_TEAM2);
+		PrintScoreboardFor(e, "Pink", "^6", COLOR_TEAM3);
+		PrintScoreboardFor(e, "Yellow", "^3", COLOR_TEAM4);
 	}
 	else
 	{
-		PrintScoreboardFor("", "^7", 0);
+		PrintScoreboardFor(e, "", "^7", 0);
 	}
-	ServerConsoleEcho(".", FALSE);
+	print_to(e, ".");
 }
 
 void RemoveFromMaplist(string m)
@@ -1444,6 +1516,22 @@
 		ServerConsoleEcho("Map already in list.", FALSE);
 }
 
+void MakeFirstInMaplist(string m)
+{
+	if(!TryFile(strcat("maps/", m, ".mapcfg")))
+	{
+		ServerConsoleEcho("Map not found.", FALSE);
+		return;
+	}
+
+	m = strzone(m);
+	RemoveFromMaplist(m);
+	cvar_set("g_maplist", strcat("'", m, "'", cvar_string("g_maplist")));
+	strunzone(m);
+
+	ServerConsoleEcho("Map added as first one.", FALSE);
+}
+
 void ShuffleMaplist()
 {
 	string result;
@@ -1491,6 +1579,11 @@
 		RemoveFromMaplist(cvar_string("_g_maplist_remove"));
 		cvar_set("_g_maplist_remove", "");
 	}
+	if(cvar_string("_g_maplist_putfirst") != "")
+	{
+		MakeFirstInMaplist(cvar_string("_g_maplist_putfirst"));
+		cvar_set("_g_maplist_putfirst", "");
+	}
 	if(cvar("_g_maplist_shufflenow") || (cvar("g_maplist_shuffle") && !cvar("_g_maplist_have_shuffled")))
 	{
 		ShuffleMaplist();
@@ -1523,7 +1616,8 @@
 	if (intermission_running)
 		if (time >= intermission_exittime + 60)
 		{
-			GotoNextMap();
+			if(!DoNextMapOverride())
+				GotoNextMap();
 			return;
 		}
 
@@ -1535,7 +1629,7 @@
 	if(cvar("_scoreboard"))
 	{
 		cvar_set("_scoreboard", "0");
-		PrintScoreboard();
+		PrintScoreboard(world);
 	}
 
 	HandleMaplistShuffleCommands();
@@ -1543,8 +1637,20 @@
 	timelimit = cvar("timelimit") * 60;
 	fraglimit = cvar("fraglimit");
 
-	if (timelimit && time >= timelimit)
-		InitiateOvertime();
+	if(checkrules_overtimeend)
+	{
+		if(!checkrules_overtimewarning)
+		{
+			checkrules_overtimewarning = TRUE;
+			//sound(world, CHAN_AUTO, "announcer/robotic/1minuteremains.ogg", 1, ATTN_NONE);
+			bcenterprint("^3Now playing ^1OVERTIME^3!\n\n^3Keep fragging until we have a ^1winner^3!");
+		}
+	}
+	else
+	{
+		if (timelimit && time >= timelimit)
+			InitiateOvertime();
+	}
 
 	if (checkrules_overtimeend && time >= checkrules_overtimeend)
 	{
@@ -1552,13 +1658,6 @@
 		return;
 	}
 
-	if(!checkrules_overtimewarning && checkrules_overtimeend)
-	{
-		checkrules_overtimewarning = TRUE;
-		//sound(world, CHAN_AUTO, "announcer/robotic/1minuteremains.ogg", 1, ATTN_NONE);
-		bcenterprint("^3Now playing ^1OVERTIME^3!\n\n^3Keep fragging until we have a ^1winner^3!");
-	}
-
 	if (!checkrules_oneminutewarning && timelimit > 0 && time > timelimit - 60)
 	{
 		checkrules_oneminutewarning = TRUE;
@@ -1599,9 +1698,351 @@
 		ClearWinners();
 
 	if(checkrules_overtimeend)
-		if(status != WINNING_NEVER)
+		if(status != WINNING_NEVER || time >= checkrules_overtimeend)
 			status = WINNING_YES;
 
 	if(status == WINNING_YES)
 		NextLevel();
 };
+
+float randsel_value;
+float randsel_priority;
+float randsel_count;
+void RandSel_Init()
+{
+	randsel_value = -1;
+	randsel_priority = -1;
+	randsel_count = -1;
+}
+void RandSel_Add(float priority, float value)
+{
+	if(priority > randsel_priority)
+	{
+		randsel_priority = priority;
+		randsel_value = value;
+		randsel_count = 1;
+	}
+	else if(priority == randsel_priority)
+	{
+		randsel_count += 1;
+		if(ceil(random() * randsel_count) == 1)
+			randsel_value = value;
+	}
+}
+
+float mapvote_nextthink;
+float mapvote_initialized;
+float mapvote_keeptwotime;
+float mapvote_timeout;
+string mapvote_message;
+
+#define MAPVOTE_COUNT 10
+float mapvote_count;
+string mapvote_maps[MAPVOTE_COUNT];
+float mapvote_maps_suggested[MAPVOTE_COUNT];
+string mapvote_suggestions[MAPVOTE_COUNT];
+float mapvote_suggestion_ptr;
+string mapvote_fillstr;
+float mapvote_maxlen;
+float mapvote_voters;
+float mapvote_votes[MAPVOTE_COUNT];
+.float mapvote;
+
+void MapVote_ClearAllVotes()
+{
+	for(other = world; (other = findflags(other, flags, FL_CLIENT)); )
+		other.mapvote = 0;
+}
+
+string MapVote_Suggest(string m)
+{
+	float i;
+	if(m == "")
+		return "That's not how to use this command.";
+	if(!cvar("g_maplist_votable_suggestions"))
+		return "Suggestions are not accepted on this server.";
+	if(mapvote_initialized)
+		return "Can't suggest - voting is already in progress!";
+	if(!TryFile(strcat("maps/", m, ".mapcfg")))
+		return "The map you suggested is not available on this server.";
+	for(i = 0; i < mapvote_suggestion_ptr; ++i)
+		if(mapvote_suggestions[i] == m)
+			return "This map was already suggested.";
+	if(mapvote_suggestion_ptr >= MAPVOTE_COUNT)
+	{
+		i = ceil(random() * mapvote_suggestion_ptr) - 1;
+	}
+	else
+	{
+		i = mapvote_suggestion_ptr;
+		mapvote_suggestion_ptr += 1;
+	}
+	if(mapvote_suggestions[i] != "")
+		strunzone(mapvote_suggestions[i]);
+	mapvote_suggestions[i] = strzone(m);
+	GameLogEcho(strcat(":vote:suggested:", m, ":", ftos(self.playerid), ":", self.netname), TRUE);
+	return "Suggestion accepted.";
+}
+
+void MapVote_Init()
+{
+	string nextMap;
+	float i, j;
+	float nmax, smax;
+
+	MapVote_ClearAllVotes();
+
+	nmax = min(MAPVOTE_COUNT, cvar("g_maplist_votable"));
+	smax = min(nmax, cvar("g_maplist_votable_suggestions"));
+	mapvote_count = 0;
+
+	for(i = 0; i < 100 && mapvote_count < smax; ++i)
+	{
+		nextMap = mapvote_suggestions[ceil(random() * mapvote_suggestion_ptr) - 1];
+		for(j = 0; j < mapvote_count; ++j)
+			if(mapvote_maps[j] == nextMap)
+			{
+				nextMap = "";
+				break;
+			}
+		if(nextMap != "")
+		{
+			if(strlen(nextMap) > mapvote_maxlen)
+				mapvote_maxlen = strlen(nextMap);
+			mapvote_maps[mapvote_count] = nextMap;
+			mapvote_maps_suggested[mapvote_count] = TRUE;
+			mapvote_count += 1;
+		}
+	}
+
+	for(i = 0; i < 100 && mapvote_count < nmax; ++i)
+	{
+		nextMap = GetNextMap();
+		for(j = 0; j < mapvote_count; ++j)
+			if(mapvote_maps[j] == nextMap)
+			{
+				nextMap = "";
+				break;
+			}
+		if(nextMap != "")
+		{
+			if(strlen(nextMap) > mapvote_maxlen)
+				mapvote_maxlen = strlen(nextMap);
+			mapvote_maps[mapvote_count] = strzone(nextMap);
+			mapvote_maps_suggested[mapvote_count] = FALSE;
+			mapvote_count += 1;
+		}
+	}
+
+	mapvote_fillstr = " ";
+	while(strlen(mapvote_fillstr) < mapvote_maxlen + 16)
+		mapvote_fillstr = strcat(mapvote_fillstr, mapvote_fillstr);
+	mapvote_fillstr = strzone(mapvote_fillstr);
+
+	mapvote_keeptwotime = time + cvar("g_maplist_votable_keeptwotime");
+	mapvote_timeout = time + cvar("g_maplist_votable_timeout");
+	if(mapvote_count < 3 || mapvote_keeptwotime <= time)
+		mapvote_keeptwotime = 0;
+	mapvote_message = "Choose a map and press its key!";
+}
+float MapVote_Finished(float mappos)
+{
+	string result;
+	float i;
+
+	result = strcat(":vote:finished:", mapvote_maps[mappos]);
+	result = strcat(result, ":", ftos(mapvote_votes[mappos]), "::");
+	for(i = 0; i < mapvote_count; ++i)
+		if(i != mappos)
+			if(mapvote_maps[i] != "")
+			{
+				result = strcat(result, ":", mapvote_maps[i]);
+				result = strcat(result, ":", ftos(mapvote_votes[i]));
+			}
+	GameLogEcho(result, FALSE);
+	if(mapvote_maps_suggested[mappos])
+		GameLogEcho(strcat(":vote:suggestion_accepted:", mapvote_maps[mappos]), FALSE);
+
+	for(other = world; (other = findflags(other, flags, FL_CLIENT)); ) if(clienttype(other) == CLIENTTYPE_REAL)
+		FixClientCvars(other);
+
+	Map_Goto_SetStr(mapvote_maps[mappos]);
+	Map_Goto();
+	return TRUE;
+}
+void MapVote_CheckRules_1()
+{
+	float i;
+
+	for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "")
+	{
+		dprint("Map ", ftos(i), ": "); dprint(mapvote_maps[i], "\n");
+		mapvote_votes[i] = 0;
+	}
+
+	mapvote_voters = 0;
+	for(other = world; (other = findflags(other, flags, FL_CLIENT)); ) if(clienttype(other) == CLIENTTYPE_REAL)
+	{
+		++mapvote_voters;
+		if(other.mapvote)
+		{
+			dprint("Player ", other.netname, " vote = ", ftos(other.mapvote - 1), "\n");
+			mapvote_votes[other.mapvote - 1] = mapvote_votes[other.mapvote - 1] + 1;
+		}
+	}
+}
+
+float MapVote_CheckRules_2()
+{
+	float i;
+	float firstPlace, secondPlace;
+	float firstPlaceVotes, secondPlaceVotes;
+	string result;
+
+	RandSel_Init();
+	for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "")
+		RandSel_Add(mapvote_votes[i], i);
+	firstPlace = randsel_value;
+	firstPlaceVotes = randsel_priority;
+	dprint("First place: ", ftos(firstPlace), "\n");
+	dprint("First place votes: ", ftos(firstPlaceVotes), "\n");
+
+	RandSel_Init();
+	for(i = 0; i < mapvote_count; ++i) if(mapvote_maps[i] != "")
+		if(i != firstPlace)
+			RandSel_Add(mapvote_votes[i], i);
+	secondPlace = randsel_value;
+	secondPlaceVotes = randsel_priority;
+	dprint("Second place: ", ftos(secondPlace), "\n");
+	dprint("Second place votes: ", ftos(secondPlaceVotes), "\n");
+
+	if(firstPlace == -1)
+		error("No first place in map vote... WTF?");
+
+	if(secondPlace == -1 || time > mapvote_timeout || (mapvote_voters - firstPlaceVotes) < firstPlaceVotes)
+		return MapVote_Finished(firstPlace);
+
+	if(mapvote_keeptwotime)
+		if(time > mapvote_keeptwotime || (mapvote_voters - firstPlaceVotes - secondPlaceVotes) < secondPlaceVotes)
+		{
+			mapvote_message = "Now decide between the TOP TWO!";
+			mapvote_keeptwotime = 0;
+			result = strcat(":vote:keeptwo:", mapvote_maps[firstPlace]);
+			result = strcat(result, ":", ftos(firstPlaceVotes));
+			result = strcat(result, ":", mapvote_maps[secondPlace]);
+			result = strcat(result, ":", ftos(secondPlaceVotes), "::");
+			for(i = 0; i < mapvote_count; ++i)
+				if(i != firstPlace)
+					if(i != secondPlace)
+						if(mapvote_maps[i] != "")
+						{
+							result = strcat(result, ":", mapvote_maps[i]);
+							result = strcat(result, ":", ftos(mapvote_votes[i]));
+							strunzone(mapvote_maps[i]);
+							mapvote_maps[i] = "";
+						}
+			GameLogEcho(result, FALSE);
+		}
+
+	return FALSE;
+}
+void MapVote_Tick()
+{
+	string msgstr;
+	string tmp;
+	float i;
+	float keeptwo;
+
+	keeptwo = mapvote_keeptwotime;
+	MapVote_CheckRules_1(); // count
+	if(MapVote_CheckRules_2()) // decide
+		return;
+
+	for(other = world; (other = findflags(other, flags, FL_CLIENT)); ) if(clienttype(other) == CLIENTTYPE_REAL)
+	{
+		// hide scoreboard again
+		if(other.health != 2342)
+		{
+			stuffcmd(other, "\nin_bind 7 1 \"impulse 1\"; in_bind 7 2 \"impulse 2\"; in_bind 7 3 \"impulse 3\"; in_bind 7 4 \"impulse 4\"; in_bind 7 5 \"impulse 5\"; in_bind 7 6 \"impulse 6\"; in_bind 7 7 \"impulse 7\"; in_bind 7 8 \"impulse 8\"; in_bind 7 9 \"impulse 9\"; in_bind 7 0 \"impulse 10\"; in_bind 7 KP_1 \"impulse 1\"; in_bind 7 KP_2 \"impulse 2\"; in_bind 7 KP_3 \"impulse 3\"; in_bind 7 KP_4 \"impulse 4\"; in_bind 7 KP_5 \"impulse 5\"; in_bind 7 KP_6 \"impulse 6\"; in_bind 7 KP_7 \"impulse 7\"; in_bind 7 KP_8 \"impulse 8\"; in_bind 7 KP_9 \"impulse 9\"; in_bind 7 KP_0 \"impulse 10\"; in_bindmap 7 0\n");
+			other.health = 2342;
+		}
+
+		// notify about keep-two
+		if(keeptwo != 0 && mapvote_keeptwotime == 0)
+			stuffcmd(other, "\nplay2 misc/invshot.wav\n");
+
+		// clear possibly invalid votes
+		if(mapvote_maps[other.mapvote - 1] == "")
+			other.mapvote = 0;
+		// use impulses as new vote
+		if(other.impulse >= 1 && other.impulse <= mapvote_count)
+			if(mapvote_maps[other.impulse - 1] != "")
+				other.mapvote = other.impulse;
+		other.impulse = 0;
+	}
+
+	MapVote_CheckRules_1(); // just count
+
+	for(other = world; (other = findflags(other, flags, FL_CLIENT)); ) if(clienttype(other) == CLIENTTYPE_REAL)
+	{
+		// display voting screen
+		msgstr = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
+		msgstr = substring(msgstr, 0, strlen(msgstr) - mapvote_count);
+		msgstr = strcat(msgstr, mapvote_message);
+		msgstr = strcat(msgstr, "\n\n");
+		for(i = 0; i < mapvote_count; ++i)
+			if(mapvote_maps[i] == "")
+				msgstr = strcat(msgstr, "\n");
+			else
+			{
+				tmp = mapvote_maps[i];
+				tmp = strcat(tmp, substring(mapvote_fillstr, 0, mapvote_maxlen  - strlen(tmp)));
+				tmp = strcat(ftos(math_mod(i + 1, 10)), ": ", tmp);
+				tmp = strcat(tmp, " ^2(", ftos(mapvote_votes[i]), " vote");
+				if(mapvote_votes[i] != 1)
+					tmp = strcat(tmp, "s");
+				tmp = strcat(tmp, ")");
+				tmp = strcat(tmp, substring(mapvote_fillstr, 0, mapvote_maxlen + 15 - strlen(tmp)));
+				if(other.mapvote == i + 1)
+					msgstr = strcat(msgstr, "^3> ", tmp, "\n");
+				else
+					msgstr = strcat(msgstr, "^7  ", tmp, "\n");
+			}
+		i = ceil(mapvote_timeout - time);
+		msgstr = strcat(msgstr, "\n\n", ftos(i), " second");
+		if(i != 1)
+			msgstr = strcat(msgstr, "s");
+		msgstr = strcat(msgstr, " left");
+
+		centerprint(other, msgstr);
+	}
+}
+void MapVote_Think()
+{
+	if(alreadychangedlevel)
+		return;
+	
+	if(time < mapvote_nextthink)
+		return;
+	dprint("tick\n");
+
+	mapvote_nextthink = time + 0.5;
+
+	if(!mapvote_initialized)
+	{
+		mapvote_initialized = TRUE;
+		if(DoNextMapOverride())
+		{
+			alreadychangedlevel = TRUE;
+			return;
+		}
+		if(!cvar("g_maplist_votable"))
+		{
+			GotoNextMap();
+			return;
+		}
+		MapVote_Init();
+	}
+
+	MapVote_Tick();
+};




More information about the nexuiz-commits mailing list