2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
32 #include "../Game_local.h"
36 idInterpreter::idInterpreter()
39 idInterpreter::idInterpreter() {
41 terminateOnExit = true;
43 memset( localstack, 0, sizeof( localstack ) );
44 memset( callStack, 0, sizeof( callStack ) );
53 void idInterpreter::Save( idSaveGame *savefile ) const {
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 ) );
62 savefile->WriteInt( -1 );
64 savefile->WriteInt( callStack[i].stackbase );
66 savefile->WriteInt( maxStackDepth );
68 savefile->WriteInt( localstackUsed );
69 savefile->Write( &localstack, localstackUsed );
71 savefile->WriteInt( localstackBase );
72 savefile->WriteInt( maxLocalstackUsed );
74 if ( currentFunction ) {
75 savefile->WriteInt( gameLocal.program.GetFunctionIndex( currentFunction ) );
77 savefile->WriteInt( -1 );
79 savefile->WriteInt( instructionPointer );
81 savefile->WriteInt( popParms );
83 if ( multiFrameEvent ) {
84 savefile->WriteString( multiFrameEvent->GetName() );
86 savefile->WriteString( "" );
88 savefile->WriteObject( eventEntity );
90 savefile->WriteObject( thread );
92 savefile->WriteBool( doneProcessing );
93 savefile->WriteBool( threadDying );
94 savefile->WriteBool( terminateOnExit );
95 savefile->WriteBool( debug );
100 idInterpreter::Restore
103 void idInterpreter::Restore( idRestoreGame *savefile ) {
108 savefile->ReadInt( callStackDepth );
109 for( i = 0; i < callStackDepth; i++ ) {
110 savefile->ReadInt( callStack[i].s );
112 savefile->ReadInt( func_index );
113 if ( func_index >= 0 ) {
114 callStack[i].f = gameLocal.program.GetFunction( func_index );
116 callStack[i].f = NULL;
119 savefile->ReadInt( callStack[i].stackbase );
121 savefile->ReadInt( maxStackDepth );
123 savefile->ReadInt( localstackUsed );
124 savefile->Read( &localstack, localstackUsed );
126 savefile->ReadInt( localstackBase );
127 savefile->ReadInt( maxLocalstackUsed );
129 savefile->ReadInt( func_index );
130 if ( func_index >= 0 ) {
131 currentFunction = gameLocal.program.GetFunction( func_index );
133 currentFunction = NULL;
135 savefile->ReadInt( instructionPointer );
137 savefile->ReadInt( popParms );
139 savefile->ReadString( funcname );
140 if ( funcname.Length() ) {
141 multiFrameEvent = idEventDef::FindEvent( funcname );
144 savefile->ReadObject( reinterpret_cast<idClass *&>( eventEntity ) );
145 savefile->ReadObject( reinterpret_cast<idClass *&>( thread ) );
147 savefile->ReadBool( doneProcessing );
148 savefile->ReadBool( threadDying );
149 savefile->ReadBool( terminateOnExit );
150 savefile->ReadBool( debug );
158 void idInterpreter::Reset( void ) {
163 maxLocalstackUsed = 0;
167 multiFrameEvent = NULL;
171 NextInstruction( 0 );
174 doneProcessing = true;
179 idInterpreter::GetRegisterValue
181 Returns a string representation of the value of the register. This is
182 used primarily for the debugger and debugging
184 //FIXME: This is pretty much wrong. won't access data in most situations.
187 bool idInterpreter::GetRegisterValue( const char *name, idStr &out, int scopeDepth ) {
190 char funcObject[ 1024 ];
192 const idVarDef *scope;
193 const idTypeDef *field;
194 const idScriptObject *obj;
195 const function_t *func;
199 if ( scopeDepth == -1 ) {
200 scopeDepth = callStackDepth;
203 if ( scopeDepth == callStackDepth ) {
204 func = currentFunction;
206 func = callStack[ scopeDepth ].f;
212 idStr::Copynz( funcObject, func->Name(), sizeof( funcObject ) );
213 funcName = strstr( funcObject, "::" );
216 scope = gameLocal.program.GetDef( NULL, funcObject, &def_namespace );
219 funcName = funcObject;
220 scope = &def_namespace;
223 // Get the function from the object
224 d = gameLocal.program.GetDef( NULL, funcName, scope );
229 // Get the variable itself and check various namespaces
230 d = gameLocal.program.GetDef( NULL, name, d );
232 if ( scope == &def_namespace ) {
236 d = gameLocal.program.GetDef( NULL, name, scope );
238 d = gameLocal.program.GetDef( NULL, name, &def_namespace );
245 reg = GetVariable( d );
246 switch( d->Type() ) {
248 if ( reg.floatPtr ) {
249 out = va("%g", *reg.floatPtr );
257 if ( reg.vectorPtr ) {
258 out = va( "%g,%g,%g", reg.vectorPtr->x, reg.vectorPtr->y, reg.vectorPtr->z );
267 out = va( "%d", *reg.intPtr );
275 if ( scope == &def_namespace ) {
276 // should never happen, but handle it safely anyway
280 field = scope->TypeDef()->GetParmType( reg.ptrOffset )->FieldType();
281 obj = *reinterpret_cast<const idScriptObject **>( &localstack[ callStack[ callStackDepth ].stackbase ] );
282 if ( !field || !obj ) {
286 switch ( field->Type() ) {
288 out = va( "%d", *( reinterpret_cast<int *>( &obj->data[ reg.ptrOffset ] ) ) );
292 out = va( "%g", *( reinterpret_cast<float *>( &obj->data[ reg.ptrOffset ] ) ) );
301 if ( reg.stringPtr ) {
303 out += reg.stringPtr;
317 idInterpreter::GetCallstackDepth
320 int idInterpreter::GetCallstackDepth( void ) const {
321 return callStackDepth;
326 idInterpreter::GetCallstack
329 const prstack_t *idInterpreter::GetCallstack( void ) const {
330 return &callStack[ 0 ];
335 idInterpreter::GetCurrentFunction
338 const function_t *idInterpreter::GetCurrentFunction( void ) const {
339 return currentFunction;
344 idInterpreter::GetThread
347 idThread *idInterpreter::GetThread( void ) const {
354 idInterpreter::SetThread
357 void idInterpreter::SetThread( idThread *pThread ) {
363 idInterpreter::CurrentLine
366 int idInterpreter::CurrentLine( void ) const {
367 if ( instructionPointer < 0 ) {
370 return gameLocal.program.GetLineNumberForStatement( instructionPointer );
375 idInterpreter::CurrentFile
378 const char *idInterpreter::CurrentFile( void ) const {
379 if ( instructionPointer < 0 ) {
382 return gameLocal.program.GetFilenameForStatement( instructionPointer );
387 idInterpreter::StackTrace
390 void idInterpreter::StackTrace( void ) const {
395 if ( callStackDepth == 0 ) {
396 gameLocal.Printf( "<NO STACK>\n" );
400 top = callStackDepth;
401 if ( top >= MAX_STACK_DEPTH ) {
402 top = MAX_STACK_DEPTH - 1;
405 if ( !currentFunction ) {
406 gameLocal.Printf( "<NO FUNCTION>\n" );
408 gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( currentFunction->filenum ), currentFunction->Name() );
411 for( i = top; i >= 0; i-- ) {
412 f = callStack[ i ].f;
414 gameLocal.Printf( "<NO FUNCTION>\n" );
416 gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( f->filenum ), f->Name() );
425 Aborts the currently executing function
428 void idInterpreter::Error( char *fmt, ... ) const {
432 va_start( argptr, fmt );
433 vsprintf( text, fmt, argptr );
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 );
442 common->Error( "Thread '%s': %s\n", thread->GetThreadName(), text );
448 idInterpreter::Warning
450 Prints file and line number information with warning.
453 void idInterpreter::Warning( char *fmt, ... ) const {
457 va_start( argptr, fmt );
458 vsprintf( text, fmt, argptr );
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 );
465 common->Warning( "Thread '%s' : %s", thread->GetThreadName(), text );
471 idInterpreter::DisplayInfo
474 void idInterpreter::DisplayInfo( void ) const {
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: " );
482 if ( callStackDepth == 0 ) {
483 gameLocal.Printf( "<NO STACK>\n" );
485 if ( !currentFunction ) {
486 gameLocal.Printf( "<NO FUNCTION>\n" );
488 gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( currentFunction->filenum ), currentFunction->Name() );
491 for( i = callStackDepth; i > 0; i-- ) {
492 gameLocal.Printf( " " );
493 f = callStack[ i ].f;
495 gameLocal.Printf( "<NO FUNCTION>\n" );
497 gameLocal.Printf( "%12s : %s\n", gameLocal.program.GetFilename( f->filenum ), f->Name() );
505 idInterpreter::ThreadCall
507 Copys the args from the calling thread's stack
510 void idInterpreter::ThreadCall( idInterpreter *source, const function_t *func, int args ) {
513 memcpy( localstack, &source->localstack[ source->localstackUsed - args ], args );
515 localstackUsed = args;
518 maxLocalstackUsed = localstackUsed;
519 EnterFunction( func, false );
521 thread->SetThreadName( currentFunction->Name() );
526 idInterpreter::EnterObjectFunction
528 Calls a function on a script object.
530 NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function.
533 void idInterpreter::EnterObjectFunction( idEntity *self, const function_t *func, bool clearStack ) {
538 PopParms( popParms );
541 Push( self->entityNumber + 1 );
542 EnterFunction( func, false );
547 idInterpreter::EnterFunction
549 Returns the new program statement counter
551 NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function.
554 void idInterpreter::EnterFunction( const function_t *func, bool clearStack ) {
562 PopParms( popParms );
566 if ( callStackDepth >= MAX_STACK_DEPTH ) {
567 Error( "call stack overflow" );
570 stack = &callStack[ callStackDepth ];
572 stack->s = instructionPointer + 1; // point to the next instruction to execute
573 stack->f = currentFunction;
574 stack->stackbase = localstackBase;
577 if ( callStackDepth > maxStackDepth ) {
578 maxStackDepth = callStackDepth;
582 Error( "NULL function" );
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" : "" );
590 gameLocal.Printf( "%d: call '%s'%s\n", gameLocal.time, func->Name(), clearStack ? " clear stack" : "" );
594 currentFunction = func;
595 assert( !func->eventdef );
596 NextInstruction( func->firstStatement );
598 // allocate space on the stack for locals
599 // parms are already on stack
600 c = func->locals - func->parmTotal;
603 if ( localstackUsed + c > LOCALSTACK_SIZE ) {
604 Error( "EnterFuncton: locals stack overflow\n" );
607 // initialize local stack variables to zero
608 memset( &localstack[ localstackUsed ], 0, c );
611 localstackBase = localstackUsed - func->locals;
613 if ( localstackUsed > maxLocalstackUsed ) {
614 maxLocalstackUsed = localstackUsed ;
620 idInterpreter::LeaveFunction
623 void idInterpreter::LeaveFunction( idVarDef *returnDef ) {
627 if ( callStackDepth <= 0 ) {
628 Error( "prog stack underflow" );
633 switch( returnDef->Type() ) {
635 gameLocal.program.ReturnString( GetString( returnDef ) );
639 ret = GetVariable( returnDef );
640 gameLocal.program.ReturnVector( *ret.vectorPtr );
644 ret = GetVariable( returnDef );
645 gameLocal.program.ReturnInteger( *ret.intPtr );
649 // remove locals from the stack
650 PopParms( currentFunction->locals );
651 assert( localstackUsed == localstackBase );
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 );
659 gameLocal.Printf( " done\n" );
665 stack = &callStack[ callStackDepth ];
666 currentFunction = stack->f;
667 localstackBase = stack->stackbase;
668 NextInstruction( stack->s );
670 if ( !callStackDepth ) {
672 doneProcessing = true;
680 idInterpreter::CallEvent
683 void idInterpreter::CallEvent( const function_t *func, int argsize ) {
689 int data[ D_EVENT_MAXARGS ];
690 const idEventDef *evdef;
694 Error( "NULL function" );
697 assert( func->eventdef );
698 evdef = func->eventdef;
700 start = localstackUsed - argsize;
701 var.intPtr = ( int * )&localstack[ start ];
702 eventEntity = GetEntity( *var.entityNumberPtr );
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() );
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 );
716 gameLocal.program.ReturnFloat( 0 );
719 case D_EVENT_VECTOR :
720 gameLocal.program.ReturnVector( vec3_zero );
723 case D_EVENT_STRING :
724 gameLocal.program.ReturnString( "" );
727 case D_EVENT_ENTITY :
728 case D_EVENT_ENTITY_NULL :
729 gameLocal.program.ReturnEntity( ( idEntity * )NULL );
734 // unsupported data type
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 );
752 var.intPtr = ( int * )&localstack[ start + pos ];
753 ( *( float * )&data[ i ] ) = *var.floatPtr;
756 case D_EVENT_VECTOR :
757 var.intPtr = ( int * )&localstack[ start + pos ];
758 ( *( idVec3 ** )&data[ i ] ) = var.vectorPtr;
761 case D_EVENT_STRING :
762 ( *( const char ** )&data[ i ] ) = ( char * )&localstack[ start + pos ];
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() );
776 case D_EVENT_ENTITY_NULL :
777 var.intPtr = ( int * )&localstack[ start + pos ];
778 ( *( idEntity ** )&data[ i ] ) = GetEntity( *var.entityNumberPtr );
782 Error( "trace type not supported from script for '%s' event.", evdef->GetName() );
786 Error( "Invalid arg format string for '%s' event.", evdef->GetName() );
790 pos += func->parmSize[ j++ ];
794 eventEntity->ProcessEventArgPtr( evdef, data );
796 if ( !multiFrameEvent ) {
798 PopParms( popParms );
802 doneProcessing = true;
809 idInterpreter::BeginMultiFrameEvent
812 bool idInterpreter::BeginMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
813 if ( eventEntity != ent ) {
814 Error( "idInterpreter::BeginMultiFrameEvent called with wrong entity" );
816 if ( multiFrameEvent ) {
817 if ( multiFrameEvent != event ) {
818 Error( "idInterpreter::BeginMultiFrameEvent called with wrong event" );
823 multiFrameEvent = event;
829 idInterpreter::EndMultiFrameEvent
832 void idInterpreter::EndMultiFrameEvent( idEntity *ent, const idEventDef *event ) {
833 if ( multiFrameEvent != event ) {
834 Error( "idInterpreter::EndMultiFrameEvent called with wrong event" );
837 multiFrameEvent = NULL;
842 idInterpreter::MultiFrameEventInProgress
845 bool idInterpreter::MultiFrameEventInProgress( void ) const {
846 return multiFrameEvent != NULL;
851 idInterpreter::CallSysEvent
854 void idInterpreter::CallSysEvent( const function_t *func, int argsize ) {
860 int data[ D_EVENT_MAXARGS ];
861 const idEventDef *evdef;
865 Error( "NULL function" );
868 assert( func->eventdef );
869 evdef = func->eventdef;
871 start = localstackUsed - argsize;
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 );
882 source.intPtr = ( int * )&localstack[ start + pos ];
883 *( float * )&data[ i ] = *source.floatPtr;
886 case D_EVENT_VECTOR :
887 source.intPtr = ( int * )&localstack[ start + pos ];
888 *( idVec3 ** )&data[ i ] = source.vectorPtr;
891 case D_EVENT_STRING :
892 *( const char ** )&data[ i ] = ( char * )&localstack[ start + pos ];
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() );
906 case D_EVENT_ENTITY_NULL :
907 source.intPtr = ( int * )&localstack[ start + pos ];
908 *( idEntity ** )&data[ i ] = GetEntity( *source.entityNumberPtr );
912 Error( "trace type not supported from script for '%s' event.", evdef->GetName() );
916 Error( "Invalid arg format string for '%s' event.", evdef->GetName() );
920 pos += func->parmSize[ j++ ];
924 thread->ProcessEventArgPtr( evdef, data );
926 PopParms( popParms );
933 idInterpreter::Execute
936 bool idInterpreter::Execute( void ) {
946 const function_t *func;
948 if ( threadDying || !currentFunction ) {
952 if ( multiFrameEvent ) {
953 // move to previous instruction and call it again
954 instructionPointer--;
959 doneProcessing = false;
960 while( !doneProcessing && !threadDying ) {
961 instructionPointer++;
964 Error( "runaway loop error" );
968 st = &gameLocal.program.GetStatement( instructionPointer );
972 LeaveFunction( st->a );
976 newThread = new idThread( this, st->a->value.functionPtr, st->b->value.argSize );
979 // return the thread number to the script
980 gameLocal.program.ReturnFloat( newThread->GetThreadNum() );
981 PopParms( st->b->value.argSize );
985 var_a = GetVariable( st->a );
986 obj = GetScriptObject( *var_a.entityNumberPtr );
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 );
993 // return the thread number to the script
994 gameLocal.program.ReturnFloat( newThread->GetThreadNum() );
996 // return a null thread to the script
997 gameLocal.program.ReturnFloat( 0.0f );
999 PopParms( st->c->value.argSize );
1003 EnterFunction( st->a->value.functionPtr, false );
1007 CallEvent( st->a->value.functionPtr, st->b->value.argSize );
1011 var_a = GetVariable( st->a );
1012 obj = GetScriptObject( *var_a.entityNumberPtr );
1014 func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction );
1015 EnterFunction( func, false );
1017 // return a 'safe' value
1018 gameLocal.program.ReturnVector( vec3_zero );
1019 gameLocal.program.ReturnString( "" );
1020 PopParms( st->c->value.argSize );
1025 CallSysEvent( st->a->value.functionPtr, st->b->value.argSize );
1029 var_a = GetVariable( st->a );
1030 if ( *var_a.intPtr == 0 ) {
1031 NextInstruction( instructionPointer + st->b->value.jumpOffset );
1036 var_a = GetVariable( st->a );
1037 if ( *var_a.intPtr != 0 ) {
1038 NextInstruction( instructionPointer + st->b->value.jumpOffset );
1043 NextInstruction( instructionPointer + st->a->value.jumpOffset );
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;
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;
1061 SetString( st->c, GetString( st->a ) );
1062 AppendString( st->c, GetString( st->b ) );
1066 var_a = GetVariable( st->a );
1067 SetString( st->c, FloatToString( *var_a.floatPtr ) );
1068 AppendString( st->c, GetString( st->b ) );
1072 var_b = GetVariable( st->b );
1073 SetString( st->c, GetString( st->a ) );
1074 AppendString( st->c, FloatToString( *var_b.floatPtr ) );
1078 var_a = GetVariable( st->a );
1079 SetString( st->c, var_a.vectorPtr->ToString() );
1080 AppendString( st->c, GetString( st->b ) );
1084 var_b = GetVariable( st->b );
1085 SetString( st->c, GetString( st->a ) );
1086 AppendString( st->c, var_b.vectorPtr->ToString() );
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;
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;
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;
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;
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;
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;
1132 var_a = GetVariable( st->a );
1133 var_b = GetVariable( st->b );
1134 var_c = GetVariable( st->c );
1136 if ( *var_b.floatPtr == 0.0f ) {
1137 Warning( "Divide by zero" );
1138 *var_c.floatPtr = idMath::INFINITY;
1140 *var_c.floatPtr = *var_a.floatPtr / *var_b.floatPtr;
1145 var_a = GetVariable( st->a );
1146 var_b = GetVariable( st->b );
1147 var_c = GetVariable ( st->c );
1149 if ( *var_b.floatPtr == 0.0f ) {
1150 Warning( "Divide by zero" );
1151 *var_c.floatPtr = *var_a.floatPtr;
1153 *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) % static_cast<int>( *var_b.floatPtr );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
1256 var_a = GetVariable( st->a );
1257 var_c = GetVariable( st->c );
1258 *var_c.floatPtr = ( *var_a.intPtr == 0 );
1262 var_a = GetVariable( st->a );
1263 var_c = GetVariable( st->c );
1264 *var_c.floatPtr = ( *var_a.floatPtr == 0.0f );
1268 var_a = GetVariable( st->a );
1269 var_c = GetVariable( st->c );
1270 *var_c.floatPtr = ( *var_a.vectorPtr == vec3_zero );
1274 var_c = GetVariable( st->c );
1275 *var_c.floatPtr = ( strlen( GetString( st->a ) ) == 0 );
1279 var_a = GetVariable( st->a );
1280 var_c = GetVariable( st->c );
1281 *var_c.floatPtr = ( GetEntity( *var_a.entityNumberPtr ) == NULL );
1285 var_a = GetVariable( st->a );
1286 var_c = GetVariable( st->c );
1287 *var_c.floatPtr = -*var_a.floatPtr;
1291 var_a = GetVariable( st->a );
1292 var_c = GetVariable( st->c );
1293 *var_c.vectorPtr = -*var_a.vectorPtr;
1297 var_a = GetVariable( st->a );
1298 var_c = GetVariable( st->c );
1299 *var_c.floatPtr = static_cast<int>( *var_a.floatPtr );
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 );
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 );
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 );
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 );
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 );
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 );
1348 var_c = GetVariable( st->c );
1349 *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) != 0 );
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 );
1363 var_a = GetVariable( st->a );
1364 var_b = GetVariable( st->b );
1365 *var_b.floatPtr += *var_a.floatPtr;
1369 var_a = GetVariable( st->a );
1370 var_b = GetVariable( st->b );
1371 *var_b.vectorPtr += *var_a.vectorPtr;
1375 var_a = GetVariable( st->a );
1376 var_b = GetVariable( st->b );
1377 *var_b.floatPtr -= *var_a.floatPtr;
1381 var_a = GetVariable( st->a );
1382 var_b = GetVariable( st->b );
1383 *var_b.vectorPtr -= *var_a.vectorPtr;
1387 var_a = GetVariable( st->a );
1388 var_b = GetVariable( st->b );
1389 *var_b.floatPtr *= *var_a.floatPtr;
1393 var_a = GetVariable( st->a );
1394 var_b = GetVariable( st->b );
1395 *var_b.vectorPtr *= *var_a.floatPtr;
1399 var_a = GetVariable( st->a );
1400 var_b = GetVariable( st->b );
1402 if ( *var_a.floatPtr == 0.0f ) {
1403 Warning( "Divide by zero" );
1404 *var_b.floatPtr = idMath::INFINITY;
1406 *var_b.floatPtr = *var_b.floatPtr / *var_a.floatPtr;
1411 var_a = GetVariable( st->a );
1412 var_b = GetVariable( st->b );
1414 if ( *var_a.floatPtr == 0.0f ) {
1415 Warning( "Divide by zero" );
1416 var_b.vectorPtr->Set( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY );
1418 *var_b.vectorPtr = *var_b.vectorPtr / *var_a.floatPtr;
1423 var_a = GetVariable( st->a );
1424 var_b = GetVariable( st->b );
1426 if ( *var_a.floatPtr == 0.0f ) {
1427 Warning( "Divide by zero" );
1428 *var_b.floatPtr = *var_a.floatPtr;
1430 *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) % static_cast<int>( *var_a.floatPtr );
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 );
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 );
1447 var_a = GetVariable( st->a );
1448 ( *var_a.floatPtr )++;
1452 var_a = GetVariable( st->a );
1453 obj = GetScriptObject( *var_a.entityNumberPtr );
1455 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1456 ( *var.floatPtr )++;
1461 var_a = GetVariable( st->a );
1462 ( *var_a.floatPtr )--;
1466 var_a = GetVariable( st->a );
1467 obj = GetScriptObject( *var_a.entityNumberPtr );
1469 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1470 ( *var.floatPtr )--;
1475 var_a = GetVariable( st->a );
1476 var_c = GetVariable( st->c );
1477 *var_c.floatPtr = ~static_cast<int>( *var_a.floatPtr );
1481 var_a = GetVariable( st->a );
1482 var_b = GetVariable( st->b );
1483 *var_b.floatPtr = *var_a.floatPtr;
1487 var_a = GetVariable( st->a );
1488 var_b = GetVariable( st->b );
1489 *var_b.entityNumberPtr = *var_a.entityNumberPtr;
1493 var_a = GetVariable( st->a );
1494 var_b = GetVariable( st->b );
1495 *var_b.intPtr = *var_a.intPtr;
1498 case OP_STORE_OBJENT:
1499 var_a = GetVariable( st->a );
1500 var_b = GetVariable( st->b );
1501 obj = GetScriptObject( *var_a.entityNumberPtr );
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;
1508 *var_b.entityNumberPtr = *var_a.entityNumberPtr;
1513 case OP_STORE_ENTOBJ:
1514 var_a = GetVariable( st->a );
1515 var_b = GetVariable( st->b );
1516 *var_b.entityNumberPtr = *var_a.entityNumberPtr;
1520 SetString( st->b, GetString( st->a ) );
1524 var_a = GetVariable( st->a );
1525 var_b = GetVariable( st->b );
1526 *var_b.vectorPtr = *var_a.vectorPtr;
1530 var_a = GetVariable( st->a );
1531 SetString( st->b, FloatToString( *var_a.floatPtr ) );
1535 var_a = GetVariable( st->a );
1536 SetString( st->b, *var_a.intPtr ? "true" : "false" );
1540 var_a = GetVariable( st->a );
1541 SetString( st->b, var_a.vectorPtr->ToString() );
1544 case OP_STORE_FTOBOOL:
1545 var_a = GetVariable( st->a );
1546 var_b = GetVariable( st->b );
1547 if ( *var_a.floatPtr != 0.0f ) {
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 );
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;
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;
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;
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;
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 );
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;
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 );
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 );
1622 idStr::Copynz( var_b.evalPtr->stringPtr, "false", MAX_STRING_LEN );
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 );
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;
1642 *var_b.evalPtr->intPtr = 0;
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 );
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;
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 );
1669 *var_b.evalPtr->entityNumberPtr = 0;
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;
1678 *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr;
1684 var_a = GetVariable( st->a );
1685 var_c = GetVariable( st->c );
1686 obj = GetScriptObject( *var_a.entityNumberPtr );
1688 var_c.evalPtr->bytePtr = &obj->data[ st->b->value.ptrOffset ];
1690 var_c.evalPtr->bytePtr = NULL;
1695 var_a = GetVariable( st->a );
1696 var_c = GetVariable( st->c );
1697 obj = GetScriptObject( *var_a.entityNumberPtr );
1699 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1700 *var_c.floatPtr = *var.floatPtr;
1702 *var_c.floatPtr = 0.0f;
1706 case OP_INDIRECT_ENT:
1707 var_a = GetVariable( st->a );
1708 var_c = GetVariable( st->c );
1709 obj = GetScriptObject( *var_a.entityNumberPtr );
1711 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1712 *var_c.entityNumberPtr = *var.entityNumberPtr;
1714 *var_c.entityNumberPtr = 0;
1718 case OP_INDIRECT_BOOL:
1719 var_a = GetVariable( st->a );
1720 var_c = GetVariable( st->c );
1721 obj = GetScriptObject( *var_a.entityNumberPtr );
1723 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1724 *var_c.intPtr = *var.intPtr;
1731 var_a = GetVariable( st->a );
1732 obj = GetScriptObject( *var_a.entityNumberPtr );
1734 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1735 SetString( st->c, var.stringPtr );
1737 SetString( st->c, "" );
1742 var_a = GetVariable( st->a );
1743 var_c = GetVariable( st->c );
1744 obj = GetScriptObject( *var_a.entityNumberPtr );
1746 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1747 *var_c.vectorPtr = *var.vectorPtr;
1749 var_c.vectorPtr->Zero();
1753 case OP_INDIRECT_OBJ:
1754 var_a = GetVariable( st->a );
1755 var_c = GetVariable( st->c );
1756 obj = GetScriptObject( *var_a.entityNumberPtr );
1758 *var_c.entityNumberPtr = 0;
1760 var.bytePtr = &obj->data[ st->b->value.ptrOffset ];
1761 *var_c.entityNumberPtr = *var.entityNumberPtr;
1766 var_a = GetVariable( st->a );
1767 Push( *var_a.intPtr );
1771 var_a = GetVariable( st->a );
1772 PushString( FloatToString( *var_a.floatPtr ) );
1776 var_a = GetVariable( st->a );
1777 floatVal = *var_a.intPtr;
1778 Push( *reinterpret_cast<int *>( &floatVal ) );
1782 var_a = GetVariable( st->a );
1783 if ( *var_a.floatPtr != 0.0f ) {
1791 var_a = GetVariable( st->a );
1792 PushString( var_a.vectorPtr->ToString() );
1796 var_a = GetVariable( st->a );
1797 PushString( *var_a.intPtr ? "true" : "false" );
1801 var_a = GetVariable( st->a );
1802 Push( *var_a.entityNumberPtr );
1806 PushString( GetString( st->a ) );
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 ) );
1817 var_a = GetVariable( st->a );
1818 Push( *var_a.entityNumberPtr );
1821 case OP_PUSH_OBJENT:
1822 var_a = GetVariable( st->a );
1823 Push( *var_a.entityNumberPtr );
1829 Error( "Bad opcode %i", st->op );