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