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