1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 #include "g_headers.h"
25 
26 #include "g_local.h"
27 #include "objectives.h"
28 #include "wp_saber.h"
29 
30 extern	bool		in_camera;
31 
32 extern void ForceThrow( gentity_t *self, qboolean pull );
33 extern void ForceLevitation( gentity_t *self );
34 extern void ForceLightning( gentity_t *self );
35 extern void ForceHeal( gentity_t *self );
36 extern void ForceGrip( gentity_t *self );
37 extern void ForceTelepathy( gentity_t *self );
38 extern void G_ActivatePersonalShield( gentity_t *ent );
39 extern void G_ActivateSeeker( gentity_t *ent );
40 extern void G_PilotXWing( gentity_t *ent );
41 extern void G_DriveATST( gentity_t *ent, gentity_t *atst );
42 extern void G_StartMatrixEffect( gentity_t *ent, qboolean falling = qfalse, int length = 1000 );
43 extern void ItemUse_Bacta(gentity_t *ent);
44 extern gentity_t *G_GetSelfForPlayerCmd( void );
45 
46 /*
47 ==================
48 CheatsOk
49 ==================
50 */
CheatsOk(gentity_t * ent)51 qboolean	CheatsOk( gentity_t *ent ) {
52 	if ( !g_cheats->integer ) {
53 		gi.SendServerCommand( ent-g_entities, "print \"Cheats are not enabled on this server.\n\"");
54 		return qfalse;
55 	}
56 	if ( ent->health <= 0 ) {
57 		gi.SendServerCommand( ent-g_entities, "print \"You must be alive to use this command.\n\"");
58 		return qfalse;
59 	}
60 	return qtrue;
61 }
62 
63 
64 /*
65 ==================
66 ConcatArgs
67 ==================
68 */
ConcatArgs(int start)69 char	*ConcatArgs( int start ) {
70 	int		i, c, tlen;
71 	static char	line[MAX_STRING_CHARS];
72 	int		len;
73 	const char	*arg;
74 
75 	len = 0;
76 	c = gi.argc();
77 	for ( i = start ; i < c ; i++ ) {
78 		arg = gi.argv( i );
79 		tlen = strlen( arg );
80 		if ( len + tlen >= MAX_STRING_CHARS - 1 ) {
81 			break;
82 		}
83 		memcpy( line + len, arg, tlen );
84 		len += tlen;
85 		if ( i != c - 1 ) {
86 			line[len] = ' ';
87 			len++;
88 		}
89 	}
90 
91 	line[len] = 0;
92 
93 	return line;
94 }
95 
96 /*
97 ==================
98 SanitizeString
99 
100 Remove case and control characters
101 ==================
102 */
SanitizeString(char * in,char * out)103 void SanitizeString( char *in, char *out ) {
104 	while ( *in ) {
105 		if ( *in == 94 ) {
106 			in += 2;		// skip color code
107 			continue;
108 		}
109 		if ( *in < 32 ) {
110 			in++;
111 			continue;
112 		}
113 		*out++ = tolower( *in++ );
114 	}
115 
116 	*out = 0;
117 }
118 
119 /*
120 ==================
121 ClientNumberFromString
122 
123 Returns a player number for either a number or name string
124 Returns -1 if invalid
125 ==================
126 */
ClientNumberFromString(gentity_t * to,char * s)127 int ClientNumberFromString( gentity_t *to, char *s ) {
128 	gclient_t	*cl;
129 	int			idnum;
130 	char		s2[MAX_STRING_CHARS];
131 	char		n2[MAX_STRING_CHARS];
132 
133 	// numeric values are just slot numbers
134 	if (s[0] >= '0' && s[0] <= '9') {
135 		idnum = atoi( s );
136 		if ( idnum < 0 || idnum >= level.maxclients ) {
137 			gi.SendServerCommand( to-g_entities, "print \"Bad client slot: %i\n\"", idnum);
138 			return -1;
139 		}
140 
141 		cl = &level.clients[idnum];
142 		if ( cl->pers.connected != CON_CONNECTED ) {
143 			gi.SendServerCommand( to-g_entities, "print \"Client %i is not active\n\"", idnum);
144 			return -1;
145 		}
146 		return idnum;
147 	}
148 
149 	// check for a name match
150 	SanitizeString( s, s2 );
151 	for ( idnum=0,cl=level.clients ; idnum < level.maxclients ; idnum++,cl++ ) {
152 		if ( cl->pers.connected != CON_CONNECTED ) {
153 			continue;
154 		}
155 		SanitizeString( cl->pers.netname, n2 );
156 		if ( !strcmp( n2, s2 ) ) {
157 			return idnum;
158 		}
159 	}
160 
161 	gi.SendServerCommand( to-g_entities, "print \"User %s is not on the server\n\"", s);
162 	return -1;
163 }
164 
G_Give(gentity_t * ent,const char * name,const char * args,int argc)165 void G_Give( gentity_t *ent, const char *name, const char *args, int argc )
166 {
167 	gitem_t		*it;
168 	int			i;
169 	qboolean	give_all = qfalse;
170 
171 	if ( !Q_stricmp( name, "all" ) )
172 		give_all = qtrue;
173 
174 	if ( give_all || !Q_stricmp( name, "health") )
175 	{
176 		if ( argc == 3 )
177 			ent->health = Com_Clampi( 1, ent->client->ps.stats[STAT_MAX_HEALTH], atoi( args ) );
178 		else
179 			ent->health = ent->client->ps.stats[STAT_MAX_HEALTH];
180 		if ( !give_all )
181 			return;
182 	}
183 
184 	if ( give_all || !Q_stricmp( name, "armor" ) || !Q_stricmp( name, "shield" ) )
185 	{
186 		if ( argc == 3 )
187 			ent->client->ps.stats[STAT_ARMOR] = Com_Clampi( 0, ent->client->ps.stats[STAT_MAX_HEALTH], atoi( args ) );
188 		else
189 			ent->client->ps.stats[STAT_ARMOR] = ent->client->ps.stats[STAT_MAX_HEALTH];
190 
191 		if ( ent->client->ps.stats[STAT_ARMOR] > 0 )
192 			ent->client->ps.powerups[PW_BATTLESUIT] = Q3_INFINITE;
193 		else
194 			ent->client->ps.powerups[PW_BATTLESUIT] = 0;
195 
196 		if ( !give_all )
197 			return;
198 	}
199 
200 	if ( give_all || !Q_stricmp( name, "force" ) )
201 	{
202 		if ( argc == 3 )
203 			ent->client->ps.forcePower = Com_Clampi( 0, FORCE_POWER_MAX, atoi( args ) );
204 		else
205 			ent->client->ps.forcePower = FORCE_POWER_MAX;
206 
207 		if ( !give_all )
208 			return;
209 	}
210 
211 	if ( give_all || !Q_stricmp( name, "weapons" ) )
212 	{
213 		ent->client->ps.stats[STAT_WEAPONS] = (1 << (MAX_PLAYER_WEAPONS+1)) - ( 1 << WP_NONE );
214 		if ( !give_all )
215 			return;
216 	}
217 
218 	if ( !give_all && !Q_stricmp( name, "weaponnum" ) )
219 	{
220 		ent->client->ps.stats[STAT_WEAPONS] |= (1 << atoi( args ));
221 		return;
222 	}
223 
224 	if ( !give_all && !Q_stricmp( name, "eweaps" ) )	//for developing, gives you all the weapons, including enemy
225 	{
226 		ent->client->ps.stats[STAT_WEAPONS] = (unsigned)(1 << WP_NUM_WEAPONS) - ( 1 << WP_NONE ); // NOTE: this wasn't giving the last weapon in the list
227 		return;
228 	}
229 
230 	if ( give_all || !Q_stricmp( name, "ammo" ) )
231 	{
232 		int num = 999;
233 		if ( argc == 3 )
234 			num = Com_Clampi( -1, 999, atoi( args ) );
235 		for ( i=AMMO_BLASTER; i<AMMO_MAX; i++ )
236 			ent->client->ps.ammo[i] = num != -1 ? num : ammoData[i].max;
237 		if ( !give_all )
238 			return;
239 	}
240 
241 	if ( give_all || !Q_stricmp( name, "batteries" ) )
242 	{
243 		if ( argc == 3 )
244 			ent->client->ps.batteryCharge = Com_Clampi( 0, MAX_BATTERIES, atoi( args ) );
245 		else
246 			ent->client->ps.batteryCharge = MAX_BATTERIES;
247 
248 		if ( !give_all )
249 			return;
250 	}
251 
252 	if ( give_all || !Q_stricmp( name, "inventory" ) )
253 	{
254 		// Huh?  Was doing a INV_MAX+1 which was wrong because then you'd actually have every inventory item including INV_MAX
255 		ent->client->ps.stats[STAT_ITEMS] = (1 << (INV_MAX)) - ( 1 << INV_ELECTROBINOCULARS );
256 
257 		ent->client->ps.inventory[INV_ELECTROBINOCULARS] = 1;
258 		ent->client->ps.inventory[INV_BACTA_CANISTER] = 5;
259 		ent->client->ps.inventory[INV_SEEKER] = 5;
260 		ent->client->ps.inventory[INV_LIGHTAMP_GOGGLES] = 1;
261 		ent->client->ps.inventory[INV_SENTRY] = 5;
262 		ent->client->ps.inventory[INV_GOODIE_KEY] = 5;
263 		ent->client->ps.inventory[INV_SECURITY_KEY] = 5;
264 
265 		if ( !give_all )
266 			return;
267 	}
268 
269 	// spawn a specific item right on the player
270 	if ( !give_all ) {
271 		gentity_t	*it_ent;
272 		trace_t		trace;
273 		it = FindItem (args);
274 		if (!it) {
275 			it = FindItem (name);
276 			if (!it) {
277 				gi.SendServerCommand( ent-g_entities, "print \"unknown item\n\"");
278 				return;
279 			}
280 		}
281 
282 		it_ent = G_Spawn();
283 		VectorCopy( ent->currentOrigin, it_ent->s.origin );
284 		it_ent->classname = G_NewString(it->classname);
285 		G_SpawnItem (it_ent, it);
286 		FinishSpawningItem(it_ent );
287 		memset( &trace, 0, sizeof( trace ) );
288 		Touch_Item (it_ent, ent, &trace);
289 		if (it_ent->inuse) {
290 			G_FreeEntity( it_ent );
291 		}
292 	}
293 }
294 
Cmd_Give_f(gentity_t * ent)295 void Cmd_Give_f( gentity_t *ent )
296 {
297 	if ( !CheatsOk( ent ) ) {
298 		return;
299 	}
300 
301 	G_Give( ent, gi.argv(1), ConcatArgs( 2 ), gi.argc() );
302 }
303 
304 //------------------
Cmd_Fx(gentity_t * ent)305 void Cmd_Fx( gentity_t *ent )
306 {
307 	vec3_t		dir;
308 	gentity_t	*fx_ent = NULL;
309 
310 	if ( Q_stricmp( gi.argv(1), "play" ) == 0 )
311 	{
312 		if ( gi.argc() == 3 )
313 		{
314 			// I guess, only allow one active at a time
315 			while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL )
316 			{
317 				G_FreeEntity( fx_ent );
318 			}
319 
320 			fx_ent = G_Spawn();
321 
322 			fx_ent->fxFile = gi.argv( 2 );
323 
324 			// Move out in front of the person spawning the effect
325 			AngleVectors( ent->currentAngles, dir, NULL, NULL );
326 			VectorMA( ent->currentOrigin, 32, dir, fx_ent->s.origin );
327 
328 extern void SP_fx_runner( gentity_t *ent );
329 
330 			SP_fx_runner( fx_ent );
331 			fx_ent->delay = 2000;			// adjusting delay
332 			fx_ent->classname = "cmd_fx";	//	and classname
333 
334 			return;
335 		}
336 	}
337 	else if ( Q_stricmp( gi.argv(1), "stop" ) == 0 )
338 	{
339 		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL )
340 		{
341 			G_FreeEntity( fx_ent );
342 		}
343 
344 		return;
345 	}
346 	else if ( Q_stricmp( gi.argv(1), "delay" ) == 0 )
347 	{
348 		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL )
349 		{
350 			if ( gi.argc() == 3 )
351 			{
352 				fx_ent->delay = atoi( gi.argv( 2 ));
353 			}
354 			else
355 			{
356 				gi.Printf( S_COLOR_GREEN"FX: current delay is: %i\n", fx_ent->delay );
357 			}
358 
359 			return;
360 		}
361 	}
362 	else if ( Q_stricmp( gi.argv(1), "random" ) == 0 )
363 	{
364 		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL )
365 		{
366 			if ( gi.argc() == 3 )
367 			{
368 				fx_ent->random = atoi( gi.argv( 2 ));
369 			}
370 			else
371 			{
372 				gi.Printf( S_COLOR_GREEN"FX: current random is: %6.2f\n", fx_ent->random );
373 			}
374 
375 			return;
376 		}
377 	}
378 	else if ( Q_stricmp( gi.argv(1), "origin" ) == 0 )
379 	{
380 		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL )
381 		{
382 			if ( gi.argc() == 5 )
383 			{
384 				fx_ent->s.origin[0] = atof( gi.argv( 2 ));
385 				fx_ent->s.origin[1] = atof( gi.argv( 3 ));
386 				fx_ent->s.origin[2] = atof( gi.argv( 4 ));
387 
388 				G_SetOrigin( fx_ent, fx_ent->s.origin );
389 			}
390 			else
391 			{
392 				gi.Printf( S_COLOR_GREEN"FX: current origin is: <%6.2f %6.2f %6.2f>\n",
393 									fx_ent->currentOrigin[0], fx_ent->currentOrigin[1], fx_ent->currentOrigin[2] );
394 			}
395 
396 			return;
397 		}
398 	}
399 	else if ( Q_stricmp( gi.argv(1), "dir" ) == 0 )
400 	{
401 		while (( fx_ent = G_Find( fx_ent, FOFS(classname), "cmd_fx")) != NULL )
402 		{
403 			if ( gi.argc() == 5 )
404 			{
405 				fx_ent->s.angles[0] = atof( gi.argv( 2 ));
406 				fx_ent->s.angles[1] = atof( gi.argv( 3 ));
407 				fx_ent->s.angles[2] = atof( gi.argv( 4 ));
408 
409 				if ( !VectorNormalize( fx_ent->s.angles ))
410 				{
411 					// must have been zero length
412 					fx_ent->s.angles[2] = 1;
413 				}
414 			}
415 			else
416 			{
417 				gi.Printf( S_COLOR_GREEN"FX: current dir is: <%6.2f %6.2f %6.2f>\n",
418 									fx_ent->s.angles[0], fx_ent->s.angles[1], fx_ent->s.angles[2] );
419 			}
420 
421 			return;
422 		}
423 	}
424 
425 	gi.Printf( S_COLOR_CYAN"Fx--------------------------------------------------------\n" );
426 	gi.Printf( S_COLOR_CYAN"commands:              sample usage:\n" );
427 	gi.Printf( S_COLOR_CYAN"----------------------------------------------------------\n" );
428 	gi.Printf( S_COLOR_CYAN"fx play <filename>     fx play sparks, fx play env/fire\n" );
429 	gi.Printf( S_COLOR_CYAN"fx stop                fx stop\n" );
430 	gi.Printf( S_COLOR_CYAN"fx delay <#>           fx delay 1000\n" );
431 	gi.Printf( S_COLOR_CYAN"fx random <#>          fx random 200\n" );
432 	gi.Printf( S_COLOR_CYAN"fx origin <#><#><#>    fx origin 10 20 30\n" );
433 	gi.Printf( S_COLOR_CYAN"fx dir <#><#><#>       fx dir 0 0 -1\n\n" );
434 }
435 
436 /*
437 ==================
438 Cmd_God_f
439 
440 Sets client to godmode
441 
442 argv(0) god
443 ==================
444 */
Cmd_God_f(gentity_t * ent)445 void Cmd_God_f (gentity_t *ent)
446 {
447 	const char	*msg;
448 
449 	if ( !CheatsOk( ent ) ) {
450 		return;
451 	}
452 
453 	ent->flags ^= FL_GODMODE;
454 	if (!(ent->flags & FL_GODMODE) )
455 		msg = "godmode OFF\n";
456 	else
457 		msg = "godmode ON\n";
458 
459 	gi.SendServerCommand( ent-g_entities, "print \"%s\"", msg);
460 }
461 
462 /*
463 ==================
464 Cmd_Undying_f
465 
466 Sets client to undead mode
467 
468 argv(0) undying
469 ==================
470 */
Cmd_Undying_f(gentity_t * ent)471 void Cmd_Undying_f (gentity_t *ent)
472 {
473 	const char	*msg;
474 
475 	if ( !CheatsOk( ent ) )
476 	{
477 		return;
478 	}
479 
480 	ent->flags ^= FL_UNDYING;
481 	if (!(ent->flags & FL_UNDYING) )
482 	{
483 		msg = "undead mode OFF\n";
484 	}
485 	else
486 	{
487 		int		max;
488 		const char	*cmd;
489 
490 		cmd = gi.argv(1);
491 		if ( cmd && atoi( cmd ) )
492 		{
493 			max = atoi( cmd );
494 		}
495 		else
496 		{
497 			max = 999;
498 		}
499 
500 		ent->health = ent->max_health = max;
501 
502 		msg = "undead mode ON\n";
503 
504 		if ( ent->client )
505 		{
506 			ent->client->ps.stats[STAT_HEALTH] = ent->client->ps.stats[STAT_MAX_HEALTH] = 999;
507 		}
508 	}
509 
510 	gi.SendServerCommand( ent-g_entities, "print \"%s\"", msg);
511 }
512 
513 /*
514 ==================
515 Cmd_Notarget_f
516 
517 Sets client to notarget
518 
519 argv(0) notarget
520 ==================
521 */
Cmd_Notarget_f(gentity_t * ent)522 void Cmd_Notarget_f( gentity_t *ent ) {
523 	const char	*msg;
524 
525 	if ( !CheatsOk( ent ) ) {
526 		return;
527 	}
528 
529 	ent->flags ^= FL_NOTARGET;
530 	if (!(ent->flags & FL_NOTARGET) )
531 		msg = "notarget OFF\n";
532 	else
533 		msg = "notarget ON\n";
534 
535 	gi.SendServerCommand( ent-g_entities, "print \"%s\"", msg);
536 }
537 
538 
539 /*
540 ==================
541 Cmd_Noclip_f
542 
543 argv(0) noclip
544 ==================
545 */
Cmd_Noclip_f(gentity_t * ent)546 void Cmd_Noclip_f( gentity_t *ent ) {
547 	const char	*msg;
548 
549 	if ( !CheatsOk( ent ) ) {
550 		return;
551 	}
552 
553 	if ( ent->client->noclip ) {
554 		msg = "noclip OFF\n";
555 	} else {
556 		msg = "noclip ON\n";
557 	}
558 	ent->client->noclip = (qboolean)!ent->client->noclip;
559 
560 	gi.SendServerCommand( ent-g_entities, "print \"%s\"", msg);
561 }
562 
563 
564 /*
565 ==================
566 Cmd_LevelShot_f
567 
568 This is just to help generate the level pictures
569 for the menus.  It goes to the intermission immediately
570 and sends over a command to the client to resize the view,
571 hide the scoreboard, and take a special screenshot
572 ==================
573 */
Cmd_LevelShot_f(gentity_t * ent)574 void Cmd_LevelShot_f( gentity_t *ent ) {
575 	if ( !CheatsOk( ent ) ) {
576 		return;
577 	}
578 
579 	gi.SendServerCommand( ent-g_entities, "clientLevelShot" );
580 }
581 
582 
583 /*
584 =================
585 Cmd_Kill_f
586 =================
587 */
Cmd_Kill_f(gentity_t * ent)588 void Cmd_Kill_f( gentity_t *ent ) {
589 	if( ( level.time - ent->client->respawnTime ) < 5000 ) {
590 		gi.SendServerCommand( ent-g_entities, "cp @INGAME_ONE_KILL_PER_5_SECONDS");
591 		return;
592 	}
593 	ent->flags &= ~FL_GODMODE;
594 	ent->client->ps.stats[STAT_HEALTH] = ent->health = 0;
595 	player_die (ent, ent, ent, 100000, MOD_SUICIDE);
596 }
597 
598 
599 /*
600 ==================
601 Cmd_Where_f
602 ==================
603 */
Cmd_Where_f(gentity_t * ent)604 void Cmd_Where_f( gentity_t *ent ) {
605 	const char *s = gi.argv(1);
606 	const int len = strlen(s);
607 	gentity_t	*check;
608 
609 	if ( gi.argc () < 2 ) {
610 		gi.Printf("usage: where classname\n");
611 		return;
612 	}
613 	for (int i = 0; i < globals.num_entities; i++)
614 	{
615 		if(!PInUse(i))
616 			continue;
617 //		if(!check || !check->inuse) {
618 //			continue;
619 //		}
620 		check = &g_entities[i];
621 		if (!Q_stricmpn(s, check->classname, len) ) {
622 			gi.SendServerCommand( ent-g_entities, "print \"%s %s\n\"", check->classname, vtos( check->s.pos.trBase ) );
623 		}
624 	}
625 }
626 
627 
628 /*
629 -------------------------
630 UserSpawn
631 -------------------------
632 */
633 
634 extern qboolean G_CallSpawn( gentity_t *ent );
635 
UserSpawn(gentity_t * ent,const char * name)636 void UserSpawn( gentity_t *ent, const char *name )
637 {
638 	vec3_t		origin;
639 	vec3_t		vf;
640 	vec3_t		angles;
641 	gentity_t	*ent2;
642 
643 	//Spawn the ent
644 	ent2 = G_Spawn();
645 	ent2->classname = G_NewString( name );	//FIXME: This will leave floating memory...
646 
647 	//TODO: This should ultimately make sure this is a safe spawn!
648 
649 	//Spawn the entity and place it there
650 	VectorSet( angles, 0, ent->s.apos.trBase[YAW], 0 );
651 	AngleVectors( angles, vf, NULL, NULL );
652 	VectorMA( ent->s.pos.trBase, 96, vf, origin );	//FIXME: Find the radius size of the object, and push out 32 + radius
653 
654 	origin[2] += 8;
655 	VectorCopy( origin, ent2->s.pos.trBase );
656 	VectorCopy( origin, ent2->s.origin );
657 	VectorCopy( ent->s.apos.trBase, ent2->s.angles );
658 
659 	gi.linkentity( ent2 );
660 
661 	//Find a valid spawning spot
662 	if ( G_CallSpawn( ent2 ) == qfalse )
663 	{
664 		gi.SendServerCommand( ent-g_entities, "print \"Failed to spawn '%s'\n\"", name );
665 		G_FreeEntity( ent2 );
666 		return;
667 	}
668 }
669 
670 /*
671 -------------------------
672 Cmd_Spawn
673 -------------------------
674 */
675 
Cmd_Spawn(gentity_t * ent)676 void Cmd_Spawn( gentity_t *ent )
677 {
678 	char	*name;
679 
680 	name = ConcatArgs( 1 );
681 
682 	gi.SendServerCommand( ent-g_entities, "print \"Spawning '%s'\n\"", name );
683 
684 	UserSpawn( ent, name );
685 }
686 
687 /*
688 =================
689 Cmd_SetViewpos_f
690 =================
691 */
Cmd_SetViewpos_f(gentity_t * ent)692 void Cmd_SetViewpos_f( gentity_t *ent ) {
693 	vec3_t		origin, angles;
694 	int			i;
695 
696 	if ( !g_cheats->integer ) {
697 		gi.SendServerCommand( ent-g_entities, va("print \"Cheats are not enabled on this server.\n\""));
698 		return;
699 	}
700 	if ( gi.argc() != 5 ) {
701 		gi.SendServerCommand( ent-g_entities, va("print \"usage: setviewpos x y z yaw\n\""));
702 		return;
703 	}
704 
705 	VectorClear( angles );
706 	for ( i = 0 ; i < 3 ; i++ ) {
707 		origin[i] = atof( gi.argv( i+1 ) );
708 	}
709 
710 	angles[YAW] = atof( gi.argv( 4 ) );
711 
712 	TeleportPlayer( ent, origin, angles );
713 }
714 
715 
716 
717 /*
718 =================
719 Cmd_SetObjective_f
720 =================
721 */
Cmd_SetObjective_f(gentity_t * ent)722 void Cmd_SetObjective_f( gentity_t *ent )
723 {
724 	int objectiveI,status,displayStatus;
725 
726 	if ( gi.argc() == 2 ) {
727 		objectiveI = atoi(gi.argv(1));
728 		gi.Printf("objective #%d  display status=%d, status=%d\n",objectiveI,
729 			ent->client->sess.mission_objectives[objectiveI].display,
730 			ent->client->sess.mission_objectives[objectiveI].status
731 			);
732 		return;
733 	}
734 	if ( gi.argc() != 4 ) {
735 		gi.SendServerCommand( ent-g_entities, va("print \"usage: setobjective <objective #>  <display status> <status>\n\""));
736 		return;
737 	}
738 
739 	if ( !CheatsOk( ent ) )
740 	{
741 		return;
742 	}
743 
744 	objectiveI = atoi(gi.argv(1));
745 	displayStatus = atoi(gi.argv(2));
746 	status = atoi(gi.argv(3));
747 
748 	ent->client->sess.mission_objectives[objectiveI].display = displayStatus;
749 	ent->client->sess.mission_objectives[objectiveI].status = status;
750 }
751 
752 /*
753 =================
754 Cmd_ViewObjective_f
755 =================
756 */
Cmd_ViewObjective_f(gentity_t * ent)757 void Cmd_ViewObjective_f( gentity_t *ent )
758 {
759 	int objectiveI;
760 
761 	if ( gi.argc() != 2 ) {
762 		gi.SendServerCommand( ent-g_entities, va("print \"usage: viewobjective <objective #>\n\""));
763 		return;
764 	}
765 
766 	objectiveI = atoi(gi.argv(1));
767 
768 	gi.SendServerCommand( ent-g_entities, va("print \"Objective %d   Display Status(1=show): %d  Status:%d\n\"",objectiveI,ent->client->sess.mission_objectives[objectiveI].display,ent->client->sess.mission_objectives[objectiveI].status));
769 }
770 
771 
772 /*
773 ================
774 Cmd_UseElectrobinoculars_f
775 ================
776 */
Cmd_UseElectrobinoculars_f(gentity_t * ent)777 void Cmd_UseElectrobinoculars_f(gentity_t *ent)
778 {
779 	if ( ent->health < 1 || in_camera )
780 	{
781 		return;
782 	}
783 
784 	G_AddEvent( ent, EV_USE_INV_BINOCULARS, 0 );
785 }
786 
787 /*
788 ================
789 Cmd_UseBacta_f
790 ================
791 */
Cmd_UseBacta_f(gentity_t * ent)792 void Cmd_UseBacta_f(gentity_t *ent)
793 {
794 	if ( ent->health < 1 || in_camera )
795 	{
796 		return;
797 	}
798 
799 	ItemUse_Bacta(ent);
800 }
801 
802 //----------------------------------------------------------------------------------
PickSeekerSpawnPoint(vec3_t org,vec3_t fwd,vec3_t right,int skip,vec3_t spot)803 qboolean PickSeekerSpawnPoint( vec3_t org, vec3_t fwd, vec3_t right, int skip, vec3_t spot )
804 {
805 	vec3_t	mins, maxs, forward, end;
806 	trace_t tr;
807 
808 	VectorSet( maxs, -8, -8, -24); // ?? size
809 	VectorSet( maxs, 8, 8, 8 );
810 
811 	VectorCopy( fwd, forward );
812 
813 	// to the front and side a bit
814 	forward[2] = 0.3f; // start up a bit
815 
816 	VectorMA( org, 48, forward, end );
817 	VectorMA( end, -8, right, end );
818 
819 	gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID, G2_NOCOLLIDE, 0 );
820 
821 	if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f )
822 	{
823 		VectorCopy( tr.endpos, spot );
824 		return qtrue;
825 	}
826 
827 	// side
828 	VectorMA( org, 48, right, end );
829 
830 	gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID, G2_NOCOLLIDE, 0 );
831 
832 	if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f )
833 	{
834 		VectorCopy( tr.endpos, spot );
835 		return qtrue;
836 	}
837 
838 	// other side
839 	VectorMA( org, -48, right, end );
840 
841 	gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID, G2_NOCOLLIDE, 0 );
842 
843 	if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f )
844 	{
845 		VectorCopy( tr.endpos, spot );
846 		return qtrue;
847 	}
848 
849 	// behind
850 	VectorMA( org, -48, fwd, end );
851 
852 	gi.trace( &tr, org, mins, maxs, end, skip, MASK_PLAYERSOLID, G2_NOCOLLIDE, 0 );
853 
854 	if ( !tr.startsolid && !tr.allsolid && tr.fraction >= 1.0f )
855 	{
856 		VectorCopy( tr.endpos, spot );
857 		return qtrue;
858 	}
859 
860 	return qfalse;
861 }
862 
863 /*
864 ================
865 Cmd_UseSeeker_f
866 ================
867 */
Cmd_UseSeeker_f(gentity_t * ent)868 void Cmd_UseSeeker_f( gentity_t *ent )
869 {
870 	if ( ent->health < 1 || in_camera )
871 	{
872 		return;
873 	}
874 
875 	// don't use them if we don't have any...also don't use them if one is already going
876 	if ( ent->client && ent->client->ps.inventory[INV_SEEKER] > 0 && level.time > ent->client->ps.powerups[PW_SEEKER] )
877 	{
878 		gentity_t	*tent = G_Spawn();
879 
880 		if ( tent )
881 		{
882 			vec3_t	fwd, right, spot;
883 
884 			AngleVectors( ent->client->ps.viewangles, fwd, right, NULL );
885 
886 			VectorCopy( ent->currentOrigin, spot ); // does nothing really, just initialize the goods...
887 
888 			if ( PickSeekerSpawnPoint( ent->currentOrigin, fwd, right, ent->s.number, spot ))
889 			{
890 				VectorCopy( spot, tent->s.origin );
891 				G_SetOrigin( tent, spot );
892 				G_SetAngles( tent, ent->currentAngles );
893 
894 extern void SP_NPC_Droid_Seeker( gentity_t *ent );
895 
896 				SP_NPC_Droid_Seeker( tent );
897 				G_Sound( tent, G_SoundIndex( "sound/chars/seeker/misc/hiss" ));
898 
899 				// make sure that we even have some
900 				ent->client->ps.inventory[INV_SEEKER]--;
901 				ent->client->ps.powerups[PW_SEEKER] = level.time + 1000;// can only drop one every second..maybe this is annoying?
902 
903 			}
904 		}
905 	}
906 }
907 
908 /*
909 ================
910 Cmd_UseGoggles_f
911 ================
912 */
Cmd_UseGoggles_f(gentity_t * ent)913 void Cmd_UseGoggles_f(gentity_t *ent)
914 {
915 	if ( ent->health < 1 || in_camera )
916 	{
917 		return;
918 	}
919 
920 	if ( ent->client && ent->client->ps.inventory[INV_LIGHTAMP_GOGGLES] > 0 )
921 	{
922 		G_AddEvent( ent, EV_USE_INV_LIGHTAMP_GOGGLES, 0 );
923 	}
924 }
925 
926 /*
927 ================
928 Cmd_UseSentry_f
929 ================
930 */
931 qboolean place_portable_assault_sentry( gentity_t *self, vec3_t origin, vec3_t dir );
Cmd_UseSentry_f(gentity_t * ent)932 void Cmd_UseSentry_f(gentity_t *ent)
933 {
934 	if ( ent->health < 1 || in_camera )
935 	{
936 		return;
937 	}
938 
939 	if ( ent->client->ps.inventory[INV_SENTRY] <= 0 )
940 	{
941 		// have none to place...play sound?
942 		return;
943 	}
944 
945 	if ( place_portable_assault_sentry( ent, ent->currentOrigin, ent->client->ps.viewangles ))
946 	{
947 		ent->client->ps.inventory[INV_SENTRY]--;
948 		G_AddEvent( ent, EV_USE_INV_SENTRY, 0 );
949 	}
950 	else
951 	{
952 		// couldn't be placed....play a notification sound!!
953 	}
954 }
955 
956 /*
957 ================
958 Cmd_UseInventory_f
959 ================
960 */
Cmd_UseInventory_f(gentity_t * ent)961 void Cmd_UseInventory_f(gentity_t *ent)
962 {
963 	switch (cg.inventorySelect)
964 	{
965 		case INV_ELECTROBINOCULARS :
966 			Cmd_UseElectrobinoculars_f(ent);
967 			return;
968 		case INV_BACTA_CANISTER :
969 			Cmd_UseBacta_f(ent);
970 			return;
971 		case INV_SEEKER :
972 			Cmd_UseSeeker_f(ent);
973 			return;
974 		case INV_LIGHTAMP_GOGGLES :
975 			Cmd_UseGoggles_f(ent);
976 			return;
977 		case INV_SENTRY :
978 			Cmd_UseSentry_f(ent);
979 			return;
980 		default :
981 			return;
982 
983 	}
984 }
985 
G_Taunt(gentity_t * ent)986 void G_Taunt( gentity_t *ent )
987 {
988 	if ( ent->client )
989 	{
990 		ent->client->ps.taunting = level.time + 100;
991 	}
992 }
993 
994 extern void G_SoundOnEnt( gentity_t *ent, soundChannel_t channel, const char *soundPath );
G_Victory(gentity_t * ent)995 void G_Victory( gentity_t *ent )
996 {
997 	if ( ent->health > 0 )
998 	{//say something and put away saber
999 		G_SoundOnEnt( ent, CHAN_VOICE, "sound/chars/kyle/misc/taunt1.wav" );
1000 		if ( ent->client )
1001 		{
1002 			ent->client->ps.saberActive = qfalse;
1003 		}
1004 	}
1005 }
1006 /*
1007 =================
1008 ClientCommand
1009 =================
1010 */
ClientCommand(int clientNum)1011 void ClientCommand( int clientNum ) {
1012 	gentity_t *ent;
1013 	const char	*cmd;
1014 
1015 	ent = g_entities + clientNum;
1016 	if ( !ent->client ) {
1017 		return;		// not fully in game yet
1018 	}
1019 
1020 	cmd = gi.argv(0);
1021 
1022 	if (Q_stricmp (cmd, "spawn") == 0)
1023 	{
1024 		Cmd_Spawn( ent );
1025 		return;
1026 	}
1027 
1028 	if (Q_stricmp (cmd, "give") == 0)
1029 		Cmd_Give_f (ent);
1030 	else if (Q_stricmp (cmd, "god") == 0)
1031 		Cmd_God_f (ent);
1032 	else if (Q_stricmp (cmd, "undying") == 0)
1033 		Cmd_Undying_f (ent);
1034 	else if (Q_stricmp (cmd, "notarget") == 0)
1035 		Cmd_Notarget_f (ent);
1036 	else if (Q_stricmp (cmd, "noclip") == 0)
1037 	{
1038 		Cmd_Noclip_f (ent);
1039 	}
1040 	else if (Q_stricmp (cmd, "kill") == 0)
1041 	{
1042 		if ( !CheatsOk( ent ) )
1043 		{
1044 			return;
1045 		}
1046 		Cmd_Kill_f (ent);
1047 	}
1048 	else if (Q_stricmp (cmd, "levelshot") == 0)
1049 		Cmd_LevelShot_f (ent);
1050 	else if (Q_stricmp (cmd, "where") == 0)
1051 		Cmd_Where_f (ent);
1052 	else if (Q_stricmp (cmd, "setviewpos") == 0)
1053 		Cmd_SetViewpos_f( ent );
1054 	else if (Q_stricmp (cmd, "setobjective") == 0)
1055 		Cmd_SetObjective_f( ent );
1056 	else if (Q_stricmp (cmd, "viewobjective") == 0)
1057 		Cmd_ViewObjective_f( ent );
1058 	else if (Q_stricmp (cmd, "force_throw") == 0)
1059 	{
1060 		ent = G_GetSelfForPlayerCmd();
1061 		ForceThrow( ent, qfalse );
1062 	}
1063 	else if (Q_stricmp (cmd, "force_pull") == 0)
1064 	{
1065 		ent = G_GetSelfForPlayerCmd();
1066 		ForceThrow( ent, qtrue );
1067 	}
1068 	else if (Q_stricmp (cmd, "force_speed") == 0)
1069 	{
1070 		ent = G_GetSelfForPlayerCmd();
1071 		ForceSpeed( ent );
1072 	}
1073 	else if (Q_stricmp (cmd, "force_heal") == 0)
1074 	{
1075 		ent = G_GetSelfForPlayerCmd();
1076 		ForceHeal( ent );
1077 	}
1078 	else if (Q_stricmp (cmd, "force_grip") == 0)
1079 	{
1080 		ent = G_GetSelfForPlayerCmd();
1081 		ForceGrip( ent );
1082 	}
1083 	else if (Q_stricmp (cmd, "force_distract") == 0)
1084 	{
1085 		ent = G_GetSelfForPlayerCmd();
1086 		ForceTelepathy( ent );
1087 	}
1088 	else if (Q_stricmp (cmd, "taunt") == 0)
1089 	{
1090 		ent = G_GetSelfForPlayerCmd();
1091 		G_Taunt( ent );
1092 	}
1093 	else if (Q_stricmp (cmd, "victory") == 0)
1094 		G_Victory( ent );
1095 //	else if (Q_stricmp (cmd, "use_shield") == 0)	// sounds like the design doc states that the shields will be a pickup and so the player never decides whether to use them or not.
1096 //		G_ActivatePersonalShield( ent );			//	If you want shields (armor),  type "give all" or "give armor" or "give armor #amt#"
1097 	else if (Q_stricmp (cmd, "fly_xwing") == 0)
1098 		G_PilotXWing( ent );
1099 	else if (Q_stricmp (cmd, "drive_atst") == 0)
1100 	{
1101 		if ( CheatsOk( ent ) )
1102 		{
1103 			G_DriveATST( ent, NULL );
1104 		}
1105 	}
1106 	else if (Q_stricmp (cmd, "thereisnospoon") == 0)
1107 		G_StartMatrixEffect( ent );
1108 	else if (Q_stricmp (cmd, "use_electrobinoculars") == 0)
1109 		Cmd_UseElectrobinoculars_f( ent );
1110 	else if (Q_stricmp (cmd, "use_bacta") == 0)
1111 		Cmd_UseBacta_f( ent );
1112 	else if (Q_stricmp (cmd, "use_seeker") == 0)
1113 		Cmd_UseSeeker_f( ent );
1114 	else if (Q_stricmp (cmd, "use_lightamp_goggles") == 0)
1115 		Cmd_UseGoggles_f( ent );
1116 	else if (Q_stricmp (cmd, "use_sentry") == 0)
1117 		Cmd_UseSentry_f( ent );
1118 	else if (Q_stricmp (cmd, "fx") == 0)
1119 		Cmd_Fx( ent );
1120 	else if (Q_stricmp (cmd, "invuse") == 0)
1121 	{
1122 		Cmd_UseInventory_f( ent );
1123 	}
1124 	else if (Q_stricmp (cmd, "playmusic") == 0)
1125 	{
1126 		const char *cmd2 = gi.argv(1);
1127 		if ( cmd2 )
1128 		{
1129 			gi.SetConfigstring( CS_MUSIC, cmd2 );
1130 		}
1131 	}
1132 	else
1133 	{
1134 		gi.SendServerCommand( clientNum, va("print \"Unknown command %s\n\"", cmd ) );
1135 	}
1136 }
1137