DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Script_Interpreter.cpp (46131B)


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