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 }