1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "g_local.h"
30 
31 
32 /*
33 =======================================================================
34 
35   SESSION DATA
36 
37 Session data is the only data that stays persistant across level loads
38 and tournament restarts.
39 =======================================================================
40 */
41 
42 /*
43 ================
44 G_WriteClientSessionData
45 
46 Called on game shutdown
47 ================
48 */
G_WriteClientSessionData(gclient_t * client)49 void G_WriteClientSessionData( gclient_t *client ) {
50 	const char  *s;
51 	const char  *var;
52 
53 	s = va( "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",       // DHM - Nerve
54 			client->sess.sessionTeam,
55 			client->sess.spectatorNum,
56 			client->sess.spectatorState,
57 			client->sess.spectatorClient,
58 			client->sess.wins,
59 			client->sess.losses,
60 			client->sess.playerType,        // DHM - Nerve
61 			client->sess.playerWeapon,      // DHM - Nerve
62 			client->sess.playerItem,        // DHM - Nerve
63 			client->sess.playerSkin,        // DHM - Nerve
64 			client->sess.spawnObjectiveIndex, // DHM - Nerve
65 			client->sess.latchPlayerType,   // DHM - Nerve
66 			client->sess.latchPlayerWeapon, // DHM - Nerve
67 			client->sess.latchPlayerItem,   // DHM - Nerve
68 			client->sess.latchPlayerSkin    // DHM - Nerve
69 			);
70 
71 	var = va( "session%i", (int)(client - level.clients) );
72 
73 	trap_Cvar_Set( var, s );
74 }
75 
76 /*
77 ================
78 G_ReadSessionData
79 
80 Called on a reconnect
81 ================
82 */
G_ReadSessionData(gclient_t * client)83 void G_ReadSessionData( gclient_t *client ) {
84 	char s[MAX_STRING_CHARS];
85 	const char  *var;
86 	qboolean test;
87 
88 	var = va( "session%i", (int)(client - level.clients) );
89 	trap_Cvar_VariableStringBuffer( var, s, sizeof( s ) );
90 
91 	sscanf( s, "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",       // DHM - Nerve
92 			(int *)&client->sess.sessionTeam,
93 			&client->sess.spectatorNum,
94 			(int *)&client->sess.spectatorState,
95 			&client->sess.spectatorClient,
96 			&client->sess.wins,
97 			&client->sess.losses,
98 			&client->sess.playerType,       // DHM - Nerve
99 			&client->sess.playerWeapon,     // DHM - Nerve
100 			&client->sess.playerItem,       // DHM - Nerve
101 			&client->sess.playerSkin,       // DHM - Nerve
102 			&client->sess.spawnObjectiveIndex, // DHM - Nerve
103 			&client->sess.latchPlayerType,  // DHM - Nerve
104 			&client->sess.latchPlayerWeapon, // DHM - Nerve
105 			&client->sess.latchPlayerItem,  // DHM - Nerve
106 			&client->sess.latchPlayerSkin   // DHM - Nerve
107 			);
108 
109 	// NERVE - SMF
110 	if ( g_altStopwatchMode.integer ) {
111 		test = qtrue;
112 	} else {
113 		test = g_currentRound.integer == 1;
114 	}
115 
116 	if ( g_gametype.integer == GT_WOLF_STOPWATCH && level.warmupTime > 0 && test ) {
117 		if ( client->sess.sessionTeam == TEAM_RED ) {
118 			client->sess.sessionTeam = TEAM_BLUE;
119 		} else if ( client->sess.sessionTeam == TEAM_BLUE )   {
120 			client->sess.sessionTeam = TEAM_RED;
121 		}
122 	}
123 
124 	if ( g_swapteams.integer ) {
125 		trap_Cvar_Set( "g_swapteams", "0" );
126 
127 		if ( client->sess.sessionTeam == TEAM_RED ) {
128 			client->sess.sessionTeam = TEAM_BLUE;
129 		} else if ( client->sess.sessionTeam == TEAM_BLUE )   {
130 			client->sess.sessionTeam = TEAM_RED;
131 		}
132 	}
133 }
134 
135 
136 /*
137 ================
138 G_InitSessionData
139 
140 Called on a first-time connect
141 ================
142 */
G_InitSessionData(gclient_t * client,char * userinfo)143 void G_InitSessionData( gclient_t *client, char *userinfo ) {
144 	clientSession_t *sess;
145 	const char      *value;
146 
147 	sess = &client->sess;
148 
149 	// check for team preference, mainly for bots
150 	value = Info_ValueForKey( userinfo, "teampref" );
151 
152 	// check for human's team preference set by start server menu
153 	if ( !value[0] && g_localTeamPref.string[0] /*&& client->pers.localClient*/ ) {
154 		value = g_localTeamPref.string;
155 
156 		// clear team so it's only used once
157 		trap_Cvar_Set( "g_localTeamPref", "" );
158 	}
159 
160 	// initial team determination
161 	if ( g_gametype.integer >= GT_TEAM ) {
162 		// always spawn as spectator in team games
163 		sess->sessionTeam = TEAM_SPECTATOR;
164 		sess->spectatorState = SPECTATOR_FREE;
165 
166 		if ( value[0] || g_teamAutoJoin.integer ) {
167 			SetTeam( &g_entities[client - level.clients], value );
168 		}
169 	} else {
170 		if ( value[0] == 's' ) {
171 			// a willing spectator, not a waiting-in-line
172 			sess->sessionTeam = TEAM_SPECTATOR;
173 		} else {
174 			switch ( g_gametype.integer ) {
175 			default:
176 			case GT_FFA:
177 			case GT_SINGLE_PLAYER:
178 				if ( g_maxGameClients.integer > 0 &&
179 					 level.numNonSpectatorClients >= g_maxGameClients.integer ) {
180 					sess->sessionTeam = TEAM_SPECTATOR;
181 				} else {
182 					sess->sessionTeam = TEAM_FREE;
183 				}
184 				break;
185 			case GT_TOURNAMENT:
186 				// if the game is full, go into a waiting mode
187 				if ( level.numNonSpectatorClients >= 2 ) {
188 					sess->sessionTeam = TEAM_SPECTATOR;
189 				} else {
190 					sess->sessionTeam = TEAM_FREE;
191 				}
192 				break;
193 			}
194 		}
195 
196 		sess->spectatorState = SPECTATOR_FREE;
197 	}
198 
199 	AddTournamentQueue(client);
200 
201 	// DHM - Nerve
202 	sess->latchPlayerType = sess->playerType = 0;
203 	sess->latchPlayerWeapon = sess->playerWeapon = 0;
204 	sess->latchPlayerItem = sess->playerItem = 0;
205 	sess->latchPlayerSkin = sess->playerSkin = 0;
206 
207 	sess->spawnObjectiveIndex = 0;
208 	// dhm - end
209 
210 	G_WriteClientSessionData( client );
211 }
212 
213 
214 /*
215 ==================
216 G_InitWorldSession
217 
218 ==================
219 */
G_InitWorldSession(void)220 void G_InitWorldSession( void ) {
221 	char s[MAX_STRING_CHARS];
222 	int gt;
223 
224 	trap_Cvar_VariableStringBuffer( "session", s, sizeof( s ) );
225 	gt = atoi( s );
226 
227 	// if the gametype changed since the last session, don't use any
228 	// client sessions
229 	if ( g_gametype.integer != gt ) {
230 		level.newSession = qtrue;
231 		G_Printf( "Gametype changed, clearing session data.\n" );
232 	}
233 }
234 
235 /*
236 ==================
237 G_WriteSessionData
238 
239 ==================
240 */
G_WriteSessionData(void)241 void G_WriteSessionData( void ) {
242 	int i;
243 
244 	trap_Cvar_Set( "session", va( "%i", g_gametype.integer ) );
245 
246 	for ( i = 0 ; i < level.maxclients ; i++ ) {
247 		if ( level.clients[i].pers.connected == CON_CONNECTED ) {
248 			G_WriteClientSessionData( &level.clients[i] );
249 		}
250 	}
251 }
252