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