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