1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein single player 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 single player GPL Source Code (“RTCW SP Source Code”).
8 
9 RTCW SP 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 SP 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 SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW SP 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 SP 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 /*
30  * name:		cg_consolecmds.c
31  *
32  * desc:		text commands typed in at the local console, or executed by a key binding
33  *
34 */
35 
36 
37 #include "cg_local.h"
38 #include "../ui/ui_shared.h"
39 
40 
41 
CG_TargetCommand_f(void)42 void CG_TargetCommand_f( void ) {
43 	int targetNum;
44 	char test[4];
45 
46 	targetNum = CG_CrosshairPlayer();
47 	if ( targetNum == -1 ) {
48 		return;
49 	}
50 
51 	trap_Argv( 1, test, 4 );
52 	trap_SendClientCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
53 }
54 
55 
56 
57 /*
58 =================
59 CG_SizeUp_f
60 
61 Keybinding command
62 =================
63 */
CG_SizeUp_f(void)64 static void CG_SizeUp_f( void ) {
65 	trap_Cvar_Set( "cg_viewsize", va( "%i",(int)( cg_viewsize.integer + 10 ) ) );
66 }
67 
68 
69 /*
70 =================
71 CG_SizeDown_f
72 
73 Keybinding command
74 =================
75 */
CG_SizeDown_f(void)76 static void CG_SizeDown_f( void ) {
77 	trap_Cvar_Set( "cg_viewsize", va( "%i",(int)( cg_viewsize.integer - 10 ) ) );
78 }
79 
80 
81 /*
82 =============
83 CG_Viewpos_f
84 
85 Debugging command to print the current position
86 =============
87 */
CG_Viewpos_f(void)88 static void CG_Viewpos_f( void ) {
89 	CG_Printf( "(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0],
90 			   (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2],
91 			   (int)cg.refdefViewAngles[YAW] );
92 }
93 
94 
CG_ScoresDown_f(void)95 static void CG_ScoresDown_f( void ) {
96 	if ( cg.scoresRequestTime + 2000 < cg.time ) {
97 		// the scores are more than two seconds out of data,
98 		// so request new ones
99 		cg.scoresRequestTime = cg.time;
100 		trap_SendClientCommand( "score" );
101 
102 		// leave the current scores up if they were already
103 		// displayed, but if this is the first hit, clear them out
104 		if ( !cg.showScores ) {
105 			cg.showScores = qtrue;
106 			cg.numScores = 0;
107 		}
108 	} else {
109 		// show the cached contents even if they just pressed if it
110 		// is within two seconds
111 		cg.showScores = qtrue;
112 	}
113 }
114 
CG_ScoresUp_f(void)115 static void CG_ScoresUp_f( void ) {
116 	if ( cg.showScores ) {
117 		cg.showScores = qfalse;
118 		cg.scoreFadeTime = cg.time;
119 	}
120 }
121 
122 
123 extern menuDef_t *menuScoreboard;
124 void Menu_Reset( void );          // FIXME: add to right include file
125 
CG_LoadHud_f(void)126 static void CG_LoadHud_f( void ) {
127 	char buff[1024];
128 	const char *hudSet;
129 	memset( buff, 0, sizeof( buff ) );
130 
131 	String_Init();
132 	Menu_Reset();
133 
134 	trap_Cvar_VariableStringBuffer( "cg_hudFiles", buff, sizeof( buff ) );
135 	hudSet = buff;
136 	if ( hudSet[0] == '\0' ) {
137 		hudSet = "ui/hud.txt";
138 	}
139 
140 	CG_LoadMenus( hudSet );
141 	menuScoreboard = NULL;
142 }
143 
144 // TTimo: defined but not used
145 /*
146 static void CG_scrollScoresDown_f( void) {
147 	if (menuScoreboard && cg.scoreBoardShowing) {
148 		Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qtrue);
149 		Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qtrue);
150 		Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qtrue);
151 	}
152 }
153 
154 
155 static void CG_scrollScoresUp_f( void) {
156 	if (menuScoreboard && cg.scoreBoardShowing) {
157 		Menu_ScrollFeeder(menuScoreboard, FEEDER_SCOREBOARD, qfalse);
158 		Menu_ScrollFeeder(menuScoreboard, FEEDER_REDTEAM_LIST, qfalse);
159 		Menu_ScrollFeeder(menuScoreboard, FEEDER_BLUETEAM_LIST, qfalse);
160 	}
161 }
162 
163 
164 static void CG_spWin_f( void) {
165 	trap_Cvar_Set("cg_cameraOrbit", "2");
166 	trap_Cvar_Set("cg_cameraOrbitDelay", "35");
167 	trap_Cvar_Set("cg_thirdPerson", "1");
168 	trap_Cvar_Set("cg_thirdPersonAngle", "0");
169 	trap_Cvar_Set("cg_thirdPersonRange", "100");
170 //	CG_AddBufferedSound(cgs.media.winnerSound);
171 	//trap_S_StartLocalSound(cgs.media.winnerSound, CHAN_ANNOUNCER);
172 	CG_CenterPrint("YOU WIN!", SCREEN_HEIGHT * .30, 0);
173 }
174 
175 static void CG_spLose_f( void) {
176 	trap_Cvar_Set("cg_cameraOrbit", "2");
177 	trap_Cvar_Set("cg_cameraOrbitDelay", "35");
178 	trap_Cvar_Set("cg_thirdPerson", "1");
179 	trap_Cvar_Set("cg_thirdPersonAngle", "0");
180 	trap_Cvar_Set("cg_thirdPersonRange", "100");
181 //	CG_AddBufferedSound(cgs.media.loserSound);
182 	//trap_S_StartLocalSound(cgs.media.loserSound, CHAN_ANNOUNCER);
183 	CG_CenterPrint("YOU LOSE...", SCREEN_HEIGHT * .30, 0);
184 }
185 */
186 
187 //----(SA)	item (key/pickup) drawing
CG_InventoryDown_f(void)188 static void CG_InventoryDown_f( void ) {
189 	cg.showItems = qtrue;
190 }
191 
CG_InventoryUp_f(void)192 static void CG_InventoryUp_f( void ) {
193 	cg.showItems = qfalse;
194 	cg.itemFadeTime = cg.time;
195 }
196 
197 //----(SA)	end
198 
CG_TellTarget_f(void)199 static void CG_TellTarget_f( void ) {
200 	int clientNum;
201 	char command[128];
202 	char message[128];
203 
204 	clientNum = CG_CrosshairPlayer();
205 	if ( clientNum == -1 ) {
206 		return;
207 	}
208 
209 	trap_Args( message, 128 );
210 	Com_sprintf( command, 128, "tell %i %s", clientNum, message );
211 	trap_SendClientCommand( command );
212 }
213 
CG_TellAttacker_f(void)214 static void CG_TellAttacker_f( void ) {
215 	int clientNum;
216 	char command[128];
217 	char message[128];
218 
219 	clientNum = CG_LastAttacker();
220 	if ( clientNum == -1 ) {
221 		return;
222 	}
223 
224 	trap_Args( message, 128 );
225 	Com_sprintf( command, 128, "tell %i %s", clientNum, message );
226 	trap_SendClientCommand( command );
227 }
228 
229 
230 // TTimo: defined but not used
231 /*
232 static void CG_NextTeamMember_f( void ) {
233   CG_SelectNextPlayer();
234 }
235 
236 static void CG_PrevTeamMember_f( void ) {
237   CG_SelectPrevPlayer();
238 }
239 */
240 
241 /////////// cameras
242 
243 #define MAX_CAMERAS 64  // matches define in splines.cpp
244 qboolean cameraInuse[MAX_CAMERAS];
245 
CG_LoadCamera(const char * name)246 int CG_LoadCamera( const char *name ) {
247 	int i;
248 	for ( i = 1; i < MAX_CAMERAS; i++ ) {    // start at '1' since '0' is always taken by the cutscene camera
249 		if ( !cameraInuse[i] ) {
250 			if ( trap_loadCamera( i, name ) ) {
251 				cameraInuse[i] = qtrue;
252 				return i;
253 			}
254 		}
255 	}
256 	return -1;
257 }
258 
CG_FreeCamera(int camNum)259 void CG_FreeCamera( int camNum ) {
260 	cameraInuse[camNum] = qfalse;
261 }
262 
263 /*
264 ==============
265 CG_StartCamera
266 ==============
267 */
CG_StartCamera(const char * name,qboolean startBlack)268 void CG_StartCamera( const char *name, qboolean startBlack ) {
269 	char lname[MAX_QPATH];
270 
271 	//if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 )	// don't allow camera to start if you're dead
272 	//	return;
273 
274 	COM_StripExtension( name, lname, sizeof( lname ) );    //----(SA)	added
275 	Q_strcat( lname, sizeof( lname ), ".camera" );
276 
277 	if ( trap_loadCamera( CAM_PRIMARY, va( "cameras/%s", lname ) ) ) {
278 		cg.cameraMode = qtrue;				// camera on in cgame
279 		if ( startBlack ) {
280 			CG_Fade( 0, 0, 0, 255, cg.time, 0 );		// go black
281 		}
282 		trap_Cvar_Set( "cg_letterbox", "1" ); // go letterbox
283 		trap_SendClientCommand( "startCamera" );	// camera on in game
284 		trap_startCamera( CAM_PRIMARY, cg.time );	// camera on in client
285 	} else {
286 		//----(SA)	removed check for cams in main dir
287 		cg.cameraMode = qfalse;                 // camera off in cgame
288 		trap_SendClientCommand( "stopCamera" );    // camera off in game
289 		trap_stopCamera( CAM_PRIMARY );           // camera off in client
290 		CG_Fade( 0, 0, 0, 0, cg.time, 0 );        // ensure fadeup
291 		trap_Cvar_Set( "cg_letterbox", "0" );
292 		CG_Printf( "Unable to load camera %s\n",lname );
293 	}
294 }
295 
296 /*
297 ==============
298 CG_StopCamera
299 ==============
300 */
CG_StopCamera(void)301 void CG_StopCamera( void ) {
302 	cg.cameraMode = qfalse;                 // camera off in cgame
303 	trap_SendClientCommand( "stopCamera" );    // camera off in game
304 	trap_stopCamera( CAM_PRIMARY );           // camera off in client
305 	trap_Cvar_Set( "cg_letterbox", "0" );
306 
307 	// fade back into world
308 	CG_Fade( 0, 0, 0, 255, 0, 0 );
309 	CG_Fade( 0, 0, 0, 0, cg.time + 500, 2000 );
310 
311 }
312 
CG_Camera_f(void)313 static void CG_Camera_f( void ) {
314 	char name[MAX_QPATH];
315 
316 	trap_Argv( 1, name, sizeof( name ) );
317 
318 	CG_StartCamera( name, qfalse );
319 }
320 
CG_Fade_f(void)321 static void CG_Fade_f( void ) {
322 	int r, g, b, a;
323 	float duration;
324 
325 	if ( trap_Argc() < 6 ) {
326 		return;
327 	}
328 
329 	r = atof( CG_Argv( 1 ) );
330 	g = atof( CG_Argv( 2 ) );
331 	b = atof( CG_Argv( 3 ) );
332 	a = atof( CG_Argv( 4 ) );
333 
334 	duration = atof( CG_Argv( 5 ) ) * 1000;
335 
336 	CG_Fade( r, g, b, a, cg.time, duration );
337 }
338 
339 // NERVE - SMF
CG_QuickMessage_f(void)340 static void CG_QuickMessage_f( void ) {
341 	if ( cgs.gametype != GT_WOLF ) {
342 		return;
343 	}
344 	trap_UI_Popup( "UIMENU_WM_QUICKMESSAGE" );
345 }
346 
CG_OpenLimbo_f(void)347 static void CG_OpenLimbo_f( void ) {
348 	if ( cgs.gametype != GT_WOLF ) {
349 		return;
350 	}
351 	trap_UI_Popup( "UIMENU_WM_LIMBO" );
352 }
353 
CG_CloseLimbo_f(void)354 static void CG_CloseLimbo_f( void ) {
355 	if ( cgs.gametype != GT_WOLF ) {
356 		return;
357 	}
358 	trap_UI_ClosePopup( "UIMENU_WM_LIMBO" );
359 }
360 
CG_LimboMessage_f(void)361 static void CG_LimboMessage_f( void ) {
362 	char teamStr[80], classStr[80], weapStr[80];
363 
364 	if ( cgs.gametype != GT_WOLF ) {
365 		return;
366 	}
367 
368 	Q_strncpyz( teamStr, CG_Argv( 1 ), 80 );
369 	Q_strncpyz( classStr, CG_Argv( 2 ), 80 );
370 	Q_strncpyz( weapStr, CG_Argv( 3 ), 80 );
371 
372 	CG_CenterPrint( va( "You will spawn as a %s \n%s with a %s.", teamStr, classStr, weapStr ),
373 					SCREEN_HEIGHT - ( SCREEN_HEIGHT * 0.25 ), SMALLCHAR_WIDTH );
374 }
375 // -NERVE - SMF
376 
377 typedef struct {
378 	char    *cmd;
379 	void ( *function )( void );
380 } consoleCommand_t;
381 
382 static consoleCommand_t commands[] = {
383 	{ "testgun", CG_TestGun_f },
384 	{ "testmodel", CG_TestModel_f },
385 	{ "nextframe", CG_TestModelNextFrame_f },
386 	{ "prevframe", CG_TestModelPrevFrame_f },
387 	{ "nextskin", CG_TestModelNextSkin_f },
388 	{ "prevskin", CG_TestModelPrevSkin_f },
389 	{ "viewpos", CG_Viewpos_f },
390 	{ "+scores", CG_ScoresDown_f },
391 	{ "-scores", CG_ScoresUp_f },
392 	{ "+inventory", CG_InventoryDown_f },
393 	{ "-inventory", CG_InventoryUp_f },
394 //	{ "+zoom", CG_ZoomDown_f },		// (SA) zoom moved to a wbutton so server can determine weapon firing based on zoom status
395 //	{ "-zoom", CG_ZoomUp_f },
396 	{ "zoomin", CG_ZoomIn_f },
397 	{ "zoomout", CG_ZoomOut_f },
398 	{ "sizeup", CG_SizeUp_f },
399 	{ "sizedown", CG_SizeDown_f },
400 	{ "weaplastused", CG_LastWeaponUsed_f },
401 	{ "weapnextinbank", CG_NextWeaponInBank_f },
402 	{ "weapprevinbank", CG_PrevWeaponInBank_f },
403 	{ "weapnext", CG_NextWeapon_f },
404 	{ "weapprev", CG_PrevWeapon_f },
405 	{ "weapalt", CG_AltWeapon_f },
406 	{ "weapon", CG_Weapon_f },
407 	{ "weaponbank", CG_WeaponBank_f },
408 	{ "itemnext", CG_NextItem_f },
409 	{ "itemprev", CG_PrevItem_f },
410 	{ "item", CG_Item_f },
411 	{ "tell_target", CG_TellTarget_f },
412 	{ "tell_attacker", CG_TellAttacker_f },
413 	{ "tcmd", CG_TargetCommand_f },
414 	{ "loadhud", CG_LoadHud_f },
415 	{ "loaddeferred", CG_LoadDeferredPlayers },  // spelling fixed (SA)
416 	{ "camera", CG_Camera_f },   // duffy
417 	{ "fade", CG_Fade_f },   // duffy
418 
419 	// NERVE - SMF
420 	{ "mp_QuickMessage", CG_QuickMessage_f },
421 	{ "OpenLimboMenu", CG_OpenLimbo_f },
422 	{ "CloseLimboMenu", CG_CloseLimbo_f },
423 	{ "LimboMessage", CG_LimboMessage_f }
424 	// -NERVE - SMF
425 };
426 
427 
428 /*
429 =================
430 CG_ConsoleCommand
431 
432 The string has been tokenized and can be retrieved with
433 Cmd_Argc() / Cmd_Argv()
434 =================
435 */
CG_ConsoleCommand(void)436 qboolean CG_ConsoleCommand( void ) {
437 	const char  *cmd;
438 	int i;
439 
440 	cmd = CG_Argv( 0 );
441 
442 	for ( i = 0 ; i < ARRAY_LEN( commands ) ; i++ ) {
443 		if ( !Q_stricmp( cmd, commands[i].cmd ) ) {
444 			commands[i].function();
445 			return qtrue;
446 		}
447 	}
448 
449 	return qfalse;
450 }
451 
452 
453 /*
454 =================
455 CG_InitConsoleCommands
456 
457 Let the client system know about all of our commands
458 so it can perform tab completion
459 =================
460 */
CG_InitConsoleCommands(void)461 void CG_InitConsoleCommands( void ) {
462 	int i;
463 
464 	for ( i = 0 ; i < ARRAY_LEN( commands ) ; i++ ) {
465 		trap_AddCommand( commands[i].cmd );
466 	}
467 
468 	//
469 	// the game server will interpret these commands, which will be automatically
470 	// forwarded to the server after they are not recognized locally
471 	//
472 	trap_AddCommand( "kill" );
473 	trap_AddCommand( "say" );
474 	trap_AddCommand( "say_team" );
475 	trap_AddCommand( "say_limbo" );           // NERVE - SMF
476 	trap_AddCommand( "tell" );
477 //	trap_AddCommand( "vsay" );
478 //	trap_AddCommand( "vsay_team" );
479 //	trap_AddCommand( "vtell" );
480 //	trap_AddCommand( "vtaunt" );
481 //	trap_AddCommand( "vosay" );
482 //	trap_AddCommand( "vosay_team" );
483 //	trap_AddCommand( "votell" );
484 	trap_AddCommand( "give" );
485 	trap_AddCommand( "god" );
486 	trap_AddCommand( "notarget" );
487 	trap_AddCommand( "noclip" );
488 	trap_AddCommand( "where" );
489 	trap_AddCommand( "team" );
490 	trap_AddCommand( "follow" );
491 	trap_AddCommand( "follownext" );
492 	trap_AddCommand( "followprev" );
493 	trap_AddCommand( "levelshot" );
494 	trap_AddCommand( "addbot" );
495 	trap_AddCommand( "setviewpos" );
496 	trap_AddCommand( "callvote" );
497 	trap_AddCommand( "vote" );
498 //	trap_AddCommand( "callteamvote" );
499 //	trap_AddCommand( "teamvote" );
500 	trap_AddCommand( "stats" );
501 //	trap_AddCommand( "teamtask" );
502 	trap_AddCommand( "loaddeferred" );        // spelling fixed (SA)
503 
504 	trap_AddCommand( "startCamera" );
505 	trap_AddCommand( "stopCamera" );
506 	trap_AddCommand( "setCameraOrigin" );
507 
508 	// Rafael
509 	trap_AddCommand( "nofatigue" );
510 
511 	// NERVE - SMF
512 	trap_AddCommand( "setspawnpt" );
513 	// NERVE - SMF
514 }
515