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