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' );
53 const idEventDef EV_Thread_RandomInt( "randomInt", "d", 'd' );
55 const idEventDef EV_Thread_GetTime( "getTime", NULL, 'f' );
56 const idEventDef EV_Thread_KillThread( "killthread", "s" );
57 const idEventDef EV_Thread_SetThreadName( "threadname", "s" );
58 const idEventDef EV_Thread_GetEntity( "getEntity", "s", 'e' );
59 const idEventDef EV_Thread_Spawn( "spawn", "s", 'e' );
60 const idEventDef EV_Thread_CopySpawnArgs( "copySpawnArgs", "e" );
61 const idEventDef EV_Thread_SetSpawnArg( "setSpawnArg", "ss" );
62 const idEventDef EV_Thread_SpawnString( "SpawnString", "ss", 's' );
63 const idEventDef EV_Thread_SpawnFloat( "SpawnFloat", "sf", 'f' );
64 const idEventDef EV_Thread_SpawnVector( "SpawnVector", "sv", 'v' );
65 const idEventDef EV_Thread_ClearPersistantArgs( "clearPersistantArgs" );
66 const idEventDef EV_Thread_SetPersistantArg( "setPersistantArg", "ss" );
67 const idEventDef EV_Thread_GetPersistantString( "getPersistantString", "s", 's' );
68 const idEventDef EV_Thread_GetPersistantFloat( "getPersistantFloat", "s", 'f' );
69 const idEventDef EV_Thread_GetPersistantVector( "getPersistantVector", "s", 'v' );
70 const idEventDef EV_Thread_AngToForward( "angToForward", "v", 'v' );
71 const idEventDef EV_Thread_AngToRight( "angToRight", "v", 'v' );
72 const idEventDef EV_Thread_AngToUp( "angToUp", "v", 'v' );
73 const idEventDef EV_Thread_Sine( "sin", "f", 'f' );
74 const idEventDef EV_Thread_Cosine( "cos", "f", 'f' );
76 const idEventDef EV_Thread_ArcSine( "asin", "f", 'f' );
77 const idEventDef EV_Thread_ArcCosine( "acos", "f", 'f' );
79 const idEventDef EV_Thread_SquareRoot( "sqrt", "f", 'f' );
80 const idEventDef EV_Thread_Normalize( "vecNormalize", "v", 'v' );
81 const idEventDef EV_Thread_VecLength( "vecLength", "v", 'f' );
82 const idEventDef EV_Thread_VecDotProduct( "DotProduct", "vv", 'f' );
83 const idEventDef EV_Thread_VecCrossProduct( "CrossProduct", "vv", 'v' );
84 const idEventDef EV_Thread_VecToAngles( "VecToAngles", "v", 'v' );
86 const idEventDef EV_Thread_VecToOrthoBasisAngles( "VecToOrthoBasisAngles", "v", 'v' );
87 const idEventDef EV_Thread_RotateVector("rotateVector", "vv", 'v');
89 const idEventDef EV_Thread_OnSignal( "onSignal", "des" );
90 const idEventDef EV_Thread_ClearSignal( "clearSignalThread", "de" );
91 const idEventDef EV_Thread_SetCamera( "setCamera", "e" );
92 const idEventDef EV_Thread_FirstPerson( "firstPerson", NULL );
93 const idEventDef EV_Thread_Trace( "trace", "vvvvde", 'f' );
94 const idEventDef EV_Thread_TracePoint( "tracePoint", "vvde", 'f' );
95 const idEventDef EV_Thread_GetTraceFraction( "getTraceFraction", NULL, 'f' );
96 const idEventDef EV_Thread_GetTraceEndPos( "getTraceEndPos", NULL, 'v' );
97 const idEventDef EV_Thread_GetTraceNormal( "getTraceNormal", NULL, 'v' );
98 const idEventDef EV_Thread_GetTraceEntity( "getTraceEntity", NULL, 'e' );
99 const idEventDef EV_Thread_GetTraceJoint( "getTraceJoint", NULL, 's' );
100 const idEventDef EV_Thread_GetTraceBody( "getTraceBody", NULL, 's' );
101 const idEventDef EV_Thread_FadeIn( "fadeIn", "vf" );
102 const idEventDef EV_Thread_FadeOut( "fadeOut", "vf" );
103 const idEventDef EV_Thread_FadeTo( "fadeTo", "vff" );
104 const idEventDef EV_Thread_StartMusic( "music", "s" );
105 const idEventDef EV_Thread_Error( "error", "s" );
106 const idEventDef EV_Thread_Warning( "warning", "s" );
107 const idEventDef EV_Thread_StrLen( "strLength", "s", 'd' );
108 const idEventDef EV_Thread_StrLeft( "strLeft", "sd", 's' );
109 const idEventDef EV_Thread_StrRight( "strRight", "sd", 's' );
110 const idEventDef EV_Thread_StrSkip( "strSkip", "sd", 's' );
111 const idEventDef EV_Thread_StrMid( "strMid", "sdd", 's' );
112 const idEventDef EV_Thread_StrToFloat( "strToFloat", "s", 'f' );
113 const idEventDef EV_Thread_RadiusDamage( "radiusDamage", "vEEEsf" );
114 const idEventDef EV_Thread_IsClient( "isClient", NULL, 'f' );
115 const idEventDef EV_Thread_IsMultiplayer( "isMultiplayer", NULL, 'f' );
116 const idEventDef EV_Thread_GetFrameTime( "getFrameTime", NULL, 'f' );
117 const idEventDef EV_Thread_GetTicsPerSecond( "getTicsPerSecond", NULL, 'f' );
118 const idEventDef EV_Thread_DebugLine( "debugLine", "vvvf" );
119 const idEventDef EV_Thread_DebugArrow( "debugArrow", "vvvdf" );
120 const idEventDef EV_Thread_DebugCircle( "debugCircle", "vvvfdf" );
121 const idEventDef EV_Thread_DebugBounds( "debugBounds", "vvvf" );
122 const idEventDef EV_Thread_DrawText( "drawText", "svfvdf" );
123 const idEventDef EV_Thread_InfluenceActive( "influenceActive", NULL, 'd' );
125 CLASS_DECLARATION( idClass, idThread )
126 EVENT( EV_Thread_Execute, idThread::Event_Execute )
127 EVENT( EV_Thread_TerminateThread, idThread::Event_TerminateThread )
128 EVENT( EV_Thread_Pause, idThread::Event_Pause )
129 EVENT( EV_Thread_Wait, idThread::Event_Wait )
130 EVENT( EV_Thread_WaitFrame, idThread::Event_WaitFrame )
131 EVENT( EV_Thread_WaitFor, idThread::Event_WaitFor )
132 EVENT( EV_Thread_WaitForThread, idThread::Event_WaitForThread )
133 EVENT( EV_Thread_Print, idThread::Event_Print )
134 EVENT( EV_Thread_PrintLn, idThread::Event_PrintLn )
135 EVENT( EV_Thread_Say, idThread::Event_Say )
136 EVENT( EV_Thread_Assert, idThread::Event_Assert )
137 EVENT( EV_Thread_Trigger, idThread::Event_Trigger )
138 EVENT( EV_Thread_SetCvar, idThread::Event_SetCvar )
139 EVENT( EV_Thread_GetCvar, idThread::Event_GetCvar )
140 EVENT( EV_Thread_Random, idThread::Event_Random )
142 EVENT( EV_Thread_RandomInt, idThread::Event_RandomInt )
144 EVENT( EV_Thread_GetTime, idThread::Event_GetTime )
145 EVENT( EV_Thread_KillThread, idThread::Event_KillThread )
146 EVENT( EV_Thread_SetThreadName, idThread::Event_SetThreadName )
147 EVENT( EV_Thread_GetEntity, idThread::Event_GetEntity )
148 EVENT( EV_Thread_Spawn, idThread::Event_Spawn )
149 EVENT( EV_Thread_CopySpawnArgs, idThread::Event_CopySpawnArgs )
150 EVENT( EV_Thread_SetSpawnArg, idThread::Event_SetSpawnArg )
151 EVENT( EV_Thread_SpawnString, idThread::Event_SpawnString )
152 EVENT( EV_Thread_SpawnFloat, idThread::Event_SpawnFloat )
153 EVENT( EV_Thread_SpawnVector, idThread::Event_SpawnVector )
154 EVENT( EV_Thread_ClearPersistantArgs, idThread::Event_ClearPersistantArgs )
155 EVENT( EV_Thread_SetPersistantArg, idThread::Event_SetPersistantArg )
156 EVENT( EV_Thread_GetPersistantString, idThread::Event_GetPersistantString )
157 EVENT( EV_Thread_GetPersistantFloat, idThread::Event_GetPersistantFloat )
158 EVENT( EV_Thread_GetPersistantVector, idThread::Event_GetPersistantVector )
159 EVENT( EV_Thread_AngToForward, idThread::Event_AngToForward )
160 EVENT( EV_Thread_AngToRight, idThread::Event_AngToRight )
161 EVENT( EV_Thread_AngToUp, idThread::Event_AngToUp )
162 EVENT( EV_Thread_Sine, idThread::Event_GetSine )
163 EVENT( EV_Thread_Cosine, idThread::Event_GetCosine )
165 EVENT( EV_Thread_ArcSine, idThread::Event_GetArcSine )
166 EVENT( EV_Thread_ArcCosine, idThread::Event_GetArcCosine )
168 EVENT( EV_Thread_SquareRoot, idThread::Event_GetSquareRoot )
169 EVENT( EV_Thread_Normalize, idThread::Event_VecNormalize )
170 EVENT( EV_Thread_VecLength, idThread::Event_VecLength )
171 EVENT( EV_Thread_VecDotProduct, idThread::Event_VecDotProduct )
172 EVENT( EV_Thread_VecCrossProduct, idThread::Event_VecCrossProduct )
173 EVENT( EV_Thread_VecToAngles, idThread::Event_VecToAngles )
175 EVENT( EV_Thread_VecToOrthoBasisAngles, idThread::Event_VecToOrthoBasisAngles )
176 EVENT( EV_Thread_RotateVector, idThread::Event_RotateVector )
178 EVENT( EV_Thread_OnSignal, idThread::Event_OnSignal )
179 EVENT( EV_Thread_ClearSignal, idThread::Event_ClearSignalThread )
180 EVENT( EV_Thread_SetCamera, idThread::Event_SetCamera )
181 EVENT( EV_Thread_FirstPerson, idThread::Event_FirstPerson )
182 EVENT( EV_Thread_Trace, idThread::Event_Trace )
183 EVENT( EV_Thread_TracePoint, idThread::Event_TracePoint )
184 EVENT( EV_Thread_GetTraceFraction, idThread::Event_GetTraceFraction )
185 EVENT( EV_Thread_GetTraceEndPos, idThread::Event_GetTraceEndPos )
186 EVENT( EV_Thread_GetTraceNormal, idThread::Event_GetTraceNormal )
187 EVENT( EV_Thread_GetTraceEntity, idThread::Event_GetTraceEntity )
188 EVENT( EV_Thread_GetTraceJoint, idThread::Event_GetTraceJoint )
189 EVENT( EV_Thread_GetTraceBody, idThread::Event_GetTraceBody )
190 EVENT( EV_Thread_FadeIn, idThread::Event_FadeIn )
191 EVENT( EV_Thread_FadeOut, idThread::Event_FadeOut )
192 EVENT( EV_Thread_FadeTo, idThread::Event_FadeTo )
193 EVENT( EV_SetShaderParm, idThread::Event_SetShaderParm )
194 EVENT( EV_Thread_StartMusic, idThread::Event_StartMusic )
195 EVENT( EV_Thread_Warning, idThread::Event_Warning )
196 EVENT( EV_Thread_Error, idThread::Event_Error )
197 EVENT( EV_Thread_StrLen, idThread::Event_StrLen )
198 EVENT( EV_Thread_StrLeft, idThread::Event_StrLeft )
199 EVENT( EV_Thread_StrRight, idThread::Event_StrRight )
200 EVENT( EV_Thread_StrSkip, idThread::Event_StrSkip )
201 EVENT( EV_Thread_StrMid, idThread::Event_StrMid )
202 EVENT( EV_Thread_StrToFloat, idThread::Event_StrToFloat )
203 EVENT( EV_Thread_RadiusDamage, idThread::Event_RadiusDamage )
204 EVENT( EV_Thread_IsClient, idThread::Event_IsClient )
205 EVENT( EV_Thread_IsMultiplayer, idThread::Event_IsMultiplayer )
206 EVENT( EV_Thread_GetFrameTime, idThread::Event_GetFrameTime )
207 EVENT( EV_Thread_GetTicsPerSecond, idThread::Event_GetTicsPerSecond )
208 EVENT( EV_CacheSoundShader, idThread::Event_CacheSoundShader )
209 EVENT( EV_Thread_DebugLine, idThread::Event_DebugLine )
210 EVENT( EV_Thread_DebugArrow, idThread::Event_DebugArrow )
211 EVENT( EV_Thread_DebugCircle, idThread::Event_DebugCircle )
212 EVENT( EV_Thread_DebugBounds, idThread::Event_DebugBounds )
213 EVENT( EV_Thread_DrawText, idThread::Event_DrawText )
214 EVENT( EV_Thread_InfluenceActive, idThread::Event_InfluenceActive )
217 idThread *idThread::currentThread = NULL;
218 int idThread::threadIndex = 0;
219 idList<idThread *> idThread::threadList;
220 trace_t idThread::trace;
224 idThread::CurrentThread
227 idThread *idThread::CurrentThread( void ) {
228 return currentThread;
233 idThread::CurrentThreadNum
236 int idThread::CurrentThreadNum( void ) {
237 if ( currentThread ) {
238 return currentThread->GetThreadNum();
246 idThread::BeginMultiFrameEvent
249 bool idThread::BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
250 if ( !currentThread ) {
251 gameLocal.Error( "idThread::BeginMultiFrameEvent called without a current thread" );
253 return currentThread->interpreter.BeginMultiFrameEvent( ent, event );
258 idThread::EndMultiFrameEvent
261 void idThread::EndMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
262 if ( !currentThread ) {
263 gameLocal.Error( "idThread::EndMultiFrameEvent called without a current thread" );
265 currentThread->interpreter.EndMultiFrameEvent( ent, event );
273 idThread::idThread() {
275 SetThreadName( va( "thread_%d", threadIndex ) );
276 if ( g_debugScript.GetBool() ) {
277 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
286 idThread::idThread( idEntity *self, const function_t *func ) {
290 SetThreadName( self->name );
291 interpreter.EnterObjectFunction( self, func, false );
292 if ( g_debugScript.GetBool() ) {
293 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
302 idThread::idThread( const function_t *func ) {
306 SetThreadName( func->Name() );
307 interpreter.EnterFunction( func, false );
308 if ( g_debugScript.GetBool() ) {
309 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
318 idThread::idThread( idInterpreter *source, const function_t *func, int args ) {
320 interpreter.ThreadCall( source, func, args );
321 if ( g_debugScript.GetBool() ) {
322 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
331 idThread::idThread( idInterpreter *source, idEntity *self, const function_t *func, int args ) {
335 SetThreadName( self->name );
336 interpreter.ThreadCall( source, func, args );
337 if ( g_debugScript.GetBool() ) {
338 gameLocal.Printf( "%d: create thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
347 idThread::~idThread() {
352 if ( g_debugScript.GetBool() ) {
353 gameLocal.Printf( "%d: end thread (%d) '%s'\n", gameLocal.time, threadNum, threadName.c_str() );
355 threadList.Remove( this );
356 n = threadList.Num();
357 for( i = 0; i < n; i++ ) {
358 thread = threadList[ i ];
359 if ( thread->WaitingOnThread() == this ) {
360 thread->ThreadCallback( this );
364 if ( currentThread == this ) {
365 currentThread = NULL;
371 idThread::ManualDelete
374 void idThread::ManualDelete( void ) {
375 interpreter.terminateOnExit = false;
383 void idThread::Save( idSaveGame *savefile ) const {
385 // We will check on restore that threadNum is still the same,
386 // threads should have been restored in the same order.
387 savefile->WriteInt( threadNum );
389 savefile->WriteObject( waitingForThread );
390 savefile->WriteInt( waitingFor );
391 savefile->WriteInt( waitingUntil );
393 interpreter.Save( savefile );
395 savefile->WriteDict( &spawnArgs );
396 savefile->WriteString( threadName );
398 savefile->WriteInt( lastExecuteTime );
399 savefile->WriteInt( creationTime );
401 savefile->WriteBool( manualControl );
409 void idThread::Restore( idRestoreGame *savefile ) {
410 savefile->ReadInt( threadNum );
412 savefile->ReadObject( reinterpret_cast<idClass *&>( waitingForThread ) );
413 savefile->ReadInt( waitingFor );
414 savefile->ReadInt( waitingUntil );
416 interpreter.Restore( savefile );
418 savefile->ReadDict( &spawnArgs );
419 savefile->ReadString( threadName );
421 savefile->ReadInt( lastExecuteTime );
422 savefile->ReadInt( creationTime );
424 savefile->ReadBool( manualControl );
432 void idThread::Init( void ) {
433 // create a unique threadNum
436 if ( threadIndex == 0 ) {
439 } while( GetThread( threadIndex ) );
441 threadNum = threadIndex;
442 threadList.Append( this );
444 creationTime = gameLocal.time;
446 manualControl = false;
450 interpreter.SetThread( this );
458 idThread *idThread::GetThread( int num ) {
463 n = threadList.Num();
464 for( i = 0; i < n; i++ ) {
465 thread = threadList[ i ];
466 if ( thread->GetThreadNum() == num ) {
476 idThread::DisplayInfo
479 void idThread::DisplayInfo( void ) {
483 " Created: %d (%d ms ago)\n"
485 threadNum, threadName.c_str(),
486 interpreter.CurrentFile(), interpreter.CurrentLine(),
487 creationTime, gameLocal.time - creationTime );
489 if ( interpreter.threadDying ) {
490 gameLocal.Printf( "Dying\n" );
491 } else if ( interpreter.doneProcessing ) {
493 "Paused since %d (%d ms)\n"
494 " Reason: ", lastExecuteTime, gameLocal.time - lastExecuteTime );
495 if ( waitingForThread ) {
496 gameLocal.Printf( "Waiting for thread #%3i '%s'\n", waitingForThread->GetThreadNum(), waitingForThread->GetThreadName() );
497 } else if ( ( waitingFor != ENTITYNUM_NONE ) && ( gameLocal.entities[ waitingFor ] ) ) {
498 gameLocal.Printf( "Waiting for entity #%3i '%s'\n", waitingFor, gameLocal.entities[ waitingFor ]->name.c_str() );
499 } else if ( waitingUntil ) {
500 gameLocal.Printf( "Waiting until %d (%d ms total wait time)\n", waitingUntil, waitingUntil - lastExecuteTime );
502 gameLocal.Printf( "None\n" );
505 gameLocal.Printf( "Processing\n" );
508 interpreter.DisplayInfo();
510 gameLocal.Printf( "\n" );
515 idThread::ListThreads_f
518 void idThread::ListThreads_f( const idCmdArgs &args ) {
522 n = threadList.Num();
523 for( i = 0; i < n; i++ ) {
524 //threadList[ i ]->DisplayInfo();
525 gameLocal.Printf( "%3i: %-20s : %s(%d)\n", threadList[ i ]->threadNum, threadList[ i ]->threadName.c_str(), threadList[ i ]->interpreter.CurrentFile(), threadList[ i ]->interpreter.CurrentLine() );
527 gameLocal.Printf( "%d active threads\n\n", n );
535 void idThread::Restart( void ) {
539 // reset the threadIndex
542 currentThread = NULL;
543 n = threadList.Num();
544 for( i = n - 1; i >= 0; i-- ) {
545 delete threadList[ i ];
549 memset( &trace, 0, sizeof( trace ) );
550 trace.c.entityNum = ENTITYNUM_NONE;
555 idThread::DelayedStart
558 void idThread::DelayedStart( int delay ) {
559 CancelEvents( &EV_Thread_Execute );
560 if ( gameLocal.time <= 0 ) {
563 PostEventMS( &EV_Thread_Execute, delay );
571 bool idThread::Start( void ) {
574 CancelEvents( &EV_Thread_Execute );
582 idThread::SetThreadName
585 void idThread::SetThreadName( const char *name ) {
591 idThread::ObjectMoveDone
594 void idThread::ObjectMoveDone( int threadnum, idEntity *obj ) {
601 thread = GetThread( threadnum );
603 thread->ObjectMoveDone( obj );
612 void idThread::End( void ) {
613 // Tell thread to die. It will exit on its own.
615 interpreter.threadDying = true;
623 void idThread::KillThread( const char *name ) {
630 // see if the name uses a wild card
631 ptr = strchr( name, '*' );
635 len = strlen( name );
638 // kill only those threads whose name matches name
639 num = threadList.Num();
640 for( i = 0; i < num; i++ ) {
641 thread = threadList[ i ];
642 if ( !idStr::Cmpn( thread->GetThreadName(), name, len ) ) {
653 void idThread::KillThread( int num ) {
656 thread = GetThread( num );
658 // Tell thread to die. It will delete itself on it's own.
668 bool idThread::Execute( void ) {
672 if ( manualControl && ( waitingUntil > gameLocal.time ) ) {
676 oldThread = currentThread;
677 currentThread = this;
679 lastExecuteTime = gameLocal.time;
681 done = interpreter.Execute();
684 if ( interpreter.terminateOnExit ) {
685 PostEventMS( &EV_Remove, 0 );
687 } else if ( !manualControl ) {
688 if ( waitingUntil > lastExecuteTime ) {
689 PostEventMS( &EV_Thread_Execute, waitingUntil - lastExecuteTime );
690 } else if ( interpreter.MultiFrameEventInProgress() ) {
691 PostEventMS( &EV_Thread_Execute, gameLocal.msec );
695 currentThread = oldThread;
704 Checks if thread is still waiting for some event to occur.
707 bool idThread::IsWaiting( void ) {
708 if ( waitingForThread || ( waitingFor != ENTITYNUM_NONE ) ) {
712 if ( waitingUntil && ( waitingUntil > gameLocal.time ) ) {
721 idThread::CallFunction
723 NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function.
726 void idThread::CallFunction( const function_t *func, bool clearStack ) {
728 interpreter.EnterFunction( func, clearStack );
733 idThread::CallFunction
735 NOTE: If this is called from within a event called by this thread, the function arguments will be invalid after calling this function.
738 void idThread::CallFunction( idEntity *self, const function_t *func, bool clearStack ) {
741 interpreter.EnterObjectFunction( self, func, clearStack );
746 idThread::ClearWaitFor
749 void idThread::ClearWaitFor( void ) {
750 waitingFor = ENTITYNUM_NONE;
751 waitingForThread = NULL;
757 idThread::IsWaitingFor
760 bool idThread::IsWaitingFor( idEntity *obj ) {
762 return waitingFor == obj->entityNumber;
767 idThread::ObjectMoveDone
770 void idThread::ObjectMoveDone( idEntity *obj ) {
773 if ( IsWaitingFor( obj ) ) {
781 idThread::ThreadCallback
784 void idThread::ThreadCallback( idThread *thread ) {
785 if ( interpreter.threadDying ) {
789 if ( thread == waitingForThread ) {
797 idThread::Event_SetThreadName
800 void idThread::Event_SetThreadName( const char *name ) {
801 SetThreadName( name );
809 void idThread::Error( const char *fmt, ... ) const {
813 va_start( argptr, fmt );
814 vsprintf( text, fmt, argptr );
817 interpreter.Error( text );
825 void idThread::Warning( const char *fmt, ... ) const {
829 va_start( argptr, fmt );
830 vsprintf( text, fmt, argptr );
833 interpreter.Warning( text );
838 idThread::ReturnString
841 void idThread::ReturnString( const char *text ) {
842 gameLocal.program.ReturnString( text );
847 idThread::ReturnFloat
850 void idThread::ReturnFloat( float value ) {
851 gameLocal.program.ReturnFloat( value );
859 void idThread::ReturnInt( int value ) {
860 // true integers aren't supported in the compiler,
861 // so int values are stored as floats
862 gameLocal.program.ReturnFloat( value );
867 idThread::ReturnVector
870 void idThread::ReturnVector( idVec3 const &vec ) {
871 gameLocal.program.ReturnVector( vec );
876 idThread::ReturnEntity
879 void idThread::ReturnEntity( idEntity *ent ) {
880 gameLocal.program.ReturnEntity( ent );
885 idThread::Event_Execute
888 void idThread::Event_Execute( void ) {
897 void idThread::Pause( void ) {
899 interpreter.doneProcessing = true;
907 void idThread::WaitMS( int time ) {
909 waitingUntil = gameLocal.time + time;
917 void idThread::WaitSec( float time ) {
918 WaitMS( SEC2MS( time ) );
926 void idThread::WaitFrame( void ) {
929 // manual control threads don't set waitingUntil so that they can be run again
930 // that frame if necessary.
931 if ( !manualControl ) {
932 waitingUntil = gameLocal.time + gameLocal.msec;
936 /***********************************************************************
938 Script callable events
940 ***********************************************************************/
944 idThread::Event_TerminateThread
947 void idThread::Event_TerminateThread( int num ) {
950 thread = GetThread( num );
956 idThread::Event_Pause
959 void idThread::Event_Pause( void ) {
968 void idThread::Event_Wait( float time ) {
974 idThread::Event_WaitFrame
977 void idThread::Event_WaitFrame( void ) {
983 idThread::Event_WaitFor
986 void idThread::Event_WaitFor( idEntity *ent ) {
987 if ( ent && ent->RespondsTo( EV_Thread_SetCallback ) ) {
988 ent->ProcessEvent( &EV_Thread_SetCallback );
989 if ( gameLocal.program.GetReturnedInteger() ) {
991 waitingFor = ent->entityNumber;
998 idThread::Event_WaitForThread
1001 void idThread::Event_WaitForThread( int num ) {
1004 thread = GetThread( num );
1006 if ( g_debugScript.GetBool() ) {
1007 // just print a warning and continue executing
1008 Warning( "Thread %d not running", num );
1012 waitingForThread = thread;
1018 idThread::Event_Print
1021 void idThread::Event_Print( const char *text ) {
1022 gameLocal.Printf( "%s", text );
1027 idThread::Event_PrintLn
1030 void idThread::Event_PrintLn( const char *text ) {
1031 gameLocal.Printf( "%s\n", text );
1039 void idThread::Event_Say( const char *text ) {
1040 cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "say \"%s\"", text ) );
1045 idThread::Event_Assert
1048 void idThread::Event_Assert( float value ) {
1054 idThread::Event_Trigger
1057 void idThread::Event_Trigger( idEntity *ent ) {
1059 ent->Signal( SIG_TRIGGER );
1060 ent->ProcessEvent( &EV_Activate, gameLocal.GetLocalPlayer() );
1067 idThread::Event_SetCvar
1070 void idThread::Event_SetCvar( const char *name, const char *value ) const {
1071 cvarSystem->SetCVarString( name, value );
1076 idThread::Event_GetCvar
1079 void idThread::Event_GetCvar( const char *name ) const {
1080 ReturnString( cvarSystem->GetCVarString( name ) );
1085 idThread::Event_Random
1088 void idThread::Event_Random( float range ) const {
1091 result = gameLocal.random.RandomFloat();
1092 ReturnFloat( range * result );
1097 void idThread::Event_RandomInt( int range ) const {
1099 result = gameLocal.random.RandomInt(range);
1100 ReturnFloat(result);
1107 idThread::Event_GetTime
1110 void idThread::Event_GetTime( void ) {
1111 ReturnFloat( MS2SEC( gameLocal.realClientTime ) );
1116 idThread::Event_KillThread
1119 void idThread::Event_KillThread( const char *name ) {
1125 idThread::Event_GetEntity
1128 void idThread::Event_GetEntity( const char *name ) {
1134 if ( name[ 0 ] == '*' ) {
1135 entnum = atoi( &name[ 1 ] );
1136 if ( ( entnum < 0 ) || ( entnum >= MAX_GENTITIES ) ) {
1137 Error( "Entity number in string out of range." );
1139 ReturnEntity( gameLocal.entities[ entnum ] );
1141 ent = gameLocal.FindEntity( name );
1142 ReturnEntity( ent );
1148 idThread::Event_Spawn
1151 void idThread::Event_Spawn( const char *classname ) {
1154 spawnArgs.Set( "classname", classname );
1155 gameLocal.SpawnEntityDef( spawnArgs, &ent );
1156 ReturnEntity( ent );
1162 idThread::Event_CopySpawnArgs
1165 void idThread::Event_CopySpawnArgs( idEntity *ent ) {
1166 spawnArgs.Copy( ent->spawnArgs );
1171 idThread::Event_SetSpawnArg
1174 void idThread::Event_SetSpawnArg( const char *key, const char *value ) {
1175 spawnArgs.Set( key, value );
1180 idThread::Event_SpawnString
1183 void idThread::Event_SpawnString( const char *key, const char *defaultvalue ) {
1186 spawnArgs.GetString( key, defaultvalue, &result );
1187 ReturnString( result );
1192 idThread::Event_SpawnFloat
1195 void idThread::Event_SpawnFloat( const char *key, float defaultvalue ) {
1198 spawnArgs.GetFloat( key, va( "%f", defaultvalue ), result );
1199 ReturnFloat( result );
1204 idThread::Event_SpawnVector
1207 void idThread::Event_SpawnVector( const char *key, idVec3 &defaultvalue ) {
1210 spawnArgs.GetVector( key, va( "%f %f %f", defaultvalue.x, defaultvalue.y, defaultvalue.z ), result );
1211 ReturnVector( result );
1216 idThread::Event_ClearPersistantArgs
1219 void idThread::Event_ClearPersistantArgs( void ) {
1220 gameLocal.persistentLevelInfo.Clear();
1226 idThread::Event_SetPersistantArg
1229 void idThread::Event_SetPersistantArg( const char *key, const char *value ) {
1230 gameLocal.persistentLevelInfo.Set( key, value );
1235 idThread::Event_GetPersistantString
1238 void idThread::Event_GetPersistantString( const char *key ) {
1241 gameLocal.persistentLevelInfo.GetString( key, "", &result );
1242 ReturnString( result );
1247 idThread::Event_GetPersistantFloat
1250 void idThread::Event_GetPersistantFloat( const char *key ) {
1253 gameLocal.persistentLevelInfo.GetFloat( key, "0", result );
1254 ReturnFloat( result );
1259 idThread::Event_GetPersistantVector
1262 void idThread::Event_GetPersistantVector( const char *key ) {
1265 gameLocal.persistentLevelInfo.GetVector( key, "0 0 0", result );
1266 ReturnVector( result );
1271 idThread::Event_AngToForward
1274 void idThread::Event_AngToForward( idAngles &ang ) {
1275 ReturnVector( ang.ToForward() );
1280 idThread::Event_AngToRight
1283 void idThread::Event_AngToRight( idAngles &ang ) {
1286 ang.ToVectors( NULL, &vec );
1287 ReturnVector( vec );
1292 idThread::Event_AngToUp
1295 void idThread::Event_AngToUp( idAngles &ang ) {
1298 ang.ToVectors( NULL, NULL, &vec );
1299 ReturnVector( vec );
1304 idThread::Event_GetSine
1307 void idThread::Event_GetSine( float angle ) {
1308 ReturnFloat( idMath::Sin( DEG2RAD( angle ) ) );
1313 idThread::Event_GetCosine
1316 void idThread::Event_GetCosine( float angle ) {
1317 ReturnFloat( idMath::Cos( DEG2RAD( angle ) ) );
1323 idThread::Event_GetArcSine
1326 void idThread::Event_GetArcSine( float a ) {
1327 ReturnFloat(RAD2DEG(idMath::ASin(a)));
1332 idThread::Event_GetArcCosine
1335 void idThread::Event_GetArcCosine( float a ) {
1336 ReturnFloat(RAD2DEG(idMath::ACos(a)));
1342 idThread::Event_GetSquareRoot
1345 void idThread::Event_GetSquareRoot( float theSquare ) {
1346 ReturnFloat( idMath::Sqrt( theSquare ) );
1351 idThread::Event_VecNormalize
1354 void idThread::Event_VecNormalize( idVec3 &vec ) {
1364 idThread::Event_VecLength
1367 void idThread::Event_VecLength( idVec3 &vec ) {
1368 ReturnFloat( vec.Length() );
1373 idThread::Event_VecDotProduct
1376 void idThread::Event_VecDotProduct( idVec3 &vec1, idVec3 &vec2 ) {
1377 ReturnFloat( vec1 * vec2 );
1382 idThread::Event_VecCrossProduct
1385 void idThread::Event_VecCrossProduct( idVec3 &vec1, idVec3 &vec2 ) {
1386 ReturnVector( vec1.Cross( vec2 ) );
1391 idThread::Event_VecToAngles
1394 void idThread::Event_VecToAngles( idVec3 &vec ) {
1395 idAngles ang = vec.ToAngles();
1396 ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
1402 idThread::Event_VecToOrthoBasisAngles
1405 void idThread::Event_VecToOrthoBasisAngles( idVec3 &vec ) {
1409 vec.OrthogonalBasis( left, up );
1410 idMat3 axis( left, up, vec );
1412 ang = axis.ToAngles();
1414 ReturnVector( idVec3( ang[0], ang[1], ang[2] ) );
1417 void idThread::Event_RotateVector( idVec3 &vec, idVec3 &ang ) {
1419 idAngles tempAng(ang);
1420 idMat3 axis = tempAng.ToMat3();
1421 idVec3 ret = vec * axis;
1429 idThread::Event_OnSignal
1432 void idThread::Event_OnSignal( int signal, idEntity *ent, const char *func ) {
1433 const function_t *function;
1438 Error( "Entity not found" );
1441 if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) {
1442 Error( "Signal out of range" );
1445 function = gameLocal.program.FindFunction( func );
1447 Error( "Function '%s' not found", func );
1450 ent->SetSignal( ( signalNum_t )signal, this, function );
1455 idThread::Event_ClearSignalThread
1458 void idThread::Event_ClearSignalThread( int signal, idEntity *ent ) {
1460 Error( "Entity not found" );
1463 if ( ( signal < 0 ) || ( signal >= NUM_SIGNALS ) ) {
1464 Error( "Signal out of range" );
1467 ent->ClearSignalThread( ( signalNum_t )signal, this );
1472 idThread::Event_SetCamera
1475 void idThread::Event_SetCamera( idEntity *ent ) {
1477 Error( "Entity not found" );
1481 if ( !ent->IsType( idCamera::Type ) ) {
1482 Error( "Entity is not a camera" );
1486 gameLocal.SetCamera( ( idCamera * )ent );
1491 idThread::Event_FirstPerson
1494 void idThread::Event_FirstPerson( void ) {
1495 gameLocal.SetCamera( NULL );
1500 idThread::Event_Trace
1503 void idThread::Event_Trace( const idVec3 &start, const idVec3 &end, const idVec3 &mins, const idVec3 &maxs, int contents_mask, idEntity *passEntity ) {
1504 if ( mins == vec3_origin && maxs == vec3_origin ) {
1505 gameLocal.clip.TracePoint( trace, start, end, contents_mask, passEntity );
1507 gameLocal.clip.TraceBounds( trace, start, end, idBounds( mins, maxs ), contents_mask, passEntity );
1509 ReturnFloat( trace.fraction );
1514 idThread::Event_TracePoint
1517 void idThread::Event_TracePoint( const idVec3 &start, const idVec3 &end, int contents_mask, idEntity *passEntity ) {
1518 gameLocal.clip.TracePoint( trace, start, end, contents_mask, passEntity );
1519 ReturnFloat( trace.fraction );
1524 idThread::Event_GetTraceFraction
1527 void idThread::Event_GetTraceFraction( void ) {
1528 ReturnFloat( trace.fraction );
1533 idThread::Event_GetTraceEndPos
1536 void idThread::Event_GetTraceEndPos( void ) {
1537 ReturnVector( trace.endpos );
1542 idThread::Event_GetTraceNormal
1545 void idThread::Event_GetTraceNormal( void ) {
1546 if ( trace.fraction < 1.0f ) {
1547 ReturnVector( trace.c.normal );
1549 ReturnVector( vec3_origin );
1555 idThread::Event_GetTraceEntity
1558 void idThread::Event_GetTraceEntity( void ) {
1559 if ( trace.fraction < 1.0f ) {
1560 ReturnEntity( gameLocal.entities[ trace.c.entityNum ] );
1562 ReturnEntity( ( idEntity * )NULL );
1568 idThread::Event_GetTraceJoint
1571 void idThread::Event_GetTraceJoint( void ) {
1572 if ( trace.fraction < 1.0f && trace.c.id < 0 ) {
1573 idAFEntity_Base *af = static_cast<idAFEntity_Base *>( gameLocal.entities[ trace.c.entityNum ] );
1574 if ( af && af->IsType( idAFEntity_Base::Type ) && af->IsActiveAF() ) {
1575 ReturnString( af->GetAnimator()->GetJointName( CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ) ) );
1584 idThread::Event_GetTraceBody
1587 void idThread::Event_GetTraceBody( void ) {
1588 if ( trace.fraction < 1.0f && trace.c.id < 0 ) {
1589 idAFEntity_Base *af = static_cast<idAFEntity_Base *>( gameLocal.entities[ trace.c.entityNum ] );
1590 if ( af && af->IsType( idAFEntity_Base::Type ) && af->IsActiveAF() ) {
1591 int bodyId = af->BodyForClipModelId( trace.c.id );
1592 idAFBody *body = af->GetAFPhysics()->GetBody( bodyId );
1594 ReturnString( body->GetName() );
1604 idThread::Event_FadeIn
1607 void idThread::Event_FadeIn( idVec3 &color, float time ) {
1611 player = gameLocal.GetLocalPlayer();
1613 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 0.0f );
1614 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1620 idThread::Event_FadeOut
1623 void idThread::Event_FadeOut( idVec3 &color, float time ) {
1627 player = gameLocal.GetLocalPlayer();
1629 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], 1.0f );
1630 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1636 idThread::Event_FadeTo
1639 void idThread::Event_FadeTo( idVec3 &color, float alpha, float time ) {
1643 player = gameLocal.GetLocalPlayer();
1645 fadeColor.Set( color[ 0 ], color[ 1 ], color[ 2 ], alpha );
1646 player->playerView.Fade(fadeColor, SEC2MS( time ) );
1652 idThread::Event_SetShaderParm
1655 void idThread::Event_SetShaderParm( int parmnum, float value ) {
1656 if ( ( parmnum < 0 ) || ( parmnum >= MAX_GLOBAL_SHADER_PARMS ) ) {
1657 Error( "shader parm index (%d) out of range", parmnum );
1660 gameLocal.globalShaderParms[ parmnum ] = value;
1665 idThread::Event_StartMusic
1668 void idThread::Event_StartMusic( const char *text ) {
1669 gameSoundWorld->PlayShaderDirectly( text );
1674 idThread::Event_Warning
1677 void idThread::Event_Warning( const char *text ) {
1678 Warning( "%s", text );
1683 idThread::Event_Error
1686 void idThread::Event_Error( const char *text ) {
1687 Error( "%s", text );
1692 idThread::Event_StrLen
1695 void idThread::Event_StrLen( const char *string ) {
1698 len = strlen( string );
1699 idThread::ReturnInt( len );
1704 idThread::Event_StrLeft
1707 void idThread::Event_StrLeft( const char *string, int num ) {
1711 idThread::ReturnString( "" );
1715 len = strlen( string );
1717 idThread::ReturnString( string );
1721 idStr result( string, 0, num );
1722 idThread::ReturnString( result );
1727 idThread::Event_StrRight
1730 void idThread::Event_StrRight( const char *string, int num ) {
1734 idThread::ReturnString( "" );
1738 len = strlen( string );
1740 idThread::ReturnString( string );
1744 idThread::ReturnString( string + len - num );
1749 idThread::Event_StrSkip
1752 void idThread::Event_StrSkip( const char *string, int num ) {
1756 idThread::ReturnString( string );
1760 len = strlen( string );
1762 idThread::ReturnString( "" );
1766 idThread::ReturnString( string + num );
1771 idThread::Event_StrMid
1774 void idThread::Event_StrMid( const char *string, int start, int num ) {
1778 idThread::ReturnString( "" );
1785 len = strlen( string );
1786 if ( start > len ) {
1790 if ( start + num > len ) {
1794 idStr result( string, start, start + num );
1795 idThread::ReturnString( result );
1800 idThread::Event_StrToFloat( const char *string )
1803 void idThread::Event_StrToFloat( const char *string ) {
1806 result = atof( string );
1807 idThread::ReturnFloat( result );
1812 idThread::Event_RadiusDamage
1815 void idThread::Event_RadiusDamage( const idVec3 &origin, idEntity *inflictor, idEntity *attacker, idEntity *ignore, const char *damageDefName, float dmgPower ) {
1816 gameLocal.RadiusDamage( origin, inflictor, attacker, ignore, ignore, damageDefName, dmgPower );
1821 idThread::Event_IsClient
1824 void idThread::Event_IsClient( void ) {
1825 idThread::ReturnFloat( gameLocal.isClient );
1830 idThread::Event_IsMultiplayer
1833 void idThread::Event_IsMultiplayer( void ) {
1834 idThread::ReturnFloat( gameLocal.isMultiplayer );
1839 idThread::Event_GetFrameTime
1842 void idThread::Event_GetFrameTime( void ) {
1843 idThread::ReturnFloat( MS2SEC( gameLocal.msec ) );
1848 idThread::Event_GetTicsPerSecond
1851 void idThread::Event_GetTicsPerSecond( void ) {
1852 idThread::ReturnFloat( USERCMD_HZ );
1857 idThread::Event_CacheSoundShader
1860 void idThread::Event_CacheSoundShader( const char *soundName ) {
1861 declManager->FindSound( soundName );
1866 idThread::Event_DebugLine
1869 void idThread::Event_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end, const float lifetime ) {
1870 gameRenderWorld->DebugLine( idVec4( color.x, color.y, color.z, 0.0f ), start, end, SEC2MS( lifetime ) );
1875 idThread::Event_DebugArrow
1878 void idThread::Event_DebugArrow( const idVec3 &color, const idVec3 &start, const idVec3 &end, const int size, const float lifetime ) {
1879 gameRenderWorld->DebugArrow( idVec4( color.x, color.y, color.z, 0.0f ), start, end, size, SEC2MS( lifetime ) );
1884 idThread::Event_DebugCircle
1887 void idThread::Event_DebugCircle( const idVec3 &color, const idVec3 &origin, const idVec3 &dir, const float radius, const int numSteps, const float lifetime ) {
1888 gameRenderWorld->DebugCircle( idVec4( color.x, color.y, color.z, 0.0f ), origin, dir, radius, numSteps, SEC2MS( lifetime ) );
1893 idThread::Event_DebugBounds
1896 void idThread::Event_DebugBounds( const idVec3 &color, const idVec3 &mins, const idVec3 &maxs, const float lifetime ) {
1897 gameRenderWorld->DebugBounds( idVec4( color.x, color.y, color.z, 0.0f ), idBounds( mins, maxs ), vec3_origin, SEC2MS( lifetime ) );
1902 idThread::Event_DrawText
1905 void idThread::Event_DrawText( const char *text, const idVec3 &origin, float scale, const idVec3 &color, const int align, const float lifetime ) {
1906 gameRenderWorld->DrawText( text, origin, scale, idVec4( color.x, color.y, color.z, 0.0f ), gameLocal.GetLocalPlayer()->viewAngles.ToMat3(), align, SEC2MS( lifetime ) );
1911 idThread::Event_InfluenceActive
1914 void idThread::Event_InfluenceActive( void ) {
1917 player = gameLocal.GetLocalPlayer();
1918 if ( player && player->GetInfluenceLevel() ) {
1919 idThread::ReturnInt( true );
1921 idThread::ReturnInt( false );