2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "../Game_local.h"
34 const idEventDef EV_Thread_Execute( "<execute>", NULL );
35 const idEventDef EV_Thread_SetCallback( "<script_setcallback>", NULL );
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' );
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 )
195 idThread *idThread::currentThread = NULL;
196 int idThread::threadIndex = 0;
197 idList<idThread *> idThread::threadList;
198 trace_t idThread::trace;
202 idThread::CurrentThread
205 idThread *idThread::CurrentThread( void ) {
206 return currentThread;
211 idThread::CurrentThreadNum
214 int idThread::CurrentThreadNum( void ) {
215 if ( currentThread ) {
216 return currentThread->GetThreadNum();
224 idThread::BeginMultiFrameEvent
227 bool idThread::BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
228 if ( !currentThread ) {
229 gameLocal.Error( "idThread::BeginMultiFrameEvent called without a current thread" );
231 return currentThread->interpreter.BeginMultiFrameEvent( ent, event );
236 idThread::EndMultiFrameEvent
239 void idThread::EndMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
240 if ( !currentThread ) {
241 gameLocal.Error( "idThread::EndMultiFrameEvent called without a current thread" );
243 currentThread->interpreter.EndMultiFrameEvent( ent, event );
251 idThread::idThread() {
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() );
264 idThread::idThread( idEntity *self, const function_t *func ) {
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() );
280 idThread::idThread( const function_t *func ) {
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() );
296 idThread::idThread( idInterpreter *source, const function_t *func, int args ) {
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() );
309 idThread::idThread( idInterpreter *source, idEntity *self, const function_t *func, int args ) {
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() );
325 idThread::~idThread() {
330 if ( g_debugScript.GetBool() ) {
331 gameLocal.Printf( "%d: end thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
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 );
342 if ( currentThread == this ) {
343 currentThread = NULL;
349 idThread::ManualDelete
352 void idThread::ManualDelete( void ) {
353 interpreter.terminateOnExit = false;
361 void idThread::Save( idSaveGame *savefile ) const {
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 );
367 savefile->WriteObject( waitingForThread );
368 savefile->WriteInt( waitingFor );
369 savefile->WriteInt( waitingUntil );
371 interpreter.Save( savefile );
373 savefile->WriteDict( &spawnArgs );
374 savefile->WriteString( threadName );
376 savefile->WriteInt( lastExecuteTime );
377 savefile->WriteInt( creationTime );
379 savefile->WriteBool( manualControl );
387 void idThread::Restore( idRestoreGame *savefile ) {
388 savefile->ReadInt( threadNum );
390 savefile->ReadObject( reinterpret_cast<idClass *&>( waitingForThread ) );
391 savefile->ReadInt( waitingFor );
392 savefile->ReadInt( waitingUntil );
394 interpreter.Restore( savefile );
396 savefile->ReadDict( &spawnArgs );
397 savefile->ReadString( threadName );
399 savefile->ReadInt( lastExecuteTime );
400 savefile->ReadInt( creationTime );
402 savefile->ReadBool( manualControl );
410 void idThread::Init( void ) {
411 // create a unique threadNum
414 if ( threadIndex == 0 ) {
417 } while( GetThread( threadIndex ) );
419 threadNum = threadIndex;
420 threadList.Append( this );
422 creationTime = gameLocal.time;
424 manualControl = false;
428 interpreter.SetThread( this );
436 idThread *idThread::GetThread( int num ) {
441 n = threadList.Num();
442 for( i = 0; i < n; i++ ) {
443 thread = threadList[ i ];
444 if ( thread->GetThreadNum() == num ) {
454 idThread::DisplayInfo
457 void idThread::DisplayInfo( void ) {
461 " Created: %d (%d ms ago)\n"
463 threadNum, threadName.c_str(),
464 interpreter.CurrentFile(), interpreter.CurrentLine(),
465 creationTime, gameLocal.time - creationTime );
467 if ( interpreter.threadDying ) {
468 gameLocal.Printf( "Dying\n" );
469 } else if ( interpreter.doneProcessing ) {
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 );
480 gameLocal.Printf( "None\n" );
483 gameLocal.Printf( "Processing\n" );
486 interpreter.DisplayInfo();
488 gameLocal.Printf( "\n" );
493 idThread::ListThreads_f
496 void idThread::ListThreads_f( const idCmdArgs &args ) {
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() );
505 gameLocal.Printf( "%d active threads\n\n", n );
513 void idThread::Restart( void ) {
517 // reset the threadIndex
520 currentThread = NULL;
521 n = threadList.Num();
522 for( i = n - 1; i >= 0; i-- ) {
523 delete threadList[ i ];
527 memset( &trace, 0, sizeof( trace ) );
528 trace.c.entityNum = ENTITYNUM_NONE;
533 idThread::DelayedStart
536 void idThread::DelayedStart( int delay ) {
537 CancelEvents( &EV_Thread_Execute );
538 if ( gameLocal.time <= 0 ) {
541 PostEventMS( &EV_Thread_Execute, delay );
549 bool idThread::Start( void ) {
552 CancelEvents( &EV_Thread_Execute );
560 idThread::SetThreadName
563 void idThread::SetThreadName( const char *name ) {
569 idThread::ObjectMoveDone
572 void idThread::ObjectMoveDone( int threadnum, idEntity *obj ) {
579 thread = GetThread( threadnum );
581 thread->ObjectMoveDone( obj );
590 void idThread::End( void ) {
591 // Tell thread to die. It will exit on its own.
593 interpreter.threadDying = true;
601 void idThread::KillThread( const char *name ) {
608 // see if the name uses a wild card
609 ptr = strchr( name, '*' );
613 len = strlen( name );
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 ) ) {
631 void idThread::KillThread( int num ) {
634 thread = GetThread( num );
636 // Tell thread to die. It will delete itself on it's own.
646 bool idThread::Execute( void ) {
650 if ( manualControl && ( waitingUntil > gameLocal.time ) ) {
654 oldThread = currentThread;
655 currentThread = this;
657 lastExecuteTime = gameLocal.time;
659 done = interpreter.Execute();
662 if ( interpreter.terminateOnExit ) {
663 PostEventMS( &EV_Remove, 0 );
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 );
673 currentThread = oldThread;
682 Checks if thread is still waiting for some event to occur.
685 bool idThread::IsWaiting( void ) {
686 if ( waitingForThread || ( waitingFor != ENTITYNUM_NONE ) ) {
690 if ( waitingUntil && ( waitingUntil > gameLocal.time ) ) {
699 idThread::CallFunction
701 NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function.
704 void idThread::CallFunction( const function_t *func, bool clearStack ) {
706 interpreter.EnterFunction( func, clearStack );
711 idThread::CallFunction
713 NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function.
716 void idThread::CallFunction( idEntity *self, const function_t *func, bool clearStack ) {
719 interpreter.EnterObjectFunction( self, func, clearStack );
724 idThread::ClearWaitFor
727 void idThread::ClearWaitFor( void ) {
728 waitingFor = ENTITYNUM_NONE;
729 waitingForThread = NULL;
735 idThread::IsWaitingFor
738 bool idThread::IsWaitingFor( idEntity *obj ) {
740 return waitingFor == obj->entityNumber;
745 idThread::ObjectMoveDone
748 void idThread::ObjectMoveDone( idEntity *obj ) {
751 if ( IsWaitingFor( obj ) ) {
759 idThread::ThreadCallback
762 void idThread::ThreadCallback( idThread *thread ) {
763 if ( interpreter.threadDying ) {
767 if ( thread == waitingForThread ) {
775 idThread::Event_SetThreadName
778 void idThread::Event_SetThreadName( const char *name ) {
779 SetThreadName( name );
787 void idThread::Error( const char *fmt, ... ) const {
791 va_start( argptr, fmt );
792 vsprintf( text, fmt, argptr );
795 interpreter.Error( text );
803 void idThread::Warning( const char *fmt, ... ) const {
807 va_start( argptr, fmt );
808 vsprintf( text, fmt, argptr );
811 interpreter.Warning( text );
816 idThread::ReturnString
819 void idThread::ReturnString( const char *text ) {
820 gameLocal.program.ReturnString( text );
825 idThread::ReturnFloat
828 void idThread::ReturnFloat( float value ) {
829 gameLocal.program.ReturnFloat( value );
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 );
845 idThread::ReturnVector
848 void idThread::ReturnVector( idVec3 const &vec ) {
849 gameLocal.program.ReturnVector( vec );
854 idThread::ReturnEntity
857 void idThread::ReturnEntity( idEntity *ent ) {
858 gameLocal.program.ReturnEntity( ent );
863 idThread::Event_Execute
866 void idThread::Event_Execute( void ) {
875 void idThread::Pause( void ) {
877 interpreter.doneProcessing = true;
885 void idThread::WaitMS( int time ) {
887 waitingUntil = gameLocal.time + time;
895 void idThread::WaitSec( float time ) {
896 WaitMS( SEC2MS( time ) );
904 void idThread::WaitFrame( void ) {
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;
914 /***********************************************************************
916 Script callable events
918 ***********************************************************************/
922 idThread::Event_TerminateThread
925 void idThread::Event_TerminateThread( int num ) {
928 thread = GetThread( num );
934 idThread::Event_Pause
937 void idThread::Event_Pause( void ) {
946 void idThread::Event_Wait( float time ) {
952 idThread::Event_WaitFrame
955 void idThread::Event_WaitFrame( void ) {
961 idThread::Event_WaitFor
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() ) {
969 waitingFor = ent->entityNumber;
976 idThread::Event_WaitForThread
979 void idThread::Event_WaitForThread( int num ) {
982 thread = GetThread( num );
984 if ( g_debugScript.GetBool() ) {
985 // just print a warning and continue executing
986 Warning( "Thread %d not running", num );
990 waitingForThread = thread;
996 idThread::Event_Print
999 void idThread::Event_Print( const char *text ) {
1000 gameLocal.Printf( "%s", text );
1005 idThread::Event_PrintLn
1008 void idThread::Event_PrintLn( const char *text ) {
1009 gameLocal.Printf( "%s\n", text );
1017 void idThread::Event_Say( const char *text ) {
1018 cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say \"%s\"", text ) );
1023 idThread::Event_Assert
1026 void idThread::Event_Assert( float value ) {
1032 idThread::Event_Trigger
1035 void idThread::Event_Trigger( idEntity *ent ) {
1037 ent->Signal( SIG_TRIGGER );
1038 ent->ProcessEvent( &EV_Activate, gameLocal.GetLocalPlayer() );
1045 idThread::Event_SetCvar
1048 void idThread::Event_SetCvar( const char *name, const char *value ) const {
1049 cvarSystem->SetCVarString( name, value );
1054 idThread::Event_GetCvar
1057 void idThread::Event_GetCvar( const char *name ) const {
1058 ReturnString( cvarSystem->GetCVarString( name ) );
1063 idThread::Event_Random
1066 void idThread::Event_Random( float range ) const {
1069 result = gameLocal.random.RandomFloat();
1070 ReturnFloat( range * result );
1075 idThread::Event_GetTime
1078 void idThread::Event_GetTime( void ) {
1079 ReturnFloat( MS2SEC( gameLocal.realClientTime ) );
1084 idThread::Event_KillThread
1087 void idThread::Event_KillThread( const char *name ) {
1093 idThread::Event_GetEntity
1096 void idThread::Event_GetEntity( const char *name ) {
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." );
1107 ReturnEntity( gameLocal.entities[ entnum ] );
1109 ent = gameLocal.FindEntity( name );
1110 ReturnEntity( ent );
1116 idThread::Event_Spawn
1119 void idThread::Event_Spawn( const char *classname ) {
1122 spawnArgs.Set( "classname", classname );
1123 gameLocal.SpawnEntityDef( spawnArgs, &ent );
1124 ReturnEntity( ent );
1130 idThread::Event_CopySpawnArgs
1133 void idThread::Event_CopySpawnArgs( idEntity *ent ) {
1134 spawnArgs.Copy( ent->spawnArgs );
1139 idThread::Event_SetSpawnArg
1142 void idThread::Event_SetSpawnArg( const char *key, const char *value ) {
1143 spawnArgs.Set( key, value );
1148 idThread::Event_SpawnString
1151 void idThread::Event_SpawnString( const char *key, const char *defaultvalue ) {
1154 spawnArgs.GetString( key, defaultvalue, &result );
1155 ReturnString( result );
1160 idThread::Event_SpawnFloat
1163 void idThread::Event_SpawnFloat( const char *key, float defaultvalue ) {
1166 spawnArgs.GetFloat( key, va( "%f", defaultvalue ), result );
1167 ReturnFloat( result );
1172 idThread::Event_SpawnVector
1175 void idThread::Event_SpawnVector( const char *key, idVec3 &defaultvalue ) {
1178 spawnArgs.GetVector( key, va( "%f %f %f", defaultvalue.x, defaultvalue.y, defaultvalue.z ), result );
1179 ReturnVector( result );
1184 idThread::Event_ClearPersistantArgs
1187 void idThread::Event_ClearPersistantArgs( void ) {
1188 gameLocal.persistentLevelInfo.Clear();
1194 idThread::Event_SetPersistantArg
1197 void idThread::Event_SetPersistantArg( const char *key, const char *value ) {
1198 gameLocal.persistentLevelInfo.Set( key, value );
1203 idThread::Event_GetPersistantString
1206 void idThread::Event_GetPersistantString( const char *key ) {
1209 gameLocal.persistentLevelInfo.GetString( key, "", &result );
1210 ReturnString( result );
1215 idThread::Event_GetPersistantFloat
1218 void idThread::Event_GetPersistantFloat( const char *key ) {
1221 gameLocal.persistentLevelInfo.GetFloat( key, "0", result );
1222 ReturnFloat( result );
1227 idThread::Event_GetPersistantVector
1230 void idThread::Event_GetPersistantVector( const char *key ) {
1233 gameLocal.persistentLevelInfo.GetVector( key, "0 0 0", result );
1234 ReturnVector( result );
1239 idThread::Event_AngToForward
1242 void idThread::Event_AngToForward( idAngles &ang ) {
1243 ReturnVector( ang.ToForward() );
1248 idThread::Event_AngToRight
1251 void idThread::Event_AngToRight( idAngles &ang ) {
1254 ang.ToVectors( NULL, &vec );
1255 ReturnVector( vec );
1260 idThread::Event_AngToUp
1263 void idThread::Event_AngToUp( idAngles &ang ) {
1266 ang.ToVectors( NULL, NULL, &vec );
1267 ReturnVector( vec );
1272 idThread::Event_GetSine
1275 void idThread::Event_GetSine( float angle ) {
1276 ReturnFloat( idMath::Sin( DEG2RAD( angle ) ) );
1281 idThread::Event_GetCosine
1284 void idThread::Event_GetCosine( float angle ) {
1285 ReturnFloat( idMath::Cos( DEG2RAD( angle ) ) );
1290 idThread::Event_GetSquareRoot
1293 void idThread::Event_GetSquareRoot( float theSquare ) {
1294 ReturnFloat( idMath::Sqrt( theSquare ) );
1299 idThread::Event_VecNormalize
1302 void idThread::Event_VecNormalize( idVec3 &vec ) {
1312 idThread::Event_VecLength
1315 void idThread::Event_VecLength( idVec3 &vec ) {
1316 ReturnFloat( vec.Length() );
1321 idThread::Event_VecDotProduct
1324 void idThread::Event_VecDotProduct( idVec3 &vec1, idVec3 &vec2 ) {
1325 ReturnFloat( vec1 * vec2 );
1330 idThread::Event_VecCrossProduct
1333 void idThread::Event_VecCrossProduct( idVec3 &vec1, idVec3 &vec2 ) {
1334 ReturnVector( vec1.Cross( vec2 ) );
1339 idThread::Event_VecToAngles
1342 void idThread::Event_VecToAngles( idVec3 &vec ) {
1343 idAngles ang = vec.ToAngles();
1344 ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
1349 idThread::Event_OnSignal
1352 void idThread::Event_OnSignal( int signal, idEntity *ent, const char *func ) {
1353 const function_t *function;
1358 Error( "Entity not found" );
1361 if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) {
1362 Error( "Signal out of range" );
1365 function = gameLocal.program.FindFunction( func );
1367 Error( "Function '%s' not found", func );
1370 ent->SetSignal( ( signalNum_t )signal, this, function );
1375 idThread::Event_ClearSignalThread
1378 void idThread::Event_ClearSignalThread( int signal, idEntity *ent ) {
1380 Error( "Entity not found" );
1383 if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) {
1384 Error( "Signal out of range" );
1387 ent->ClearSignalThread( ( signalNum_t )signal, this );
1392 idThread::Event_SetCamera
1395 void idThread::Event_SetCamera( idEntity *ent ) {
1397 Error( "Entity not found" );
1401 if ( !ent->IsType( idCamera::Type ) ) {
1402 Error( "Entity is not a camera" );
1406 gameLocal.SetCamera( ( idCamera * )ent );
1411 idThread::Event_FirstPerson
1414 void idThread::Event_FirstPerson( void ) {
1415 gameLocal.SetCamera( NULL );
1420 idThread::Event_Trace
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 );
1427 gameLocal.clip.TraceBounds( trace, start, end, idBounds( mins, maxs ), contents_mask, passEntity );
1429 ReturnFloat( trace.fraction );
1434 idThread::Event_TracePoint
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 );
1444 idThread::Event_GetTraceFraction
1447 void idThread::Event_GetTraceFraction( void ) {
1448 ReturnFloat( trace.fraction );
1453 idThread::Event_GetTraceEndPos
1456 void idThread::Event_GetTraceEndPos( void ) {
1457 ReturnVector( trace.endpos );
1462 idThread::Event_GetTraceNormal
1465 void idThread::Event_GetTraceNormal( void ) {
1466 if ( trace.fraction < 1.0f ) {
1467 ReturnVector( trace.c.normal );
1469 ReturnVector( vec3_origin );
1475 idThread::Event_GetTraceEntity
1478 void idThread::Event_GetTraceEntity( void ) {
1479 if ( trace.fraction < 1.0f ) {
1480 ReturnEntity( gameLocal.entities[ trace.c.entityNum ] );
1482 ReturnEntity( ( idEntity * )NULL );
1488 idThread::Event_GetTraceJoint
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 ) ) );
1504 idThread::Event_GetTraceBody
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 );
1514 ReturnString( body->GetName() );
1524 idThread::Event_FadeIn
1527 void idThread::Event_FadeIn( idVec3 &color, float time ) {
1531 player = gameLocal.GetLocalPlayer();
1533 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 0.0f );
1534 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1540 idThread::Event_FadeOut
1543 void idThread::Event_FadeOut( idVec3 &color, float time ) {
1547 player = gameLocal.GetLocalPlayer();
1549 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 1.0f );
1550 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1556 idThread::Event_FadeTo
1559 void idThread::Event_FadeTo( idVec3 &color, float alpha, float time ) {
1563 player = gameLocal.GetLocalPlayer();
1565 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], alpha );
1566 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1572 idThread::Event_SetShaderParm
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 );
1580 gameLocal.globalShaderParms[ parmnum ] = value;
1585 idThread::Event_StartMusic
1588 void idThread::Event_StartMusic( const char *text ) {
1589 gameSoundWorld->PlayShaderDirectly( text );
1594 idThread::Event_Warning
1597 void idThread::Event_Warning( const char *text ) {
1598 Warning( "%s", text );
1603 idThread::Event_Error
1606 void idThread::Event_Error( const char *text ) {
1607 Error( "%s", text );
1612 idThread::Event_StrLen
1615 void idThread::Event_StrLen( const char *string ) {
1618 len = strlen( string );
1619 idThread::ReturnInt( len );
1624 idThread::Event_StrLeft
1627 void idThread::Event_StrLeft( const char *string, int num ) {
1631 idThread::ReturnString( "" );
1635 len = strlen( string );
1637 idThread::ReturnString( string );
1641 idStr result( string, 0, num );
1642 idThread::ReturnString( result );
1647 idThread::Event_StrRight
1650 void idThread::Event_StrRight( const char *string, int num ) {
1654 idThread::ReturnString( "" );
1658 len = strlen( string );
1660 idThread::ReturnString( string );
1664 idThread::ReturnString( string + len - num );
1669 idThread::Event_StrSkip
1672 void idThread::Event_StrSkip( const char *string, int num ) {
1676 idThread::ReturnString( string );
1680 len = strlen( string );
1682 idThread::ReturnString( "" );
1686 idThread::ReturnString( string + num );
1691 idThread::Event_StrMid
1694 void idThread::Event_StrMid( const char *string, int start, int num ) {
1698 idThread::ReturnString( "" );
1705 len = strlen( string );
1706 if ( start > len ) {
1710 if ( start + num > len ) {
1714 idStr result( string, start, start + num );
1715 idThread::ReturnString( result );
1720 idThread::Event_StrToFloat( const char *string )
1723 void idThread::Event_StrToFloat( const char *string ) {
1726 result = atof( string );
1727 idThread::ReturnFloat( result );
1732 idThread::Event_RadiusDamage
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 );
1741 idThread::Event_IsClient
1744 void idThread::Event_IsClient( void ) {
1745 idThread::ReturnFloat( gameLocal.isClient );
1750 idThread::Event_IsMultiplayer
1753 void idThread::Event_IsMultiplayer( void ) {
1754 idThread::ReturnFloat( gameLocal.isMultiplayer );
1759 idThread::Event_GetFrameTime
1762 void idThread::Event_GetFrameTime( void ) {
1763 idThread::ReturnFloat( MS2SEC( gameLocal.msec ) );
1768 idThread::Event_GetTicsPerSecond
1771 void idThread::Event_GetTicsPerSecond( void ) {
1772 idThread::ReturnFloat( USERCMD_HZ );
1777 idThread::Event_CacheSoundShader
1780 void idThread::Event_CacheSoundShader( const char *soundName ) {
1781 declManager->FindSound( soundName );
1786 idThread::Event_DebugLine
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 ) );
1795 idThread::Event_DebugArrow
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 ) );
1804 idThread::Event_DebugCircle
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 ) );
1813 idThread::Event_DebugBounds
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 ) );
1822 idThread::Event_DrawText
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 ) );
1831 idThread::Event_InfluenceActive
1834 void idThread::Event_InfluenceActive( void ) {
1837 player = gameLocal.GetLocalPlayer();
1838 if ( player && player->GetInfluenceLevel() ) {
1839 idThread::ReturnInt( true );
1841 idThread::ReturnInt( false );