/* ==================== idInterpreter::LeaveFunction ==================== */ void idInterpreter::LeaveFunction( idVarDef *returnDef ) { prstack_t *stack; varEval_t ret; if ( callStackDepth <= 0 ) { Error( "prog stack underflow" ); } // return value if ( returnDef ) { switch( returnDef->Type() ) { case ev_string : gameLocal.program.ReturnString( GetString( returnDef ) ); break; case ev_vector : ret = GetVariable( returnDef ); gameLocal.program.ReturnVector( *ret.vectorPtr ); break; default : ret = GetVariable( returnDef ); gameLocal.program.ReturnInteger( *ret.intPtr ); } } // remove locals from the stack PopParms( currentFunction->locals ); assert( localstackUsed == localstackBase ); if ( debug ) { statement_t &line = gameLocal.program.GetStatement( instructionPointer ); gameLocal.Printf( "%d: %s(%d): exit %s", gameLocal.time, gameLocal.program.GetFilename( line.file ), line.linenumber, currentFunction->Name() ); if ( callStackDepth > 1 ) { gameLocal.Printf( " return to %s(line %d)\n", callStack[ callStackDepth - 1 ].f->Name(), gameLocal.program.GetStatement( callStack[ callStackDepth - 1 ].s ).linenumber ); } else { gameLocal.Printf( " done\n" ); } } // up stack callStackDepth--; stack = &callStack[ callStackDepth ]; currentFunction = stack->f; localstackBase = stack->stackbase; NextInstruction( stack->s ); if ( !callStackDepth ) { // all done doneProcessing = true; threadDying = true; currentFunction = 0; } }
/* ================ idInterpreter::EnterObjectFunction Calls a function on a script object. NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function. ================ */ void idInterpreter::EnterObjectFunction( idEntity *self, const function_t *func, bool clearStack ) { if ( clearStack ) { Reset(); } if ( popParms ) { PopParms( popParms ); popParms = 0; } Push( self->entityNumber + 1 ); EnterFunction( func, false ); }
/* ==================== idInterpreter::EnterFunction Returns the new program statement counter NOTE: If this is called from within a event called by this interpreter, the function arguments will be invalid after calling this function. ==================== */ void idInterpreter::EnterFunction( const function_t *func, bool clearStack ) { int c; prstack_t *stack; if( clearStack ) { Reset(); } if( popParms ) { PopParms( popParms ); popParms = 0; } if( callStackDepth >= MAX_STACK_DEPTH ) { Error( "call stack overflow" ); } stack = &callStack[ callStackDepth ]; stack->s = instructionPointer + 1; // point to the next instruction to execute stack->f = currentFunction; stack->stackbase = localstackBase; callStackDepth++; if( callStackDepth > maxStackDepth ) { maxStackDepth = callStackDepth; } if( !func ) { Error( "NULL function" ); } if( debug ) { if( currentFunction ) { gameLocal.Printf( "%d: call '%s' from '%s'(line %d)%s\n", gameLocal.time, func->Name(), currentFunction->Name(), gameLocal.program.GetStatement( instructionPointer ).linenumber, clearStack ? " clear stack" : "" ); } else { gameLocal.Printf( "%d: call '%s'%s\n", gameLocal.time, func->Name(), clearStack ? " clear stack" : "" ); } } currentFunction = func; assert( !func->eventdef ); NextInstruction( func->firstStatement ); // allocate space on the stack for locals // parms are already on stack c = func->locals - func->parmTotal; assert( c >= 0 ); if( localstackUsed + c > LOCALSTACK_SIZE ) { Error( "EnterFuncton: locals stack overflow\n" ); } // initialize local stack variables to zero memset( &localstack[ localstackUsed ], 0, c ); localstackUsed += c; localstackBase = localstackUsed - func->locals; if( localstackUsed > maxLocalstackUsed ) { maxLocalstackUsed = localstackUsed ; } }
/* ==================== idInterpreter::Execute ==================== */ bool idInterpreter::Execute( void ) { varEval_t var_a; varEval_t var_b; varEval_t var_c; varEval_t var; statement_t *st; int runaway; idThread *newThread; float floatVal; idScriptObject *obj; const function_t *func; if ( threadDying || !currentFunction ) { return true; } if ( multiFrameEvent ) { // move to previous instruction and call it again instructionPointer--; } runaway = 5000000; doneProcessing = false; while( !doneProcessing && !threadDying ) { instructionPointer++; if ( !--runaway ) { Error( "runaway loop error" ); } // next statement st = &gameLocal.program.GetStatement( instructionPointer ); switch( st->op ) { case OP_RETURN: LeaveFunction( st->a ); break; case OP_THREAD: newThread = new idThread( this, st->a->value.functionPtr, st->b->value.argSize ); newThread->Start(); // return the thread number to the script gameLocal.program.ReturnFloat( newThread->GetThreadNum() ); PopParms( st->b->value.argSize ); break; case OP_OBJTHREAD: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction ); assert( st->c->value.argSize == func->parmTotal ); newThread = new idThread( this, GetEntity( *var_a.entityNumberPtr ), func, func->parmTotal ); newThread->Start(); // return the thread number to the script gameLocal.program.ReturnFloat( newThread->GetThreadNum() ); } else { // return a null thread to the script gameLocal.program.ReturnFloat( 0.0f ); } PopParms( st->c->value.argSize ); break; case OP_CALL: EnterFunction( st->a->value.functionPtr, false ); break; case OP_EVENTCALL: CallEvent( st->a->value.functionPtr, st->b->value.argSize ); break; case OP_OBJECTCALL: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { func = obj->GetTypeDef()->GetFunction( st->b->value.virtualFunction ); EnterFunction( func, false ); } else { // return a 'safe' value gameLocal.program.ReturnVector( vec3_zero ); gameLocal.program.ReturnString( "" ); PopParms( st->c->value.argSize ); } break; case OP_SYSCALL: CallSysEvent( st->a->value.functionPtr, st->b->value.argSize ); break; case OP_IFNOT: var_a = GetVariable( st->a ); if ( *var_a.intPtr == 0 ) { NextInstruction( instructionPointer + st->b->value.jumpOffset ); } break; case OP_IF: var_a = GetVariable( st->a ); if ( *var_a.intPtr != 0 ) { NextInstruction( instructionPointer + st->b->value.jumpOffset ); } break; case OP_GOTO: NextInstruction( instructionPointer + st->a->value.jumpOffset ); break; case OP_ADD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.floatPtr + *var_b.floatPtr; break; case OP_ADD_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.vectorPtr + *var_b.vectorPtr; break; case OP_ADD_S: SetString( st->c, GetString( st->a ) ); AppendString( st->c, GetString( st->b ) ); break; case OP_ADD_FS: var_a = GetVariable( st->a ); SetString( st->c, FloatToString( *var_a.floatPtr ) ); AppendString( st->c, GetString( st->b ) ); break; case OP_ADD_SF: var_b = GetVariable( st->b ); SetString( st->c, GetString( st->a ) ); AppendString( st->c, FloatToString( *var_b.floatPtr ) ); break; case OP_ADD_VS: var_a = GetVariable( st->a ); SetString( st->c, var_a.vectorPtr->ToString() ); AppendString( st->c, GetString( st->b ) ); break; case OP_ADD_SV: var_b = GetVariable( st->b ); SetString( st->c, GetString( st->a ) ); AppendString( st->c, var_b.vectorPtr->ToString() ); break; case OP_SUB_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.floatPtr - *var_b.floatPtr; break; case OP_SUB_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.vectorPtr - *var_b.vectorPtr; break; case OP_MUL_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.floatPtr * *var_b.floatPtr; break; case OP_MUL_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = *var_a.vectorPtr * *var_b.vectorPtr; break; case OP_MUL_FV: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.floatPtr * *var_b.vectorPtr; break; case OP_MUL_VF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.vectorPtr = *var_a.vectorPtr * *var_b.floatPtr; break; case OP_DIV_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); if ( *var_b.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_c.floatPtr = idMath::INFINITY; } else { *var_c.floatPtr = *var_a.floatPtr / *var_b.floatPtr; } break; case OP_MOD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable ( st->c ); if ( *var_b.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_c.floatPtr = *var_a.floatPtr; } else { *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) % static_cast<int>( *var_b.floatPtr ); } break; case OP_BITAND: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) & static_cast<int>( *var_b.floatPtr ); break; case OP_BITOR: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ) | static_cast<int>( *var_b.floatPtr ); break; case OP_GE: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr >= *var_b.floatPtr ); break; case OP_LE: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr <= *var_b.floatPtr ); break; case OP_GT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr > *var_b.floatPtr ); break; case OP_LT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr < *var_b.floatPtr ); break; case OP_AND: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.floatPtr != 0.0f ); break; case OP_AND_BOOLF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.floatPtr != 0.0f ); break; case OP_AND_FBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) && ( *var_b.intPtr != 0 ); break; case OP_AND_BOOLBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) && ( *var_b.intPtr != 0 ); break; case OP_OR: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.floatPtr != 0.0f ); break; case OP_OR_BOOLF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.floatPtr != 0.0f ); break; case OP_OR_FBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != 0.0f ) || ( *var_b.intPtr != 0 ); break; case OP_OR_BOOLBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr != 0 ) || ( *var_b.intPtr != 0 ); break; case OP_NOT_BOOL: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.intPtr == 0 ); break; case OP_NOT_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr == 0.0f ); break; case OP_NOT_V: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.vectorPtr == vec3_zero ); break; case OP_NOT_S: var_c = GetVariable( st->c ); *var_c.floatPtr = ( strlen( GetString( st->a ) ) == 0 ); break; case OP_NOT_ENT: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( GetEntity( *var_a.entityNumberPtr ) == NULL ); break; case OP_NEG_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = -*var_a.floatPtr; break; case OP_NEG_V: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.vectorPtr = -*var_a.vectorPtr; break; case OP_INT_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = static_cast<int>( *var_a.floatPtr ); break; case OP_EQ_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr == *var_b.floatPtr ); break; case OP_EQ_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.vectorPtr == *var_b.vectorPtr ); break; case OP_EQ_S: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) == 0 ); break; case OP_EQ_E: case OP_EQ_EO: case OP_EQ_OE: case OP_EQ_OO: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.entityNumberPtr == *var_b.entityNumberPtr ); break; case OP_NE_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.floatPtr != *var_b.floatPtr ); break; case OP_NE_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.vectorPtr != *var_b.vectorPtr ); break; case OP_NE_S: var_c = GetVariable( st->c ); *var_c.floatPtr = ( idStr::Cmp( GetString( st->a ), GetString( st->b ) ) != 0 ); break; case OP_NE_E: case OP_NE_EO: case OP_NE_OE: case OP_NE_OO: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); var_c = GetVariable( st->c ); *var_c.floatPtr = ( *var_a.entityNumberPtr != *var_b.entityNumberPtr ); break; case OP_UADD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr += *var_a.floatPtr; break; case OP_UADD_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr += *var_a.vectorPtr; break; case OP_USUB_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr -= *var_a.floatPtr; break; case OP_USUB_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr -= *var_a.vectorPtr; break; case OP_UMUL_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr *= *var_a.floatPtr; break; case OP_UMUL_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr *= *var_a.floatPtr; break; case OP_UDIV_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_b.floatPtr = idMath::INFINITY; } else { *var_b.floatPtr = *var_b.floatPtr / *var_a.floatPtr; } break; case OP_UDIV_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr == 0.0f ) { Warning( "Divide by zero" ); var_b.vectorPtr->Set( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY ); } else { *var_b.vectorPtr = *var_b.vectorPtr / *var_a.floatPtr; } break; case OP_UMOD_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr == 0.0f ) { Warning( "Divide by zero" ); *var_b.floatPtr = *var_a.floatPtr; } else { *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) % static_cast<int>( *var_a.floatPtr ); } break; case OP_UOR_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) | static_cast<int>( *var_a.floatPtr ); break; case OP_UAND_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = static_cast<int>( *var_b.floatPtr ) & static_cast<int>( *var_a.floatPtr ); break; case OP_UINC_F: var_a = GetVariable( st->a ); ( *var_a.floatPtr )++; break; case OP_UINCP_F: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; ( *var.floatPtr )++; } break; case OP_UDEC_F: var_a = GetVariable( st->a ); ( *var_a.floatPtr )--; break; case OP_UDECP_F: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; ( *var.floatPtr )--; } break; case OP_COMP_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); *var_c.floatPtr = ~static_cast<int>( *var_a.floatPtr ); break; case OP_STORE_F: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = *var_a.floatPtr; break; case OP_STORE_ENT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.entityNumberPtr = *var_a.entityNumberPtr; break; case OP_STORE_BOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.intPtr = *var_a.intPtr; break; case OP_STORE_OBJENT: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( !obj ) { *var_b.entityNumberPtr = 0; } else if ( !obj->GetTypeDef()->Inherits( st->b->TypeDef() ) ) { //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->b->TypeDef()->Name() ); *var_b.entityNumberPtr = 0; } else { *var_b.entityNumberPtr = *var_a.entityNumberPtr; } break; case OP_STORE_OBJ: case OP_STORE_ENTOBJ: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.entityNumberPtr = *var_a.entityNumberPtr; break; case OP_STORE_S: SetString( st->b, GetString( st->a ) ); break; case OP_STORE_V: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.vectorPtr = *var_a.vectorPtr; break; case OP_STORE_FTOS: var_a = GetVariable( st->a ); SetString( st->b, FloatToString( *var_a.floatPtr ) ); break; case OP_STORE_BTOS: var_a = GetVariable( st->a ); SetString( st->b, *var_a.intPtr ? "true" : "false" ); break; case OP_STORE_VTOS: var_a = GetVariable( st->a ); SetString( st->b, var_a.vectorPtr->ToString() ); break; case OP_STORE_FTOBOOL: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); if ( *var_a.floatPtr != 0.0f ) { *var_b.intPtr = 1; } else { *var_b.intPtr = 0; } break; case OP_STORE_BOOLTOF: var_a = GetVariable( st->a ); var_b = GetVariable( st->b ); *var_b.floatPtr = static_cast<float>( *var_a.intPtr ); break; case OP_STOREP_F: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->floatPtr = *var_a.floatPtr; } break; case OP_STOREP_ENT: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; } break; case OP_STOREP_FLD: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->intPtr = *var_a.intPtr; } break; case OP_STOREP_BOOL: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->intPtr = *var_a.intPtr; } break; case OP_STOREP_S: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { idStr::Copynz( var_b.evalPtr->stringPtr, GetString( st->a ), MAX_STRING_LEN ); } break; case OP_STOREP_V: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->vectorPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->vectorPtr = *var_a.vectorPtr; } break; case OP_STOREP_FTOS: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { var_a = GetVariable( st->a ); idStr::Copynz( var_b.evalPtr->stringPtr, FloatToString( *var_a.floatPtr ), MAX_STRING_LEN ); } break; case OP_STOREP_BTOS: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { var_a = GetVariable( st->a ); if ( *var_a.floatPtr != 0.0f ) { idStr::Copynz( var_b.evalPtr->stringPtr, "true", MAX_STRING_LEN ); } else { idStr::Copynz( var_b.evalPtr->stringPtr, "false", MAX_STRING_LEN ); } } break; case OP_STOREP_VTOS: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->stringPtr ) { var_a = GetVariable( st->a ); idStr::Copynz( var_b.evalPtr->stringPtr, var_a.vectorPtr->ToString(), MAX_STRING_LEN ); } break; case OP_STOREP_FTOBOOL: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->intPtr ) { var_a = GetVariable( st->a ); if ( *var_a.floatPtr != 0.0f ) { *var_b.evalPtr->intPtr = 1; } else { *var_b.evalPtr->intPtr = 0; } } break; case OP_STOREP_BOOLTOF: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->floatPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->floatPtr = static_cast<float>( *var_a.intPtr ); } break; case OP_STOREP_OBJ: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { var_a = GetVariable( st->a ); *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; } break; case OP_STOREP_OBJENT: var_b = GetVariable( st->b ); if ( var_b.evalPtr && var_b.evalPtr->entityNumberPtr ) { var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( !obj ) { *var_b.evalPtr->entityNumberPtr = 0; // 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 // 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 // comes from an entity } else if ( !obj->GetTypeDef()->Inherits( st->c->TypeDef() ) ) { //Warning( "object '%s' cannot be converted to '%s'", obj->GetTypeName(), st->c->TypeDef()->Name() ); *var_b.evalPtr->entityNumberPtr = 0; } else { *var_b.evalPtr->entityNumberPtr = *var_a.entityNumberPtr; } } break; case OP_ADDRESS: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var_c.evalPtr->bytePtr = &obj->data[ st->b->value.ptrOffset ]; } else { var_c.evalPtr->bytePtr = NULL; } break; case OP_INDIRECT_F: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.floatPtr = *var.floatPtr; } else { *var_c.floatPtr = 0.0f; } break; case OP_INDIRECT_ENT: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.entityNumberPtr = *var.entityNumberPtr; } else { *var_c.entityNumberPtr = 0; } break; case OP_INDIRECT_BOOL: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.intPtr = *var.intPtr; } else { *var_c.intPtr = 0; } break; case OP_INDIRECT_S: var_a = GetVariable( st->a ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; SetString( st->c, var.stringPtr ); } else { SetString( st->c, "" ); } break; case OP_INDIRECT_V: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( obj ) { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.vectorPtr = *var.vectorPtr; } else { var_c.vectorPtr->Zero(); } break; case OP_INDIRECT_OBJ: var_a = GetVariable( st->a ); var_c = GetVariable( st->c ); obj = GetScriptObject( *var_a.entityNumberPtr ); if ( !obj ) { *var_c.entityNumberPtr = 0; } else { var.bytePtr = &obj->data[ st->b->value.ptrOffset ]; *var_c.entityNumberPtr = *var.entityNumberPtr; } break; case OP_PUSH_F: var_a = GetVariable( st->a ); Push( *var_a.intPtr ); break; case OP_PUSH_FTOS: var_a = GetVariable( st->a ); PushString( FloatToString( *var_a.floatPtr ) ); break; case OP_PUSH_BTOF: var_a = GetVariable( st->a ); floatVal = *var_a.intPtr; Push( *reinterpret_cast<int *>( &floatVal ) ); break; case OP_PUSH_FTOB: var_a = GetVariable( st->a ); if ( *var_a.floatPtr != 0.0f ) { Push( 1 ); } else { Push( 0 ); } break; case OP_PUSH_VTOS: var_a = GetVariable( st->a ); PushString( var_a.vectorPtr->ToString() ); break; case OP_PUSH_BTOS: var_a = GetVariable( st->a ); PushString( *var_a.intPtr ? "true" : "false" ); break; case OP_PUSH_ENT: var_a = GetVariable( st->a ); Push( *var_a.entityNumberPtr ); break; case OP_PUSH_S: PushString( GetString( st->a ) ); break; case OP_PUSH_V: var_a = GetVariable( st->a ); Push( *reinterpret_cast<int *>( &var_a.vectorPtr->x ) ); Push( *reinterpret_cast<int *>( &var_a.vectorPtr->y ) ); Push( *reinterpret_cast<int *>( &var_a.vectorPtr->z ) ); break; case OP_PUSH_OBJ: var_a = GetVariable( st->a ); Push( *var_a.entityNumberPtr ); break; case OP_PUSH_OBJENT: var_a = GetVariable( st->a ); Push( *var_a.entityNumberPtr ); break; case OP_BREAK: case OP_CONTINUE: default: Error( "Bad opcode %i", st->op ); break; } } return threadDying; }
/* ================ idInterpreter::CallSysEvent ================ */ void idInterpreter::CallSysEvent( const function_t *func, int argsize ) { int i; int j; varEval_t source; int pos; int start; intptr_t data[ D_EVENT_MAXARGS ]; const idEventDef *evdef; const char *format; if ( !func ) { Error( "NULL function" ); } assert( func->eventdef ); evdef = func->eventdef; start = localstackUsed - argsize; format = evdef->GetArgFormat(); for( j = 0, i = 0, pos = 0; ( pos < argsize ) || ( format[ i ] != 0 ); i++ ) { switch( format[ i ] ) { case D_EVENT_INTEGER : source.intPtr = ( int * )&localstack[ start + pos ]; *( int * )&data[ i ] = int( *source.floatPtr ); break; case D_EVENT_FLOAT : source.intPtr = ( int * )&localstack[ start + pos ]; *( float * )&data[ i ] = *source.floatPtr; break; case D_EVENT_VECTOR : source.intPtr = ( int * )&localstack[ start + pos ]; *( idVec3 ** )&data[ i ] = source.vectorPtr; break; case D_EVENT_STRING : *( const char ** )&data[ i ] = ( char * )&localstack[ start + pos ]; break; case D_EVENT_ENTITY : source.intPtr = ( int * )&localstack[ start + pos ]; *( idEntity ** )&data[ i ] = GetEntity( *source.entityNumberPtr ); if ( !*( idEntity ** )&data[ i ] ) { Warning( "Entity not found for event '%s'. Terminating thread.", evdef->GetName() ); threadDying = true; PopParms( argsize ); return; } break; case D_EVENT_ENTITY_NULL : source.intPtr = ( int * )&localstack[ start + pos ]; *( idEntity ** )&data[ i ] = GetEntity( *source.entityNumberPtr ); break; case D_EVENT_TRACE : Error( "trace type not supported from script for '%s' event.", evdef->GetName() ); break; default : Error( "Invalid arg format string for '%s' event.", evdef->GetName() ); break; } pos += func->parmSize[ j++ ]; } popParms = argsize; thread->ProcessEventArgPtr( evdef, data ); if ( popParms ) { PopParms( popParms ); } popParms = 0; }
/* ================ idInterpreter::CallEvent ================ */ void idInterpreter::CallEvent( const function_t *func, int argsize ) { int i; int j; varEval_t var; int pos; int start; intptr_t data[ D_EVENT_MAXARGS ]; const idEventDef *evdef; const char *format; if ( !func ) { Error( "NULL function" ); } assert( func->eventdef ); evdef = func->eventdef; start = localstackUsed - argsize; var.intPtr = ( int * )&localstack[ start ]; eventEntity = GetEntity( *var.entityNumberPtr ); if ( !eventEntity || !eventEntity->RespondsTo( *evdef ) ) { if ( eventEntity && developer.GetBool() ) { // give a warning in developer mode Warning( "Function '%s' not supported on entity '%s'", evdef->GetName(), eventEntity->name.c_str() ); } // always return a safe value when an object doesn't exist switch( evdef->GetReturnType() ) { case D_EVENT_INTEGER : gameLocal.program.ReturnInteger( 0 ); break; case D_EVENT_FLOAT : gameLocal.program.ReturnFloat( 0 ); break; case D_EVENT_VECTOR : gameLocal.program.ReturnVector( vec3_zero ); break; case D_EVENT_STRING : gameLocal.program.ReturnString( "" ); break; case D_EVENT_ENTITY : case D_EVENT_ENTITY_NULL : gameLocal.program.ReturnEntity( ( idEntity * )NULL ); break; case D_EVENT_TRACE : default: // unsupported data type break; } PopParms( argsize ); eventEntity = NULL; return; } format = evdef->GetArgFormat(); // The sizeof(int) is a event entity that is the first (implied?) argument. // It is stored on the stack as an int, not a pointer to one. for( j = 0, i = 0, pos = sizeof(int); ( pos < argsize ) || ( format[ i ] != 0 ); i++ ) { switch( format[ i ] ) { case D_EVENT_INTEGER : var.intPtr = ( int * )&localstack[ start + pos ]; data[ i ] = int( *var.floatPtr ); break; case D_EVENT_FLOAT : var.intPtr = ( int * )&localstack[ start + pos ]; ( *( float * )&data[ i ] ) = *var.floatPtr; break; case D_EVENT_VECTOR : var.intPtr = ( int * )&localstack[ start + pos ]; ( *( idVec3 ** )&data[ i ] ) = var.vectorPtr; break; case D_EVENT_STRING : ( *( const char ** )&data[ i ] ) = ( char * )&localstack[ start + pos ]; break; case D_EVENT_ENTITY : var.intPtr = ( int * )&localstack[ start + pos ]; ( *( idEntity ** )&data[ i ] ) = GetEntity( *var.entityNumberPtr ); if ( !( *( idEntity ** )&data[ i ] ) ) { Warning( "Entity not found for event '%s'. Terminating thread.", evdef->GetName() ); threadDying = true; PopParms( argsize ); return; } break; case D_EVENT_ENTITY_NULL : var.intPtr = ( int * )&localstack[ start + pos ]; ( *( idEntity ** )&data[ i ] ) = GetEntity( *var.entityNumberPtr ); break; case D_EVENT_TRACE : Error( "trace type not supported from script for '%s' event.", evdef->GetName() ); break; default : Error( "Invalid arg format string for '%s' event.", evdef->GetName() ); break; } pos += func->parmSize[ j++ ]; } popParms = argsize; eventEntity->ProcessEventArgPtr( evdef, data ); if ( !multiFrameEvent ) { if ( popParms ) { PopParms( popParms ); } eventEntity = NULL; } else { doneProcessing = true; } popParms = 0; }