]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/d3xp/script/Script_Thread.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / d3xp / script / Script_Thread.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 const idEventDef EV_Thread_Execute( "<execute>", NULL );
35 const idEventDef EV_Thread_SetCallback( "<script_setcallback>", NULL );
36                                                                                                                                         
37 // script callable events
38 const idEventDef EV_Thread_TerminateThread( "terminate", "d" );
39 const idEventDef EV_Thread_Pause( "pause", NULL );
40 const idEventDef EV_Thread_Wait( "wait", "f" );
41 const idEventDef EV_Thread_WaitFrame( "waitFrame" );
42 const idEventDef EV_Thread_WaitFor( "waitFor", "e" );
43 const idEventDef EV_Thread_WaitForThread( "waitForThread", "d" );
44 const idEventDef EV_Thread_Print( "print", "s" );
45 const idEventDef EV_Thread_PrintLn( "println", "s" );
46 const idEventDef EV_Thread_Say( "say", "s" );
47 const idEventDef EV_Thread_Assert( "assert", "f" );
48 const idEventDef EV_Thread_Trigger( "trigger", "e" );
49 const idEventDef EV_Thread_SetCvar( "setcvar", "ss" );
50 const idEventDef EV_Thread_GetCvar( "getcvar", "s", 's' );
51 const idEventDef EV_Thread_Random( "random", "f", 'f' );
52 #ifdef _D3XP
53 const idEventDef EV_Thread_RandomInt( "randomInt", "d", 'd' );
54 #endif
55 const idEventDef EV_Thread_GetTime( "getTime", NULL, 'f' );
56 const idEventDef EV_Thread_KillThread( "killthread", "s" );
57 const idEventDef EV_Thread_SetThreadName( "threadname", "s" );
58 const idEventDef EV_Thread_GetEntity( "getEntity", "s", 'e' );
59 const idEventDef EV_Thread_Spawn( "spawn", "s", 'e' );
60 const idEventDef EV_Thread_CopySpawnArgs( "copySpawnArgs", "e" );
61 const idEventDef EV_Thread_SetSpawnArg( "setSpawnArg", "ss" );
62 const idEventDef EV_Thread_SpawnString( "SpawnString", "ss", 's' );
63 const idEventDef EV_Thread_SpawnFloat( "SpawnFloat", "sf", 'f' );
64 const idEventDef EV_Thread_SpawnVector( "SpawnVector", "sv", 'v' );
65 const idEventDef EV_Thread_ClearPersistantArgs( "clearPersistantArgs" );
66 const idEventDef EV_Thread_SetPersistantArg( "setPersistantArg", "ss" );
67 const idEventDef EV_Thread_GetPersistantString( "getPersistantString", "s", 's' );
68 const idEventDef EV_Thread_GetPersistantFloat( "getPersistantFloat", "s", 'f' );
69 const idEventDef EV_Thread_GetPersistantVector( "getPersistantVector", "s", 'v' );
70 const idEventDef EV_Thread_AngToForward( "angToForward", "v", 'v' );
71 const idEventDef EV_Thread_AngToRight( "angToRight", "v", 'v' );
72 const idEventDef EV_Thread_AngToUp( "angToUp", "v", 'v' );
73 const idEventDef EV_Thread_Sine( "sin", "f", 'f' );
74 const idEventDef EV_Thread_Cosine( "cos", "f", 'f' );
75 #ifdef _D3XP
76 const idEventDef EV_Thread_ArcSine( "asin", "f", 'f' );
77 const idEventDef EV_Thread_ArcCosine( "acos", "f", 'f' );
78 #endif
79 const idEventDef EV_Thread_SquareRoot( "sqrt", "f", 'f' );
80 const idEventDef EV_Thread_Normalize( "vecNormalize", "v", 'v' );
81 const idEventDef EV_Thread_VecLength( "vecLength", "v", 'f' );
82 const idEventDef EV_Thread_VecDotProduct( "DotProduct", "vv", 'f' );
83 const idEventDef EV_Thread_VecCrossProduct( "CrossProduct", "vv", 'v' );
84 const idEventDef EV_Thread_VecToAngles( "VecToAngles", "v", 'v' );
85 #ifdef _D3XP
86 const idEventDef EV_Thread_VecToOrthoBasisAngles( "VecToOrthoBasisAngles", "v", 'v' );
87 const idEventDef EV_Thread_RotateVector("rotateVector", "vv", 'v');
88 #endif
89 const idEventDef EV_Thread_OnSignal( "onSignal", "des" );
90 const idEventDef EV_Thread_ClearSignal( "clearSignalThread", "de" );
91 const idEventDef EV_Thread_SetCamera( "setCamera", "e" );
92 const idEventDef EV_Thread_FirstPerson( "firstPerson", NULL );
93 const idEventDef EV_Thread_Trace( "trace", "vvvvde", 'f' );
94 const idEventDef EV_Thread_TracePoint( "tracePoint", "vvde", 'f' );
95 const idEventDef EV_Thread_GetTraceFraction( "getTraceFraction", NULL, 'f' );
96 const idEventDef EV_Thread_GetTraceEndPos( "getTraceEndPos", NULL, 'v' );
97 const idEventDef EV_Thread_GetTraceNormal( "getTraceNormal", NULL, 'v' );
98 const idEventDef EV_Thread_GetTraceEntity( "getTraceEntity", NULL, 'e' );
99 const idEventDef EV_Thread_GetTraceJoint( "getTraceJoint", NULL, 's' );
100 const idEventDef EV_Thread_GetTraceBody( "getTraceBody", NULL, 's' );
101 const idEventDef EV_Thread_FadeIn( "fadeIn", "vf" );
102 const idEventDef EV_Thread_FadeOut( "fadeOut", "vf" );
103 const idEventDef EV_Thread_FadeTo( "fadeTo", "vff" );
104 const idEventDef EV_Thread_StartMusic( "music", "s" );
105 const idEventDef EV_Thread_Error( "error", "s" );
106 const idEventDef EV_Thread_Warning( "warning", "s" );
107 const idEventDef EV_Thread_StrLen( "strLength", "s", 'd' );
108 const idEventDef EV_Thread_StrLeft( "strLeft", "sd", 's' );
109 const idEventDef EV_Thread_StrRight( "strRight", "sd", 's' );
110 const idEventDef EV_Thread_StrSkip( "strSkip", "sd", 's' );
111 const idEventDef EV_Thread_StrMid( "strMid", "sdd", 's' );
112 const idEventDef EV_Thread_StrToFloat( "strToFloat", "s", 'f' );
113 const idEventDef EV_Thread_RadiusDamage( "radiusDamage", "vEEEsf" );
114 const idEventDef EV_Thread_IsClient( "isClient", NULL, 'f' );
115 const idEventDef EV_Thread_IsMultiplayer( "isMultiplayer", NULL, 'f' );
116 const idEventDef EV_Thread_GetFrameTime( "getFrameTime", NULL, 'f' );
117 const idEventDef EV_Thread_GetTicsPerSecond( "getTicsPerSecond", NULL, 'f' );
118 const idEventDef EV_Thread_DebugLine( "debugLine", "vvvf" );
119 const idEventDef EV_Thread_DebugArrow( "debugArrow", "vvvdf" );
120 const idEventDef EV_Thread_DebugCircle( "debugCircle", "vvvfdf" );
121 const idEventDef EV_Thread_DebugBounds( "debugBounds", "vvvf" );
122 const idEventDef EV_Thread_DrawText( "drawText", "svfvdf" );
123 const idEventDef EV_Thread_InfluenceActive( "influenceActive", NULL, 'd' );
124
125 CLASS_DECLARATION( idClass, idThread )
126         EVENT( EV_Thread_Execute,                               idThread::Event_Execute )
127         EVENT( EV_Thread_TerminateThread,               idThread::Event_TerminateThread )
128         EVENT( EV_Thread_Pause,                                 idThread::Event_Pause )
129         EVENT( EV_Thread_Wait,                                  idThread::Event_Wait )
130         EVENT( EV_Thread_WaitFrame,                             idThread::Event_WaitFrame )
131         EVENT( EV_Thread_WaitFor,                               idThread::Event_WaitFor )
132         EVENT( EV_Thread_WaitForThread,                 idThread::Event_WaitForThread )
133         EVENT( EV_Thread_Print,                                 idThread::Event_Print )
134         EVENT( EV_Thread_PrintLn,                               idThread::Event_PrintLn )
135         EVENT( EV_Thread_Say,                                   idThread::Event_Say )
136         EVENT( EV_Thread_Assert,                                idThread::Event_Assert )
137         EVENT( EV_Thread_Trigger,                               idThread::Event_Trigger )
138         EVENT( EV_Thread_SetCvar,                               idThread::Event_SetCvar )
139         EVENT( EV_Thread_GetCvar,                               idThread::Event_GetCvar )
140         EVENT( EV_Thread_Random,                                idThread::Event_Random )
141 #ifdef _D3XP
142         EVENT( EV_Thread_RandomInt,                             idThread::Event_RandomInt )
143 #endif
144         EVENT( EV_Thread_GetTime,                               idThread::Event_GetTime )
145         EVENT( EV_Thread_KillThread,                    idThread::Event_KillThread )
146         EVENT( EV_Thread_SetThreadName,                 idThread::Event_SetThreadName )
147         EVENT( EV_Thread_GetEntity,                             idThread::Event_GetEntity )
148         EVENT( EV_Thread_Spawn,                                 idThread::Event_Spawn )
149         EVENT( EV_Thread_CopySpawnArgs,                 idThread::Event_CopySpawnArgs )
150         EVENT( EV_Thread_SetSpawnArg,                   idThread::Event_SetSpawnArg )
151         EVENT( EV_Thread_SpawnString,                   idThread::Event_SpawnString )
152         EVENT( EV_Thread_SpawnFloat,                    idThread::Event_SpawnFloat )
153         EVENT( EV_Thread_SpawnVector,                   idThread::Event_SpawnVector )
154         EVENT( EV_Thread_ClearPersistantArgs,   idThread::Event_ClearPersistantArgs )
155         EVENT( EV_Thread_SetPersistantArg,              idThread::Event_SetPersistantArg )
156         EVENT( EV_Thread_GetPersistantString,   idThread::Event_GetPersistantString )
157         EVENT( EV_Thread_GetPersistantFloat,    idThread::Event_GetPersistantFloat )
158         EVENT( EV_Thread_GetPersistantVector,   idThread::Event_GetPersistantVector )
159         EVENT( EV_Thread_AngToForward,                  idThread::Event_AngToForward )
160         EVENT( EV_Thread_AngToRight,                    idThread::Event_AngToRight )
161         EVENT( EV_Thread_AngToUp,                               idThread::Event_AngToUp )
162         EVENT( EV_Thread_Sine,                                  idThread::Event_GetSine )
163         EVENT( EV_Thread_Cosine,                                idThread::Event_GetCosine )
164 #ifdef _D3XP
165         EVENT( EV_Thread_ArcSine,                               idThread::Event_GetArcSine )
166         EVENT( EV_Thread_ArcCosine,                             idThread::Event_GetArcCosine )
167 #endif
168         EVENT( EV_Thread_SquareRoot,                    idThread::Event_GetSquareRoot )
169         EVENT( EV_Thread_Normalize,                             idThread::Event_VecNormalize )
170         EVENT( EV_Thread_VecLength,                             idThread::Event_VecLength )
171         EVENT( EV_Thread_VecDotProduct,                 idThread::Event_VecDotProduct )
172         EVENT( EV_Thread_VecCrossProduct,               idThread::Event_VecCrossProduct )
173         EVENT( EV_Thread_VecToAngles,                   idThread::Event_VecToAngles )
174 #ifdef _D3XP
175         EVENT( EV_Thread_VecToOrthoBasisAngles, idThread::Event_VecToOrthoBasisAngles )
176         EVENT( EV_Thread_RotateVector,                  idThread::Event_RotateVector )
177 #endif
178         EVENT( EV_Thread_OnSignal,                              idThread::Event_OnSignal )
179         EVENT( EV_Thread_ClearSignal,                   idThread::Event_ClearSignalThread )
180         EVENT( EV_Thread_SetCamera,                             idThread::Event_SetCamera )
181         EVENT( EV_Thread_FirstPerson,                   idThread::Event_FirstPerson )
182         EVENT( EV_Thread_Trace,                                 idThread::Event_Trace )
183         EVENT( EV_Thread_TracePoint,                    idThread::Event_TracePoint )
184         EVENT( EV_Thread_GetTraceFraction,              idThread::Event_GetTraceFraction )
185         EVENT( EV_Thread_GetTraceEndPos,                idThread::Event_GetTraceEndPos )
186         EVENT( EV_Thread_GetTraceNormal,                idThread::Event_GetTraceNormal )
187         EVENT( EV_Thread_GetTraceEntity,                idThread::Event_GetTraceEntity )
188         EVENT( EV_Thread_GetTraceJoint,                 idThread::Event_GetTraceJoint )
189         EVENT( EV_Thread_GetTraceBody,                  idThread::Event_GetTraceBody )
190         EVENT( EV_Thread_FadeIn,                                idThread::Event_FadeIn )
191         EVENT( EV_Thread_FadeOut,                               idThread::Event_FadeOut )
192         EVENT( EV_Thread_FadeTo,                                idThread::Event_FadeTo )
193         EVENT( EV_SetShaderParm,                                idThread::Event_SetShaderParm )
194         EVENT( EV_Thread_StartMusic,                    idThread::Event_StartMusic )
195         EVENT( EV_Thread_Warning,                               idThread::Event_Warning )
196         EVENT( EV_Thread_Error,                                 idThread::Event_Error )
197         EVENT( EV_Thread_StrLen,                                idThread::Event_StrLen )
198         EVENT( EV_Thread_StrLeft,                               idThread::Event_StrLeft )
199         EVENT( EV_Thread_StrRight,                              idThread::Event_StrRight )
200         EVENT( EV_Thread_StrSkip,                               idThread::Event_StrSkip )
201         EVENT( EV_Thread_StrMid,                                idThread::Event_StrMid )
202         EVENT( EV_Thread_StrToFloat,                    idThread::Event_StrToFloat )
203         EVENT( EV_Thread_RadiusDamage,                  idThread::Event_RadiusDamage )
204         EVENT( EV_Thread_IsClient,                              idThread::Event_IsClient )
205         EVENT( EV_Thread_IsMultiplayer,                 idThread::Event_IsMultiplayer )
206         EVENT( EV_Thread_GetFrameTime,                  idThread::Event_GetFrameTime )
207         EVENT( EV_Thread_GetTicsPerSecond,              idThread::Event_GetTicsPerSecond )
208         EVENT( EV_CacheSoundShader,                             idThread::Event_CacheSoundShader )
209         EVENT( EV_Thread_DebugLine,                             idThread::Event_DebugLine )
210         EVENT( EV_Thread_DebugArrow,                    idThread::Event_DebugArrow )
211         EVENT( EV_Thread_DebugCircle,                   idThread::Event_DebugCircle )
212         EVENT( EV_Thread_DebugBounds,                   idThread::Event_DebugBounds )
213         EVENT( EV_Thread_DrawText,                              idThread::Event_DrawText )
214         EVENT( EV_Thread_InfluenceActive,               idThread::Event_InfluenceActive )
215 END_CLASS
216
217 idThread                        *idThread::currentThread = NULL;
218 int                                     idThread::threadIndex = 0;
219 idList<idThread *>      idThread::threadList;
220 trace_t                         idThread::trace;
221
222 /*
223 ================
224 idThread::CurrentThread
225 ================
226 */
227 idThread *idThread::CurrentThread( void ) {
228         return currentThread;
229 }
230
231 /*
232 ================
233 idThread::CurrentThreadNum
234 ================
235 */
236 int idThread::CurrentThreadNum( void ) {
237         if ( currentThread ) {
238                 return currentThread->GetThreadNum();
239         } else {
240                 return 0;
241         }
242 }
243
244 /*
245 ================
246 idThread::BeginMultiFrameEvent
247 ================
248 */
249 bool idThread::BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
250         if ( !currentThread ) {
251                 gameLocal.Error( "idThread::BeginMultiFrameEvent called without a current thread" );
252         }
253         return currentThread->interpreter.BeginMultiFrameEvent( ent, event );
254 }
255
256 /*
257 ================
258 idThread::EndMultiFrameEvent
259 ================
260 */
261 void idThread::EndMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
262         if ( !currentThread ) {
263                 gameLocal.Error( "idThread::EndMultiFrameEvent called without a current thread" );
264         }
265         currentThread->interpreter.EndMultiFrameEvent( ent, event );
266 }
267
268 /*
269 ================
270 idThread::idThread
271 ================
272 */
273 idThread::idThread() {
274         Init();
275         SetThreadName( va( "thread_%d", threadIndex ) );
276         if ( g_debugScript.GetBool() ) {
277                 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
278         }
279 }
280
281 /*
282 ================
283 idThread::idThread
284 ================
285 */
286 idThread::idThread( idEntity *self, const function_t *func ) {
287         assert( self );
288         
289         Init();
290         SetThreadName( self->name );
291         interpreter.EnterObjectFunction( self, func, false );
292         if ( g_debugScript.GetBool() ) {
293                 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
294         }
295 }
296
297 /*
298 ================
299 idThread::idThread
300 ================
301 */
302 idThread::idThread( const function_t *func ) {
303         assert( func );
304
305         Init();
306         SetThreadName( func->Name() );
307         interpreter.EnterFunction( func, false );
308         if ( g_debugScript.GetBool() ) {
309                 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
310         }
311 }
312
313 /*
314 ================
315 idThread::idThread
316 ================
317 */
318 idThread::idThread( idInterpreter *source, const function_t *func, int args ) {
319         Init();
320         interpreter.ThreadCall( source, func, args );
321         if ( g_debugScript.GetBool() ) {
322                 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
323         }
324 }
325
326 /*
327 ================
328 idThread::idThread
329 ================
330 */
331 idThread::idThread( idInterpreter *source, idEntity *self, const function_t *func, int args ) {
332         assert( self );
333
334         Init();
335         SetThreadName( self->name );
336         interpreter.ThreadCall( source, func, args );
337         if ( g_debugScript.GetBool() ) {
338                 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
339         }
340 }
341
342 /*
343 ================
344 idThread::~idThread
345 ================
346 */
347 idThread::~idThread() {
348         idThread        *thread;
349         int                     i;
350         int                     n;
351
352         if ( g_debugScript.GetBool() ) {
353                 gameLocal.Printf( "%d: end thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
354         }
355         threadList.Remove( this );
356         n = threadList.Num();
357         for( i = 0; i < n; i++ ) {
358                 thread = threadList[ i ];
359                 if ( thread->WaitingOnThread() == this ) {
360                         thread->ThreadCallback( this );
361                 }
362         }
363
364         if ( currentThread == this ) {
365                 currentThread = NULL;
366         }
367 }
368
369 /*
370 ================
371 idThread::ManualDelete
372 ================
373 */
374 void idThread::ManualDelete( void ) {
375         interpreter.terminateOnExit = false;
376 }
377
378 /*
379 ================
380 idThread::Save
381 ================
382 */
383 void idThread::Save( idSaveGame *savefile ) const {
384
385         // We will check on restore that threadNum is still the same,
386         //  threads should have been restored in the same order.
387         savefile->WriteInt( threadNum );
388
389         savefile->WriteObject( waitingForThread );
390         savefile->WriteInt( waitingFor );
391         savefile->WriteInt( waitingUntil );
392
393         interpreter.Save( savefile );
394
395         savefile->WriteDict( &spawnArgs );
396         savefile->WriteString( threadName );
397
398         savefile->WriteInt( lastExecuteTime );
399         savefile->WriteInt( creationTime );
400
401         savefile->WriteBool( manualControl );
402 }
403
404 /*
405 ================
406 idThread::Restore
407 ================
408 */
409 void idThread::Restore( idRestoreGame *savefile ) {
410         savefile->ReadInt( threadNum );
411
412         savefile->ReadObject( reinterpret_cast<idClass *&>( waitingForThread ) );
413         savefile->ReadInt( waitingFor );
414         savefile->ReadInt( waitingUntil );
415
416         interpreter.Restore( savefile );
417
418         savefile->ReadDict( &spawnArgs );
419         savefile->ReadString( threadName );
420
421         savefile->ReadInt( lastExecuteTime );
422         savefile->ReadInt( creationTime );
423
424         savefile->ReadBool( manualControl );
425 }
426
427 /*
428 ================
429 idThread::Init
430 ================
431 */
432 void idThread::Init( void ) {
433         // create a unique threadNum
434         do {
435                 threadIndex++;
436                 if ( threadIndex == 0 ) {
437                         threadIndex = 1;
438                 }
439         } while( GetThread( threadIndex ) );
440
441         threadNum = threadIndex;
442         threadList.Append( this );
443         
444         creationTime = gameLocal.time;
445         lastExecuteTime = 0;
446         manualControl = false;
447
448         ClearWaitFor();
449
450         interpreter.SetThread( this );
451 }
452
453 /*
454 ================
455 idThread::GetThread
456 ================
457 */
458 idThread *idThread::GetThread( int num ) {
459         int                     i;
460         int                     n;
461         idThread        *thread;
462
463         n = threadList.Num();
464         for( i = 0; i < n; i++ ) {
465                 thread = threadList[ i ];
466                 if ( thread->GetThreadNum() == num ) {
467                         return thread;
468                 }
469         }
470
471         return NULL;
472 }
473
474 /*
475 ================
476 idThread::DisplayInfo
477 ================
478 */
479 void idThread::DisplayInfo( void ) {
480         gameLocal.Printf( 
481                 "%12i: '%s'\n"
482                 "        File: %s(%d)\n"
483                 "     Created: %d (%d ms ago)\n"
484                 "      Status: ", 
485                 threadNum, threadName.c_str(), 
486                 interpreter.CurrentFile(), interpreter.CurrentLine(), 
487                 creationTime, gameLocal.time - creationTime );
488
489         if ( interpreter.threadDying ) {
490                 gameLocal.Printf( "Dying\n" );
491         } else if ( interpreter.doneProcessing ) {
492                 gameLocal.Printf( 
493                         "Paused since %d (%d ms)\n"
494                         "      Reason: ",  lastExecuteTime, gameLocal.time - lastExecuteTime );
495                 if ( waitingForThread ) {
496                         gameLocal.Printf( "Waiting for thread #%3i '%s'\n", waitingForThread->GetThreadNum(), waitingForThread->GetThreadName() );
497                 } else if ( ( waitingFor != ENTITYNUM_NONE ) && ( gameLocal.entities[ waitingFor ] ) ) {
498                         gameLocal.Printf( "Waiting for entity #%3i '%s'\n", waitingFor, gameLocal.entities[ waitingFor ]->name.c_str() );
499                 } else if ( waitingUntil ) {
500                         gameLocal.Printf( "Waiting until %d (%d ms total wait time)\n", waitingUntil, waitingUntil - lastExecuteTime );
501                 } else {
502                         gameLocal.Printf( "None\n" );
503                 }
504         } else {
505                 gameLocal.Printf( "Processing\n" );
506         }
507
508         interpreter.DisplayInfo();
509
510         gameLocal.Printf( "\n" );
511 }
512
513 /*
514 ================
515 idThread::ListThreads_f
516 ================
517 */
518 void idThread::ListThreads_f( const idCmdArgs &args ) {
519         int     i;
520         int     n;
521
522         n = threadList.Num();
523         for( i = 0; i < n; i++ ) {
524                 //threadList[ i ]->DisplayInfo();
525                 gameLocal.Printf( "%3i: %-20s : %s(%d)\n", threadList[ i ]->threadNum, threadList[ i ]->threadName.c_str(), threadList[ i ]->interpreter.CurrentFile(), threadList[ i ]->interpreter.CurrentLine() );
526         }
527         gameLocal.Printf( "%d active threads\n\n", n );
528 }
529
530 /*
531 ================
532 idThread::Restart
533 ================
534 */
535 void idThread::Restart( void ) {
536         int     i;
537         int     n;
538
539         // reset the threadIndex
540         threadIndex = 0;
541
542         currentThread = NULL;
543         n = threadList.Num();
544         for( i = n - 1; i >= 0; i-- ) {
545                 delete threadList[ i ];
546         }
547         threadList.Clear();
548
549         memset( &trace, 0, sizeof( trace ) );
550         trace.c.entityNum = ENTITYNUM_NONE;
551 }
552
553 /*
554 ================
555 idThread::DelayedStart
556 ================
557 */
558 void idThread::DelayedStart( int delay ) {
559         CancelEvents( &EV_Thread_Execute );
560         if ( gameLocal.time <= 0 ) {
561                 delay++;
562         }
563         PostEventMS( &EV_Thread_Execute, delay );
564 }
565
566 /*
567 ================
568 idThread::Start
569 ================
570 */
571 bool idThread::Start( void ) {
572         bool result;
573
574         CancelEvents( &EV_Thread_Execute );
575         result = Execute();
576
577         return result;
578 }
579
580 /*
581 ================
582 idThread::SetThreadName
583 ================
584 */
585 void idThread::SetThreadName( const char *name ) {
586         threadName = name;
587 }
588
589 /*
590 ================
591 idThread::ObjectMoveDone
592 ================
593 */
594 void idThread::ObjectMoveDone( int threadnum, idEntity *obj ) {
595         idThread *thread;
596
597         if ( !threadnum ) {
598                 return;
599         }
600
601         thread = GetThread( threadnum );
602         if ( thread ) {
603                 thread->ObjectMoveDone( obj );
604         }
605 }
606
607 /*
608 ================
609 idThread::End
610 ================
611 */
612 void idThread::End( void ) {
613         // Tell thread to die.  It will exit on its own.
614         Pause();
615         interpreter.threadDying = true;
616 }
617
618 /*
619 ================
620 idThread::KillThread
621 ================
622 */
623 void idThread::KillThread( const char *name ) {
624         int                     i;
625         int                     num;
626         int                     len;
627         const char      *ptr;
628         idThread        *thread;
629
630         // see if the name uses a wild card
631         ptr = strchr( name, '*' );
632         if ( ptr ) {
633                 len = ptr - name;
634         } else {
635                 len = strlen( name );
636         }
637
638         // kill only those threads whose name matches name
639         num = threadList.Num();
640         for( i = 0; i < num; i++ ) {
641                 thread = threadList[ i ];
642                 if ( !idStr::Cmpn( thread->GetThreadName(), name, len ) ) {
643                         thread->End();
644                 }
645         }
646 }
647
648 /*
649 ================
650 idThread::KillThread
651 ================
652 */
653 void idThread::KillThread( int num ) {
654         idThread *thread;
655
656         thread = GetThread( num );
657         if ( thread ) {
658                 // Tell thread to die.  It will delete itself on it's own.
659                 thread->End();
660         }
661 }
662
663 /*
664 ================
665 idThread::Execute
666 ================
667 */
668 bool idThread::Execute( void ) {
669         idThread        *oldThread;
670         bool            done;
671
672         if ( manualControl && ( waitingUntil > gameLocal.time ) ) {
673                 return false;
674         }
675
676         oldThread = currentThread;
677         currentThread = this;
678
679         lastExecuteTime = gameLocal.time;
680         ClearWaitFor();
681         done = interpreter.Execute();
682         if ( done ) {
683                 End();
684                 if ( interpreter.terminateOnExit ) {
685                         PostEventMS( &EV_Remove, 0 );
686                 }
687         } else if ( !manualControl ) {
688                 if ( waitingUntil > lastExecuteTime ) {
689                         PostEventMS( &EV_Thread_Execute, waitingUntil - lastExecuteTime );
690                 } else if ( interpreter.MultiFrameEventInProgress() ) {
691                         PostEventMS( &EV_Thread_Execute, gameLocal.msec );
692                 }
693         }
694
695         currentThread = oldThread;
696
697         return done;
698 }
699
700 /*
701 ================
702 idThread::IsWaiting
703
704 Checks if thread is still waiting for some event to occur.
705 ================
706 */
707 bool idThread::IsWaiting( void ) {
708         if ( waitingForThread || ( waitingFor != ENTITYNUM_NONE ) ) {
709                 return true;
710         }
711
712         if ( waitingUntil && ( waitingUntil > gameLocal.time ) ) {
713                 return true;
714         }
715
716         return false;
717 }
718
719 /*
720 ================
721 idThread::CallFunction
722
723 NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function.
724 ================
725 */
726 void idThread::CallFunction( const function_t *func, bool clearStack ) {
727         ClearWaitFor();
728         interpreter.EnterFunction( func, clearStack );
729 }
730
731 /*
732 ================
733 idThread::CallFunction
734
735 NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function.
736 ================
737 */
738 void idThread::CallFunction( idEntity *self, const function_t *func, bool clearStack ) {
739         assert( self );
740         ClearWaitFor();
741         interpreter.EnterObjectFunction( self, func, clearStack );
742 }
743
744 /*
745 ================
746 idThread::ClearWaitFor
747 ================
748 */
749 void idThread::ClearWaitFor( void ) {
750         waitingFor                      = ENTITYNUM_NONE;
751         waitingForThread        = NULL;
752         waitingUntil            = 0;
753 }
754
755 /*
756 ================
757 idThread::IsWaitingFor
758 ================
759 */
760 bool idThread::IsWaitingFor( idEntity *obj ) {
761         assert( obj );
762         return waitingFor == obj->entityNumber;
763 }
764
765 /*
766 ================
767 idThread::ObjectMoveDone
768 ================
769 */
770 void idThread::ObjectMoveDone( idEntity *obj ) {
771         assert( obj );
772
773         if ( IsWaitingFor( obj ) ) {
774                 ClearWaitFor();
775                 DelayedStart( 0 );
776         }
777 }
778
779 /*
780 ================
781 idThread::ThreadCallback
782 ================
783 */
784 void idThread::ThreadCallback( idThread *thread ) {
785         if ( interpreter.threadDying ) {
786                 return;
787         }
788
789         if ( thread == waitingForThread ) {
790                 ClearWaitFor();
791                 DelayedStart( 0 );
792         }
793 }
794
795 /*
796 ================
797 idThread::Event_SetThreadName
798 ================
799 */
800 void idThread::Event_SetThreadName( const char *name ) {
801         SetThreadName( name );
802 }
803
804 /*
805 ================
806 idThread::Error
807 ================
808 */
809 void idThread::Error( const char *fmt, ... ) const {
810         va_list argptr;
811         char    text[ 1024 ];
812
813         va_start( argptr, fmt );
814         vsprintf( text, fmt, argptr );
815         va_end( argptr );
816
817         interpreter.Error( text );
818 }
819
820 /*
821 ================
822 idThread::Warning
823 ================
824 */
825 void idThread::Warning( const char *fmt, ... ) const {
826         va_list argptr;
827         char    text[ 1024 ];
828
829         va_start( argptr, fmt );
830         vsprintf( text, fmt, argptr );
831         va_end( argptr );
832
833         interpreter.Warning( text );
834 }
835
836 /*
837 ================
838 idThread::ReturnString
839 ================
840 */
841 void idThread::ReturnString( const char *text ) {
842         gameLocal.program.ReturnString( text );
843 }
844
845 /*
846 ================
847 idThread::ReturnFloat
848 ================
849 */
850 void idThread::ReturnFloat( float value ) {
851         gameLocal.program.ReturnFloat( value );
852 }
853
854 /*
855 ================
856 idThread::ReturnInt
857 ================
858 */
859 void idThread::ReturnInt( int value ) {
860         // true integers aren't supported in the compiler,
861         // so int values are stored as floats
862         gameLocal.program.ReturnFloat( value );
863 }
864
865 /*
866 ================
867 idThread::ReturnVector
868 ================
869 */
870 void idThread::ReturnVector( idVec3 const &vec ) {
871         gameLocal.program.ReturnVector( vec );
872 }
873
874 /*
875 ================
876 idThread::ReturnEntity
877 ================
878 */
879 void idThread::ReturnEntity( idEntity *ent ) {
880         gameLocal.program.ReturnEntity( ent );
881 }
882
883 /*
884 ================
885 idThread::Event_Execute
886 ================
887 */
888 void idThread::Event_Execute( void ) {
889         Execute();
890 }
891
892 /*
893 ================
894 idThread::Pause
895 ================
896 */
897 void idThread::Pause( void ) {
898         ClearWaitFor();
899         interpreter.doneProcessing = true;
900 }
901
902 /*
903 ================
904 idThread::WaitMS
905 ================
906 */
907 void idThread::WaitMS( int time ) {
908         Pause();
909         waitingUntil = gameLocal.time + time;
910 }
911
912 /*
913 ================
914 idThread::WaitSec
915 ================
916 */
917 void idThread::WaitSec( float time ) {
918         WaitMS( SEC2MS( time ) );
919 }
920
921 /*
922 ================
923 idThread::WaitFrame
924 ================
925 */
926 void idThread::WaitFrame( void ) {
927         Pause();
928
929         // manual control threads don't set waitingUntil so that they can be run again
930         // that frame if necessary.
931         if ( !manualControl ) {
932                 waitingUntil = gameLocal.time + gameLocal.msec;
933         }
934 }
935
936 /***********************************************************************
937
938   Script callable events  
939         
940 ***********************************************************************/
941
942 /*
943 ================
944 idThread::Event_TerminateThread
945 ================
946 */
947 void idThread::Event_TerminateThread( int num ) {
948         idThread *thread;
949
950         thread = GetThread( num );
951         KillThread( num );
952 }
953
954 /*
955 ================
956 idThread::Event_Pause
957 ================
958 */
959 void idThread::Event_Pause( void ) {
960         Pause();
961 }
962
963 /*
964 ================
965 idThread::Event_Wait
966 ================
967 */
968 void idThread::Event_Wait( float time ) {
969         WaitSec( time );
970 }
971
972 /*
973 ================
974 idThread::Event_WaitFrame
975 ================
976 */
977 void idThread::Event_WaitFrame( void ) {
978         WaitFrame();
979 }
980
981 /*
982 ================
983 idThread::Event_WaitFor
984 ================
985 */
986 void idThread::Event_WaitFor( idEntity *ent ) {
987         if ( ent && ent->RespondsTo( EV_Thread_SetCallback ) ) {
988                 ent->ProcessEvent( &EV_Thread_SetCallback );
989                 if ( gameLocal.program.GetReturnedInteger() ) {
990                         Pause();
991                         waitingFor = ent->entityNumber;
992                 }
993         }
994 }
995
996 /*
997 ================
998 idThread::Event_WaitForThread
999 ================
1000 */
1001 void idThread::Event_WaitForThread( int num ) {
1002         idThread *thread;
1003
1004         thread = GetThread( num );
1005         if ( !thread ) {
1006                 if ( g_debugScript.GetBool() ) {
1007                         // just print a warning and continue executing
1008                         Warning( "Thread %d not running", num );
1009                 }
1010         } else {
1011                 Pause();
1012                 waitingForThread = thread;
1013         }
1014 }
1015
1016 /*
1017 ================
1018 idThread::Event_Print
1019 ================
1020 */
1021 void idThread::Event_Print( const char *text ) {
1022         gameLocal.Printf( "%s", text );
1023 }
1024
1025 /*
1026 ================
1027 idThread::Event_PrintLn
1028 ================
1029 */
1030 void idThread::Event_PrintLn( const char *text ) {
1031         gameLocal.Printf( "%s\n", text );
1032 }
1033
1034 /*
1035 ================
1036 idThread::Event_Say
1037 ================
1038 */
1039 void idThread::Event_Say( const char *text ) {
1040         cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say \"%s\"", text ) );
1041 }
1042
1043 /*
1044 ================
1045 idThread::Event_Assert
1046 ================
1047 */
1048 void idThread::Event_Assert( float value ) {
1049         assert( value );
1050 }
1051
1052 /*
1053 ================
1054 idThread::Event_Trigger
1055 ================
1056 */
1057 void idThread::Event_Trigger( idEntity *ent ) {
1058         if ( ent ) {
1059                 ent->Signal( SIG_TRIGGER );
1060                 ent->ProcessEvent( &EV_Activate, gameLocal.GetLocalPlayer() );
1061                 ent->TriggerGuis();
1062         }
1063 }
1064
1065 /*
1066 ================
1067 idThread::Event_SetCvar
1068 ================
1069 */
1070 void idThread::Event_SetCvar( const char *name, const char *value ) const {
1071         cvarSystem->SetCVarString( name, value );
1072 }
1073
1074 /*
1075 ================
1076 idThread::Event_GetCvar
1077 ================
1078 */
1079 void idThread::Event_GetCvar( const char *name ) const {
1080         ReturnString( cvarSystem->GetCVarString( name ) );
1081 }
1082
1083 /*
1084 ================
1085 idThread::Event_Random
1086 ================
1087 */
1088 void idThread::Event_Random( float range ) const {
1089         float result;
1090
1091         result = gameLocal.random.RandomFloat();
1092         ReturnFloat( range * result );
1093 }
1094
1095 #ifdef _D3XP
1096
1097 void idThread::Event_RandomInt( int range ) const {
1098         int result;
1099         result = gameLocal.random.RandomInt(range);
1100         ReturnFloat(result);
1101 }
1102
1103 #endif
1104
1105 /*
1106 ================
1107 idThread::Event_GetTime
1108 ================
1109 */
1110 void idThread::Event_GetTime( void ) {
1111         ReturnFloat( MS2SEC( gameLocal.realClientTime ) );
1112 }
1113
1114 /*
1115 ================
1116 idThread::Event_KillThread
1117 ================
1118 */
1119 void idThread::Event_KillThread( const char *name ) {
1120         KillThread( name );
1121 }
1122
1123 /*
1124 ================
1125 idThread::Event_GetEntity
1126 ================
1127 */
1128 void idThread::Event_GetEntity( const char *name ) {
1129         int                     entnum;
1130         idEntity        *ent;
1131
1132         assert( name );
1133
1134         if ( name[ 0 ] == '*' ) {
1135                 entnum = atoi( &name[ 1 ] );
1136                 if ( ( entnum < 0 ) || ( entnum >= MAX_GENTITIES ) ) {
1137                         Error( "Entity number in string out of range." );
1138                 }
1139                 ReturnEntity( gameLocal.entities[ entnum ] );
1140         } else {
1141                 ent = gameLocal.FindEntity( name );
1142                 ReturnEntity( ent );
1143         }
1144 }
1145
1146 /*
1147 ================
1148 idThread::Event_Spawn
1149 ================
1150 */
1151 void idThread::Event_Spawn( const char *classname ) {
1152         idEntity *ent;
1153
1154         spawnArgs.Set( "classname", classname );
1155         gameLocal.SpawnEntityDef( spawnArgs, &ent );
1156         ReturnEntity( ent );
1157         spawnArgs.Clear();
1158 }
1159
1160 /*
1161 ================
1162 idThread::Event_CopySpawnArgs
1163 ================
1164 */
1165 void idThread::Event_CopySpawnArgs( idEntity *ent ) {
1166         spawnArgs.Copy( ent->spawnArgs );
1167 }
1168
1169 /*
1170 ================
1171 idThread::Event_SetSpawnArg
1172 ================
1173 */
1174 void idThread::Event_SetSpawnArg( const char *key, const char *value ) {
1175         spawnArgs.Set( key, value );
1176 }
1177
1178 /*
1179 ================
1180 idThread::Event_SpawnString
1181 ================
1182 */
1183 void idThread::Event_SpawnString( const char *key, const char *defaultvalue ) {
1184         const char *result;
1185
1186         spawnArgs.GetString( key, defaultvalue, &result );
1187         ReturnString( result );
1188 }
1189
1190 /*
1191 ================
1192 idThread::Event_SpawnFloat
1193 ================
1194 */
1195 void idThread::Event_SpawnFloat( const char *key, float defaultvalue ) {
1196         float result;
1197
1198         spawnArgs.GetFloat( key, va( "%f", defaultvalue ), result );
1199         ReturnFloat( result );
1200 }
1201
1202 /*
1203 ================
1204 idThread::Event_SpawnVector
1205 ================
1206 */
1207 void idThread::Event_SpawnVector( const char *key, idVec3 &defaultvalue ) {
1208         idVec3 result;
1209
1210         spawnArgs.GetVector( key, va( "%f %f %f", defaultvalue.x, defaultvalue.y, defaultvalue.z ), result );
1211         ReturnVector( result );
1212 }
1213
1214 /*
1215 ================
1216 idThread::Event_ClearPersistantArgs
1217 ================
1218 */
1219 void idThread::Event_ClearPersistantArgs( void ) {
1220         gameLocal.persistentLevelInfo.Clear();
1221 }
1222
1223
1224 /*
1225 ================
1226 idThread::Event_SetPersistantArg
1227 ================
1228 */
1229 void idThread::Event_SetPersistantArg( const char *key, const char *value ) {
1230         gameLocal.persistentLevelInfo.Set( key, value );
1231 }
1232
1233 /*
1234 ================
1235 idThread::Event_GetPersistantString
1236 ================
1237 */
1238 void idThread::Event_GetPersistantString( const char *key ) {
1239         const char *result;
1240
1241         gameLocal.persistentLevelInfo.GetString( key, "", &result );
1242         ReturnString( result );
1243 }
1244
1245 /*
1246 ================
1247 idThread::Event_GetPersistantFloat
1248 ================
1249 */
1250 void idThread::Event_GetPersistantFloat( const char *key ) {
1251         float result;
1252
1253         gameLocal.persistentLevelInfo.GetFloat( key, "0", result );
1254         ReturnFloat( result );
1255 }
1256
1257 /*
1258 ================
1259 idThread::Event_GetPersistantVector
1260 ================
1261 */
1262 void idThread::Event_GetPersistantVector( const char *key ) {
1263         idVec3 result;
1264
1265         gameLocal.persistentLevelInfo.GetVector( key, "0 0 0", result );
1266         ReturnVector( result );
1267 }
1268
1269 /*
1270 ================
1271 idThread::Event_AngToForward
1272 ================
1273 */
1274 void idThread::Event_AngToForward( idAngles &ang ) {
1275         ReturnVector( ang.ToForward() );
1276 }
1277
1278 /*
1279 ================
1280 idThread::Event_AngToRight
1281 ================
1282 */
1283 void idThread::Event_AngToRight( idAngles &ang ) {
1284         idVec3 vec;
1285
1286         ang.ToVectors( NULL, &vec );
1287         ReturnVector( vec );
1288 }
1289
1290 /*
1291 ================
1292 idThread::Event_AngToUp
1293 ================
1294 */
1295 void idThread::Event_AngToUp( idAngles &ang ) {
1296         idVec3 vec;
1297
1298         ang.ToVectors( NULL, NULL, &vec );
1299         ReturnVector( vec );
1300 }
1301
1302 /*
1303 ================
1304 idThread::Event_GetSine
1305 ================
1306 */
1307 void idThread::Event_GetSine( float angle ) {
1308         ReturnFloat( idMath::Sin( DEG2RAD( angle ) ) );
1309 }
1310
1311 /*
1312 ================
1313 idThread::Event_GetCosine
1314 ================
1315 */
1316 void idThread::Event_GetCosine( float angle ) {
1317         ReturnFloat( idMath::Cos( DEG2RAD( angle ) ) );
1318 }
1319
1320 #ifdef _D3XP
1321 /*
1322 ================
1323 idThread::Event_GetArcSine
1324 ================
1325 */
1326 void idThread::Event_GetArcSine( float a ) {
1327         ReturnFloat(RAD2DEG(idMath::ASin(a)));
1328 }
1329
1330 /*
1331 ================
1332 idThread::Event_GetArcCosine
1333 ================
1334 */
1335 void idThread::Event_GetArcCosine( float a ) {
1336         ReturnFloat(RAD2DEG(idMath::ACos(a)));
1337 }
1338 #endif
1339
1340 /*
1341 ================
1342 idThread::Event_GetSquareRoot
1343 ================
1344 */
1345 void idThread::Event_GetSquareRoot( float theSquare ) {
1346         ReturnFloat( idMath::Sqrt( theSquare ) );
1347 }
1348
1349 /*
1350 ================
1351 idThread::Event_VecNormalize
1352 ================
1353 */
1354 void idThread::Event_VecNormalize( idVec3 &vec ) {
1355         idVec3 n;
1356
1357         n = vec;
1358         n.Normalize();
1359         ReturnVector( n );
1360 }
1361
1362 /*
1363 ================
1364 idThread::Event_VecLength
1365 ================
1366 */
1367 void idThread::Event_VecLength( idVec3 &vec ) {
1368         ReturnFloat( vec.Length() );
1369 }
1370
1371 /*
1372 ================
1373 idThread::Event_VecDotProduct
1374 ================
1375 */
1376 void idThread::Event_VecDotProduct( idVec3 &vec1, idVec3 &vec2 ) {
1377         ReturnFloat( vec1 * vec2 );
1378 }
1379
1380 /*
1381 ================
1382 idThread::Event_VecCrossProduct
1383 ================
1384 */
1385 void idThread::Event_VecCrossProduct( idVec3 &vec1, idVec3 &vec2 ) {
1386         ReturnVector( vec1.Cross( vec2 ) );
1387 }
1388
1389 /*
1390 ================
1391 idThread::Event_VecToAngles
1392 ================
1393 */
1394 void idThread::Event_VecToAngles( idVec3 &vec ) {
1395         idAngles ang = vec.ToAngles();
1396         ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
1397 }
1398
1399 #ifdef _D3XP
1400 /*
1401 ================
1402 idThread::Event_VecToOrthoBasisAngles
1403 ================
1404 */
1405 void idThread::Event_VecToOrthoBasisAngles( idVec3 &vec ) {
1406         idVec3 left, up;
1407         idAngles ang;
1408
1409         vec.OrthogonalBasis( left, up );
1410         idMat3 axis( left, up, vec );
1411
1412         ang = axis.ToAngles();
1413
1414         ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
1415 }
1416
1417 void idThread::Event_RotateVector( idVec3 &vec, idVec3 &ang ) {
1418
1419         idAngles tempAng(ang);
1420         idMat3 axis = tempAng.ToMat3();
1421         idVec3 ret = vec * axis;
1422         ReturnVector(ret);
1423
1424 }
1425 #endif
1426
1427 /*
1428 ================
1429 idThread::Event_OnSignal
1430 ================
1431 */
1432 void idThread::Event_OnSignal( int signal, idEntity *ent, const char *func ) {
1433         const function_t *function;
1434
1435         assert( func );
1436
1437         if ( !ent ) {
1438                 Error( "Entity not found" );
1439         }
1440         
1441         if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) {
1442                 Error( "Signal out of range" );
1443         }
1444
1445         function = gameLocal.program.FindFunction( func );
1446         if ( !function ) {
1447                 Error( "Function '%s' not found", func );
1448         }
1449
1450         ent->SetSignal( ( signalNum_t )signal, this, function );
1451 }
1452
1453 /*
1454 ================
1455 idThread::Event_ClearSignalThread
1456 ================
1457 */
1458 void idThread::Event_ClearSignalThread( int signal, idEntity *ent ) {
1459         if ( !ent ) {
1460                 Error( "Entity not found" );
1461         }
1462         
1463         if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) {
1464                 Error( "Signal out of range" );
1465         }
1466
1467         ent->ClearSignalThread( ( signalNum_t )signal, this );
1468 }
1469
1470 /*
1471 ================
1472 idThread::Event_SetCamera
1473 ================
1474 */
1475 void idThread::Event_SetCamera( idEntity *ent ) {
1476         if ( !ent ) {
1477                 Error( "Entity not found" );
1478                 return;
1479         }
1480
1481         if ( !ent->IsType( idCamera::Type ) ) {
1482                 Error( "Entity is not a camera" );
1483                 return;
1484         }
1485
1486         gameLocal.SetCamera( ( idCamera * )ent );
1487 }
1488
1489 /*
1490 ================
1491 idThread::Event_FirstPerson
1492 ================
1493 */
1494 void idThread::Event_FirstPerson( void ) {
1495         gameLocal.SetCamera( NULL );
1496 }
1497
1498 /*
1499 ================
1500 idThread::Event_Trace
1501 ================
1502 */
1503 void idThread::Event_Trace( const idVec3 &start, const idVec3 &end, const idVec3 &mins, const idVec3 &maxs, int contents_mask, idEntity *passEntity ) {
1504         if ( mins == vec3_origin && maxs == vec3_origin ) {
1505                 gameLocal.clip.TracePoint( trace, start, end, contents_mask, passEntity );
1506         } else {
1507                 gameLocal.clip.TraceBounds( trace, start, end, idBounds( mins, maxs ), contents_mask, passEntity );
1508         }
1509         ReturnFloat( trace.fraction );
1510 }
1511
1512 /*
1513 ================
1514 idThread::Event_TracePoint
1515 ================
1516 */
1517 void idThread::Event_TracePoint( const idVec3 &start, const idVec3 &end, int contents_mask, idEntity *passEntity ) {
1518         gameLocal.clip.TracePoint( trace, start, end, contents_mask, passEntity );
1519         ReturnFloat( trace.fraction );
1520 }
1521
1522 /*
1523 ================
1524 idThread::Event_GetTraceFraction
1525 ================
1526 */
1527 void idThread::Event_GetTraceFraction( void ) {
1528         ReturnFloat( trace.fraction );
1529 }
1530
1531 /*
1532 ================
1533 idThread::Event_GetTraceEndPos
1534 ================
1535 */
1536 void idThread::Event_GetTraceEndPos( void ) {
1537         ReturnVector( trace.endpos );
1538 }
1539
1540 /*
1541 ================
1542 idThread::Event_GetTraceNormal
1543 ================
1544 */
1545 void idThread::Event_GetTraceNormal( void ) {
1546         if ( trace.fraction < 1.0f ) {
1547                 ReturnVector( trace.c.normal );
1548         } else {
1549                 ReturnVector( vec3_origin );
1550         }
1551 }
1552
1553 /*
1554 ================
1555 idThread::Event_GetTraceEntity
1556 ================
1557 */
1558 void idThread::Event_GetTraceEntity( void ) {
1559         if ( trace.fraction < 1.0f ) {
1560                 ReturnEntity( gameLocal.entities[ trace.c.entityNum ] );
1561         } else {
1562                 ReturnEntity( ( idEntity * )NULL );
1563         }
1564 }
1565
1566 /*
1567 ================
1568 idThread::Event_GetTraceJoint
1569 ================
1570 */
1571 void idThread::Event_GetTraceJoint( void ) {
1572         if ( trace.fraction < 1.0f && trace.c.id < 0 ) {
1573                 idAFEntity_Base *af = static_cast<idAFEntity_Base *>( gameLocal.entities[ trace.c.entityNum ] );
1574                 if ( af && af->IsType( idAFEntity_Base::Type ) && af->IsActiveAF() ) {
1575                         ReturnString( af->GetAnimator()->GetJointName( CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ) ) );
1576                         return;
1577                 }
1578         }
1579         ReturnString( "" );
1580 }
1581
1582 /*
1583 ================
1584 idThread::Event_GetTraceBody
1585 ================
1586 */
1587 void idThread::Event_GetTraceBody( void ) {
1588         if ( trace.fraction < 1.0f && trace.c.id < 0 ) {
1589                 idAFEntity_Base *af = static_cast<idAFEntity_Base *>( gameLocal.entities[ trace.c.entityNum ] );
1590                 if ( af && af->IsType( idAFEntity_Base::Type ) && af->IsActiveAF() ) {
1591                         int bodyId = af->BodyForClipModelId( trace.c.id );
1592                         idAFBody *body = af->GetAFPhysics()->GetBody( bodyId );
1593                         if ( body ) {
1594                                 ReturnString( body->GetName() );
1595                                 return;
1596                         }
1597                 }
1598         }
1599         ReturnString( "" );
1600 }
1601
1602 /*
1603 ================
1604 idThread::Event_FadeIn
1605 ================
1606 */
1607 void idThread::Event_FadeIn( idVec3 &color, float time ) {
1608         idVec4          fadeColor;
1609         idPlayer        *player;
1610
1611         player = gameLocal.GetLocalPlayer();
1612         if ( player ) {
1613                 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 0.0f );
1614                 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1615         }
1616 }
1617
1618 /*
1619 ================
1620 idThread::Event_FadeOut
1621 ================
1622 */
1623 void idThread::Event_FadeOut( idVec3 &color, float time ) {
1624         idVec4          fadeColor;
1625         idPlayer        *player;
1626
1627         player = gameLocal.GetLocalPlayer();
1628         if ( player ) {
1629                 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 1.0f );
1630                 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1631         }
1632 }
1633
1634 /*
1635 ================
1636 idThread::Event_FadeTo
1637 ================
1638 */
1639 void idThread::Event_FadeTo( idVec3 &color, float alpha, float time ) {
1640         idVec4          fadeColor;
1641         idPlayer        *player;
1642
1643         player = gameLocal.GetLocalPlayer();
1644         if ( player ) {
1645                 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], alpha );
1646                 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1647         }
1648 }
1649
1650 /*
1651 ================
1652 idThread::Event_SetShaderParm
1653 ================
1654 */
1655 void idThread::Event_SetShaderParm( int parmnum, float value ) {
1656         if ( ( parmnum < 0 ) || ( parmnum >= MAX_GLOBAL_SHADER_PARMS ) ) {
1657                 Error( "shader parm index (%d) out of range", parmnum );
1658         }
1659
1660         gameLocal.globalShaderParms[ parmnum ] = value;
1661 }
1662
1663 /*
1664 ================
1665 idThread::Event_StartMusic
1666 ================
1667 */
1668 void idThread::Event_StartMusic( const char *text ) {
1669         gameSoundWorld->PlayShaderDirectly( text );
1670 }
1671
1672 /*
1673 ================
1674 idThread::Event_Warning
1675 ================
1676 */
1677 void idThread::Event_Warning( const char *text ) {
1678         Warning( "%s", text );
1679 }
1680
1681 /*
1682 ================
1683 idThread::Event_Error
1684 ================
1685 */
1686 void idThread::Event_Error( const char *text ) {
1687         Error( "%s", text );
1688 }
1689
1690 /*
1691 ================
1692 idThread::Event_StrLen
1693 ================
1694 */
1695 void idThread::Event_StrLen( const char *string ) {
1696         int len;
1697
1698         len = strlen( string );
1699         idThread::ReturnInt( len );
1700 }
1701
1702 /*
1703 ================
1704 idThread::Event_StrLeft
1705 ================
1706 */
1707 void idThread::Event_StrLeft( const char *string, int num ) {
1708         int len;
1709
1710         if ( num < 0 ) {
1711                 idThread::ReturnString( "" );
1712                 return;
1713         }
1714
1715         len = strlen( string );
1716         if ( len < num ) {
1717                 idThread::ReturnString( string );
1718                 return;
1719         }
1720
1721         idStr result( string, 0, num );
1722         idThread::ReturnString( result );
1723 }
1724
1725 /*
1726 ================
1727 idThread::Event_StrRight 
1728 ================
1729 */
1730 void idThread::Event_StrRight( const char *string, int num ) {
1731         int len;
1732
1733         if ( num < 0 ) {
1734                 idThread::ReturnString( "" );
1735                 return;
1736         }
1737
1738         len = strlen( string );
1739         if ( len < num ) {
1740                 idThread::ReturnString( string );
1741                 return;
1742         }
1743
1744         idThread::ReturnString( string + len - num );
1745 }
1746
1747 /*
1748 ================
1749 idThread::Event_StrSkip
1750 ================
1751 */
1752 void idThread::Event_StrSkip( const char *string, int num ) {
1753         int len;
1754
1755         if ( num < 0 ) {
1756                 idThread::ReturnString( string );
1757                 return;
1758         }
1759
1760         len = strlen( string );
1761         if ( len < num ) {
1762                 idThread::ReturnString( "" );
1763                 return;
1764         }
1765
1766         idThread::ReturnString( string + num );
1767 }
1768
1769 /*
1770 ================
1771 idThread::Event_StrMid
1772 ================
1773 */
1774 void idThread::Event_StrMid( const char *string, int start, int num ) {
1775         int len;
1776
1777         if ( num < 0 ) {
1778                 idThread::ReturnString( "" );
1779                 return;
1780         }
1781
1782         if ( start < 0 ) {
1783                 start = 0;
1784         }
1785         len = strlen( string );
1786         if ( start > len ) {
1787                 start = len;
1788         }
1789
1790         if ( start + num > len ) {
1791                 num = len - start;
1792         }
1793
1794         idStr result( string, start, start + num );
1795         idThread::ReturnString( result );
1796 }
1797
1798 /*
1799 ================
1800 idThread::Event_StrToFloat( const char *string )
1801 ================
1802 */
1803 void idThread::Event_StrToFloat( const char *string ) {
1804         float result;
1805
1806         result = atof( string );
1807         idThread::ReturnFloat( result );
1808 }
1809
1810 /*
1811 ================
1812 idThread::Event_RadiusDamage
1813 ================
1814 */
1815 void idThread::Event_RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignore, const char *damageDefName, float dmgPower ) {
1816         gameLocal.RadiusDamage( origin, inflictor, attacker, ignore, ignore, damageDefName, dmgPower );
1817 }
1818
1819 /*
1820 ================
1821 idThread::Event_IsClient
1822 ================
1823 */
1824 void idThread::Event_IsClient( void ) { 
1825         idThread::ReturnFloat( gameLocal.isClient );
1826 }
1827
1828 /*
1829 ================
1830 idThread::Event_IsMultiplayer
1831 ================
1832 */
1833 void idThread::Event_IsMultiplayer( void ) { 
1834         idThread::ReturnFloat( gameLocal.isMultiplayer );
1835 }
1836
1837 /*
1838 ================
1839 idThread::Event_GetFrameTime
1840 ================
1841 */
1842 void idThread::Event_GetFrameTime( void ) { 
1843         idThread::ReturnFloat( MS2SEC( gameLocal.msec ) );
1844 }
1845
1846 /*
1847 ================
1848 idThread::Event_GetTicsPerSecond
1849 ================
1850 */
1851 void idThread::Event_GetTicsPerSecond( void ) { 
1852         idThread::ReturnFloat( USERCMD_HZ );
1853 }
1854
1855 /*
1856 ================
1857 idThread::Event_CacheSoundShader
1858 ================
1859 */
1860 void idThread::Event_CacheSoundShader( const char *soundName ) {
1861         declManager->FindSound( soundName );
1862 }
1863
1864 /*
1865 ================
1866 idThread::Event_DebugLine
1867 ================
1868 */
1869 void idThread::Event_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end, const float lifetime ) {
1870         gameRenderWorld->DebugLine( idVec4( color.x, color.y, color.z, 0.0f ), start, end, SEC2MS( lifetime ) );
1871 }
1872
1873 /*
1874 ================
1875 idThread::Event_DebugArrow
1876 ================
1877 */
1878 void idThread::Event_DebugArrow( const idVec3 &color, const idVec3 &start, const idVec3 &end, const int size, const float lifetime ) {
1879         gameRenderWorld->DebugArrow( idVec4( color.x, color.y, color.z, 0.0f ), start, end, size, SEC2MS( lifetime ) );
1880 }
1881
1882 /*
1883 ================
1884 idThread::Event_DebugCircle
1885 ================
1886 */
1887 void idThread::Event_DebugCircle( const idVec3 &color, const idVec3 &origin, const idVec3 &dir, const float radius, const int numSteps, const float lifetime ) {
1888         gameRenderWorld->DebugCircle( idVec4( color.x, color.y, color.z, 0.0f ), origin, dir, radius, numSteps, SEC2MS( lifetime ) );
1889 }
1890
1891 /*
1892 ================
1893 idThread::Event_DebugBounds
1894 ================
1895 */
1896 void idThread::Event_DebugBounds( const idVec3 &color, const idVec3 &mins, const idVec3 &maxs, const float lifetime ) {
1897         gameRenderWorld->DebugBounds( idVec4( color.x, color.y, color.z, 0.0f ), idBounds( mins, maxs ), vec3_origin, SEC2MS( lifetime ) );
1898 }
1899
1900 /*
1901 ================
1902 idThread::Event_DrawText
1903 ================
1904 */
1905 void idThread::Event_DrawText( const char *text, const idVec3 &origin, float scale, const idVec3 &color, const int align, const float lifetime ) {
1906         gameRenderWorld->DrawText( text, origin, scale, idVec4( color.x, color.y, color.z, 0.0f ), gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), align, SEC2MS( lifetime ) );
1907 }
1908
1909 /*
1910 ================
1911 idThread::Event_InfluenceActive
1912 ================
1913 */
1914 void idThread::Event_InfluenceActive( void ) {
1915         idPlayer *player;
1916
1917         player = gameLocal.GetLocalPlayer();
1918         if ( player && player->GetInfluenceLevel() ) {
1919                 idThread::ReturnInt( true );
1920         } else {
1921                 idThread::ReturnInt( false );
1922         }
1923 }