]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/game/gamesys/SysCmds.cpp
hello world
[icculus/iodoom3.git] / neo / game / gamesys / SysCmds.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 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 Doom 3 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 Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 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 Doom 3 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 "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../Game_local.h"
33
34 #include "TypeInfo.h"
35
36 /*
37 ==================
38 Cmd_GetFloatArg
39 ==================
40 */
41 float Cmd_GetFloatArg( const idCmdArgs &args, int &argNum ) {
42         const char *value;
43
44         value = args.Argv( argNum++ );
45         return atof( value );
46 }
47
48 /*
49 ===================
50 Cmd_EntityList_f
51 ===================
52 */
53 void Cmd_EntityList_f( const idCmdArgs &args ) {
54         int                     e;
55         idEntity        *check;
56         int                     count;
57         size_t          size;
58         idStr           match;
59
60         if ( args.Argc() > 1 ) {
61                 match = args.Args();
62                 match.Replace( " ", "" );
63         } else {
64                 match = "";
65         }
66
67         count = 0;
68         size = 0;
69
70         gameLocal.Printf( "%-4s  %-20s %-20s %s\n", " Num", "EntityDef", "Class", "Name" );
71         gameLocal.Printf( "--------------------------------------------------------------------\n" );
72         for( e = 0; e < MAX_GENTITIES; e++ ) {
73                 check = gameLocal.entities[ e ];
74
75                 if ( !check ) {
76                         continue;
77                 }
78
79                 if ( !check->name.Filter( match, true ) ) {
80                         continue;
81                 }
82
83                 gameLocal.Printf( "%4i: %-20s %-20s %s\n", e,
84                         check->GetEntityDefName(), check->GetClassname(), check->name.c_str() );
85
86                 count++;
87                 size += check->spawnArgs.Allocated();
88         }
89
90         gameLocal.Printf( "...%d entities\n...%d bytes of spawnargs\n", count, size );
91 }
92
93 /*
94 ===================
95 Cmd_ActiveEntityList_f
96 ===================
97 */
98 void Cmd_ActiveEntityList_f( const idCmdArgs &args ) {
99         idEntity        *check;
100         int                     count;
101
102         count = 0;
103
104         gameLocal.Printf( "%-4s  %-20s %-20s %s\n", " Num", "EntityDef", "Class", "Name" );
105         gameLocal.Printf( "--------------------------------------------------------------------\n" );
106         for( check = gameLocal.activeEntities.Next(); check != NULL; check = check->activeNode.Next() ) {
107                 char    dormant = check->fl.isDormant ? '-' : ' ';
108                 gameLocal.Printf( "%4i:%c%-20s %-20s %s\n", check->entityNumber, dormant, check->GetEntityDefName(), check->GetClassname(), check->name.c_str() );
109                 count++;
110         }
111
112         gameLocal.Printf( "...%d active entities\n", count );
113 }
114
115 /*
116 ===================
117 Cmd_ListSpawnArgs_f
118 ===================
119 */
120 void Cmd_ListSpawnArgs_f( const idCmdArgs &args ) {
121         int i;
122         idEntity *ent;
123
124         ent = gameLocal.FindEntity( args.Argv( 1 ) );
125         if ( !ent ) {
126                 gameLocal.Printf( "entity not found\n" );
127                 return;
128         }
129
130         for ( i = 0; i < ent->spawnArgs.GetNumKeyVals(); i++ ) {
131                 const idKeyValue *kv = ent->spawnArgs.GetKeyVal( i );
132                 gameLocal.Printf( "\"%s\"  "S_COLOR_WHITE"\"%s\"\n", kv->GetKey().c_str(), kv->GetValue().c_str() );
133         }
134 }
135
136 /*
137 ===================
138 Cmd_ReloadScript_f
139 ===================
140 */
141 void Cmd_ReloadScript_f( const idCmdArgs &args ) {
142         // shutdown the map because entities may point to script objects
143         gameLocal.MapShutdown();
144
145         // recompile the scripts
146         gameLocal.program.Startup( SCRIPT_DEFAULT );
147
148         // error out so that the user can rerun the scripts
149         gameLocal.Error( "Exiting map to reload scripts" );
150 }
151
152 /*
153 ===================
154 Cmd_Script_f
155 ===================
156 */
157 void Cmd_Script_f( const idCmdArgs &args ) {
158         const char *    script;
159         idStr                   text;
160         idStr                   funcname;
161         static int              funccount = 0;
162         idThread *              thread;
163         const function_t *func;
164         idEntity                *ent;
165
166         if ( !gameLocal.CheatsOk() ) {
167                 return;
168         }
169
170         sprintf( funcname, "ConsoleFunction_%d", funccount++ );
171
172         script = args.Args();
173         sprintf( text, "void %s() {%s;}\n", funcname.c_str(), script );
174         if ( gameLocal.program.CompileText( "console", text, true ) ) {
175                 func = gameLocal.program.FindFunction( funcname );
176                 if ( func ) {
177                         // set all the entity names in case the user named one in the script that wasn't referenced in the default script
178                         for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
179                                 gameLocal.program.SetEntity( ent->name, ent );
180                         }
181
182                         thread = new idThread( func );
183                         thread->Start();
184                 }
185         }
186 }
187
188 /*
189 ==================
190 KillEntities
191
192 Kills all the entities of the given class in a level.
193 ==================
194 */
195 void KillEntities( const idCmdArgs &args, const idTypeInfo &superClass ) {
196         idEntity        *ent;
197         idStrList       ignore;
198         const char *name;
199         int                     i;
200
201         if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) {
202                 return;
203         }
204
205         for( i = 1; i < args.Argc(); i++ ) {
206                 name = args.Argv( i );
207                 ignore.Append( name );
208         }
209
210         for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
211                 if ( ent->IsType( superClass ) ) {
212                         for( i = 0; i < ignore.Num(); i++ ) {
213                                 if ( ignore[ i ] == ent->name ) {
214                                         break;
215                                 }
216                         }
217
218                         if ( i >= ignore.Num() ) {
219                                 ent->PostEventMS( &EV_Remove, 0 );
220                         }
221                 }
222         }
223 }
224
225 /*
226 ==================
227 Cmd_KillMonsters_f
228
229 Kills all the monsters in a level.
230 ==================
231 */
232 void Cmd_KillMonsters_f( const idCmdArgs &args ) {
233         KillEntities( args, idAI::Type );
234
235         // kill any projectiles as well since they have pointers to the monster that created them
236         KillEntities( args, idProjectile::Type );
237 }
238
239 /*
240 ==================
241 Cmd_KillMovables_f
242
243 Kills all the moveables in a level.
244 ==================
245 */
246 void Cmd_KillMovables_f( const idCmdArgs &args ) {
247         if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) {
248                 return;
249         }
250         KillEntities( args, idMoveable::Type );
251 }
252
253 /*
254 ==================
255 Cmd_KillRagdolls_f
256
257 Kills all the ragdolls in a level.
258 ==================
259 */
260 void Cmd_KillRagdolls_f( const idCmdArgs &args ) {
261         if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) {
262                 return;
263         }
264         KillEntities( args, idAFEntity_Generic::Type );
265         KillEntities( args, idAFEntity_WithAttachedHead::Type );
266 }
267
268 /*
269 ==================
270 Cmd_Give_f
271
272 Give items to a client
273 ==================
274 */
275 void Cmd_Give_f( const idCmdArgs &args ) {
276         const char *name;
277         int                     i;
278         bool            give_all;
279         idPlayer        *player;
280
281         player = gameLocal.GetLocalPlayer();
282         if ( !player || !gameLocal.CheatsOk() ) {
283                 return;
284         }
285
286         name = args.Argv( 1 );
287
288         if ( idStr::Icmp( name, "all" ) == 0 ) {
289                 give_all = true;
290         } else {
291                 give_all = false;
292         }
293
294         if ( give_all || ( idStr::Cmpn( name, "weapon", 6 ) == 0 ) ) {
295                 if ( gameLocal.world->spawnArgs.GetBool( "no_Weapons" ) ) {
296                         gameLocal.world->spawnArgs.SetBool( "no_Weapons", false );
297                         for( i = 0; i < gameLocal.numClients; i++ ) {
298                                 if ( gameLocal.entities[ i ] ) {
299                                         gameLocal.entities[ i ]->PostEventSec( &EV_Player_SelectWeapon, 0.5f, gameLocal.entities[ i ]->spawnArgs.GetString( "def_weapon1" ) );
300                                 }
301                         }
302                 }
303         }
304
305         if ( ( idStr::Cmpn( name, "weapon_", 7 ) == 0 ) || ( idStr::Cmpn( name, "item_", 5 ) == 0 ) || ( idStr::Cmpn( name, "ammo_", 5 ) == 0 ) ) {
306                 player->GiveItem( name );
307                 return;
308         }
309
310         if ( give_all || idStr::Icmp( name, "health" ) == 0 )   {
311                 player->health = player->inventory.maxHealth;
312                 if ( !give_all ) {
313                         return;
314                 }
315         }
316
317         if ( give_all || idStr::Icmp( name, "weapons" ) == 0 ) {
318                 player->inventory.weapons = BIT( MAX_WEAPONS ) - 1;
319                 player->CacheWeapons();
320
321                 if ( !give_all ) {
322                         return;
323                 }
324         }
325
326         if ( give_all || idStr::Icmp( name, "ammo" ) == 0 ) {
327                 for ( i = 0 ; i < AMMO_NUMTYPES; i++ ) {
328                         player->inventory.ammo[ i ] = player->inventory.MaxAmmoForAmmoClass( player, idWeapon::GetAmmoNameForNum( ( ammo_t )i ) );
329                 }
330                 if ( !give_all ) {
331                         return;
332                 }
333         }
334
335         if ( give_all || idStr::Icmp( name, "armor" ) == 0 ) {
336                 player->inventory.armor = player->inventory.maxarmor;
337                 if ( !give_all ) {
338                         return;
339                 }
340         }
341
342         if ( idStr::Icmp( name, "berserk" ) == 0 ) {
343                 player->GivePowerUp( BERSERK, SEC2MS( 30.0f ) );
344                 return;
345         }
346
347         if ( idStr::Icmp( name, "invis" ) == 0 ) {
348                 player->GivePowerUp( INVISIBILITY, SEC2MS( 30.0f ) );
349                 return;
350         }
351
352         if ( idStr::Icmp( name, "pda" ) == 0 ) {
353                 player->GivePDA( args.Argv(2), NULL );
354                 return;
355         }
356
357         if ( idStr::Icmp( name, "video" ) == 0 ) {
358                 player->GiveVideo( args.Argv(2), NULL );
359                 return;
360         }
361
362         if ( !give_all && !player->Give( args.Argv(1), args.Argv(2) ) ) {
363                 gameLocal.Printf( "unknown item\n" );
364         }
365 }
366
367 /*
368 ==================
369 Cmd_CenterView_f
370
371 Centers the players pitch
372 ==================
373 */
374 void Cmd_CenterView_f( const idCmdArgs &args ) {
375         idPlayer        *player;
376         idAngles        ang;
377
378         player = gameLocal.GetLocalPlayer();
379         if ( !player ) {
380                 return;
381         }
382
383         ang = player->viewAngles;
384         ang.pitch = 0.0f;
385         player->SetViewAngles( ang );
386 }
387
388 /*
389 ==================
390 Cmd_God_f
391
392 Sets client to godmode
393
394 argv(0) god
395 ==================
396 */
397 void Cmd_God_f( const idCmdArgs &args ) {
398         char            *msg;
399         idPlayer        *player;
400
401         player = gameLocal.GetLocalPlayer();
402         if ( !player || !gameLocal.CheatsOk() ) {
403                 return;
404         }
405
406         if ( player->godmode ) {
407                 player->godmode = false;
408                 msg = "godmode OFF\n";
409         } else {
410                 player->godmode = true;
411                 msg = "godmode ON\n";
412         }
413
414         gameLocal.Printf( "%s", msg );
415 }
416
417 /*
418 ==================
419 Cmd_Notarget_f
420
421 Sets client to notarget
422
423 argv(0) notarget
424 ==================
425 */
426 void Cmd_Notarget_f( const idCmdArgs &args ) {
427         char            *msg;
428         idPlayer        *player;
429
430         player = gameLocal.GetLocalPlayer();
431         if ( !player || !gameLocal.CheatsOk() ) {
432                 return;
433         }
434
435         if ( player->fl.notarget ) {
436                 player->fl.notarget = false;
437                 msg = "notarget OFF\n";
438         } else {
439                 player->fl.notarget = true;
440                 msg = "notarget ON\n";
441         }
442
443         gameLocal.Printf( "%s", msg );
444 }
445
446 /*
447 ==================
448 Cmd_Noclip_f
449
450 argv(0) noclip
451 ==================
452 */
453 void Cmd_Noclip_f( const idCmdArgs &args ) {
454         char            *msg;
455         idPlayer        *player;
456
457         player = gameLocal.GetLocalPlayer();
458         if ( !player || !gameLocal.CheatsOk() ) {
459                 return;
460         }
461
462         if ( player->noclip ) {
463                 msg = "noclip OFF\n";
464         } else {
465                 msg = "noclip ON\n";
466         }
467         player->noclip = !player->noclip;
468
469         gameLocal.Printf( "%s", msg );
470 }
471
472 /*
473 =================
474 Cmd_Kill_f
475 =================
476 */
477 void Cmd_Kill_f( const idCmdArgs &args ) {
478         idPlayer        *player;
479
480         if ( gameLocal.isMultiplayer ) {
481                 if ( gameLocal.isClient ) {
482                         idBitMsg        outMsg;
483                         byte            msgBuf[ MAX_GAME_MESSAGE_SIZE ];
484                         outMsg.Init( msgBuf, sizeof( msgBuf ) );
485                         outMsg.WriteByte( GAME_RELIABLE_MESSAGE_KILL );
486                         networkSystem->ClientSendReliableMessage( outMsg );
487                 } else {
488                         player = gameLocal.GetClientByCmdArgs( args );
489                         if ( !player ) {
490                                 common->Printf( "kill <client nickname> or kill <client index>\n" );
491                                 return;
492                         }
493                         player->Kill( false, false );
494                         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say killed client %d '%s^0'\n", player->entityNumber, gameLocal.userInfo[ player->entityNumber ].GetString( "ui_name" ) ) );
495                 }
496         } else {
497                 player = gameLocal.GetLocalPlayer();
498                 if ( !player ) {
499                         return;
500                 }
501                 player->Kill( false, false );
502         }
503 }
504
505 /*
506 =================
507 Cmd_PlayerModel_f
508 =================
509 */
510 void Cmd_PlayerModel_f( const idCmdArgs &args ) {
511         idPlayer        *player;
512         const char *name;
513         idVec3          pos;
514         idAngles        ang;
515
516         player = gameLocal.GetLocalPlayer();
517         if ( !player || !gameLocal.CheatsOk() ) {
518                 return;
519         }
520
521         if ( args.Argc() < 2 ) {
522                 gameLocal.Printf( "usage: playerModel <modelname>\n" );
523                 return;
524         }
525
526         name = args.Argv( 1 );
527         player->spawnArgs.Set( "model", name );
528
529         pos = player->GetPhysics()->GetOrigin();
530         ang = player->viewAngles;
531         player->SpawnToPoint( pos, ang );
532 }
533
534 /*
535 ==================
536 Cmd_Say
537 ==================
538 */
539 static void Cmd_Say( bool team, const idCmdArgs &args ) {
540         const char *name;
541         idStr text;
542         const char *cmd = team ? "sayTeam" : "say" ;
543
544         if ( !gameLocal.isMultiplayer ) {
545                 gameLocal.Printf( "%s can only be used in a multiplayer game\n", cmd );
546                 return;
547         }
548
549         if ( args.Argc() < 2 ) {
550                 gameLocal.Printf( "usage: %s <text>\n", cmd );
551                 return;
552         }
553
554         text = args.Args();
555         if ( text.Length() == 0 ) {
556                 return;
557         }
558
559         if ( text[ text.Length() - 1 ] == '\n' ) {
560                 text[ text.Length() - 1 ] = '\0';
561         }
562         name = "player";
563
564         idPlayer *      player;
565
566         // here we need to special case a listen server to use the real client name instead of "server"
567         // "server" will only appear on a dedicated server
568         if ( gameLocal.isClient || cvarSystem->GetCVarInteger( "net_serverDedicated" ) == 0 ) {
569                 player = gameLocal.localClientNum >= 0 ? static_cast<idPlayer *>( gameLocal.entities[ gameLocal.localClientNum ] ) : NULL;
570                 if ( player ) {
571                         name = player->GetUserInfo()->GetString( "ui_name", "player" );
572                 }
573         } else {
574                 name = "server";
575         }
576
577         if ( gameLocal.isClient ) {
578                 idBitMsg        outMsg;
579                 byte            msgBuf[ 256 ];
580                 outMsg.Init( msgBuf, sizeof( msgBuf ) );
581                 outMsg.WriteByte( team ? GAME_RELIABLE_MESSAGE_TCHAT : GAME_RELIABLE_MESSAGE_CHAT );
582                 outMsg.WriteString( name );
583                 outMsg.WriteString( text, -1, false );
584                 networkSystem->ClientSendReliableMessage( outMsg );
585         } else {
586                 gameLocal.mpGame.ProcessChatMessage( gameLocal.localClientNum, team, name, text, NULL );
587         }
588 }
589
590 /*
591 ==================
592 Cmd_Say_f
593 ==================
594 */
595 static void Cmd_Say_f( const idCmdArgs &args ) {
596         Cmd_Say( false, args );
597 }
598
599 /*
600 ==================
601 Cmd_SayTeam_f
602 ==================
603 */
604 static void Cmd_SayTeam_f( const idCmdArgs &args ) {
605         Cmd_Say( true, args );
606 }
607
608 /*
609 ==================
610 Cmd_AddChatLine_f
611 ==================
612 */
613 static void Cmd_AddChatLine_f( const idCmdArgs &args ) {
614         gameLocal.mpGame.AddChatLine( args.Argv( 1 ) );
615 }
616
617 /*
618 ==================
619 Cmd_Kick_f
620 ==================
621 */
622 static void Cmd_Kick_f( const idCmdArgs &args ) {
623         idPlayer *player;
624
625         if ( !gameLocal.isMultiplayer ) {
626                 gameLocal.Printf( "kick can only be used in a multiplayer game\n" );
627                 return;
628         }
629
630         if ( gameLocal.isClient ) {
631                 gameLocal.Printf( "You have no such power. This is a server command\n" );
632                 return;
633         }
634
635         player = gameLocal.GetClientByCmdArgs( args );
636         if ( !player ) {
637                 gameLocal.Printf( "usage: kick <client nickname> or kick <client index>\n" );
638                 return;
639         }
640         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say kicking out client %d '%s^0'\n", player->entityNumber, gameLocal.userInfo[ player->entityNumber ].GetString( "ui_name" ) ) );
641         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "kick %d\n", player->entityNumber ) );
642 }
643
644 /*
645 ==================
646 Cmd_GetViewpos_f
647 ==================
648 */
649 void Cmd_GetViewpos_f( const idCmdArgs &args ) {
650         idPlayer        *player;
651         idVec3          origin;
652         idMat3          axis;
653
654         player = gameLocal.GetLocalPlayer();
655         if ( !player ) {
656                 return;
657         }
658
659         const renderView_t *view = player->GetRenderView();
660         if ( view ) {
661                 gameLocal.Printf( "(%s) %.1f\n", view->vieworg.ToString(), view->viewaxis[0].ToYaw() );
662         } else {
663                 player->GetViewPos( origin, axis );
664                 gameLocal.Printf( "(%s) %.1f\n", origin.ToString(), axis[0].ToYaw() );
665         }
666 }
667
668 /*
669 =================
670 Cmd_SetViewpos_f
671 =================
672 */
673 void Cmd_SetViewpos_f( const idCmdArgs &args ) {
674         idVec3          origin;
675         idAngles        angles;
676         int                     i;
677         idPlayer        *player;
678
679         player = gameLocal.GetLocalPlayer();
680         if ( !player || !gameLocal.CheatsOk() ) {
681                 return;
682         }
683
684         if ( ( args.Argc() != 4 ) && ( args.Argc() != 5 ) ) {
685                 gameLocal.Printf( "usage: setviewpos <x> <y> <z> <yaw>\n" );
686                 return;
687         }
688
689         angles.Zero();
690         if ( args.Argc() == 5 ) {
691                 angles.yaw = atof( args.Argv( 4 ) );
692         }
693
694         for ( i = 0 ; i < 3 ; i++ ) {
695                 origin[i] = atof( args.Argv( i + 1 ) );
696         }
697         origin.z -= pm_normalviewheight.GetFloat() - 0.25f;
698
699         player->Teleport( origin, angles, NULL );
700 }
701
702 /*
703 =================
704 Cmd_Teleport_f
705 =================
706 */
707 void Cmd_Teleport_f( const idCmdArgs &args ) {
708         idVec3          origin;
709         idAngles        angles;
710         idPlayer        *player;
711         idEntity        *ent;
712
713         player = gameLocal.GetLocalPlayer();
714         if ( !player || !gameLocal.CheatsOk() ) {
715                 return;
716         }
717
718         if ( args.Argc() != 2 ) {
719                 gameLocal.Printf( "usage: teleport <name of entity to teleport to>\n" );
720                 return;
721         }
722
723         ent = gameLocal.FindEntity( args.Argv( 1 ) );
724         if ( !ent ) {
725                 gameLocal.Printf( "entity not found\n" );
726                 return;
727         }
728
729         angles.Zero();
730         angles.yaw = ent->GetPhysics()->GetAxis()[ 0 ].ToYaw();
731         origin = ent->GetPhysics()->GetOrigin();
732
733         player->Teleport( origin, angles, ent );
734 }
735
736 /*
737 =================
738 Cmd_Trigger_f
739 =================
740 */
741 void Cmd_Trigger_f( const idCmdArgs &args ) {
742         idVec3          origin;
743         idAngles        angles;
744         idPlayer        *player;
745         idEntity        *ent;
746
747         player = gameLocal.GetLocalPlayer();
748         if ( !player || !gameLocal.CheatsOk() ) {
749                 return;
750         }
751
752         if ( args.Argc() != 2 ) {
753                 gameLocal.Printf( "usage: trigger <name of entity to trigger>\n" );
754                 return;
755         }
756
757         ent = gameLocal.FindEntity( args.Argv( 1 ) );
758         if ( !ent ) {
759                 gameLocal.Printf( "entity not found\n" );
760                 return;
761         }
762
763         ent->Signal( SIG_TRIGGER );
764         ent->ProcessEvent( &EV_Activate, player );
765         ent->TriggerGuis();
766 }
767
768 /*
769 ===================
770 Cmd_Spawn_f
771 ===================
772 */
773 void Cmd_Spawn_f( const idCmdArgs &args ) {
774         const char *key, *value;
775         int                     i;
776         float           yaw;
777         idVec3          org;
778         idPlayer        *player;
779         idDict          dict;
780
781         player = gameLocal.GetLocalPlayer();
782         if ( !player || !gameLocal.CheatsOk( false ) ) {
783                 return;
784         }
785
786         if ( args.Argc() & 1 ) {        // must always have an even number of arguments
787                 gameLocal.Printf( "usage: spawn classname [key/value pairs]\n" );
788                 return;
789         }
790
791         yaw = player->viewAngles.yaw;
792
793         value = args.Argv( 1 );
794         dict.Set( "classname", value );
795         dict.Set( "angle", va( "%f", yaw + 180 ) );
796
797         org = player->GetPhysics()->GetOrigin() + idAngles( 0, yaw, 0 ).ToForward() * 80 + idVec3( 0, 0, 1 );
798         dict.Set( "origin", org.ToString() );
799
800         for( i = 2; i < args.Argc() - 1; i += 2 ) {
801
802                 key = args.Argv( i );
803                 value = args.Argv( i + 1 );
804
805                 dict.Set( key, value );
806         }
807
808         gameLocal.SpawnEntityDef( dict );
809 }
810
811 /*
812 ==================
813 Cmd_Damage_f
814
815 Damages the specified entity
816 ==================
817 */
818 void Cmd_Damage_f( const idCmdArgs &args ) {
819         if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) {
820                 return;
821         }
822         if ( args.Argc() != 3 ) {
823                 gameLocal.Printf( "usage: damage <name of entity to damage> <damage>\n" );
824                 return;
825         }
826
827         idEntity *ent = gameLocal.FindEntity( args.Argv( 1 ) );
828         if ( !ent ) {
829                 gameLocal.Printf( "entity not found\n" );
830                 return;
831         }
832
833         ent->Damage( gameLocal.world, gameLocal.world, idVec3( 0, 0, 1 ), "damage_moverCrush", atoi( args.Argv( 2 ) ), INVALID_JOINT );
834 }
835
836
837 /*
838 ==================
839 Cmd_Remove_f
840
841 Removes the specified entity
842 ==================
843 */
844 void Cmd_Remove_f( const idCmdArgs &args ) {
845         if ( !gameLocal.GetLocalPlayer() || !gameLocal.CheatsOk( false ) ) {
846                 return;
847         }
848         if ( args.Argc() != 2 ) {
849                 gameLocal.Printf( "usage: remove <name of entity to remove>\n" );
850                 return;
851         }
852
853         idEntity *ent = gameLocal.FindEntity( args.Argv( 1 ) );
854         if ( !ent ) {
855                 gameLocal.Printf( "entity not found\n" );
856                 return;
857         }
858
859         delete ent;
860 }
861
862 /*
863 ===================
864 Cmd_TestLight_f
865 ===================
866 */
867 void Cmd_TestLight_f( const idCmdArgs &args ) {
868         int                     i;
869         idStr           filename;
870         const char *key, *value, *name;
871         idPlayer *      player;
872         idDict          dict;
873
874         player = gameLocal.GetLocalPlayer();
875         if ( !player || !gameLocal.CheatsOk( false ) ) {
876                 return;
877         }
878
879         renderView_t    *rv = player->GetRenderView();
880
881         float fov = tan( idMath::M_DEG2RAD * rv->fov_x / 2 );
882
883
884         dict.SetMatrix( "rotation", mat3_default );
885         dict.SetVector( "origin", rv->vieworg );
886         dict.SetVector( "light_target", rv->viewaxis[0] );
887         dict.SetVector( "light_right", rv->viewaxis[1] * -fov );
888         dict.SetVector( "light_up", rv->viewaxis[2] * fov );
889         dict.SetVector( "light_start", rv->viewaxis[0] * 16 );
890         dict.SetVector( "light_end", rv->viewaxis[0] * 1000 );
891
892         if ( args.Argc() >= 2 ) {
893                 value = args.Argv( 1 );
894                 filename = args.Argv(1);
895                 filename.DefaultFileExtension( ".tga" );
896                 dict.Set( "texture", filename );
897         }
898
899         dict.Set( "classname", "light" );
900         for( i = 2; i < args.Argc() - 1; i += 2 ) {
901
902                 key = args.Argv( i );
903                 value = args.Argv( i + 1 );
904
905                 dict.Set( key, value );
906         }
907
908         for ( i = 0; i < MAX_GENTITIES; i++ ) {
909                 name = va( "spawned_light_%d", i );             // not just light_, or it might pick up a prelight shadow
910                 if ( !gameLocal.FindEntity( name ) ) {
911                         break;
912                 }
913         }
914         dict.Set( "name", name );
915
916         gameLocal.SpawnEntityDef( dict );
917
918         gameLocal.Printf( "Created new light\n");
919 }
920
921 /*
922 ===================
923 Cmd_TestPointLight_f
924 ===================
925 */
926 void Cmd_TestPointLight_f( const idCmdArgs &args ) {
927         const char *key, *value, *name;
928         int                     i;
929         idPlayer        *player;
930         idDict          dict;
931
932         player = gameLocal.GetLocalPlayer();
933         if ( !player || !gameLocal.CheatsOk( false ) ) {
934                 return;
935         }
936
937         dict.SetVector("origin", player->GetRenderView()->vieworg);
938
939         if ( args.Argc() >= 2 ) {
940                 value = args.Argv( 1 );
941                 dict.Set("light", value);
942         } else {
943                 dict.Set("light", "300");
944         }
945
946         dict.Set( "classname", "light" );
947         for( i = 2; i < args.Argc() - 1; i += 2 ) {
948
949                 key = args.Argv( i );
950                 value = args.Argv( i + 1 );
951
952                 dict.Set( key, value );
953         }
954
955         for ( i = 0; i < MAX_GENTITIES; i++ ) {
956                 name = va( "light_%d", i );
957                 if ( !gameLocal.FindEntity( name ) ) {
958                         break;
959                 }
960         }
961         dict.Set( "name", name );
962
963         gameLocal.SpawnEntityDef( dict );
964
965         gameLocal.Printf( "Created new point light\n");
966 }
967
968 /*
969 ==================
970 Cmd_PopLight_f
971 ==================
972 */
973 void Cmd_PopLight_f( const idCmdArgs &args ) {
974         idEntity        *ent;
975         idMapEntity *mapEnt;
976         idMapFile       *mapFile = gameLocal.GetLevelMap();
977         idLight         *lastLight;
978         int                     last;
979
980         if ( !gameLocal.CheatsOk() ) {
981                 return;
982         }
983
984         bool removeFromMap = ( args.Argc() > 1 );
985
986         lastLight = NULL;
987         last = -1;
988         for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
989                 if ( !ent->IsType( idLight::Type ) ) {
990                         continue;
991                 }
992
993                 if ( gameLocal.spawnIds[ ent->entityNumber ] > last ) {
994                         last = gameLocal.spawnIds[ ent->entityNumber ];
995                         lastLight = static_cast<idLight*>( ent );
996                 }
997         }
998
999         if ( lastLight ) {
1000                 // find map file entity
1001                 mapEnt = mapFile->FindEntity( lastLight->name );
1002
1003                 if ( removeFromMap && mapEnt ) {
1004                         mapFile->RemoveEntity( mapEnt );
1005                 }
1006                 gameLocal.Printf( "Removing light %i\n", lastLight->GetLightDefHandle() );
1007                 delete lastLight;
1008         } else {
1009                 gameLocal.Printf( "No lights to clear.\n" );
1010         }
1011
1012 }
1013
1014 /*
1015 ====================
1016 Cmd_ClearLights_f
1017 ====================
1018 */
1019 void Cmd_ClearLights_f( const idCmdArgs &args ) {
1020         idEntity *ent;
1021         idEntity *next;
1022         idLight *light;
1023         idMapEntity *mapEnt;
1024         idMapFile *mapFile = gameLocal.GetLevelMap();
1025
1026         bool removeFromMap = ( args.Argc() > 1 );
1027
1028         gameLocal.Printf( "Clearing all lights.\n" );
1029         for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = next ) {
1030                 next = ent->spawnNode.Next();
1031                 if ( !ent->IsType( idLight::Type ) ) {
1032                         continue;
1033                 }
1034
1035                 light = static_cast<idLight*>( ent );
1036                 mapEnt = mapFile->FindEntity( light->name );
1037
1038                 if ( removeFromMap && mapEnt ) {
1039                         mapFile->RemoveEntity( mapEnt );
1040                 }
1041
1042                 delete light;
1043         }
1044 }
1045
1046 /*
1047 ==================
1048 Cmd_TestFx_f
1049 ==================
1050 */
1051 void Cmd_TestFx_f( const idCmdArgs &args ) {
1052         idVec3          offset;
1053         const char *name;
1054         idPlayer *      player;
1055         idDict          dict;
1056
1057         player = gameLocal.GetLocalPlayer();
1058         if ( !player || !gameLocal.CheatsOk() ) {
1059                 return;
1060         }
1061
1062         // delete the testModel if active
1063         if ( gameLocal.testFx ) {
1064                 delete gameLocal.testFx;
1065                 gameLocal.testFx = NULL;
1066         }
1067
1068         if ( args.Argc() < 2 ) {
1069                 return;
1070         }
1071
1072         name = args.Argv( 1 );
1073
1074         offset = player->GetPhysics()->GetOrigin() + player->viewAngles.ToForward() * 100.0f;
1075
1076         dict.Set( "origin", offset.ToString() );
1077         dict.Set( "test", "1");
1078         dict.Set( "fx", name );
1079         gameLocal.testFx = ( idEntityFx * )gameLocal.SpawnEntityType( idEntityFx::Type, &dict );
1080 }
1081
1082 #define MAX_DEBUGLINES  128
1083
1084 typedef struct {
1085         bool used;
1086         idVec3 start, end;
1087         int color;
1088         bool blink;
1089         bool arrow;
1090 } gameDebugLine_t;
1091
1092 gameDebugLine_t debugLines[MAX_DEBUGLINES];
1093
1094 /*
1095 ==================
1096 Cmd_AddDebugLine_f
1097 ==================
1098 */
1099 static void Cmd_AddDebugLine_f( const idCmdArgs &args ) {
1100         int i, argNum;
1101         const char *value;
1102
1103         if ( !gameLocal.CheatsOk() ) {
1104                 return;
1105         }
1106
1107         if ( args.Argc () < 7 ) {
1108                 gameLocal.Printf( "usage: addline <x y z> <x y z> <color>\n" );
1109                 return;
1110         }
1111         for ( i = 0; i < MAX_DEBUGLINES; i++ ) {
1112                 if ( !debugLines[i].used ) {
1113                         break;
1114                 }
1115         }
1116         if ( i >= MAX_DEBUGLINES ) {
1117                 gameLocal.Printf( "no free debug lines\n" );
1118                 return;
1119         }
1120         value = args.Argv( 0 );
1121         if ( !idStr::Icmp( value, "addarrow" ) ) {
1122                 debugLines[i].arrow = true;
1123         } else {
1124                 debugLines[i].arrow = false;
1125         }
1126         debugLines[i].used = true;
1127         debugLines[i].blink = false;
1128         argNum = 1;
1129         debugLines[i].start.x = Cmd_GetFloatArg( args, argNum );
1130         debugLines[i].start.y = Cmd_GetFloatArg( args, argNum );
1131         debugLines[i].start.z = Cmd_GetFloatArg( args, argNum );
1132         debugLines[i].end.x = Cmd_GetFloatArg( args, argNum );
1133         debugLines[i].end.y = Cmd_GetFloatArg( args, argNum );
1134         debugLines[i].end.z = Cmd_GetFloatArg( args, argNum );
1135         debugLines[i].color = Cmd_GetFloatArg( args, argNum );
1136 }
1137
1138 /*
1139 ==================
1140 Cmd_RemoveDebugLine_f
1141 ==================
1142 */
1143 static void Cmd_RemoveDebugLine_f( const idCmdArgs &args ) {
1144         int i, num;
1145         const char *value;
1146
1147         if ( !gameLocal.CheatsOk() ) {
1148                 return;
1149         }
1150
1151         if ( args.Argc () < 2 ) {
1152                 gameLocal.Printf( "usage: removeline <num>\n" );
1153                 return;
1154         }
1155         value = args.Argv( 1 );
1156         num = atoi(value);
1157         for ( i = 0; i < MAX_DEBUGLINES; i++ ) {
1158                 if ( debugLines[i].used ) {
1159                         if ( --num < 0 ) {
1160                                 break;
1161                         }
1162                 }
1163         }
1164         if ( i >= MAX_DEBUGLINES ) {
1165                 gameLocal.Printf( "line not found\n" );
1166                 return;
1167         }
1168         debugLines[i].used = false;
1169 }
1170
1171 /*
1172 ==================
1173 Cmd_BlinkDebugLine_f
1174 ==================
1175 */
1176 static void Cmd_BlinkDebugLine_f( const idCmdArgs &args ) {
1177         int i, num;
1178         const char *value;
1179
1180         if ( !gameLocal.CheatsOk() ) {
1181                 return;
1182         }
1183
1184         if ( args.Argc () < 2 ) {
1185                 gameLocal.Printf( "usage: blinkline <num>\n" );
1186                 return;
1187         }
1188         value = args.Argv( 1 );
1189         num = atoi( value );
1190         for ( i = 0; i < MAX_DEBUGLINES; i++ ) {
1191                 if ( debugLines[i].used ) {
1192                         if ( --num < 0 ) {
1193                                 break;
1194                         }
1195                 }
1196         }
1197         if ( i >= MAX_DEBUGLINES ) {
1198                 gameLocal.Printf( "line not found\n" );
1199                 return;
1200         }
1201         debugLines[i].blink = !debugLines[i].blink;
1202 }
1203
1204 /*
1205 ==================
1206 PrintFloat
1207 ==================
1208 */
1209 static void PrintFloat( float f ) {
1210         char buf[128], i;
1211
1212         for ( i = sprintf( buf, "%3.2f", f ); i < 7; i++ ) {
1213                 buf[i] = ' ';
1214         }
1215         buf[i] = '\0';
1216         gameLocal.Printf( buf );
1217 }
1218
1219 /*
1220 ==================
1221 Cmd_ListDebugLines_f
1222 ==================
1223 */
1224 static void Cmd_ListDebugLines_f( const idCmdArgs &args ) {
1225         int i, num;
1226
1227         if ( !gameLocal.CheatsOk() ) {
1228                 return;
1229         }
1230
1231         num = 0;
1232         gameLocal.Printf( "line num: x1     y1     z1     x2     y2     z2     c  b  a\n" );
1233         for ( i = 0; i < MAX_DEBUGLINES; i++ ) {
1234                 if ( debugLines[i].used ) {
1235                         gameLocal.Printf( "line %3d: ", num );
1236                         PrintFloat( debugLines[i].start.x );
1237                         PrintFloat( debugLines[i].start.y );
1238                         PrintFloat( debugLines[i].start.z );
1239                         PrintFloat( debugLines[i].end.x );
1240                         PrintFloat( debugLines[i].end.y );
1241                         PrintFloat( debugLines[i].end.z );
1242                         gameLocal.Printf( "%d  %d  %d\n", debugLines[i].color, debugLines[i].blink, debugLines[i].arrow );
1243                         num++;
1244                 }
1245         }
1246         if ( !num ) {
1247                 gameLocal.Printf( "no debug lines\n" );
1248         }
1249 }
1250
1251 /*
1252 ==================
1253 D_DrawDebugLines
1254 ==================
1255 */
1256 void D_DrawDebugLines( void ) {
1257         int i;
1258         idVec3 forward, right, up, p1, p2;
1259         idVec4 color;
1260         float l;
1261
1262         for ( i = 0; i < MAX_DEBUGLINES; i++ ) {
1263                 if ( debugLines[i].used ) {
1264                         if ( !debugLines[i].blink || (gameLocal.time & (1<<9)) ) {
1265                                 color = idVec4( debugLines[i].color&1, (debugLines[i].color>>1)&1, (debugLines[i].color>>2)&1, 1 );
1266                                 gameRenderWorld->DebugLine( color, debugLines[i].start, debugLines[i].end );
1267                                 //
1268                                 if ( debugLines[i].arrow ) {
1269                                         // draw a nice arrow
1270                                         forward = debugLines[i].end - debugLines[i].start;
1271                                         l = forward.Normalize() * 0.2f;
1272                                         forward.NormalVectors( right, up);
1273
1274                                         if ( l > 3.0f ) {
1275                                                 l = 3.0f;
1276                                         }
1277                                         p1 = debugLines[i].end - l * forward + (l * 0.4f) * right;
1278                                         p2 = debugLines[i].end - l * forward - (l * 0.4f) * right;
1279                                         gameRenderWorld->DebugLine( color, debugLines[i].end, p1 );
1280                                         gameRenderWorld->DebugLine( color, debugLines[i].end, p2 );
1281                                         gameRenderWorld->DebugLine( color, p1, p2 );
1282                                 }
1283                         }
1284                 }
1285         }
1286 }
1287
1288 /*
1289 ==================
1290 Cmd_ListCollisionModels_f
1291 ==================
1292 */
1293 static void Cmd_ListCollisionModels_f( const idCmdArgs &args ) {
1294         if ( !gameLocal.CheatsOk() ) {
1295                 return;
1296         }
1297
1298         collisionModelManager->ListModels();
1299 }
1300
1301 /*
1302 ==================
1303 Cmd_CollisionModelInfo_f
1304 ==================
1305 */
1306 static void Cmd_CollisionModelInfo_f( const idCmdArgs &args ) {
1307         const char *value;
1308
1309         if ( !gameLocal.CheatsOk() ) {
1310                 return;
1311         }
1312
1313         if ( args.Argc () < 2 ) {
1314                 gameLocal.Printf( "usage: collisionModelInfo <modelNum>\n"
1315                                         "use 'all' instead of the model number for accumulated info\n" );
1316                 return;
1317         }
1318
1319         value = args.Argv( 1 );
1320         if ( !idStr::Icmp( value, "all" ) ) {
1321                 collisionModelManager->ModelInfo( -1 );
1322         } else {
1323                 collisionModelManager->ModelInfo( atoi(value) );
1324         }
1325 }
1326
1327 /*
1328 ==================
1329 Cmd_ExportModels_f
1330 ==================
1331 */
1332 static void Cmd_ExportModels_f( const idCmdArgs &args ) {
1333         idModelExport   exporter;
1334         idStr                   name;
1335
1336         // don't allow exporting models when cheats are disabled,
1337         // but if we're not in the game, it's ok
1338         if ( gameLocal.GetLocalPlayer() && !gameLocal.CheatsOk( false ) ) {
1339                 return;
1340         }
1341
1342         if ( args.Argc() < 2 ) {
1343                 exporter.ExportModels( "def", ".def" );
1344         } else {
1345                 name = args.Argv( 1 );
1346                 name = "def/" + name;
1347                 name.DefaultFileExtension( ".def" );
1348                 exporter.ExportDefFile( name );
1349         }
1350 }
1351
1352 /*
1353 ==================
1354 Cmd_ReexportModels_f
1355 ==================
1356 */
1357 static void Cmd_ReexportModels_f( const idCmdArgs &args ) {
1358         idModelExport   exporter;
1359         idStr                   name;
1360
1361         // don't allow exporting models when cheats are disabled,
1362         // but if we're not in the game, it's ok
1363         if ( gameLocal.GetLocalPlayer() && !gameLocal.CheatsOk( false ) ) {
1364                 return;
1365         }
1366
1367         idAnimManager::forceExport = true;
1368         if ( args.Argc() < 2 ) {
1369                 exporter.ExportModels( "def", ".def" );
1370         } else {
1371                 name = args.Argv( 1 );
1372                 name = "def/" + name;
1373                 name.DefaultFileExtension( ".def" );
1374                 exporter.ExportDefFile( name );
1375         }
1376         idAnimManager::forceExport = false;
1377 }
1378
1379 /*
1380 ==================
1381 Cmd_ReloadAnims_f
1382 ==================
1383 */
1384 static void Cmd_ReloadAnims_f( const idCmdArgs &args ) {
1385         // don't allow reloading anims when cheats are disabled,
1386         // but if we're not in the game, it's ok
1387         if ( gameLocal.GetLocalPlayer() && !gameLocal.CheatsOk( false ) ) {
1388                 return;
1389         }
1390
1391         animationLib.ReloadAnims();
1392 }
1393
1394 /*
1395 ==================
1396 Cmd_ListAnims_f
1397 ==================
1398 */
1399 static void Cmd_ListAnims_f( const idCmdArgs &args ) {
1400         idEntity *              ent;
1401         int                             num;
1402         size_t                  size;
1403         size_t                  alloced;
1404         idAnimator *    animator;
1405         const char *    classname;
1406         const idDict *  dict;
1407         int                             i;
1408
1409         if ( args.Argc() > 1 ) {
1410                 idAnimator animator;
1411
1412                 classname = args.Argv( 1 );
1413
1414                 dict = gameLocal.FindEntityDefDict( classname, false );
1415                 if ( !dict ) {
1416                         gameLocal.Printf( "Entitydef '%s' not found\n", classname );
1417                         return;
1418                 }
1419                 animator.SetModel( dict->GetString( "model" ) );
1420
1421                 gameLocal.Printf( "----------------\n" );
1422                 num = animator.NumAnims();
1423                 for( i = 0; i < num; i++ ) {
1424                         gameLocal.Printf( "%s\n", animator.AnimFullName( i ) );
1425                 }
1426                 gameLocal.Printf( "%d anims\n", num );
1427         } else {
1428                 animationLib.ListAnims();
1429
1430                 size = 0;
1431                 num = 0;
1432                 for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
1433                         animator = ent->GetAnimator();
1434                         if ( animator ) {
1435                                 alloced = animator->Allocated();
1436                                 size += alloced;
1437                                 num++;
1438                         }
1439                 }
1440
1441                 gameLocal.Printf( "%d memory used in %d entity animators\n", size, num );
1442         }
1443 }
1444
1445 /*
1446 ==================
1447 Cmd_AASStats_f
1448 ==================
1449 */
1450 static void Cmd_AASStats_f( const idCmdArgs &args ) {
1451         int aasNum;
1452
1453         if ( !gameLocal.CheatsOk() ) {
1454                 return;
1455         }
1456
1457         aasNum = aas_test.GetInteger();
1458         idAAS *aas = gameLocal.GetAAS( aasNum );
1459         if ( !aas ) {
1460                 gameLocal.Printf( "No aas #%d loaded\n", aasNum );
1461         } else {
1462                 aas->Stats();
1463         }
1464 }
1465
1466 /*
1467 ==================
1468 Cmd_TestDamage_f
1469 ==================
1470 */
1471 static void Cmd_TestDamage_f( const idCmdArgs &args ) {
1472         idPlayer *player;
1473         const char *damageDefName;
1474
1475         player = gameLocal.GetLocalPlayer();
1476         if ( !player || !gameLocal.CheatsOk() ) {
1477                 return;
1478         }
1479
1480         if ( args.Argc() < 2 || args.Argc() > 3 ) {
1481                 gameLocal.Printf( "usage: testDamage <damageDefName> [angle]\n" );
1482                 return;
1483         }
1484
1485         damageDefName = args.Argv( 1 );
1486
1487         idVec3  dir;
1488         if ( args.Argc() == 3 ) {
1489                 float angle = atof( args.Argv( 2 ) );
1490
1491                 idMath::SinCos( DEG2RAD( angle ), dir[1], dir[0] );
1492                 dir[2] = 0;
1493         } else {
1494                 dir.Zero();
1495         }
1496
1497         // give the player full health before and after
1498         // running the damage
1499         player->health = player->inventory.maxHealth;
1500         player->Damage( NULL, NULL, dir, damageDefName, 1.0f, INVALID_JOINT );
1501         player->health = player->inventory.maxHealth;
1502 }
1503
1504 /*
1505 ==================
1506 Cmd_TestBoneFx_f
1507 ==================
1508 */
1509 static void Cmd_TestBoneFx_f( const idCmdArgs &args ) {
1510         idPlayer *player;
1511         const char *bone, *fx;
1512
1513         player = gameLocal.GetLocalPlayer();
1514         if ( !player || !gameLocal.CheatsOk() ) {
1515                 return;
1516         }
1517
1518         if ( args.Argc() < 3 || args.Argc() > 4 ) {
1519                 gameLocal.Printf( "usage: testBoneFx <fxName> <boneName>\n" );
1520                 return;
1521         }
1522
1523         fx = args.Argv( 1 );
1524         bone = args.Argv( 2 );
1525
1526         player->StartFxOnBone( fx, bone );
1527 }
1528
1529 /*
1530 ==================
1531 Cmd_TestDamage_f
1532 ==================
1533 */
1534 static void Cmd_TestDeath_f( const idCmdArgs &args ) {
1535         idPlayer *player;
1536
1537         player = gameLocal.GetLocalPlayer();
1538         if ( !player || !gameLocal.CheatsOk() ) {
1539                 return;
1540         }
1541
1542         idVec3 dir;
1543         idMath::SinCos( DEG2RAD( 45.0f ), dir[1], dir[0] );
1544         dir[2] = 0;
1545
1546         g_testDeath.SetBool( 1 );
1547         player->Damage( NULL, NULL, dir, "damage_triggerhurt_1000", 1.0f, INVALID_JOINT );
1548         if ( args.Argc() >= 2) {
1549                 player->SpawnGibs( dir, "damage_triggerhurt_1000" );
1550         }
1551
1552 }
1553
1554 /*
1555 ==================
1556 Cmd_WeaponSplat_f
1557 ==================
1558 */
1559 static void Cmd_WeaponSplat_f( const idCmdArgs &args ) {
1560         idPlayer *player;
1561
1562         player = gameLocal.GetLocalPlayer();
1563         if ( !player || !gameLocal.CheatsOk() ) {
1564                 return;
1565         }
1566
1567         player->weapon.GetEntity()->BloodSplat( 2.0f );
1568 }
1569
1570 /*
1571 ==================
1572 Cmd_SaveSelected_f
1573 ==================
1574 */
1575 static void Cmd_SaveSelected_f( const idCmdArgs &args ) {
1576         int i;
1577         idPlayer *player;
1578         idEntity *s;
1579         idMapEntity *mapEnt;
1580         idMapFile *mapFile = gameLocal.GetLevelMap();
1581         idDict dict;
1582         idStr mapName;
1583         const char *name;
1584
1585         player = gameLocal.GetLocalPlayer();
1586         if ( !player || !gameLocal.CheatsOk() ) {
1587                 return;
1588         }
1589
1590         s = player->dragEntity.GetSelected();
1591         if ( !s ) {
1592                 gameLocal.Printf( "no entity selected, set g_dragShowSelection 1 to show the current selection\n" );
1593                 return;
1594         }
1595
1596         if ( args.Argc() > 1 ) {
1597                 mapName = args.Argv( 1 );
1598                 mapName = "maps/" + mapName;
1599         }
1600         else {
1601                 mapName = mapFile->GetName();
1602         }
1603
1604         // find map file entity
1605         mapEnt = mapFile->FindEntity( s->name );
1606         // create new map file entity if there isn't one for this articulated figure
1607         if ( !mapEnt ) {
1608                 mapEnt = new idMapEntity();
1609                 mapFile->AddEntity( mapEnt );
1610                 for ( i = 0; i < 9999; i++ ) {
1611                         name = va( "%s_%d", s->GetEntityDefName(), i );
1612                         if ( !gameLocal.FindEntity( name ) ) {
1613                                 break;
1614                         }
1615                 }
1616                 s->name = name;
1617                 mapEnt->epairs.Set( "classname", s->GetEntityDefName() );
1618                 mapEnt->epairs.Set( "name", s->name );
1619         }
1620
1621         if ( s->IsType( idMoveable::Type ) ) {
1622                 // save the moveable state
1623                 mapEnt->epairs.Set( "origin", s->GetPhysics()->GetOrigin().ToString( 8 ) );
1624                 mapEnt->epairs.Set( "rotation", s->GetPhysics()->GetAxis().ToString( 8 ) );
1625         }
1626         else if ( s->IsType( idAFEntity_Generic::Type ) || s->IsType( idAFEntity_WithAttachedHead::Type ) ) {
1627                 // save the articulated figure state
1628                 dict.Clear();
1629                 static_cast<idAFEntity_Base *>(s)->SaveState( dict );
1630                 mapEnt->epairs.Copy( dict );
1631         }
1632
1633         // write out the map file
1634         mapFile->Write( mapName, ".map" );
1635 }
1636
1637 /*
1638 ==================
1639 Cmd_DeleteSelected_f
1640 ==================
1641 */
1642 static void Cmd_DeleteSelected_f( const idCmdArgs &args ) {
1643         idPlayer *player;
1644
1645         player = gameLocal.GetLocalPlayer();
1646         if ( !player || !gameLocal.CheatsOk() ) {
1647                 return;
1648         }
1649
1650         if ( player ) {
1651                 player->dragEntity.DeleteSelected();
1652         }
1653 }
1654
1655 /*
1656 ==================
1657 Cmd_SaveMoveables_f
1658 ==================
1659 */
1660 static void Cmd_SaveMoveables_f( const idCmdArgs &args ) {
1661         int e, i;
1662         idMoveable *m;
1663         idMapEntity *mapEnt;
1664         idMapFile *mapFile = gameLocal.GetLevelMap();
1665         idStr mapName;
1666         const char *name;
1667
1668         if ( !gameLocal.CheatsOk() ) {
1669                 return;
1670         }
1671
1672         for( e = 0; e < MAX_GENTITIES; e++ ) {
1673                 m = static_cast<idMoveable *>(gameLocal.entities[ e ]);
1674
1675                 if ( !m || !m->IsType( idMoveable::Type ) ) {
1676                         continue;
1677                 }
1678
1679                 if ( m->IsBound() ) {
1680                         continue;
1681                 }
1682
1683                 if ( !m->IsAtRest() ) {
1684                         break;
1685                 }
1686         }
1687
1688         if ( e < MAX_GENTITIES ) {
1689                 gameLocal.Warning( "map not saved because the moveable entity %s is not at rest", gameLocal.entities[ e ]->name.c_str() );
1690                 return;
1691         }
1692
1693         if ( args.Argc() > 1 ) {
1694                 mapName = args.Argv( 1 );
1695                 mapName = "maps/" + mapName;
1696         }
1697         else {
1698                 mapName = mapFile->GetName();
1699         }
1700
1701         for( e = 0; e < MAX_GENTITIES; e++ ) {
1702                 m = static_cast<idMoveable *>(gameLocal.entities[ e ]);
1703
1704                 if ( !m || !m->IsType( idMoveable::Type ) ) {
1705                         continue;
1706                 }
1707
1708                 if ( m->IsBound() ) {
1709                         continue;
1710                 }
1711
1712                 // find map file entity
1713                 mapEnt = mapFile->FindEntity( m->name );
1714                 // create new map file entity if there isn't one for this articulated figure
1715                 if ( !mapEnt ) {
1716                         mapEnt = new idMapEntity();
1717                         mapFile->AddEntity( mapEnt );
1718                         for ( i = 0; i < 9999; i++ ) {
1719                                 name = va( "%s_%d", m->GetEntityDefName(), i );
1720                                 if ( !gameLocal.FindEntity( name ) ) {
1721                                         break;
1722                                 }
1723                         }
1724                         m->name = name;
1725                         mapEnt->epairs.Set( "classname", m->GetEntityDefName() );
1726                         mapEnt->epairs.Set( "name", m->name );
1727                 }
1728                 // save the moveable state
1729                 mapEnt->epairs.Set( "origin", m->GetPhysics()->GetOrigin().ToString( 8 ) );
1730                 mapEnt->epairs.Set( "rotation", m->GetPhysics()->GetAxis().ToString( 8 ) );
1731         }
1732
1733         // write out the map file
1734         mapFile->Write( mapName, ".map" );
1735 }
1736
1737 /*
1738 ==================
1739 Cmd_SaveRagdolls_f
1740 ==================
1741 */
1742 static void Cmd_SaveRagdolls_f( const idCmdArgs &args ) {
1743         int e, i;
1744         idAFEntity_Base *af;
1745         idMapEntity *mapEnt;
1746         idMapFile *mapFile = gameLocal.GetLevelMap();
1747         idDict dict;
1748         idStr mapName;
1749         const char *name;
1750
1751         if ( !gameLocal.CheatsOk() ) {
1752                 return;
1753         }
1754
1755         if ( args.Argc() > 1 ) {
1756                 mapName = args.Argv( 1 );
1757                 mapName = "maps/" + mapName;
1758         }
1759         else {
1760                 mapName = mapFile->GetName();
1761         }
1762
1763         for( e = 0; e < MAX_GENTITIES; e++ ) {
1764                 af = static_cast<idAFEntity_Base *>(gameLocal.entities[ e ]);
1765
1766                 if ( !af ) {
1767                         continue;
1768                 }
1769
1770                 if ( !af->IsType( idAFEntity_WithAttachedHead::Type ) && !af->IsType( idAFEntity_Generic::Type ) ) {
1771                         continue;
1772                 }
1773
1774                 if ( af->IsBound() ) {
1775                         continue;
1776                 }
1777
1778                 if ( !af->IsAtRest() ) {
1779                         gameLocal.Warning( "the articulated figure for entity %s is not at rest", gameLocal.entities[ e ]->name.c_str() );
1780                 }
1781
1782                 dict.Clear();
1783                 af->SaveState( dict );
1784
1785                 // find map file entity
1786                 mapEnt = mapFile->FindEntity( af->name );
1787                 // create new map file entity if there isn't one for this articulated figure
1788                 if ( !mapEnt ) {
1789                         mapEnt = new idMapEntity();
1790                         mapFile->AddEntity( mapEnt );
1791                         for ( i = 0; i < 9999; i++ ) {
1792                                 name = va( "%s_%d", af->GetEntityDefName(), i );
1793                                 if ( !gameLocal.FindEntity( name ) ) {
1794                                         break;
1795                                 }
1796                         }
1797                         af->name = name;
1798                         mapEnt->epairs.Set( "classname", af->GetEntityDefName() );
1799                         mapEnt->epairs.Set( "name", af->name );
1800                 }
1801                 // save the articulated figure state
1802                 mapEnt->epairs.Copy( dict );
1803         }
1804
1805         // write out the map file
1806         mapFile->Write( mapName, ".map" );
1807 }
1808
1809 /*
1810 ==================
1811 Cmd_BindRagdoll_f
1812 ==================
1813 */
1814 static void Cmd_BindRagdoll_f( const idCmdArgs &args ) {
1815         idPlayer *player;
1816
1817         player = gameLocal.GetLocalPlayer();
1818         if ( !player || !gameLocal.CheatsOk() ) {
1819                 return;
1820         }
1821
1822         if ( player ) {
1823                 player->dragEntity.BindSelected();
1824         }
1825 }
1826
1827 /*
1828 ==================
1829 Cmd_UnbindRagdoll_f
1830 ==================
1831 */
1832 static void Cmd_UnbindRagdoll_f( const idCmdArgs &args ) {
1833         idPlayer *player;
1834
1835         player = gameLocal.GetLocalPlayer();
1836         if ( !player || !gameLocal.CheatsOk() ) {
1837                 return;
1838         }
1839
1840         if ( player ) {
1841                 player->dragEntity.UnbindSelected();
1842         }
1843 }
1844
1845 /*
1846 ==================
1847 Cmd_GameError_f
1848 ==================
1849 */
1850 static void Cmd_GameError_f( const idCmdArgs &args ) {
1851         gameLocal.Error( "game error" );
1852 }
1853
1854 /*
1855 ==================
1856 Cmd_SaveLights_f
1857 ==================
1858 */
1859 static void Cmd_SaveLights_f( const idCmdArgs &args ) {
1860         int e, i;
1861         idLight *light;
1862         idMapEntity *mapEnt;
1863         idMapFile *mapFile = gameLocal.GetLevelMap();
1864         idDict dict;
1865         idStr mapName;
1866         const char *name;
1867
1868         if ( !gameLocal.CheatsOk() ) {
1869                 return;
1870         }
1871
1872         if ( args.Argc() > 1 ) {
1873                 mapName = args.Argv( 1 );
1874                 mapName = "maps/" + mapName;
1875         }
1876         else {
1877                 mapName = mapFile->GetName();
1878         }
1879
1880         for( e = 0; e < MAX_GENTITIES; e++ ) {
1881                 light = static_cast<idLight*>(gameLocal.entities[ e ]);
1882
1883                 if ( !light || !light->IsType( idLight::Type ) ) {
1884                         continue;
1885                 }
1886
1887                 dict.Clear();
1888                 light->SaveState( &dict );
1889
1890                 // find map file entity
1891                 mapEnt = mapFile->FindEntity( light->name );
1892                 // create new map file entity if there isn't one for this light
1893                 if ( !mapEnt ) {
1894                         mapEnt = new idMapEntity();
1895                         mapFile->AddEntity( mapEnt );
1896                         for ( i = 0; i < 9999; i++ ) {
1897                                 name = va( "%s_%d", light->GetEntityDefName(), i );
1898                                 if ( !gameLocal.FindEntity( name ) ) {
1899                                         break;
1900                                 }
1901                         }
1902                         light->name = name;
1903                         mapEnt->epairs.Set( "classname", light->GetEntityDefName() );
1904                         mapEnt->epairs.Set( "name", light->name );
1905                 }
1906                 // save the light state
1907                 mapEnt->epairs.Copy( dict );
1908         }
1909
1910         // write out the map file
1911         mapFile->Write( mapName, ".map" );
1912 }
1913
1914
1915 /*
1916 ==================
1917 Cmd_SaveParticles_f
1918 ==================
1919 */
1920 static void Cmd_SaveParticles_f( const idCmdArgs &args ) {
1921         int e;
1922         idEntity *ent;
1923         idMapEntity *mapEnt;
1924         idMapFile *mapFile = gameLocal.GetLevelMap();
1925         idDict dict;
1926         idStr mapName, strModel;
1927
1928         if ( !gameLocal.CheatsOk() ) {
1929                 return;
1930         }
1931
1932         if ( args.Argc() > 1 ) {
1933                 mapName = args.Argv( 1 );
1934                 mapName = "maps/" + mapName;
1935         }
1936         else {
1937                 mapName = mapFile->GetName();
1938         }
1939
1940         for( e = 0; e < MAX_GENTITIES; e++ ) {
1941
1942                 ent = static_cast<idStaticEntity*> ( gameLocal.entities[ e ] );
1943
1944                 if ( !ent ) {
1945                         continue;
1946                 }
1947
1948                 strModel = ent->spawnArgs.GetString( "model" );
1949                 if ( strModel.Length() && strModel.Find( ".prt") > 0 ) {
1950                         dict.Clear();
1951                         dict.Set( "model", ent->spawnArgs.GetString( "model" ) );
1952                         dict.SetVector( "origin", ent->GetPhysics()->GetOrigin() );
1953
1954                         // find map file entity
1955                         mapEnt = mapFile->FindEntity( ent->name );
1956                         // create new map file entity if there isn't one for this entity
1957                         if ( !mapEnt ) {
1958                                 continue;
1959                         }
1960                         // save the particle state
1961                         mapEnt->epairs.Copy( dict );
1962                 }
1963         }
1964
1965         // write out the map file
1966         mapFile->Write( mapName, ".map" );
1967 }
1968
1969
1970 /*
1971 ==================
1972 Cmd_DisasmScript_f
1973 ==================
1974 */
1975 static void Cmd_DisasmScript_f( const idCmdArgs &args ) {
1976         gameLocal.program.Disassemble();
1977 }
1978
1979 /*
1980 ==================
1981 Cmd_TestSave_f
1982 ==================
1983 */
1984 static void Cmd_TestSave_f( const idCmdArgs &args ) {
1985         idFile *f;
1986
1987         f = fileSystem->OpenFileWrite( "test.sav" );
1988         gameLocal.SaveGame( f );
1989         fileSystem->CloseFile( f );
1990 }
1991
1992 /*
1993 ==================
1994 Cmd_RecordViewNotes_f
1995 ==================
1996 */
1997 static void Cmd_RecordViewNotes_f( const idCmdArgs &args ) {
1998         idPlayer *player;
1999         idVec3 origin;
2000         idMat3 axis;
2001
2002         if ( args.Argc() <= 3 ) {
2003                 return;
2004         }
2005
2006         player = gameLocal.GetLocalPlayer();
2007         if ( !player ) {
2008                 return;
2009         }
2010
2011         player->GetViewPos( origin, axis );
2012
2013         // Argv(1) = filename for map (viewnotes/mapname/person)
2014         // Argv(2) = note number (person0001)
2015         // Argv(3) = comments
2016
2017         idStr str = args.Argv(1);
2018         str.SetFileExtension( ".txt" );
2019         idFile *file = fileSystem->OpenFileAppend( str );
2020         if ( file ) {
2021                 file->WriteFloatString( "\"view\"\t( %s )\t( %s )\r\n", origin.ToString(), axis.ToString() );
2022                 file->WriteFloatString( "\"comments\"\t\"%s: %s\"\r\n\r\n", args.Argv(2), args.Argv(3) );
2023                 fileSystem->CloseFile( file );
2024         }
2025
2026         idStr viewComments = args.Argv(1);
2027         viewComments.StripLeading("viewnotes/");
2028         viewComments += " -- Loc: ";
2029         viewComments += origin.ToString();
2030         viewComments += "\n";
2031         viewComments += args.Argv(3);
2032         player->hud->SetStateString( "viewcomments", viewComments );
2033         player->hud->HandleNamedEvent( "showViewComments" );
2034 }
2035
2036 /*
2037 ==================
2038 Cmd_CloseViewNotes_f
2039 ==================
2040 */
2041 static void Cmd_CloseViewNotes_f( const idCmdArgs &args ) {
2042         idPlayer *player = gameLocal.GetLocalPlayer();
2043
2044         if ( !player ) {
2045                 return;
2046         }
2047         
2048         player->hud->SetStateString( "viewcomments", "" );
2049         player->hud->HandleNamedEvent( "hideViewComments" );
2050 }
2051
2052 /*
2053 ==================
2054 Cmd_ShowViewNotes_f
2055 ==================
2056 */
2057 static void Cmd_ShowViewNotes_f( const idCmdArgs &args ) {
2058         static idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT | LEXFL_NOFATALERRORS );
2059         idToken token;
2060         idPlayer *player;
2061         idVec3 origin;
2062         idMat3 axis;
2063
2064         player = gameLocal.GetLocalPlayer();
2065
2066         if ( !player ) {
2067                 return;
2068         }
2069
2070         if ( !parser.IsLoaded() ) {
2071                 idStr str = "viewnotes/";
2072                 str += gameLocal.GetMapName();
2073                 str.StripFileExtension();
2074                 str += "/";
2075                 if ( args.Argc() > 1 ) {
2076                         str += args.Argv( 1 );
2077                 } else {
2078                         str += "comments";
2079                 }
2080                 str.SetFileExtension( ".txt" );
2081                 if ( !parser.LoadFile( str ) ) {
2082                         gameLocal.Printf( "No view notes for %s\n", gameLocal.GetMapName() );
2083                         return;
2084                 }
2085         }
2086
2087         if ( parser.ExpectTokenString( "view" ) && parser.Parse1DMatrix( 3, origin.ToFloatPtr() ) && 
2088                 parser.Parse1DMatrix( 9, axis.ToFloatPtr() ) && parser.ExpectTokenString( "comments" ) && parser.ReadToken( &token ) ) {
2089                 player->hud->SetStateString( "viewcomments", token );
2090                 player->hud->HandleNamedEvent( "showViewComments" );
2091                 player->Teleport( origin, axis.ToAngles(), NULL );
2092         } else {
2093                 parser.FreeSource();
2094                 player->hud->HandleNamedEvent( "hideViewComments" );
2095                 return;
2096         }
2097 }
2098
2099 /*
2100 =================
2101 FindEntityGUIs
2102
2103 helper function for Cmd_NextGUI_f.  Checks the passed entity to determine if it
2104 has any valid gui surfaces.
2105 =================
2106 */
2107 bool FindEntityGUIs( idEntity *ent, const modelSurface_t ** surfaces,  int maxSurfs, int &guiSurfaces ) {
2108         renderEntity_t                  *renderEnt;
2109         idRenderModel                   *renderModel;
2110         const modelSurface_t    *surf;
2111         const idMaterial                *shader;
2112         int                                             i;
2113
2114         assert( surfaces != NULL );
2115         assert( ent != NULL );
2116
2117         memset( surfaces, 0x00, sizeof( modelSurface_t *) * maxSurfs );
2118         guiSurfaces = 0;
2119
2120         renderEnt  = ent->GetRenderEntity();
2121         renderModel = renderEnt->hModel;
2122         if ( renderModel == NULL ) {
2123                 return false;
2124         }
2125
2126         for( i = 0; i < renderModel->NumSurfaces(); i++ ) {
2127                 surf = renderModel->Surface( i );
2128                 if ( surf == NULL ) {
2129                         continue;
2130                 }
2131                 shader = surf->shader;
2132                 if ( shader == NULL ) {
2133                         continue;
2134                 }
2135                 if ( shader->GetEntityGui() > 0 ) {
2136                         surfaces[ guiSurfaces++ ] = surf;
2137                 }
2138         }
2139
2140         return ( guiSurfaces != 0 );
2141 }
2142
2143 /*
2144 =================
2145 Cmd_NextGUI_f
2146 =================
2147 */
2148 void Cmd_NextGUI_f( const idCmdArgs &args ) {
2149         idVec3                                  origin;
2150         idAngles                                angles;
2151         idPlayer                                *player;
2152         idEntity                                *ent;
2153         int                                             guiSurfaces;
2154         bool                                    newEnt;
2155         renderEntity_t                  *renderEnt;
2156         int                                             surfIndex;
2157         srfTriangles_t                  *geom;
2158         idMat4                                  modelMatrix;
2159         idVec3                                  normal;
2160         idVec3                                  center;
2161         const modelSurface_t    *surfaces[ MAX_RENDERENTITY_GUI ];
2162
2163         player = gameLocal.GetLocalPlayer();
2164         if ( !player || !gameLocal.CheatsOk() ) {
2165                 return;
2166         }
2167
2168         if ( args.Argc() != 1 ) {
2169                 gameLocal.Printf( "usage: nextgui\n" );
2170                 return;
2171         }
2172
2173         // start at the last entity
2174         ent = gameLocal.lastGUIEnt.GetEntity();
2175
2176         // see if we have any gui surfaces left to go to on the current entity.
2177         guiSurfaces = 0;
2178         newEnt = false;
2179         if ( ent == NULL ) {
2180                 newEnt = true;
2181         } else if ( FindEntityGUIs( ent, surfaces, MAX_RENDERENTITY_GUI, guiSurfaces ) == true ) {
2182                 if ( gameLocal.lastGUI >= guiSurfaces ) {
2183                         newEnt = true;
2184                 }
2185         } else {
2186                 // no actual gui surfaces on this ent, so skip it
2187                 newEnt = true;
2188         }
2189
2190         if ( newEnt == true ) {
2191                 // go ahead and skip to the next entity with a gui...
2192                 if ( ent == NULL ) {
2193                         ent = gameLocal.spawnedEntities.Next();
2194                 } else {
2195                         ent = ent->spawnNode.Next();
2196                 }
2197
2198                 for ( ; ent != NULL; ent = ent->spawnNode.Next() ) {
2199                         if ( ent->spawnArgs.GetString( "gui", NULL ) != NULL ) {
2200                                 break;
2201                         }
2202                         
2203                         if ( ent->spawnArgs.GetString( "gui2", NULL ) != NULL ) {
2204                                 break;
2205                         }
2206
2207                         if ( ent->spawnArgs.GetString( "gui3", NULL ) != NULL ) {
2208                                 break;
2209                         }
2210                         
2211                         // try the next entity
2212                         gameLocal.lastGUIEnt = ent;
2213                 }
2214
2215                 gameLocal.lastGUIEnt = ent;
2216                 gameLocal.lastGUI = 0;
2217
2218                 if ( !ent ) {
2219                         gameLocal.Printf( "No more gui entities. Starting over...\n" );
2220                         return;
2221                 }
2222         }
2223
2224         if ( FindEntityGUIs( ent, surfaces, MAX_RENDERENTITY_GUI, guiSurfaces ) == false ) {
2225                 gameLocal.Printf( "Entity \"%s\" has gui properties but no gui surfaces.\n", ent->name.c_str() );
2226         }
2227
2228         if ( guiSurfaces == 0 ) {
2229                 gameLocal.Printf( "Entity \"%s\" has gui properties but no gui surfaces!\n", ent->name.c_str() );
2230                 return;
2231         }
2232
2233         gameLocal.Printf( "Teleporting to gui entity \"%s\", gui #%d.\n" , ent->name.c_str (), gameLocal.lastGUI );
2234
2235         renderEnt = ent->GetRenderEntity();
2236         surfIndex = gameLocal.lastGUI++;
2237         geom = surfaces[ surfIndex ]->geometry;
2238         if ( geom == NULL ) {
2239                 gameLocal.Printf( "Entity \"%s\" has gui surface %d without geometry!\n", ent->name.c_str(), surfIndex );
2240                 return;
2241         }
2242
2243         assert( geom->facePlanes != NULL );
2244
2245         modelMatrix = idMat4( renderEnt->axis, renderEnt->origin );     
2246         normal = geom->facePlanes[ 0 ].Normal() * renderEnt->axis;
2247         center = geom->bounds.GetCenter() * modelMatrix;
2248
2249         origin = center + (normal * 32.0f);
2250         origin.z -= player->EyeHeight();
2251         normal *= -1.0f;
2252         angles = normal.ToAngles ();
2253
2254         //      make sure the player is in noclip
2255         player->noclip = true;
2256         player->Teleport( origin, angles, NULL );
2257 }
2258
2259 static void ArgCompletion_DefFile( const idCmdArgs &args, void(*callback)( const char *s ) ) {
2260         cmdSystem->ArgCompletion_FolderExtension( args, callback, "def/", true, ".def", NULL );
2261 }
2262
2263 /*
2264 ===============
2265 Cmd_TestId_f
2266 outputs a string from the string table for the specified id
2267 ===============
2268 */
2269 void Cmd_TestId_f( const idCmdArgs &args ) {
2270         idStr   id;
2271         int             i;
2272         if ( args.Argc() == 1 ) {
2273                 common->Printf( "usage: testid <string id>\n" );
2274                 return;
2275         }
2276
2277         for ( i = 1; i < args.Argc(); i++ ) {
2278                 id += args.Argv( i );
2279         }
2280         if ( idStr::Cmpn( id, STRTABLE_ID, STRTABLE_ID_LENGTH ) != 0 ) {
2281                 id = STRTABLE_ID + id;
2282         }
2283         gameLocal.mpGame.AddChatLine( common->GetLanguageDict()->GetString( id ), "<nothing>", "<nothing>", "<nothing>" );      
2284 }
2285
2286 /*
2287 =================
2288 idGameLocal::InitConsoleCommands
2289
2290 Let the system know about all of our commands
2291 so it can perform tab completion
2292 =================
2293 */
2294 void idGameLocal::InitConsoleCommands( void ) {
2295         cmdSystem->AddCommand( "listTypeInfo",                  ListTypeInfo_f,                         CMD_FL_GAME,                            "list type info" );
2296         cmdSystem->AddCommand( "writeGameState",                WriteGameState_f,                       CMD_FL_GAME,                            "write game state" );
2297         cmdSystem->AddCommand( "testSaveGame",                  TestSaveGame_f,                         CMD_FL_GAME|CMD_FL_CHEAT,       "test a save game for a level" );
2298         cmdSystem->AddCommand( "game_memory",                   idClass::DisplayInfo_f,         CMD_FL_GAME,                            "displays game class info" );
2299         cmdSystem->AddCommand( "listClasses",                   idClass::ListClasses_f,         CMD_FL_GAME,                            "lists game classes" );
2300         cmdSystem->AddCommand( "listThreads",                   idThread::ListThreads_f,        CMD_FL_GAME|CMD_FL_CHEAT,       "lists script threads" );
2301         cmdSystem->AddCommand( "listEntities",                  Cmd_EntityList_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "lists game entities" );
2302         cmdSystem->AddCommand( "listActiveEntities",    Cmd_ActiveEntityList_f,         CMD_FL_GAME|CMD_FL_CHEAT,       "lists active game entities" );
2303         cmdSystem->AddCommand( "listMonsters",                  idAI::List_f,                           CMD_FL_GAME|CMD_FL_CHEAT,       "lists monsters" );
2304         cmdSystem->AddCommand( "listSpawnArgs",                 Cmd_ListSpawnArgs_f,            CMD_FL_GAME|CMD_FL_CHEAT,       "list the spawn args of an entity", idGameLocal::ArgCompletion_EntityName );
2305         cmdSystem->AddCommand( "say",                                   Cmd_Say_f,                                      CMD_FL_GAME,                            "text chat" );
2306         cmdSystem->AddCommand( "sayTeam",                               Cmd_SayTeam_f,                          CMD_FL_GAME,                            "team text chat" );
2307         cmdSystem->AddCommand( "addChatLine",                   Cmd_AddChatLine_f,                      CMD_FL_GAME,                            "internal use - core to game chat lines" );
2308         cmdSystem->AddCommand( "gameKick",                              Cmd_Kick_f,                                     CMD_FL_GAME,                            "same as kick, but recognizes player names" );
2309         cmdSystem->AddCommand( "give",                                  Cmd_Give_f,                                     CMD_FL_GAME|CMD_FL_CHEAT,       "gives one or more items" );
2310         cmdSystem->AddCommand( "centerview",                    Cmd_CenterView_f,                       CMD_FL_GAME,                            "centers the view" );
2311         cmdSystem->AddCommand( "god",                                   Cmd_God_f,                                      CMD_FL_GAME|CMD_FL_CHEAT,       "enables god mode" );
2312         cmdSystem->AddCommand( "notarget",                              Cmd_Notarget_f,                         CMD_FL_GAME|CMD_FL_CHEAT,       "disables the player as a target" );
2313         cmdSystem->AddCommand( "noclip",                                Cmd_Noclip_f,                           CMD_FL_GAME|CMD_FL_CHEAT,       "disables collision detection for the player" );
2314         cmdSystem->AddCommand( "kill",                                  Cmd_Kill_f,                                     CMD_FL_GAME,                            "kills the player" );
2315         cmdSystem->AddCommand( "where",                                 Cmd_GetViewpos_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "prints the current view position" );
2316         cmdSystem->AddCommand( "getviewpos",                    Cmd_GetViewpos_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "prints the current view position" );
2317         cmdSystem->AddCommand( "setviewpos",                    Cmd_SetViewpos_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "sets the current view position" );
2318         cmdSystem->AddCommand( "teleport",                              Cmd_Teleport_f,                         CMD_FL_GAME|CMD_FL_CHEAT,       "teleports the player to an entity location", idGameLocal::ArgCompletion_EntityName );
2319         cmdSystem->AddCommand( "trigger",                               Cmd_Trigger_f,                          CMD_FL_GAME|CMD_FL_CHEAT,       "triggers an entity", idGameLocal::ArgCompletion_EntityName );
2320         cmdSystem->AddCommand( "spawn",                                 Cmd_Spawn_f,                            CMD_FL_GAME|CMD_FL_CHEAT,       "spawns a game entity", idCmdSystem::ArgCompletion_Decl<DECL_ENTITYDEF> );
2321         cmdSystem->AddCommand( "damage",                                Cmd_Damage_f,                           CMD_FL_GAME|CMD_FL_CHEAT,       "apply damage to an entity", idGameLocal::ArgCompletion_EntityName );
2322         cmdSystem->AddCommand( "remove",                                Cmd_Remove_f,                           CMD_FL_GAME|CMD_FL_CHEAT,       "removes an entity", idGameLocal::ArgCompletion_EntityName );
2323         cmdSystem->AddCommand( "killMonsters",                  Cmd_KillMonsters_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "removes all monsters" );
2324         cmdSystem->AddCommand( "killMoveables",                 Cmd_KillMovables_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "removes all moveables" );
2325         cmdSystem->AddCommand( "killRagdolls",                  Cmd_KillRagdolls_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "removes all ragdolls" );
2326         cmdSystem->AddCommand( "addline",                               Cmd_AddDebugLine_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "adds a debug line" );
2327         cmdSystem->AddCommand( "addarrow",                              Cmd_AddDebugLine_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "adds a debug arrow" );
2328         cmdSystem->AddCommand( "removeline",                    Cmd_RemoveDebugLine_f,          CMD_FL_GAME|CMD_FL_CHEAT,       "removes a debug line" );
2329         cmdSystem->AddCommand( "blinkline",                             Cmd_BlinkDebugLine_f,           CMD_FL_GAME|CMD_FL_CHEAT,       "blinks a debug line" );
2330         cmdSystem->AddCommand( "listLines",                             Cmd_ListDebugLines_f,           CMD_FL_GAME|CMD_FL_CHEAT,       "lists all debug lines" );
2331         cmdSystem->AddCommand( "playerModel",                   Cmd_PlayerModel_f,                      CMD_FL_GAME|CMD_FL_CHEAT,       "sets the given model on the player", idCmdSystem::ArgCompletion_Decl<DECL_MODELDEF> );
2332         cmdSystem->AddCommand( "testFx",                                Cmd_TestFx_f,                           CMD_FL_GAME|CMD_FL_CHEAT,       "tests an FX system", idCmdSystem::ArgCompletion_Decl<DECL_FX> );
2333         cmdSystem->AddCommand( "testBoneFx",                    Cmd_TestBoneFx_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "tests an FX system bound to a joint", idCmdSystem::ArgCompletion_Decl<DECL_FX> );
2334         cmdSystem->AddCommand( "testLight",                             Cmd_TestLight_f,                        CMD_FL_GAME|CMD_FL_CHEAT,       "tests a light" );
2335         cmdSystem->AddCommand( "testPointLight",                Cmd_TestPointLight_f,           CMD_FL_GAME|CMD_FL_CHEAT,       "tests a point light" );
2336         cmdSystem->AddCommand( "popLight",                              Cmd_PopLight_f,                         CMD_FL_GAME|CMD_FL_CHEAT,       "removes the last created light" );
2337         cmdSystem->AddCommand( "testDeath",                             Cmd_TestDeath_f,                        CMD_FL_GAME|CMD_FL_CHEAT,       "tests death" );
2338         cmdSystem->AddCommand( "testSave",                              Cmd_TestSave_f,                         CMD_FL_GAME|CMD_FL_CHEAT,       "writes out a test savegame" );
2339         cmdSystem->AddCommand( "testModel",                             idTestModel::TestModel_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "tests a model", idTestModel::ArgCompletion_TestModel );
2340         cmdSystem->AddCommand( "testSkin",                              idTestModel::TestSkin_f,                        CMD_FL_GAME|CMD_FL_CHEAT,       "tests a skin on an existing testModel", idCmdSystem::ArgCompletion_Decl<DECL_SKIN> );
2341         cmdSystem->AddCommand( "testShaderParm",                idTestModel::TestShaderParm_f,          CMD_FL_GAME|CMD_FL_CHEAT,       "sets a shaderParm on an existing testModel" );
2342         cmdSystem->AddCommand( "keepTestModel",                 idTestModel::KeepTestModel_f,           CMD_FL_GAME|CMD_FL_CHEAT,       "keeps the last test model in the game" );
2343         cmdSystem->AddCommand( "testAnim",                              idTestModel::TestAnim_f,                        CMD_FL_GAME|CMD_FL_CHEAT,       "tests an animation", idTestModel::ArgCompletion_TestAnim );
2344         cmdSystem->AddCommand( "testParticleStopTime",  idTestModel::TestParticleStopTime_f,CMD_FL_GAME|CMD_FL_CHEAT,   "tests particle stop time on a test model" );
2345         cmdSystem->AddCommand( "nextAnim",                              idTestModel::TestModelNextAnim_f,       CMD_FL_GAME|CMD_FL_CHEAT,       "shows next animation on test model" );
2346         cmdSystem->AddCommand( "prevAnim",                              idTestModel::TestModelPrevAnim_f,       CMD_FL_GAME|CMD_FL_CHEAT,       "shows previous animation on test model" );
2347         cmdSystem->AddCommand( "nextFrame",                             idTestModel::TestModelNextFrame_f,      CMD_FL_GAME|CMD_FL_CHEAT,       "shows next animation frame on test model" );
2348         cmdSystem->AddCommand( "prevFrame",                             idTestModel::TestModelPrevFrame_f,      CMD_FL_GAME|CMD_FL_CHEAT,       "shows previous animation frame on test model" );
2349         cmdSystem->AddCommand( "testBlend",                             idTestModel::TestBlend_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "tests animation blending" );
2350         cmdSystem->AddCommand( "reloadScript",                  Cmd_ReloadScript_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "reloads scripts" );
2351         cmdSystem->AddCommand( "script",                                Cmd_Script_f,                           CMD_FL_GAME|CMD_FL_CHEAT,       "executes a line of script" );
2352         cmdSystem->AddCommand( "listCollisionModels",   Cmd_ListCollisionModels_f,      CMD_FL_GAME,                            "lists collision models" );
2353         cmdSystem->AddCommand( "collisionModelInfo",    Cmd_CollisionModelInfo_f,       CMD_FL_GAME,                            "shows collision model info" );
2354         cmdSystem->AddCommand( "reexportmodels",                Cmd_ReexportModels_f,           CMD_FL_GAME|CMD_FL_CHEAT,       "reexports models", ArgCompletion_DefFile );
2355         cmdSystem->AddCommand( "reloadanims",                   Cmd_ReloadAnims_f,                      CMD_FL_GAME|CMD_FL_CHEAT,       "reloads animations" );
2356         cmdSystem->AddCommand( "listAnims",                             Cmd_ListAnims_f,                        CMD_FL_GAME,                            "lists all animations" );
2357         cmdSystem->AddCommand( "aasStats",                              Cmd_AASStats_f,                         CMD_FL_GAME,                            "shows AAS stats" );
2358         cmdSystem->AddCommand( "testDamage",                    Cmd_TestDamage_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "tests a damage def", idCmdSystem::ArgCompletion_Decl<DECL_ENTITYDEF> );
2359         cmdSystem->AddCommand( "weaponSplat",                   Cmd_WeaponSplat_f,                      CMD_FL_GAME|CMD_FL_CHEAT,       "projects a blood splat on the player weapon" );
2360         cmdSystem->AddCommand( "saveSelected",                  Cmd_SaveSelected_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "saves the selected entity to the .map file" );
2361         cmdSystem->AddCommand( "deleteSelected",                Cmd_DeleteSelected_f,           CMD_FL_GAME|CMD_FL_CHEAT,       "deletes selected entity" );
2362         cmdSystem->AddCommand( "saveMoveables",                 Cmd_SaveMoveables_f,            CMD_FL_GAME|CMD_FL_CHEAT,       "save all moveables to the .map file" );
2363         cmdSystem->AddCommand( "saveRagdolls",                  Cmd_SaveRagdolls_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "save all ragdoll poses to the .map file" );
2364         cmdSystem->AddCommand( "bindRagdoll",                   Cmd_BindRagdoll_f,                      CMD_FL_GAME|CMD_FL_CHEAT,       "binds ragdoll at the current drag position" );
2365         cmdSystem->AddCommand( "unbindRagdoll",                 Cmd_UnbindRagdoll_f,            CMD_FL_GAME|CMD_FL_CHEAT,       "unbinds the selected ragdoll" );
2366         cmdSystem->AddCommand( "saveLights",                    Cmd_SaveLights_f,                       CMD_FL_GAME|CMD_FL_CHEAT,       "saves all lights to the .map file" );
2367         cmdSystem->AddCommand( "saveParticles",                 Cmd_SaveParticles_f,            CMD_FL_GAME|CMD_FL_CHEAT,       "saves all lights to the .map file" );
2368         cmdSystem->AddCommand( "clearLights",                   Cmd_ClearLights_f,                      CMD_FL_GAME|CMD_FL_CHEAT,       "clears all lights" );
2369         cmdSystem->AddCommand( "gameError",                             Cmd_GameError_f,                        CMD_FL_GAME|CMD_FL_CHEAT,       "causes a game error" );
2370
2371 #ifndef ID_DEMO_BUILD
2372         cmdSystem->AddCommand( "disasmScript",                  Cmd_DisasmScript_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "disassembles script" );
2373         cmdSystem->AddCommand( "recordViewNotes",               Cmd_RecordViewNotes_f,          CMD_FL_GAME|CMD_FL_CHEAT,       "record the current view position with notes" );
2374         cmdSystem->AddCommand( "showViewNotes",                 Cmd_ShowViewNotes_f,            CMD_FL_GAME|CMD_FL_CHEAT,       "show any view notes for the current map, successive calls will cycle to the next note" );
2375         cmdSystem->AddCommand( "closeViewNotes",                Cmd_CloseViewNotes_f,           CMD_FL_GAME|CMD_FL_CHEAT,       "close the view showing any notes for this map" );
2376         cmdSystem->AddCommand( "exportmodels",                  Cmd_ExportModels_f,                     CMD_FL_GAME|CMD_FL_CHEAT,       "exports models", ArgCompletion_DefFile );
2377
2378         // multiplayer client commands ( replaces old impulses stuff )
2379         cmdSystem->AddCommand( "clientDropWeapon",              idMultiplayerGame::DropWeapon_f, CMD_FL_GAME,                   "drop current weapon" );
2380         cmdSystem->AddCommand( "clientMessageMode",             idMultiplayerGame::MessageMode_f, CMD_FL_GAME,                  "ingame gui message mode" );
2381         // FIXME: implement
2382 //      cmdSystem->AddCommand( "clientVote",                    idMultiplayerGame::Vote_f,      CMD_FL_GAME,                            "cast your vote: clientVote yes | no" );
2383 //      cmdSystem->AddCommand( "clientCallVote",                idMultiplayerGame::CallVote_f,  CMD_FL_GAME,                    "call a vote: clientCallVote si_.. proposed_value" );
2384         cmdSystem->AddCommand( "clientVoiceChat",               idMultiplayerGame::VoiceChat_f, CMD_FL_GAME,                    "voice chats: clientVoiceChat <sound shader>" );
2385         cmdSystem->AddCommand( "clientVoiceChatTeam",   idMultiplayerGame::VoiceChatTeam_f,     CMD_FL_GAME,            "team voice chats: clientVoiceChat <sound shader>" );
2386
2387         // multiplayer server commands
2388         cmdSystem->AddCommand( "serverMapRestart",              idGameLocal::MapRestart_f,      CMD_FL_GAME,                            "restart the current game" );
2389         cmdSystem->AddCommand( "serverForceReady",      idMultiplayerGame::ForceReady_f,CMD_FL_GAME,                            "force all players ready" );
2390         cmdSystem->AddCommand( "serverNextMap",                 idGameLocal::NextMap_f,         CMD_FL_GAME,                            "change to the next map" );
2391 #endif
2392
2393         // localization help commands
2394         cmdSystem->AddCommand( "nextGUI",                               Cmd_NextGUI_f,                          CMD_FL_GAME|CMD_FL_CHEAT,       "teleport the player to the next func_static with a gui" );
2395         cmdSystem->AddCommand( "testid",                                Cmd_TestId_f,                           CMD_FL_GAME|CMD_FL_CHEAT,       "output the string for the specified id." );
2396 }
2397
2398 /*
2399 =================
2400 idGameLocal::ShutdownConsoleCommands
2401 =================
2402 */
2403 void idGameLocal::ShutdownConsoleCommands( void ) {
2404         cmdSystem->RemoveFlaggedCommands( CMD_FL_GAME );
2405 }