]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/game/script/Script_Interpreter.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / game / script / Script_Interpreter.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "../Game_local.h"
33
34 /*
35 ================
36 idInterpreter::idInterpreter()
37 ================
38 */
39 idInterpreter::idInterpreter() {
40         localstackUsed = 0;
41         terminateOnExit = true;
42         debug = 0;
43         memset( localstack, 0, sizeof( localstack ) );
44         memset( callStack, 0, sizeof( callStack ) );
45         Reset();
46 }
47
48 /*
49 ================
50 idInterpreter::Save
51 ================
52 */
53 void idInterpreter::Save( idSaveGame *savefile ) const {
54         int i;
55
56         savefile->WriteInt( callStackDepth );
57         for( i = 0; i < callStackDepth; i++ ) {
58                 savefile->WriteInt( callStack[i].s );
59                 if ( callStack[i].f ) {
60                         savefile->WriteInt( gameLocal.program.GetFunctionIndex( callStack[i].f ) );
61                 } else {
62                         savefile->WriteInt( -1 );
63                 }
64                 savefile->WriteInt( callStack[i].stackbase );
65         }
66         savefile->WriteInt( maxStackDepth );
67
68         savefile->WriteInt( localstackUsed );
69         savefile->Write( &localstack, localstackUsed );
70
71         savefile->WriteInt( localstackBase );
72         savefile->WriteInt( maxLocalstackUsed );
73
74         if ( currentFunction ) {
75                 savefile->WriteInt( gameLocal.program.GetFunctionIndex( currentFunction ) );
76         } else {
77                 savefile->WriteInt( -1 );
78         }
79         savefile->WriteInt( instructionPointer );
80
81         savefile->WriteInt( popParms );
82
83         if ( multiFrameEvent ) {
84                 savefile->WriteString( multiFrameEvent->GetName() );
85         } else {
86                 savefile->WriteString( "" );
87         }
88         savefile->WriteObject( eventEntity );
89
90         savefile->WriteObject( thread );
91
92         savefile->WriteBool( doneProcessing );
93         savefile->WriteBool( threadDying );
94         savefile->WriteBool( terminateOnExit );
95         savefile->WriteBool( debug );
96 }
97
98 /*
99 ================
100 idInterpreter::Restore
101 ================
102 */
103 void idInterpreter::Restore( idRestoreGame *savefile ) {
104         int i;
105         idStr funcname;
106         int func_index;
107
108         savefile->ReadInt( callStackDepth );
109         for( i = 0; i < callStackDepth; i++ ) {
110                 savefile->ReadInt( callStack[i].s );
111
112                 savefile->ReadInt( func_index );
113                 if ( func_index >= 0 ) {
114                         callStack[i].f = gameLocal.program.GetFunction( func_index );
115                 } else {
116                         callStack[i].f = NULL;
117                 }
118
119                 savefile->ReadInt( callStack[i].stackbase );
120         }
121         savefile->ReadInt( maxStackDepth );
122
123         savefile->ReadInt( localstackUsed );
124         savefile->Read( &localstack, localstackUsed );
125
126         savefile->ReadInt( localstackBase );
127         savefile->ReadInt( maxLocalstackUsed );
128
129         savefile->ReadInt( func_index );
130         if ( func_index >= 0 ) {
131                 currentFunction = gameLocal.program.GetFunction( func_index );
132         } else {
133                 currentFunction = NULL;
134         }
135         savefile->ReadInt( instructionPointer );
136
137         savefile->ReadInt( popParms );
138
139         savefile->ReadString( funcname );
140         if ( funcname.Length() ) {
141                 multiFrameEvent = idEventDef::FindEvent( funcname );
142         }
143
144         savefile->ReadObject( reinterpret_cast<idClass *&>( eventEntity ) );
145         savefile->ReadObject( reinterpret_cast<idClass *&>( thread ) );
146
147         savefile->ReadBool( doneProcessing );
148         savefile->ReadBool( threadDying );
149         savefile->ReadBool( terminateOnExit );
150         savefile->ReadBool( debug );
151 }
152
153 /*
154 ================
155 idInterpreter::Reset
156 ================
157 */
158 void idInterpreter::Reset( void ) {
159         callStackDepth = 0;
160         localstackUsed = 0;
161         localstackBase = 0;
162
163         maxLocalstackUsed = 0;
164         maxStackDepth = 0;
165
166         popParms = 0;
167         multiFrameEvent = NULL;
168         eventEntity = NULL;
169
170         currentFunction = 0;
171         NextInstruction( 0 );
172
173         threadDying     = false;
174         doneProcessing  = true;
175 }
176
177 /*
178 ================
179 idInterpreter::GetRegisterValue
180
181 Returns a string representation of the value of the register.  This is 
182 used primarily for the debugger and debugging
183
184 //FIXME:  This is pretty much wrong.  won't access data in most situations.
185 ================
186 */
187 bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDepth ) {
188         varEval_t               reg;
189         idVarDef                *d;
190         char                    funcObject[ 1024 ];
191         char                    *funcName;
192         const idVarDef  *scope;
193         const idTypeDef *field;
194         const idScriptObject *obj;
195         const function_t *func;
196
197         out.Empty();
198         
199         if ( scopeDepth == -1 ) {
200                 scopeDepth = callStackDepth;
201         }       
202         
203         if ( scopeDepth == callStackDepth ) {
204                 func = currentFunction;
205         } else {
206                 func = callStack[ scopeDepth ].f;
207         }
208         if ( !func ) {
209                 return false;
210         }
211
212         idStr::Copynz( funcObject, func->Name(), sizeof( funcObject ) );
213         funcName = strstr( funcObject, "::" );
214         if ( funcName ) {
215                 *funcName = '\0';
216                 scope = gameLocal.program.GetDef( NULL, funcObject, &def_namespace );
217                 funcName += 2;
218         } else {
219                 funcName = funcObject;
220                 scope = &def_namespace;
221         }
222
223         // Get the function from the object
224         d = gameLocal.program.GetDef( NULL, funcName, scope );
225         if ( !d ) {
226                 return false;
227         }
228         
229         // Get the variable itself and check various namespaces
230         d = gameLocal.program.GetDef( NULL, name, d );
231         if ( !d ) {
232                 if ( scope == &def_namespace ) {
233                         return false;
234                 }
235                 
236                 d = gameLocal.program.GetDef( NULL, name, scope );
237                 if ( !d ) {
238                         d = gameLocal.program.GetDef( NULL, name, &def_namespace );
239                         if ( !d ) {
240                                 return false;
241                         }
242                 }
243         }
244                 
245         reg = GetVariable( d );
246         switch( d->Type() ) {
247         case ev_float:
248                 if ( reg.floatPtr ) {
249                         out = va("%g", *reg.floatPtr );
250                 } else {
251                         out = "0";
252                 }
253                 return true;
254                 break;
255
256         case ev_vector:
257                 if ( reg.vectorPtr ) {                          
258                         out = va( "%g,%g,%g", reg.vectorPtr->x, reg.vectorPtr->y, reg.vectorPtr->z );
259                 } else {
260                         out = "0,0,0";
261                 }
262                 return true;
263                 break;
264
265         case ev_boolean:
266                 if ( reg.intPtr ) {
267                         out = va( "%d", *reg.intPtr );
268                 } else {
269                         out = "0";
270                 }
271                 return true;
272                 break;
273
274         case ev_field:
275                 if ( scope == &def_namespace ) {
276                         // should never happen, but handle it safely anyway
277                         return false;
278                 }
279
280                 field = scope->TypeDef()->GetParmType( reg.ptrOffset )->FieldType();
281                 obj   = *reinterpret_cast<const idScriptObject **>( &localstack[ callStack[ callStackDepth ].stackbase ] );
282                 if ( !field || !obj ) {
283                         return false;
284                 }
285                                                                 
286                 switch ( field->Type() ) {
287                 case ev_boolean:
288                         out = va( "%d", *( reinterpret_cast<int *>( &obj->data[ reg.ptrOffset ] ) ) );
289                         return true;
290
291                 case ev_float:
292                         out = va( "%g", *( reinterpret_cast<float *>( &obj->data[ reg.ptrOffset ] ) ) );
293                         return true;
294
295                 default:
296                         return false;
297                 }
298                 break;
299
300         case ev_string:
301                 if ( reg.stringPtr ) {
302                         out = "\"";
303                         out += reg.stringPtr;
304                         out += "\"";
305                 } else {
306                         out = "\"\"";
307                 }
308                 return true;
309
310         default:
311                 return false;
312         }
313 }
314
315 /*
316 ================
317 idInterpreter::GetCallstackDepth
318 ================
319 */
320 int idInterpreter::GetCallstackDepth( void ) const {
321         return callStackDepth;
322 }
323
324 /*
325 ================
326 idInterpreter::GetCallstack
327 ================
328 */
329 const prstack_t *idInterpreter::GetCallstack( void ) const {
330         return &callStack[ 0 ];
331 }
332
333 /*
334 ================
335 idInterpreter::GetCurrentFunction
336 ================
337 */
338 const function_t *idInterpreter::GetCurrentFunction( void ) const {
339         return currentFunction;
340 }
341
342 /*
343 ================
344 idInterpreter::GetThread
345 ================
346 */
347 idThread *idInterpreter::GetThread( void ) const {
348         return thread;
349 }
350
351
352 /*
353 ================
354 idInterpreter::SetThread
355 ================
356 */
357 void idInterpreter::SetThread( idThread *pThread ) {
358         thread = pThread;
359 }
360
361 /*
362 ================
363 idInterpreter::CurrentLine
364 ================
365 */
366 int idInterpreter::CurrentLine( void ) const {
367         if ( instructionPointer < 0 ) {
368                 return 0;
369         }
370         return gameLocal.program.GetLineNumberForStatement( instructionPointer );
371 }
372
373 /*
374 ================
375 idInterpreter::CurrentFile
376 ================
377 */
378 const char *idInterpreter::CurrentFile( void ) const {
379         if ( instructionPointer < 0 ) {
380                 return "";
381         }
382         return gameLocal.program.GetFilenameForStatement( instructionPointer );
383 }
384
385 /*
386 ============
387 idInterpreter::StackTrace
388 ============
389 */
390 void idInterpreter::StackTrace( void ) const {
391         const function_t        *f;
392         int                             i;
393         int                                     top;
394
395         if ( callStackDepth == 0 ) {
396                 gameLocal.Printf( "<NO STACK>\n" );
397                 return;
398         }
399
400         top = callStackDepth;
401         if ( top >= MAX_STACK_DEPTH ) {
402                 top = MAX_STACK_DEPTH - 1;
403         }
404         
405         if ( !currentFunction ) {
406                 gameLocal.Printf( "<NO FUNCTION>\n" );
407         } else {
408                 gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( currentFunction->filenum ), currentFunction->Name() );
409         }
410
411         for( i = top; i >= 0; i-- ) {
412                 f = callStack[ i ].f;
413                 if ( !f ) {
414                         gameLocal.Printf( "<NO FUNCTION>\n" );
415                 } else {
416                         gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( f->filenum ), f->Name() );
417                 }
418         }
419 }
420
421 /*
422 ============
423 idInterpreter::Error
424
425 Aborts the currently executing function
426 ============
427 */
428 void idInterpreter::Error( char *fmt, ... ) const {
429         va_list argptr;
430         char    text[ 1024 ];
431
432         va_start( argptr, fmt );
433         vsprintf( text, fmt, argptr );
434         va_end( argptr );
435
436         StackTrace();
437
438         if ( ( instructionPointer >= 0 ) && ( instructionPointer < gameLocal.program.NumStatements() ) ) {
439                 statement_t &line = gameLocal.program.GetStatement( instructionPointer );
440                 common->Error( "%s(%d): Thread '%s': %s\n", gameLocal.program.GetFilename( line.file ), line.linenumber, thread->GetThreadName(), text );
441         } else {
442                 common->Error( "Thread '%s': %s\n", thread->GetThreadName(), text );
443         }
444 }
445
446 /*
447 ============
448 idInterpreter::Warning
449
450 Prints file and line number information with warning.
451 ============
452 */
453 void idInterpreter::Warning( char *fmt, ... ) const {
454         va_list argptr;
455         char    text[ 1024 ];
456
457         va_start( argptr, fmt );
458         vsprintf( text, fmt, argptr );
459         va_end( argptr );
460
461         if ( ( instructionPointer >= 0 ) && ( instructionPointer < gameLocal.program.NumStatements() ) ) {
462                 statement_t &line = gameLocal.program.GetStatement( instructionPointer );
463                 common->Warning( "%s(%d): Thread '%s': %s", gameLocal.program.GetFilename( line.file ), line.linenumber, thread->GetThreadName(), text );
464         } else {
465                 common->Warning( "Thread '%s' : %s", thread->GetThreadName(), text );
466         }
467 }
468
469 /*
470 ================
471 idInterpreter::DisplayInfo
472 ================
473 */
474 void idInterpreter::DisplayInfo( void ) const {
475         const function_t *f;
476         int i;
477
478         gameLocal.Printf( " Stack depth: %d bytes, %d max\n", localstackUsed, maxLocalstackUsed );
479         gameLocal.Printf( "  Call depth: %d, %d max\n", callStackDepth, maxStackDepth );
480         gameLocal.Printf( "  Call Stack: " );
481
482         if ( callStackDepth == 0 ) {
483                 gameLocal.Printf( "<NO STACK>\n" );
484         } else {
485                 if ( !currentFunction ) {
486                         gameLocal.Printf( "<NO FUNCTION>\n" );
487                 } else {
488                         gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( currentFunction->filenum ), currentFunction->Name() );
489                 }
490
491                 for( i = callStackDepth; i > 0; i-- ) {
492                         gameLocal.Printf( "              " );
493                         f = callStack[ i ].f;
494                         if ( !f ) {
495                                 gameLocal.Printf( "<NO FUNCTION>\n" );
496                         } else {
497                                 gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( f->filenum ), f->Name() );
498                         }
499                 }
500         }
501 }
502
503 /*
504 ====================
505 idInterpreter::ThreadCall
506
507 Copys the args from the calling thread's stack
508 ====================
509 */
510 void idInterpreter::ThreadCall( idInterpreter *source, const function_t *func, int args ) {
511         Reset();
512
513         memcpy( localstack, &source->localstack[ source->localstackUsed - args ], args );
514
515         localstackUsed = args;
516         localstackBase = 0;
517
518         maxLocalstackUsed = localstackUsed;
519         EnterFunction( func, false );
520
521         thread->SetThreadName( currentFunction->Name() );
522 }
523
524 /*
525 ================
526 idInterpreter::EnterObjectFunction
527
528 Calls a function on a script object.
529
530 NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function.
531 ================
532 */
533 void idInterpreter::EnterObjectFunction( idEntity *self, const function_t *func, bool clearStack ) {
534         if ( clearStack ) {
535                 Reset();
536         }
537         if ( popParms ) {
538                 PopParms( popParms );
539                 popParms = 0;
540         }
541         Push( self->entityNumber + 1 );
542         EnterFunction( func, false );
543 }
544
545 /*
546 ====================
547 idInterpreter::EnterFunction
548
549 Returns the new program statement counter
550
551 NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function.
552 ====================
553 */
554 void idInterpreter::EnterFunction( const function_t *func, bool clearStack ) {
555         int             c;
556         prstack_t       *stack;
557
558         if ( clearStack ) {
559                 Reset();
560         }
561         if ( popParms ) {
562                 PopParms( popParms );
563                 popParms = 0;
564         }
565
566         if ( callStackDepth >= MAX_STACK_DEPTH ) {
567                 Error( "call stack overflow" );
568         }
569
570         stack = &callStack[ callStackDepth ];
571
572         stack->s                        = instructionPointer + 1;       // point to the next instruction to execute
573         stack->f                        = currentFunction;
574         stack->stackbase        = localstackBase;
575
576         callStackDepth++;
577         if ( callStackDepth > maxStackDepth ) {
578                 maxStackDepth = callStackDepth;
579         }
580
581         if ( !func ) {
582                 Error( "NULL function" );
583         }
584
585         if ( debug ) {
586                 if ( currentFunction ) {
587                         gameLocal.Printf( "%d: call '%s' from '%s'(line %d)%s\n", gameLocal.time, func->Name(), currentFunction->Name(), 
588                                 gameLocal.program.GetStatement( instructionPointer ).linenumber, clearStack ? " clear stack" : "" );
589                 } else {
590             gameLocal.Printf( "%d: call '%s'%s\n", gameLocal.time, func->Name(), clearStack ? " clear stack" : "" );
591                 }
592         }
593
594         currentFunction = func;
595         assert( !func->eventdef );
596         NextInstruction( func->firstStatement );
597
598         // allocate space on the stack for locals
599         // parms are already on stack
600         c = func->locals - func->parmTotal;
601         assert( c >= 0 );
602
603         if ( localstackUsed + c > LOCALSTACK_SIZE ) {
604                 Error( "EnterFuncton: locals stack overflow\n" );
605         }
606
607         // initialize local stack variables to zero
608         memset( &localstack[ localstackUsed ], 0, c );
609
610         localstackUsed += c;
611         localstackBase = localstackUsed - func->locals;
612
613         if ( localstackUsed > maxLocalstackUsed ) {
614                 maxLocalstackUsed = localstackUsed ;
615         }
616 }
617
618 /*
619 ====================
620 idInterpreter::LeaveFunction
621 ====================
622 */
623 void idInterpreter::LeaveFunction( idVarDef *returnDef ) {
624         prstack_t *stack;
625         varEval_t ret;
626         
627         if ( callStackDepth <= 0 ) {
628                 Error( "prog stack underflow" );
629         }
630
631         // return value
632         if ( returnDef ) {
633                 switch( returnDef->Type() ) {
634                 case ev_string :
635                         gameLocal.program.ReturnString( GetString( returnDef ) );
636                         break;
637
638                 case ev_vector :
639                         ret = GetVariable( returnDef );
640                         gameLocal.program.ReturnVector( *ret.vectorPtr );
641                         break;
642
643                 default :
644                         ret = GetVariable( returnDef );
645                         gameLocal.program.ReturnInteger( *ret.intPtr );
646                 }
647         }
648
649         // remove locals from the stack
650         PopParms( currentFunction->locals );
651         assert( localstackUsed == localstackBase );
652
653         if ( debug ) {
654                 statement_t &line = gameLocal.program.GetStatement( instructionPointer );
655                 gameLocal.Printf( "%d: %s(%d): exit %s", gameLocal.time, gameLocal.program.GetFilename( line.file ), line.linenumber, currentFunction->Name() );
656                 if ( callStackDepth > 1 ) {
657                         gameLocal.Printf( " return to %s(line %d)\n", callStack[ callStackDepth - 1 ].f->Name(), gameLocal.program.GetStatement( callStack[ callStackDepth - 1 ].s ).linenumber );
658                 } else {
659                         gameLocal.Printf( " done\n" );
660                 }
661         }
662
663         // up stack
664         callStackDepth--;
665         stack = &callStack[ callStackDepth ]; 
666         currentFunction = stack->f;
667         localstackBase = stack->stackbase;
668         NextInstruction( stack->s );
669
670         if ( !callStackDepth ) {
671                 // all done
672                 doneProcessing = true;
673                 threadDying = true;
674                 currentFunction = 0;
675         }
676 }
677
678 /*
679 ================
680 idInterpreter::CallEvent
681 ================
682 */
683 void idInterpreter::CallEvent( const function_t *func, int argsize ) {
684         int                             i;
685         int                                     j;
686         varEval_t                       var;
687         int                             pos;
688         int                             start;
689         int                                     data[ D_EVENT_MAXARGS ];
690         const idEventDef        *evdef;
691         const char                      *format;
692
693         if ( !func ) {
694                 Error( "NULL function" );
695         }
696
697         assert( func->eventdef );
698         evdef = func->eventdef;
699
700         start = localstackUsed - argsize;
701         var.intPtr = ( int * )&localstack[ start ];
702         eventEntity = GetEntity( *var.entityNumberPtr );
703
704         if ( !eventEntity || !eventEntity->RespondsTo( *evdef ) ) {
705                 if ( eventEntity && developer.GetBool() ) {
706                         // give a warning in developer mode
707                         Warning( "Function '%s' not supported on entity '%s'", evdef->GetName(), eventEntity->name.c_str() );
708                 }
709                 // always return a safe value when an object doesn't exist
710                 switch( evdef->GetReturnType() ) {
711                 case D_EVENT_INTEGER :
712                         gameLocal.program.ReturnInteger( 0 );
713                         break;
714
715                 case D_EVENT_FLOAT :
716                         gameLocal.program.ReturnFloat( 0 );
717                         break;
718
719                 case D_EVENT_VECTOR :
720                         gameLocal.program.ReturnVector( vec3_zero );
721                         break;
722
723                 case D_EVENT_STRING :
724                         gameLocal.program.ReturnString( "" );
725                         break;
726
727                 case D_EVENT_ENTITY :
728                 case D_EVENT_ENTITY_NULL :
729                         gameLocal.program.ReturnEntity( ( idEntity * )NULL );
730                         break;
731
732                 case D_EVENT_TRACE :
733                 default:
734                         // unsupported data type
735                         break;
736                 }
737
738                 PopParms( argsize );
739                 eventEntity = NULL;
740                 return;
741         }
742
743         format = evdef->GetArgFormat();
744         for( j = 0, i = 0, pos = type_object.Size(); ( pos < argsize ) || ( format[ i ] != 0 ); i++ ) {
745                 switch( format[ i ] ) {
746                 case D_EVENT_INTEGER :
747                         var.intPtr = ( int * )&localstack[ start + pos ];
748                         data[ i ] = int( *var.floatPtr );
749                         break;
750
751                 case D_EVENT_FLOAT :
752                         var.intPtr = ( int * )&localstack[ start + pos ];
753                         ( *( float * )&data[ i ] ) = *var.floatPtr;
754                         break;
755
756                 case D_EVENT_VECTOR :
757                         var.intPtr = ( int * )&localstack[ start + pos ];
758                         ( *( idVec3 ** )&data[ i ] ) = var.vectorPtr;
759                         break;
760
761                 case D_EVENT_STRING :
762                         ( *( const char ** )&data[ i ] ) = ( char * )&localstack[ start + pos ];
763                         break;
764
765                 case D_EVENT_ENTITY :
766                         var.intPtr = ( int * )&localstack[ start + pos ];
767                         ( *( idEntity ** )&data[ i ] ) = GetEntity( *var.entityNumberPtr );
768                         if ( !( *( idEntity ** )&data[ i ] ) ) {
769                                 Warning( "Entity not found for event '%s'. Terminating thread.", evdef->GetName() );
770                                 threadDying = true;
771                                 PopParms( argsize );
772                                 return;
773                         }
774                         break;
775
776                 case D_EVENT_ENTITY_NULL :
777                         var.intPtr = ( int * )&localstack[ start + pos ];
778                         ( *( idEntity ** )&data[ i ] ) = GetEntity( *var.entityNumberPtr );
779                         break;
780
781                 case D_EVENT_TRACE :
782                         Error( "trace type not supported from script for '%s' event.", evdef->GetName() );
783                         break;
784
785                 default :
786                         Error( "Invalid arg format string for '%s' event.", evdef->GetName() );
787                         break;
788                 }
789
790                 pos += func->parmSize[ j++ ];
791         }
792
793         popParms = argsize;
794         eventEntity->ProcessEventArgPtr( evdef, data );
795
796         if ( !multiFrameEvent ) {
797                 if ( popParms ) {
798                         PopParms( popParms );
799                 }
800                 eventEntity = NULL;
801         } else {
802                 doneProcessing = true;
803         }
804         popParms = 0;
805 }
806
807 /*
808 ================
809 idInterpreter::BeginMultiFrameEvent
810 ================
811 */
812 bool idInterpreter::BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ) { 
813         if ( eventEntity != ent ) {
814                 Error( "idInterpreter::BeginMultiFrameEvent called with wrong entity" );
815         }
816         if ( multiFrameEvent ) {
817                 if ( multiFrameEvent != event ) {
818                         Error( "idInterpreter::BeginMultiFrameEvent called with wrong event" );
819                 }
820                 return false;
821         }
822
823         multiFrameEvent = event;
824         return true;
825 }
826
827 /*
828 ================
829 idInterpreter::EndMultiFrameEvent
830 ================
831 */
832 void idInterpreter::EndMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
833         if ( multiFrameEvent != event ) {
834                 Error( "idInterpreter::EndMultiFrameEvent called with wrong event" );
835         }
836
837         multiFrameEvent = NULL;
838 }
839
840 /*
841 ================
842 idInterpreter::MultiFrameEventInProgress
843 ================
844 */
845 bool idInterpreter::MultiFrameEventInProgress( void ) const {
846         return multiFrameEvent != NULL;
847 }
848
849 /*
850 ================
851 idInterpreter::CallSysEvent
852 ================
853 */
854 void idInterpreter::CallSysEvent( const function_t *func, int argsize ) {
855         int                             i;
856         int                                     j;
857         varEval_t                       source;
858         int                             pos;
859         int                             start;
860         int                                     data[ D_EVENT_MAXARGS ];
861         const idEventDef        *evdef;
862         const char                      *format;
863
864         if ( !func ) {
865                 Error( "NULL function" );
866         }
867
868         assert( func->eventdef );
869         evdef = func->eventdef;
870
871         start = localstackUsed - argsize;
872
873         format = evdef->GetArgFormat();
874         for( j = 0, i = 0, pos = 0; ( pos < argsize ) || ( format[ i ] != 0 ); i++ ) {
875                 switch( format[ i ] ) {
876                 case D_EVENT_INTEGER :
877                         source.intPtr = ( int * )&localstack[ start + pos ];
878                         *( int * )&data[ i ] = int( *source.floatPtr );
879                         break;
880
881                 case D_EVENT_FLOAT :
882                         source.intPtr = ( int * )&localstack[ start + pos ];
883                         *( float * )&data[ i ] = *source.floatPtr;
884                         break;
885
886                 case D_EVENT_VECTOR :
887                         source.intPtr = ( int * )&localstack[ start + pos ];
888                         *( idVec3 ** )&data[ i ] = source.vectorPtr;
889                         break;
890
891                 case D_EVENT_STRING :
892                         *( const char ** )&data[ i ] = ( char * )&localstack[ start + pos ];
893                         break;
894
895                 case D_EVENT_ENTITY :
896                         source.intPtr = ( int * )&localstack[ start + pos ];
897                         *( idEntity ** )&data[ i ] = GetEntity( *source.entityNumberPtr );
898                         if ( !*( idEntity ** )&data[ i ] ) {
899                                 Warning( "Entity not found for event '%s'. Terminating thread.", evdef->GetName() );
900                                 threadDying = true;
901                                 PopParms( argsize );
902                                 return;
903                         }
904                         break;
905
906                 case D_EVENT_ENTITY_NULL :
907                         source.intPtr = ( int * )&localstack[ start + pos ];
908                         *( idEntity ** )&data[ i ] = GetEntity( *source.entityNumberPtr );
909                         break;
910
911                 case D_EVENT_TRACE :
912                         Error( "trace type not supported from script for '%s' event.", evdef->GetName() );
913                         break;
914
915                 default :
916                         Error( "Invalid arg format string for '%s' event.", evdef->GetName() );
917                         break;
918                 }
919
920                 pos += func->parmSize[ j++ ];
921         }
922
923         popParms = argsize;
924         thread->ProcessEventArgPtr( evdef, data );
925         if ( popParms ) {
926                 PopParms( popParms );
927         }
928         popParms = 0;
929 }
930
931 /*
932 ====================
933 idInterpreter::Execute
934 ====================
935 */
936 bool idInterpreter::Execute( void ) {
937         varEval_t       var_a;
938         varEval_t       var_b;
939         varEval_t       var_c;
940         varEval_t       var;
941         statement_t     *st;
942         int             runaway;
943         idThread        *newThread;
944         float           floatVal;
945         idScriptObject *obj;
946         const function_t *func;
947
948         if ( threadDying || !currentFunction ) {
949                 return true;
950         }
951
952         if ( multiFrameEvent ) {
953                 // move to previous instruction and call it again
954                 instructionPointer--;
955         }
956
957         runaway = 5000000;
958
959         doneProcessing = false;
960         while( !doneProcessing && !threadDying ) {
961                 instructionPointer++;
962
963                 if ( !--runaway ) {
964                         Error( "runaway loop error" );
965                 }
966
967                 // next statement
968                 st = &gameLocal.program.GetStatement( instructionPointer );
969
970                 switch( st->op ) {
971                 case OP_RETURN:
972                         LeaveFunction( st->a );
973                         break;
974
975                 case OP_THREAD:
976                         newThread = new idThread( this, st->a->value.functionPtr, st->b->value.argSize );
977                         newThread->Start();
978
979                         // return the thread number to the script
980                         gameLocal.program.ReturnFloat( newThread->GetThreadNum() );
981                         PopParms( st->b->value.argSize );
982                         break;
983
984                 case OP_OBJTHREAD:
985                         var_a = GetVariable( st->a );
986                         obj = GetScriptObject( *var_a.entityNumberPtr );
987                         if ( obj ) {
988                                 func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction );
989                                 assert( st->c->value.argSize == func->parmTotal );
990                                 newThread = new idThread( this, GetEntity( *var_a.entityNumberPtr ), func, func->parmTotal );
991                                 newThread->Start();
992
993                                 // return the thread number to the script
994                                 gameLocal.program.ReturnFloat( newThread->GetThreadNum() );
995                         } else {
996                                 // return a null thread to the script
997                                 gameLocal.program.ReturnFloat( 0.0f );
998                         }
999                         PopParms( st->c->value.argSize );
1000                         break;
1001
1002                 case OP_CALL:
1003                         EnterFunction( st->a->value.functionPtr, false );
1004                         break;
1005
1006                 case OP_EVENTCALL:
1007                         CallEvent( st->a->value.functionPtr, st->b->value.argSize );
1008                         break;
1009
1010                 case OP_OBJECTCALL:     
1011                         var_a = GetVariable( st->a );
1012                         obj = GetScriptObject( *var_a.entityNumberPtr );
1013                         if ( obj ) {
1014                                 func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction );
1015                                 EnterFunction( func, false );
1016                         } else {
1017                                 // return a 'safe' value
1018                                 gameLocal.program.ReturnVector( vec3_zero );
1019                                 gameLocal.program.ReturnString( "" );
1020                                 PopParms( st->c->value.argSize );
1021                         }
1022                         break;
1023
1024                 case OP_SYSCALL:
1025                         CallSysEvent( st->a->value.functionPtr, st->b->value.argSize );
1026                         break;
1027
1028                 case OP_IFNOT:
1029                         var_a = GetVariable( st->a );
1030                         if ( *var_a.intPtr == 0 ) {
1031                                 NextInstruction( instructionPointer + st->b->value.jumpOffset );
1032                         }
1033                         break;
1034
1035                 case OP_IF:
1036                         var_a = GetVariable( st->a );
1037                         if ( *var_a.intPtr != 0 ) {
1038                                 NextInstruction( instructionPointer + st->b->value.jumpOffset );
1039                         }
1040                         break;
1041
1042                 case OP_GOTO:
1043                         NextInstruction( instructionPointer + st->a->value.jumpOffset );
1044                         break;
1045
1046                 case OP_ADD_F:
1047                         var_a = GetVariable( st->a );
1048                         var_b = GetVariable( st->b );
1049                         var_c = GetVariable( st->c );
1050                         *var_c.floatPtr = *var_a.floatPtr + *var_b.floatPtr;
1051                         break;
1052
1053                 case OP_ADD_V:
1054                         var_a = GetVariable( st->a );
1055                         var_b = GetVariable( st->b );
1056                         var_c = GetVariable( st->c );
1057                         *var_c.vectorPtr = *var_a.vectorPtr + *var_b.vectorPtr;
1058                         break;
1059
1060                 case OP_ADD_S:
1061                         SetString( st->c, GetString( st->a ) );
1062                         AppendString( st->c, GetString( st->b ) );
1063                         break;
1064
1065                 case OP_ADD_FS:
1066                         var_a = GetVariable( st->a );
1067                         SetString( st->c, FloatToString( *var_a.floatPtr ) );
1068                         AppendString( st->c, GetString( st->b ) );
1069                         break;
1070
1071                 case OP_ADD_SF:
1072                         var_b = GetVariable( st->b );
1073                         SetString( st->c, GetString( st->a ) );
1074                         AppendString( st->c, FloatToString( *var_b.floatPtr ) );
1075                         break;
1076
1077                 case OP_ADD_VS:
1078                         var_a = GetVariable( st->a );
1079                         SetString( st->c, var_a.vectorPtr->ToString() );
1080                         AppendString( st->c, GetString( st->b ) );
1081                         break;
1082
1083                 case OP_ADD_SV:
1084                         var_b = GetVariable( st->b );
1085                         SetString( st->c, GetString( st->a ) );
1086                         AppendString( st->c, var_b.vectorPtr->ToString() );
1087                         break;
1088
1089                 case OP_SUB_F:
1090                         var_a = GetVariable( st->a );
1091                         var_b = GetVariable( st->b );
1092                         var_c = GetVariable( st->c );
1093                         *var_c.floatPtr = *var_a.floatPtr - *var_b.floatPtr;
1094                         break;
1095
1096                 case OP_SUB_V:
1097                         var_a = GetVariable( st->a );
1098                         var_b = GetVariable( st->b );
1099                         var_c = GetVariable( st->c );
1100                         *var_c.vectorPtr = *var_a.vectorPtr - *var_b.vectorPtr;
1101                         break;
1102
1103                 case OP_MUL_F:
1104                         var_a = GetVariable( st->a );
1105                         var_b = GetVariable( st->b );
1106                         var_c = GetVariable( st->c );
1107                         *var_c.floatPtr = *var_a.floatPtr * *var_b.floatPtr;
1108                         break;
1109
1110                 case OP_MUL_V:
1111                         var_a = GetVariable( st->a );
1112                         var_b = GetVariable( st->b );
1113                         var_c = GetVariable( st->c );
1114                         *var_c.floatPtr = *var_a.vectorPtr * *var_b.vectorPtr;
1115                         break;
1116
1117                 case OP_MUL_FV:
1118                         var_a = GetVariable( st->a );
1119                         var_b = GetVariable( st->b );
1120                         var_c = GetVariable( st->c );
1121                         *var_c.vectorPtr = *var_a.floatPtr * *var_b.vectorPtr;
1122                         break;
1123
1124                 case OP_MUL_VF:
1125                         var_a = GetVariable( st->a );
1126                         var_b = GetVariable( st->b );
1127                         var_c = GetVariable( st->c );
1128                         *var_c.vectorPtr = *var_a.vectorPtr * *var_b.floatPtr;
1129                         break;
1130
1131                 case OP_DIV_F:
1132                         var_a = GetVariable( st->a );
1133                         var_b = GetVariable( st->b );
1134                         var_c = GetVariable( st->c );
1135
1136                         if ( *var_b.floatPtr == 0.0f ) {
1137                                 Warning( "Divide by zero" );
1138                                 *var_c.floatPtr = idMath::INFINITY;
1139                         } else {
1140                                 *var_c.floatPtr = *var_a.floatPtr / *var_b.floatPtr;
1141                         }
1142                         break;
1143
1144                 case OP_MOD_F:
1145                         var_a = GetVariable( st->a );
1146                         var_b = GetVariable( st->b );
1147                         var_c = GetVariable ( st->c );
1148
1149                         if ( *var_b.floatPtr == 0.0f ) {
1150                                 Warning( "Divide by zero" );
1151                                 *var_c.floatPtr = *var_a.floatPtr;
1152                         } else {
1153                                 *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) % static_cast<int>( *var_b.floatPtr );
1154                         }
1155                         break;
1156
1157                 case OP_BITAND:
1158                         var_a = GetVariable( st->a );
1159                         var_b = GetVariable( st->b );
1160                         var_c = GetVariable( st->c );
1161                         *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) & static_cast<int>( *var_b.floatPtr );
1162                         break;
1163
1164                 case OP_BITOR:
1165                         var_a = GetVariable( st->a );
1166                         var_b = GetVariable( st->b );
1167                         var_c = GetVariable( st->c );
1168                         *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) | static_cast<int>( *var_b.floatPtr );
1169                         break;
1170
1171                 case OP_GE:
1172                         var_a = GetVariable( st->a );
1173                         var_b = GetVariable( st->b );
1174                         var_c = GetVariable( st->c );
1175                         *var_c.floatPtr = ( *var_a.floatPtr >= *var_b.floatPtr );
1176                         break;
1177
1178                 case OP_LE:
1179                         var_a = GetVariable( st->a );
1180                         var_b = GetVariable( st->b );
1181                         var_c = GetVariable( st->c );
1182                         *var_c.floatPtr = ( *var_a.floatPtr <= *var_b.floatPtr );
1183                         break;
1184
1185                 case OP_GT:
1186                         var_a = GetVariable( st->a );
1187                         var_b = GetVariable( st->b );
1188                         var_c = GetVariable( st->c );
1189                         *var_c.floatPtr = ( *var_a.floatPtr > *var_b.floatPtr );
1190                         break;
1191
1192                 case OP_LT:
1193                         var_a = GetVariable( st->a );
1194                         var_b = GetVariable( st->b );
1195                         var_c = GetVariable( st->c );
1196                         *var_c.floatPtr = ( *var_a.floatPtr < *var_b.floatPtr );
1197                         break;
1198
1199                 case OP_AND:
1200                         var_a = GetVariable( st->a );
1201                         var_b = GetVariable( st->b );
1202                         var_c = GetVariable( st->c );
1203                         *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.floatPtr != 0.0f );
1204                         break;
1205
1206                 case OP_AND_BOOLF:
1207                         var_a = GetVariable( st->a );
1208                         var_b = GetVariable( st->b );
1209                         var_c = GetVariable( st->c );
1210                         *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.floatPtr != 0.0f );
1211                         break;
1212
1213                 case OP_AND_FBOOL:
1214                         var_a = GetVariable( st->a );
1215                         var_b = GetVariable( st->b );
1216                         var_c = GetVariable( st->c );
1217                         *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.intPtr != 0 );
1218                         break;
1219
1220                 case OP_AND_BOOLBOOL:
1221                         var_a = GetVariable( st->a );
1222                         var_b = GetVariable( st->b );
1223                         var_c = GetVariable( st->c );
1224                         *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.intPtr != 0 );
1225                         break;
1226
1227                 case OP_OR:     
1228                         var_a = GetVariable( st->a );
1229                         var_b = GetVariable( st->b );
1230                         var_c = GetVariable( st->c );
1231                         *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.floatPtr != 0.0f );
1232                         break;
1233
1234                 case OP_OR_BOOLF:
1235                         var_a = GetVariable( st->a );
1236                         var_b = GetVariable( st->b );
1237                         var_c = GetVariable( st->c );
1238                         *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.floatPtr != 0.0f );
1239                         break;
1240
1241                 case OP_OR_FBOOL:
1242                         var_a = GetVariable( st->a );
1243                         var_b = GetVariable( st->b );
1244                         var_c = GetVariable( st->c );
1245                         *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.intPtr != 0 );
1246                         break;
1247                         
1248                 case OP_OR_BOOLBOOL:
1249                         var_a = GetVariable( st->a );
1250                         var_b = GetVariable( st->b );
1251                         var_c = GetVariable( st->c );
1252                         *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.intPtr != 0 );
1253                         break;
1254                         
1255                 case OP_NOT_BOOL:
1256                         var_a = GetVariable( st->a );
1257                         var_c = GetVariable( st->c );
1258                         *var_c.floatPtr = ( *var_a.intPtr == 0 );
1259                         break;
1260
1261                 case OP_NOT_F:
1262                         var_a = GetVariable( st->a );
1263                         var_c = GetVariable( st->c );
1264                         *var_c.floatPtr = ( *var_a.floatPtr == 0.0f );
1265                         break;
1266
1267                 case OP_NOT_V:
1268                         var_a = GetVariable( st->a );
1269                         var_c = GetVariable( st->c );
1270                         *var_c.floatPtr = ( *var_a.vectorPtr == vec3_zero );
1271                         break;
1272
1273                 case OP_NOT_S:
1274                         var_c = GetVariable( st->c );
1275                         *var_c.floatPtr = ( strlen( GetString( st->a ) ) == 0 );
1276                         break;
1277
1278                 case OP_NOT_ENT:
1279                         var_a = GetVariable( st->a );
1280                         var_c = GetVariable( st->c );
1281                         *var_c.floatPtr = ( GetEntity( *var_a.entityNumberPtr ) == NULL );
1282                         break;
1283
1284                 case OP_NEG_F:
1285                         var_a = GetVariable( st->a );
1286                         var_c = GetVariable( st->c );
1287                         *var_c.floatPtr = -*var_a.floatPtr;
1288                         break;
1289
1290                 case OP_NEG_V:
1291                         var_a = GetVariable( st->a );
1292                         var_c = GetVariable( st->c );
1293                         *var_c.vectorPtr = -*var_a.vectorPtr;
1294                         break;
1295
1296                 case OP_INT_F:
1297                         var_a = GetVariable( st->a );
1298                         var_c = GetVariable( st->c );
1299                         *var_c.floatPtr = static_cast<int>( *var_a.floatPtr );
1300                         break;
1301
1302                 case OP_EQ_F:
1303                         var_a = GetVariable( st->a );
1304                         var_b = GetVariable( st->b );
1305                         var_c = GetVariable( st->c );
1306                         *var_c.floatPtr = ( *var_a.floatPtr == *var_b.floatPtr );
1307                         break;
1308
1309                 case OP_EQ_V:
1310                         var_a = GetVariable( st->a );
1311                         var_b = GetVariable( st->b );
1312                         var_c = GetVariable( st->c );
1313                         *var_c.floatPtr = ( *var_a.vectorPtr == *var_b.vectorPtr );
1314                         break;
1315
1316                 case OP_EQ_S:
1317                         var_a = GetVariable( st->a );
1318                         var_b = GetVariable( st->b );
1319                         var_c = GetVariable( st->c );
1320                         *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) == 0 );
1321                         break;
1322
1323                 case OP_EQ_E:
1324                 case OP_EQ_EO:
1325                 case OP_EQ_OE:
1326                 case OP_EQ_OO:
1327                         var_a = GetVariable( st->a );
1328                         var_b = GetVariable( st->b );
1329                         var_c = GetVariable( st->c );
1330                         *var_c.floatPtr = ( *var_a.entityNumberPtr == *var_b.entityNumberPtr );
1331                         break;
1332
1333                 case OP_NE_F:
1334                         var_a = GetVariable( st->a );
1335                         var_b = GetVariable( st->b );
1336                         var_c = GetVariable( st->c );
1337                         *var_c.floatPtr = ( *var_a.floatPtr != *var_b.floatPtr );
1338                         break;
1339
1340                 case OP_NE_V:
1341                         var_a = GetVariable( st->a );
1342                         var_b = GetVariable( st->b );
1343                         var_c = GetVariable( st->c );
1344                         *var_c.floatPtr = ( *var_a.vectorPtr != *var_b.vectorPtr );
1345                         break;
1346
1347                 case OP_NE_S:
1348                         var_c = GetVariable( st->c );
1349                         *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) != 0 );
1350                         break;
1351
1352                 case OP_NE_E:
1353                 case OP_NE_EO:
1354                 case OP_NE_OE:
1355                 case OP_NE_OO:
1356                         var_a = GetVariable( st->a );
1357                         var_b = GetVariable( st->b );
1358                         var_c = GetVariable( st->c );
1359                         *var_c.floatPtr = ( *var_a.entityNumberPtr != *var_b.entityNumberPtr );
1360                         break;
1361
1362                 case OP_UADD_F:
1363                         var_a = GetVariable( st->a );
1364                         var_b = GetVariable( st->b );
1365                         *var_b.floatPtr += *var_a.floatPtr;
1366                         break;
1367
1368                 case OP_UADD_V:
1369                         var_a = GetVariable( st->a );
1370                         var_b = GetVariable( st->b );
1371                         *var_b.vectorPtr += *var_a.vectorPtr;
1372                         break;
1373
1374                 case OP_USUB_F:
1375                         var_a = GetVariable( st->a );
1376                         var_b = GetVariable( st->b );
1377                         *var_b.floatPtr -= *var_a.floatPtr;
1378                         break;
1379
1380                 case OP_USUB_V:
1381                         var_a = GetVariable( st->a );
1382                         var_b = GetVariable( st->b );
1383                         *var_b.vectorPtr -= *var_a.vectorPtr;
1384                         break;
1385
1386                 case OP_UMUL_F:
1387                         var_a = GetVariable( st->a );
1388                         var_b = GetVariable( st->b );
1389                         *var_b.floatPtr *= *var_a.floatPtr;
1390                         break;
1391
1392                 case OP_UMUL_V:
1393                         var_a = GetVariable( st->a );
1394                         var_b = GetVariable( st->b );
1395                         *var_b.vectorPtr *= *var_a.floatPtr;
1396                         break;
1397
1398                 case OP_UDIV_F:
1399                         var_a = GetVariable( st->a );
1400                         var_b = GetVariable( st->b );
1401
1402                         if ( *var_a.floatPtr == 0.0f ) {
1403                                 Warning( "Divide by zero" );
1404                                 *var_b.floatPtr = idMath::INFINITY;
1405                         } else {
1406                                 *var_b.floatPtr = *var_b.floatPtr / *var_a.floatPtr;
1407                         }
1408                         break;
1409
1410                 case OP_UDIV_V:
1411                         var_a = GetVariable( st->a );
1412                         var_b = GetVariable( st->b );
1413
1414                         if ( *var_a.floatPtr == 0.0f ) {
1415                                 Warning( "Divide by zero" );
1416                                 var_b.vectorPtr->Set( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY );
1417                         } else {
1418                                 *var_b.vectorPtr = *var_b.vectorPtr / *var_a.floatPtr;
1419                         }
1420                         break;
1421
1422                 case OP_UMOD_F:
1423                         var_a = GetVariable( st->a );
1424                         var_b = GetVariable( st->b );
1425
1426                         if ( *var_a.floatPtr == 0.0f ) {
1427                                 Warning( "Divide by zero" );
1428                                 *var_b.floatPtr = *var_a.floatPtr;
1429                         } else {
1430                                 *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) % static_cast<int>( *var_a.floatPtr );
1431                         }
1432                         break;
1433
1434                 case OP_UOR_F:
1435                         var_a = GetVariable( st->a );
1436                         var_b = GetVariable( st->b );
1437                         *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) | static_cast<int>( *var_a.floatPtr );
1438                         break;
1439
1440                 case OP_UAND_F:
1441                         var_a = GetVariable( st->a );
1442                         var_b = GetVariable( st->b );
1443                         *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) & static_cast<int>( *var_a.floatPtr );
1444                         break;
1445
1446                 case OP_UINC_F:
1447                         var_a = GetVariable( st->a );
1448                         ( *var_a.floatPtr )++;
1449                         break;
1450
1451                 case OP_UINCP_F:
1452                         var_a = GetVariable( st->a );
1453                         obj = GetScriptObject( *var_a.entityNumberPtr );
1454                         if ( obj ) {
1455                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1456                                 ( *var.floatPtr )++;
1457                         }
1458                         break;
1459
1460                 case OP_UDEC_F:
1461                         var_a = GetVariable( st->a );
1462                         ( *var_a.floatPtr )--;
1463                         break;
1464
1465                 case OP_UDECP_F:
1466                         var_a = GetVariable( st->a );
1467                         obj = GetScriptObject( *var_a.entityNumberPtr );
1468                         if ( obj ) {
1469                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1470                                 ( *var.floatPtr )--;
1471                         }
1472                         break;
1473
1474                 case OP_COMP_F:
1475                         var_a = GetVariable( st->a );
1476                         var_c = GetVariable( st->c );
1477                         *var_c.floatPtr = ~static_cast<int>( *var_a.floatPtr );
1478                         break;
1479
1480                 case OP_STORE_F:
1481                         var_a = GetVariable( st->a );
1482                         var_b = GetVariable( st->b );
1483                         *var_b.floatPtr = *var_a.floatPtr;
1484                         break;
1485
1486                 case OP_STORE_ENT:
1487                         var_a = GetVariable( st->a );
1488                         var_b = GetVariable( st->b );
1489                         *var_b.entityNumberPtr = *var_a.entityNumberPtr;
1490                         break;
1491
1492                 case OP_STORE_BOOL:     
1493                         var_a = GetVariable( st->a );
1494                         var_b = GetVariable( st->b );
1495                         *var_b.intPtr = *var_a.intPtr;
1496                         break;
1497
1498                 case OP_STORE_OBJENT:
1499                         var_a = GetVariable( st->a );
1500                         var_b = GetVariable( st->b );
1501                         obj = GetScriptObject( *var_a.entityNumberPtr );
1502                         if ( !obj ) {
1503                                 *var_b.entityNumberPtr = 0;
1504                         } else if ( !obj->GetTypeDef()->Inherits( st->b->TypeDef() ) ) {
1505                                 //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->b->TypeDef()->Name() );
1506                                 *var_b.entityNumberPtr = 0;
1507                         } else {
1508                                 *var_b.entityNumberPtr = *var_a.entityNumberPtr;
1509                         }
1510                         break;
1511
1512                 case OP_STORE_OBJ:
1513                 case OP_STORE_ENTOBJ:
1514                         var_a = GetVariable( st->a );
1515                         var_b = GetVariable( st->b );
1516                         *var_b.entityNumberPtr = *var_a.entityNumberPtr;
1517                         break;
1518
1519                 case OP_STORE_S:
1520                         SetString( st->b, GetString( st->a ) );
1521                         break;
1522
1523                 case OP_STORE_V:
1524                         var_a = GetVariable( st->a );
1525                         var_b = GetVariable( st->b );
1526                         *var_b.vectorPtr = *var_a.vectorPtr;
1527                         break;
1528
1529                 case OP_STORE_FTOS:
1530                         var_a = GetVariable( st->a );
1531                         SetString( st->b, FloatToString( *var_a.floatPtr ) );
1532                         break;
1533
1534                 case OP_STORE_BTOS:
1535                         var_a = GetVariable( st->a );
1536                         SetString( st->b, *var_a.intPtr ? "true" : "false" );
1537                         break;
1538
1539                 case OP_STORE_VTOS:
1540                         var_a = GetVariable( st->a );
1541                         SetString( st->b, var_a.vectorPtr->ToString() );
1542                         break;
1543
1544                 case OP_STORE_FTOBOOL:
1545                         var_a = GetVariable( st->a );
1546                         var_b = GetVariable( st->b );
1547                         if ( *var_a.floatPtr != 0.0f ) {
1548                                 *var_b.intPtr = 1;
1549                         } else {
1550                                 *var_b.intPtr = 0;
1551                         }
1552                         break;
1553
1554                 case OP_STORE_BOOLTOF:
1555                         var_a = GetVariable( st->a );
1556                         var_b = GetVariable( st->b );
1557                         *var_b.floatPtr = static_cast<float>( *var_a.intPtr );
1558                         break;
1559
1560                 case OP_STOREP_F:
1561                         var_b = GetVariable( st->b );
1562                         if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) {
1563                                 var_a = GetVariable( st->a );
1564                                 *var_b.evalPtr->floatPtr = *var_a.floatPtr;
1565                         }
1566                         break;
1567
1568                 case OP_STOREP_ENT:
1569                         var_b = GetVariable( st->b );
1570                         if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) {
1571                                 var_a = GetVariable( st->a );
1572                                 *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr;
1573                         }
1574                         break;
1575
1576                 case OP_STOREP_FLD:
1577                         var_b = GetVariable( st->b );
1578                         if ( var_b.evalPtr && var_b.evalPtr->intPtr ) {
1579                                 var_a = GetVariable( st->a );
1580                                 *var_b.evalPtr->intPtr = *var_a.intPtr;
1581                         }
1582                         break;
1583
1584                 case OP_STOREP_BOOL:
1585                         var_b = GetVariable( st->b );
1586                         if ( var_b.evalPtr && var_b.evalPtr->intPtr ) {
1587                                 var_a = GetVariable( st->a );
1588                                 *var_b.evalPtr->intPtr = *var_a.intPtr;
1589                         }
1590                         break;
1591
1592                 case OP_STOREP_S:
1593                         var_b = GetVariable( st->b );
1594                         if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) {
1595                                 idStr::Copynz( var_b.evalPtr->stringPtr, GetString( st->a ), MAX_STRING_LEN );
1596                         }
1597                         break;
1598
1599                 case OP_STOREP_V:
1600                         var_b = GetVariable( st->b );
1601                         if ( var_b.evalPtr && var_b.evalPtr->vectorPtr ) {
1602                                 var_a = GetVariable( st->a );
1603                                 *var_b.evalPtr->vectorPtr = *var_a.vectorPtr;
1604                         }
1605                         break;
1606                 
1607                 case OP_STOREP_FTOS:
1608                         var_b = GetVariable( st->b );
1609                         if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) {
1610                                 var_a = GetVariable( st->a );
1611                                 idStr::Copynz( var_b.evalPtr->stringPtr, FloatToString( *var_a.floatPtr ), MAX_STRING_LEN );
1612                         }
1613                         break;
1614
1615                 case OP_STOREP_BTOS:
1616                         var_b = GetVariable( st->b );
1617                         if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) {
1618                                 var_a = GetVariable( st->a );
1619                                 if ( *var_a.floatPtr != 0.0f ) {
1620                                         idStr::Copynz( var_b.evalPtr->stringPtr, "true", MAX_STRING_LEN );
1621                                 } else {
1622                                         idStr::Copynz( var_b.evalPtr->stringPtr, "false", MAX_STRING_LEN );
1623                                 }
1624                         }
1625                         break;
1626
1627                 case OP_STOREP_VTOS:
1628                         var_b = GetVariable( st->b );
1629                         if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) {
1630                                 var_a = GetVariable( st->a );
1631                                 idStr::Copynz( var_b.evalPtr->stringPtr, var_a.vectorPtr->ToString(), MAX_STRING_LEN );
1632                         }
1633                         break;
1634
1635                 case OP_STOREP_FTOBOOL:
1636                         var_b = GetVariable( st->b );
1637                         if ( var_b.evalPtr && var_b.evalPtr->intPtr ) {
1638                                 var_a = GetVariable( st->a );
1639                                 if ( *var_a.floatPtr != 0.0f ) {
1640                                         *var_b.evalPtr->intPtr = 1;
1641                                 } else {
1642                                         *var_b.evalPtr->intPtr = 0;
1643                                 }
1644                         }
1645                         break;
1646
1647                 case OP_STOREP_BOOLTOF:
1648                         var_b = GetVariable( st->b );
1649                         if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) {
1650                                 var_a = GetVariable( st->a );
1651                                 *var_b.evalPtr->floatPtr = static_cast<float>( *var_a.intPtr );
1652                         }
1653                         break;
1654
1655                 case OP_STOREP_OBJ:
1656                         var_b = GetVariable( st->b );
1657                         if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) {
1658                                 var_a = GetVariable( st->a );
1659                                 *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr;
1660                         }
1661                         break;
1662
1663                 case OP_STOREP_OBJENT:
1664                         var_b = GetVariable( st->b );
1665                         if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) {
1666                                 var_a = GetVariable( st->a );
1667                                 obj = GetScriptObject( *var_a.entityNumberPtr );
1668                                 if ( !obj ) {
1669                                         *var_b.evalPtr->entityNumberPtr = 0;
1670
1671                                 // st->b points to type_pointer, which is just a temporary that gets its type reassigned, so we store the real type in st->c
1672                                 // so that we can do a type check during run time since we don't know what type the script object is at compile time because it
1673                                 // comes from an entity
1674                                 } else if ( !obj->GetTypeDef()->Inherits( st->c->TypeDef() ) ) {
1675                                         //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->c->TypeDef()->Name() );
1676                                         *var_b.evalPtr->entityNumberPtr = 0;
1677                                 } else {
1678                                         *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr;
1679                                 }
1680                         }
1681                         break;
1682
1683                 case OP_ADDRESS:
1684                         var_a = GetVariable( st->a );
1685                         var_c = GetVariable( st->c );
1686                         obj = GetScriptObject( *var_a.entityNumberPtr );
1687                         if ( obj ) {
1688                                 var_c.evalPtr->bytePtr = &obj->data[ st->b->value.ptrOffset ];
1689                         } else {
1690                                 var_c.evalPtr->bytePtr = NULL;
1691                         }
1692                         break;
1693
1694                 case OP_INDIRECT_F:
1695                         var_a = GetVariable( st->a );
1696                         var_c = GetVariable( st->c );
1697                         obj = GetScriptObject( *var_a.entityNumberPtr );
1698                         if ( obj ) {
1699                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1700                                 *var_c.floatPtr = *var.floatPtr;
1701                         } else {
1702                                 *var_c.floatPtr = 0.0f;
1703                         }
1704                         break;
1705
1706                 case OP_INDIRECT_ENT:
1707                         var_a = GetVariable( st->a );
1708                         var_c = GetVariable( st->c );
1709                         obj = GetScriptObject( *var_a.entityNumberPtr );
1710                         if ( obj ) {
1711                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1712                                 *var_c.entityNumberPtr = *var.entityNumberPtr;
1713                         } else {
1714                                 *var_c.entityNumberPtr = 0;
1715                         }
1716                         break;
1717
1718                 case OP_INDIRECT_BOOL:
1719                         var_a = GetVariable( st->a );
1720                         var_c = GetVariable( st->c );
1721                         obj = GetScriptObject( *var_a.entityNumberPtr );
1722                         if ( obj ) {
1723                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1724                                 *var_c.intPtr = *var.intPtr;
1725                         } else {
1726                                 *var_c.intPtr = 0;
1727                         }
1728                         break;
1729
1730                 case OP_INDIRECT_S:
1731                         var_a = GetVariable( st->a );
1732                         obj = GetScriptObject( *var_a.entityNumberPtr );
1733                         if ( obj ) {
1734                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1735                                 SetString( st->c, var.stringPtr );
1736                         } else {
1737                                 SetString( st->c, "" );
1738                         }
1739                         break;
1740
1741                 case OP_INDIRECT_V:
1742                         var_a = GetVariable( st->a );
1743                         var_c = GetVariable( st->c );
1744                         obj = GetScriptObject( *var_a.entityNumberPtr );
1745                         if ( obj ) {
1746                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1747                                 *var_c.vectorPtr = *var.vectorPtr;
1748                         } else {
1749                                 var_c.vectorPtr->Zero();
1750                         }
1751                         break;
1752
1753                 case OP_INDIRECT_OBJ:
1754                         var_a = GetVariable( st->a );
1755                         var_c = GetVariable( st->c );
1756                         obj = GetScriptObject( *var_a.entityNumberPtr );
1757                         if ( !obj ) {
1758                                 *var_c.entityNumberPtr = 0;
1759                         } else {
1760                                 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1761                                 *var_c.entityNumberPtr = *var.entityNumberPtr;
1762                         }
1763                         break;
1764
1765                 case OP_PUSH_F:
1766                         var_a = GetVariable( st->a );
1767                         Push( *var_a.intPtr );
1768                         break;
1769
1770                 case OP_PUSH_FTOS:
1771                         var_a = GetVariable( st->a );
1772                         PushString( FloatToString( *var_a.floatPtr ) );
1773                         break;
1774
1775                 case OP_PUSH_BTOF:
1776                         var_a = GetVariable( st->a );
1777                         floatVal = *var_a.intPtr;
1778                         Push( *reinterpret_cast<int *>( &floatVal ) );
1779                         break;
1780
1781                 case OP_PUSH_FTOB:
1782                         var_a = GetVariable( st->a );
1783                         if ( *var_a.floatPtr != 0.0f ) {
1784                                 Push( 1 );
1785                         } else {
1786                                 Push( 0 );
1787                         }
1788                         break;
1789
1790                 case OP_PUSH_VTOS:
1791                         var_a = GetVariable( st->a );
1792                         PushString( var_a.vectorPtr->ToString() );
1793                         break;
1794
1795                 case OP_PUSH_BTOS:
1796                         var_a = GetVariable( st->a );
1797                         PushString( *var_a.intPtr ? "true" : "false" );
1798                         break;
1799
1800                 case OP_PUSH_ENT:
1801                         var_a = GetVariable( st->a );
1802                         Push( *var_a.entityNumberPtr );
1803                         break;
1804
1805                 case OP_PUSH_S:
1806                         PushString( GetString( st->a ) );
1807                         break;
1808
1809                 case OP_PUSH_V:
1810                         var_a = GetVariable( st->a );
1811                         Push( *reinterpret_cast<int *>( &var_a.vectorPtr->x ) );
1812                         Push( *reinterpret_cast<int *>( &var_a.vectorPtr->y ) );
1813                         Push( *reinterpret_cast<int *>( &var_a.vectorPtr->z ) );
1814                         break;
1815
1816                 case OP_PUSH_OBJ:
1817                         var_a = GetVariable( st->a );
1818                         Push( *var_a.entityNumberPtr );
1819                         break;
1820
1821                 case OP_PUSH_OBJENT:
1822                         var_a = GetVariable( st->a );
1823                         Push( *var_a.entityNumberPtr );
1824                         break;
1825
1826                 case OP_BREAK:
1827                 case OP_CONTINUE:
1828                 default:
1829                         Error( "Bad opcode %i", st->op );
1830                         break;
1831                 }
1832         }
1833
1834         return threadDying;
1835 }