]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/game/script/Script_Program.cpp
Various Mac OS X tweaks to get this to build. Probably breaking things.
[icculus/iodoom3.git] / neo / game / script / Script_Program.cpp
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 // simple types.  function types are dynamically allocated
35 idTypeDef       type_void( ev_void, &def_void, "void", 0, NULL );
36 idTypeDef       type_scriptevent( ev_scriptevent, &def_scriptevent, "scriptevent", sizeof( void * ), NULL );
37 idTypeDef       type_namespace( ev_namespace, &def_namespace, "namespace", sizeof( void * ), NULL );
38 idTypeDef       type_string( ev_string, &def_string, "string", MAX_STRING_LEN, NULL );
39 idTypeDef       type_float( ev_float, &def_float, "float", sizeof( float ), NULL );
40 idTypeDef       type_vector( ev_vector, &def_vector, "vector", sizeof( idVec3 ), NULL );
41 idTypeDef       type_entity( ev_entity, &def_entity, "entity", sizeof( int * ), NULL );                                 // stored as entity number pointer
42 idTypeDef       type_field( ev_field, &def_field, "field", sizeof( void * ), NULL );
43 idTypeDef       type_function( ev_function, &def_function, "function", sizeof( void * ), &type_void );
44 idTypeDef       type_virtualfunction( ev_virtualfunction, &def_virtualfunction, "virtual function", sizeof( int ), NULL );
45 idTypeDef       type_pointer( ev_pointer, &def_pointer, "pointer", sizeof( void * ), NULL );
46 idTypeDef       type_object( ev_object, &def_object, "object", sizeof( int * ), NULL );                                 // stored as entity number pointer
47 idTypeDef       type_jumpoffset( ev_jumpoffset, &def_jumpoffset, "<jump>", sizeof( int ), NULL );               // only used for jump opcodes
48 idTypeDef       type_argsize( ev_argsize, &def_argsize, "<argsize>", sizeof( int ), NULL );                             // only used for function call and thread opcodes
49 idTypeDef       type_boolean( ev_boolean, &def_boolean, "boolean", sizeof( int ), NULL );
50
51 idVarDef        def_void( &type_void );
52 idVarDef        def_scriptevent( &type_scriptevent );
53 idVarDef        def_namespace( &type_namespace );
54 idVarDef        def_string( &type_string );
55 idVarDef        def_float( &type_float );
56 idVarDef        def_vector( &type_vector );
57 idVarDef        def_entity( &type_entity );
58 idVarDef        def_field( &type_field );
59 idVarDef        def_function( &type_function );
60 idVarDef        def_virtualfunction( &type_virtualfunction );
61 idVarDef        def_pointer( &type_pointer );
62 idVarDef        def_object( &type_object );
63 idVarDef        def_jumpoffset( &type_jumpoffset );             // only used for jump opcodes
64 idVarDef        def_argsize( &type_argsize );
65 idVarDef        def_boolean( &type_boolean );
66
67 /***********************************************************************
68
69   function_t
70
71 ***********************************************************************/
72
73 /*
74 ================
75 function_t::function_t
76 ================
77 */
78 function_t::function_t() {
79         Clear();
80 }
81
82 /*
83 ================
84 function_t::Allocated
85 ================
86 */
87 size_t function_t::Allocated( void ) const {
88         return name.Allocated() + parmSize.Allocated();
89 }
90
91 /*
92 ================
93 function_t::SetName
94 ================
95 */
96 void function_t::SetName( const char *name ) {
97         this->name = name;
98 }
99
100 /*
101 ================
102 function_t::Name
103 ================
104 */
105 const char *function_t::Name( void ) const {
106         return name;
107 }
108
109 /*
110 ================
111 function_t::Clear
112 ================
113 */
114 void function_t::Clear( void ) {
115         eventdef                = NULL;
116         def                             = NULL;
117         type                    = NULL;
118         firstStatement  = 0;
119         numStatements   = 0;
120         parmTotal               = 0;
121         locals                  = 0;
122         filenum                 = 0;
123         name.Clear();
124         parmSize.Clear();
125 }
126
127 /***********************************************************************
128
129   idTypeDef
130
131 ***********************************************************************/
132
133 /*
134 ================
135 idTypeDef::idTypeDef
136 ================
137 */
138 idTypeDef::idTypeDef( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) {
139         name            = ename;
140         type            = etype;
141         def                     = edef;
142         size            = esize;
143         auxType         = aux;
144         
145         parmTypes.SetGranularity( 1 );
146         parmNames.SetGranularity( 1 );
147         functions.SetGranularity( 1 );
148 }
149
150 /*
151 ================
152 idTypeDef::idTypeDef
153 ================
154 */
155 idTypeDef::idTypeDef( const idTypeDef &other ) {
156         *this = other;
157 }
158
159 /*
160 ================
161 idTypeDef::operator=
162 ================
163 */
164 void idTypeDef::operator=( const idTypeDef& other ) {
165         type            = other.type;
166         def                     = other.def;
167         name            = other.name;
168         size            = other.size;
169         auxType         = other.auxType;
170         parmTypes       = other.parmTypes;
171         parmNames       = other.parmNames;
172         functions       = other.functions;
173 }
174
175 /*
176 ================
177 idTypeDef::Allocated
178 ================
179 */
180 size_t idTypeDef::Allocated( void ) const {
181         size_t memsize;
182         int i;
183
184         memsize = name.Allocated() + parmTypes.Allocated() + parmNames.Allocated() + functions.Allocated();
185         for( i = 0; i < parmTypes.Num(); i++ ) {
186                 memsize += parmNames[ i ].Allocated();
187         }
188
189         return memsize;
190 }
191
192 /*
193 ================
194 idTypeDef::Inherits
195
196 Returns true if basetype is an ancestor of this type.
197 ================
198 */
199 bool idTypeDef::Inherits( const idTypeDef *basetype ) const {
200         idTypeDef *superType;
201
202         if ( type != ev_object ) {
203                 return false;
204         }
205
206         if ( this == basetype ) {
207                 return true;
208         }
209         for( superType = auxType; superType != NULL; superType = superType->auxType ) {
210                 if ( superType == basetype ) {
211                         return true;
212                 }
213         }
214
215         return false;
216 }
217
218 /*
219 ================
220 idTypeDef::MatchesType
221
222 Returns true if both types' base types and parameters match
223 ================
224 */
225 bool idTypeDef::MatchesType( const idTypeDef &matchtype ) const {
226         int i;
227
228         if ( this == &matchtype ) {
229                 return true;
230         }
231
232         if ( ( type != matchtype.type ) || ( auxType != matchtype.auxType ) ) {
233                 return false;
234         }
235
236         if ( parmTypes.Num() != matchtype.parmTypes.Num() ) {
237                 return false;
238         }
239
240         for( i = 0; i < matchtype.parmTypes.Num(); i++ ) {
241                 if ( parmTypes[ i ] != matchtype.parmTypes[ i ] ) {
242                         return false;
243                 }
244         }
245
246         return true;
247 }
248
249 /*
250 ================
251 idTypeDef::MatchesVirtualFunction
252
253 Returns true if both functions' base types and parameters match
254 ================
255 */
256 bool idTypeDef::MatchesVirtualFunction( const idTypeDef &matchfunc ) const {
257         int i;
258
259         if ( this == &matchfunc ) {
260                 return true;
261         }
262
263         if ( ( type != matchfunc.type ) || ( auxType != matchfunc.auxType ) ) {
264                 return false;
265         }
266
267         if ( parmTypes.Num() != matchfunc.parmTypes.Num() ) {
268                 return false;
269         }
270
271         if ( parmTypes.Num() > 0 ) {
272                 if ( !parmTypes[ 0 ]->Inherits( matchfunc.parmTypes[ 0 ] ) ) {
273                         return false;
274                 }
275         }
276
277         for( i = 1; i < matchfunc.parmTypes.Num(); i++ ) {
278                 if ( parmTypes[ i ] != matchfunc.parmTypes[ i ] ) {
279                         return false;
280                 }
281         }
282
283         return true;
284 }
285
286 /*
287 ================
288 idTypeDef::AddFunctionParm
289
290 Adds a new parameter for a function type.
291 ================
292 */
293 void idTypeDef::AddFunctionParm( idTypeDef *parmtype, const char *name ) {
294         if ( type != ev_function ) {
295                 throw idCompileError( "idTypeDef::AddFunctionParm : tried to add parameter on non-function type" );
296         }
297
298         parmTypes.Append( parmtype );
299         idStr &parmName = parmNames.Alloc();
300         parmName = name;
301 }
302
303 /*
304 ================
305 idTypeDef::AddField
306
307 Adds a new field to an object type.
308 ================
309 */
310 void idTypeDef::AddField( idTypeDef *fieldtype, const char *name ) {
311         if ( type != ev_object ) {
312                 throw idCompileError( "idTypeDef::AddField : tried to add field to non-object type" );
313         }
314
315         parmTypes.Append( fieldtype );
316         idStr &parmName = parmNames.Alloc();
317         parmName = name;
318
319         if ( fieldtype->FieldType()->Inherits( &type_object ) ) {
320                 size += type_object.Size();
321         } else {
322                 size += fieldtype->FieldType()->Size();
323         }
324 }
325
326 /*
327 ================
328 idTypeDef::SetName
329 ================
330 */
331 void idTypeDef::SetName( const char *newname ) {
332         name = newname;
333 }
334
335 /*
336 ================
337 idTypeDef::Name
338 ================
339 */
340 const char *idTypeDef::Name( void ) const {
341         return name;
342 }
343
344 /*
345 ================
346 idTypeDef::Type
347 ================
348 */
349 etype_t idTypeDef::Type( void ) const {
350         return type;
351 }
352
353 /*
354 ================
355 idTypeDef::Size
356 ================
357 */
358 int idTypeDef::Size( void ) const {
359         return size;
360 }
361
362 /*
363 ================
364 idTypeDef::SuperClass
365
366 If type is an object, then returns the object's superclass
367 ================
368 */
369 idTypeDef *idTypeDef::SuperClass( void ) const {
370         if ( type != ev_object ) {
371                 throw idCompileError( "idTypeDef::SuperClass : tried to get superclass of a non-object type" );
372         }
373
374         return auxType;
375 }
376
377 /*
378 ================
379 idTypeDef::ReturnType
380
381 If type is a function, then returns the function's return type
382 ================
383 */
384 idTypeDef *idTypeDef::ReturnType( void ) const {
385         if ( type != ev_function ) {
386                 throw idCompileError( "idTypeDef::ReturnType: tried to get return type on non-function type" );
387         }
388
389         return auxType;
390 }
391
392 /*
393 ================
394 idTypeDef::SetReturnType
395
396 If type is a function, then sets the function's return type
397 ================
398 */
399 void idTypeDef::SetReturnType( idTypeDef *returntype ) {
400         if ( type != ev_function ) {
401                 throw idCompileError( "idTypeDef::SetReturnType: tried to set return type on non-function type" );
402         }
403
404         auxType = returntype;
405 }
406
407 /*
408 ================
409 idTypeDef::FieldType
410
411 If type is a field, then returns it's type
412 ================
413 */
414 idTypeDef *idTypeDef::FieldType( void ) const {
415         if ( type != ev_field ) {
416                 throw idCompileError( "idTypeDef::FieldType: tried to get field type on non-field type" );
417         }
418
419         return auxType;
420 }
421
422 /*
423 ================
424 idTypeDef::SetFieldType
425
426 If type is a field, then sets the function's return type
427 ================
428 */
429 void idTypeDef::SetFieldType( idTypeDef *fieldtype ) {
430         if ( type != ev_field ) {
431                 throw idCompileError( "idTypeDef::SetFieldType: tried to set return type on non-function type" );
432         }
433
434         auxType = fieldtype;
435 }
436
437 /*
438 ================
439 idTypeDef::PointerType
440
441 If type is a pointer, then returns the type it points to
442 ================
443 */
444 idTypeDef *idTypeDef::PointerType( void ) const {
445         if ( type != ev_pointer ) {
446                 throw idCompileError( "idTypeDef::PointerType: tried to get pointer type on non-pointer" );
447         }
448
449         return auxType;
450 }
451
452 /*
453 ================
454 idTypeDef::SetPointerType
455
456 If type is a pointer, then sets the pointer's type
457 ================
458 */
459 void idTypeDef::SetPointerType( idTypeDef *pointertype ) {
460         if ( type != ev_pointer ) {
461                 throw idCompileError( "idTypeDef::SetPointerType: tried to set type on non-pointer" );
462         }
463
464         auxType = pointertype;
465 }
466
467 /*
468 ================
469 idTypeDef::NumParameters
470 ================
471 */
472 int idTypeDef::NumParameters( void ) const {
473         return parmTypes.Num();
474 }
475
476 /*
477 ================
478 idTypeDef::GetParmType
479 ================
480 */
481 idTypeDef *idTypeDef::GetParmType( int parmNumber ) const {
482         assert( parmNumber >= 0 );
483         assert( parmNumber < parmTypes.Num() );
484         return parmTypes[ parmNumber ];
485 }
486
487 /*
488 ================
489 idTypeDef::GetParmName
490 ================
491 */
492 const char *idTypeDef::GetParmName( int parmNumber ) const {
493         assert( parmNumber >= 0 );
494         assert( parmNumber < parmTypes.Num() );
495         return parmNames[ parmNumber ];
496 }
497
498 /*
499 ================
500 idTypeDef::NumFunctions
501 ================
502 */
503 int idTypeDef::NumFunctions( void ) const {
504         return functions.Num();
505 }
506
507 /*
508 ================
509 idTypeDef::GetFunctionNumber
510 ================
511 */
512 int idTypeDef::GetFunctionNumber( const function_t *func ) const {
513         int i;
514
515         for( i = 0; i < functions.Num(); i++ ) {
516                 if ( functions[ i ] == func ) {
517                         return i;
518                 }
519         }
520         return -1;
521 }
522
523 /*
524 ================
525 idTypeDef::GetFunction
526 ================
527 */
528 const function_t *idTypeDef::GetFunction( int funcNumber ) const {
529         assert( funcNumber >= 0 );
530         assert( funcNumber < functions.Num() );
531         return functions[ funcNumber ];
532 }
533
534 /*
535 ================
536 idTypeDef::AddFunction
537 ================
538 */
539 void idTypeDef::AddFunction( const function_t *func ) {
540         int i;
541
542         for( i = 0; i < functions.Num(); i++ ) {
543                 if ( !strcmp( functions[ i ]->def->Name(), func->def->Name() ) ) {
544                         if ( func->def->TypeDef()->MatchesVirtualFunction( *functions[ i ]->def->TypeDef() ) ) {
545                                 functions[ i ] = func;
546                                 return;
547                         }
548                 }
549         }
550         functions.Append( func );
551 }
552
553 /***********************************************************************
554
555   idVarDef
556
557 ***********************************************************************/
558
559 /*
560 ================
561 idVarDef::idVarDef()
562 ================
563 */
564 idVarDef::idVarDef( idTypeDef *typeptr ) {
565         typeDef         = typeptr;
566         num                     = 0;
567         scope           = NULL;
568         numUsers        = 0;
569         initialized = idVarDef::uninitialized;
570         memset( &value, 0, sizeof( value ) );
571         name            = NULL;
572         next            = NULL;
573 }
574
575 /*
576 ============
577 idVarDef::~idVarDef
578 ============
579 */
580 idVarDef::~idVarDef() {
581         if ( name ) {
582                 name->RemoveDef( this );
583         }
584 }
585
586 /*
587 ============
588 idVarDef::Name
589 ============
590 */
591 const char *idVarDef::Name( void ) const {
592         return name->Name();
593 }
594
595 /*
596 ============
597 idVarDef::GlobalName
598 ============
599 */
600 const char *idVarDef::GlobalName( void ) const {
601         if ( scope != &def_namespace ) {
602                 return va( "%s::%s", scope->GlobalName(), name->Name() );
603         } else {
604                 return name->Name();
605         }
606 }
607
608 /*
609 ============
610 idVarDef::DepthOfScope
611 ============
612 */
613 int idVarDef::DepthOfScope( const idVarDef *otherScope ) const {
614         const idVarDef *def;
615         int depth;
616
617         depth = 1;
618         for( def = otherScope; def != NULL; def = def->scope ) {
619                 if ( def == scope ) {
620                         return depth;
621                 }
622                 depth++;
623         }
624
625         return 0;
626 }
627
628 /*
629 ============
630 idVarDef::SetFunction
631 ============
632 */
633 void idVarDef::SetFunction( function_t *func ) {
634         assert( typeDef );
635         initialized = initializedConstant;
636         assert( typeDef->Type() == ev_function );
637         value.functionPtr = func;
638 }
639
640 /*
641 ============
642 idVarDef::SetObject
643 ============
644 */
645 void idVarDef::SetObject( idScriptObject *object ) {
646         assert( typeDef );
647         initialized = initialized;
648         assert( typeDef->Inherits( &type_object ) );
649         *value.objectPtrPtr = object;
650 }
651
652 /*
653 ============
654 idVarDef::SetValue
655 ============
656 */
657 void idVarDef::SetValue( const eval_t &_value, bool constant ) {
658         assert( typeDef );
659         if ( constant ) {
660                 initialized = initializedConstant;
661         } else {
662                 initialized = initializedVariable;
663         }
664
665         switch( typeDef->Type() ) {
666         case ev_pointer :
667         case ev_boolean :
668         case ev_field :
669                 *value.intPtr = _value._int;
670                 break;
671
672         case ev_jumpoffset :
673                 value.jumpOffset = _value._int;
674                 break;
675
676         case ev_argsize :
677                 value.argSize = _value._int;
678                 break;
679
680         case ev_entity :
681                 *value.entityNumberPtr = _value.entity;
682                 break;
683
684         case ev_string :
685                 idStr::Copynz( value.stringPtr, _value.stringPtr, MAX_STRING_LEN );
686                 break;
687
688         case ev_float :
689                 *value.floatPtr = _value._float;
690                 break;
691
692         case ev_vector :
693                 value.vectorPtr->x = _value.vector[ 0 ];
694                 value.vectorPtr->y = _value.vector[ 1 ];
695                 value.vectorPtr->z = _value.vector[ 2 ];
696                 break;
697
698         case ev_function :
699                 value.functionPtr = _value.function;
700                 break;
701
702         case ev_virtualfunction :
703                 value.virtualFunction = _value._int;
704                 break;
705
706         case ev_object :
707                 *value.entityNumberPtr = _value.entity;
708                 break;
709
710         default :
711                 throw idCompileError( va( "weird type on '%s'", Name() ) );
712                 break;
713         }
714 }
715
716 /*
717 ============
718 idVarDef::SetString
719 ============
720 */
721 void idVarDef::SetString( const char *string, bool constant ) {
722         if ( constant ) {
723                 initialized = initializedConstant;
724         } else {
725                 initialized = initializedVariable;
726         }
727         
728         assert( typeDef && ( typeDef->Type() == ev_string ) );
729         idStr::Copynz( value.stringPtr, string, MAX_STRING_LEN );
730 }
731
732 /*
733 ============
734 idVarDef::PrintInfo
735 ============
736 */
737 void idVarDef::PrintInfo( idFile *file, int instructionPointer ) const {
738         statement_t     *jumpst;
739         int                     jumpto;
740         etype_t         etype;
741         int                     i;
742         int                     len;
743         const char      *ch;
744
745         if ( initialized == initializedConstant ) {
746                 file->Printf( "const " );
747         }
748
749         etype = typeDef->Type();
750         switch( etype ) {
751         case ev_jumpoffset :
752                 jumpto = instructionPointer + value.jumpOffset;
753                 jumpst = &gameLocal.program.GetStatement( jumpto );
754                 file->Printf( "address %d [%s(%d)]", jumpto, gameLocal.program.GetFilename( jumpst->file ), jumpst->linenumber );
755                 break;
756
757         case ev_function :
758                 if ( value.functionPtr->eventdef ) {
759                         file->Printf( "event %s", GlobalName() );
760                 } else {
761                         file->Printf( "function %s", GlobalName() );
762                 }
763                 break;
764
765         case ev_field :
766                 file->Printf( "field %d", value.ptrOffset );
767                 break;
768
769         case ev_argsize:
770                 file->Printf( "args %d", value.argSize );
771                 break;
772
773         default:
774                 file->Printf( "%s ", typeDef->Name() );
775                 if ( initialized == initializedConstant ) {
776                         switch( etype ) {
777                         case ev_string :
778                                 file->Printf( "\"" );
779                                 len = strlen( value.stringPtr );
780                                 ch = value.stringPtr;
781                                 for( i = 0; i < len; i++, ch++ ) {
782                                         if ( idStr::CharIsPrintable( *ch ) ) {
783                                                 file->Printf( "%c", *ch );
784                                         } else if ( *ch == '\n' ) {
785                                                 file->Printf( "\\n" );
786                                         } else {
787                                                 file->Printf( "\\x%.2x", static_cast<int>( *ch ) );
788                                         }
789                                 }
790                                 file->Printf( "\"" );
791                                 break;
792
793                         case ev_vector :
794                                 file->Printf( "'%s'", value.vectorPtr->ToString() );
795                                 break;
796
797                         case ev_float :
798                 file->Printf( "%f", *value.floatPtr );
799                                 break;
800
801                         case ev_virtualfunction :
802                                 file->Printf( "vtable[ %d ]", value.virtualFunction );
803                                 break;
804
805                         default :
806                                 file->Printf( "%d", *value.intPtr );
807                                 break;
808                         }
809                 } else if ( initialized == stackVariable ) {
810                         file->Printf( "stack[%d]", value.stackOffset );
811                 } else {
812                         file->Printf( "global[%d]", num );
813                 }
814                 break;
815         }
816 }
817
818 /***********************************************************************
819
820   idVarDef
821
822 ***********************************************************************/
823
824 /*
825 ============
826 idVarDefName::AddDef
827 ============
828 */
829 void idVarDefName::AddDef( idVarDef *def ) {
830         assert( def->next == NULL );
831         def->name = this;
832         def->next = defs;
833         defs = def;
834 }
835
836 /*
837 ============
838 idVarDefName::RemoveDef
839 ============
840 */
841 void idVarDefName::RemoveDef( idVarDef *def ) {
842         if ( defs == def ) {
843                 defs = def->next;
844         } else {
845                 for ( idVarDef *d = defs; d->next != NULL; d = d->next ) {
846                         if ( d->next == def ) {
847                                 d->next = def->next;
848                                 break;
849                         }
850                 }
851         }
852         def->next = NULL;
853         def->name = NULL;
854 }
855
856 /***********************************************************************
857
858   idScriptObject
859
860 ***********************************************************************/
861
862 /*
863 ============
864 idScriptObject::idScriptObject
865 ============
866 */
867 idScriptObject::idScriptObject() {
868         data = NULL;
869         type = &type_object;
870 }
871
872 /*
873 ============
874 idScriptObject::~idScriptObject
875 ============
876 */
877 idScriptObject::~idScriptObject() {
878         Free();
879 }
880
881 /*
882 ============
883 idScriptObject::Free
884 ============
885 */
886 void idScriptObject::Free( void ) {
887         if ( data ) {
888                 Mem_Free( data );
889         }
890
891         data = NULL;
892         type = &type_object;
893 }
894
895 /*
896 ================
897 idScriptObject::Save
898 ================
899 */
900 void idScriptObject::Save( idSaveGame *savefile ) const {
901         size_t size;
902
903         if ( type == &type_object && data == NULL ) {
904                 // Write empty string for uninitialized object
905                 savefile->WriteString( "" );
906         } else {
907                 savefile->WriteString( type->Name() );
908                 size = type->Size();
909                 savefile->WriteInt( size );
910                 savefile->Write( data, size );
911         }
912 }
913
914 /*
915 ================
916 idScriptObject::Restore
917 ================
918 */
919 void idScriptObject::Restore( idRestoreGame *savefile ) {
920         idStr typeName;
921         size_t size;
922
923         savefile->ReadString( typeName );
924
925         // Empty string signals uninitialized object
926         if ( typeName.Length() == 0 ) {
927                 return;
928         }
929
930         if ( !SetType( typeName ) ) {
931                 savefile->Error( "idScriptObject::Restore: failed to restore object of type '%s'.", typeName.c_str() );
932         }
933
934         savefile->ReadInt( (int &)size );
935         if ( size != type->Size() ) {
936                 savefile->Error( "idScriptObject::Restore: size of object '%s' doesn't match size in save game.", typeName.c_str() );
937         }
938
939         savefile->Read( data, size );
940 }
941
942 /*
943 ============
944 idScriptObject::SetType
945
946 Allocates an object and initializes memory.
947 ============
948 */
949 bool idScriptObject::SetType( const char *typeName ) {
950         size_t size;
951         idTypeDef *newtype;
952
953         // lookup the type
954         newtype = gameLocal.program.FindType( typeName );
955
956         // only allocate memory if the object type changes
957         if ( newtype != type ) {        
958                 Free();
959                 if ( !newtype ) {
960                         gameLocal.Warning( "idScriptObject::SetType: Unknown type '%s'", typeName );
961                         return false;
962                 }
963
964                 if ( !newtype->Inherits( &type_object ) ) {
965                         gameLocal.Warning( "idScriptObject::SetType: Can't create object of type '%s'.  Must be an object type.", newtype->Name() );
966                         return false;
967                 }
968
969                 // set the type
970                 type = newtype;
971
972                 // allocate the memory
973                 size = type->Size();
974                 data = ( byte * )Mem_Alloc( size );
975         }
976
977         // init object memory
978         ClearObject();
979
980         return true;
981 }
982
983 /*
984 ============
985 idScriptObject::ClearObject
986
987 Resets the memory for the script object without changing its type.
988 ============
989 */
990 void idScriptObject::ClearObject( void ) {
991         size_t size;
992
993         if ( type != &type_object ) {
994                 // init object memory
995                 size = type->Size();
996                 memset( data, 0, size );
997         }
998 }
999
1000 /*
1001 ============
1002 idScriptObject::HasObject
1003 ============
1004 */
1005 bool idScriptObject::HasObject( void ) const {
1006         return ( type != &type_object );
1007 }
1008
1009 /*
1010 ============
1011 idScriptObject::GetTypeDef
1012 ============
1013 */
1014 idTypeDef *idScriptObject::GetTypeDef( void ) const {
1015         return type;
1016 }
1017
1018 /*
1019 ============
1020 idScriptObject::GetTypeName
1021 ============
1022 */
1023 const char *idScriptObject::GetTypeName( void ) const {
1024         return type->Name();
1025 }
1026
1027 /*
1028 ============
1029 idScriptObject::GetConstructor
1030 ============
1031 */
1032 const function_t *idScriptObject::GetConstructor( void ) const {
1033         const function_t *func;
1034
1035         func = GetFunction( "init" );
1036         return func;
1037 }
1038
1039 /*
1040 ============
1041 idScriptObject::GetDestructor
1042 ============
1043 */
1044 const function_t *idScriptObject::GetDestructor( void ) const {
1045         const function_t *func;
1046
1047         func = GetFunction( "destroy" );
1048         return func;
1049 }
1050
1051 /*
1052 ============
1053 idScriptObject::GetFunction
1054 ============
1055 */
1056 const function_t *idScriptObject::GetFunction( const char *name ) const {
1057         const function_t *func;
1058
1059         if ( type == &type_object ) {
1060                 return NULL;
1061         }
1062
1063         func = gameLocal.program.FindFunction( name, type );
1064         return func;
1065 }
1066
1067 /*
1068 ============
1069 idScriptObject::GetVariable
1070 ============
1071 */
1072 byte *idScriptObject::GetVariable( const char *name, etype_t etype ) const {
1073         int                             i;
1074         int                             pos;
1075         const idTypeDef *t;
1076         const idTypeDef *parm;
1077
1078         if ( type == &type_object ) {
1079                 return NULL;
1080         }
1081
1082         t = type;
1083         do {
1084                 if ( t->SuperClass() != &type_object ) {
1085                         pos = t->SuperClass()->Size();
1086                 } else {
1087                         pos = 0;
1088                 }
1089                 for( i = 0; i < t->NumParameters(); i++ ) {
1090                         parm = t->GetParmType( i );
1091                         if ( !strcmp( t->GetParmName( i ), name ) ) {
1092                                 if ( etype != parm->FieldType()->Type() ) {
1093                                         return NULL;
1094                                 }
1095                                 return &data[ pos ];
1096                         }
1097
1098                         if ( parm->FieldType()->Inherits( &type_object ) ) {
1099                                 pos += type_object.Size();
1100                         } else {
1101                                 pos += parm->FieldType()->Size();
1102                         }
1103                 }
1104                 t = t->SuperClass();
1105         } while( t && ( t != &type_object ) );
1106
1107         return NULL;
1108 }
1109
1110 /***********************************************************************
1111
1112   idProgram
1113
1114 ***********************************************************************/
1115
1116 /*
1117 ============
1118 idProgram::AllocType
1119 ============
1120 */
1121 idTypeDef *idProgram::AllocType( idTypeDef &type ) {
1122         idTypeDef *newtype;
1123
1124         newtype = new idTypeDef( type ); 
1125         types.Append( newtype );
1126
1127         return newtype;
1128 }
1129
1130 /*
1131 ============
1132 idProgram::AllocType
1133 ============
1134 */
1135 idTypeDef *idProgram::AllocType( etype_t etype, idVarDef *edef, const char *ename, int esize, idTypeDef *aux ) {
1136         idTypeDef *newtype;
1137
1138         newtype = new idTypeDef( etype, edef, ename, esize, aux );
1139         types.Append( newtype );
1140
1141         return newtype;
1142 }
1143
1144 /*
1145 ============
1146 idProgram::GetType
1147
1148 Returns a preexisting complex type that matches the parm, or allocates
1149 a new one and copies it out.
1150 ============
1151 */
1152 idTypeDef *idProgram::GetType( idTypeDef &type, bool allocate ) {
1153         int i;
1154
1155         //FIXME: linear search == slow
1156         for( i = types.Num() - 1; i >= 0; i-- ) {
1157                 if ( types[ i ]->MatchesType( type ) && !strcmp( types[ i ]->Name(), type.Name() ) ) {
1158                         return types[ i ];
1159                 }
1160         }
1161
1162         if ( !allocate ) {
1163                 return NULL;
1164         }
1165
1166         // allocate a new one
1167         return AllocType( type );
1168 }
1169
1170 /*
1171 ============
1172 idProgram::FindType
1173
1174 Returns a preexisting complex type that matches the name, or returns NULL if not found
1175 ============
1176 */
1177 idTypeDef *idProgram::FindType( const char *name ) {
1178         idTypeDef       *check;
1179         int                     i;
1180
1181         for( i = types.Num() - 1; i >= 0; i-- ) {
1182                 check = types[ i ];
1183                 if ( !strcmp( check->Name(), name ) ) {
1184                         return check;
1185                 }
1186         }
1187
1188         return NULL;
1189 }
1190
1191 /*
1192 ============
1193 idProgram::GetDefList
1194 ============
1195 */
1196 idVarDef *idProgram::GetDefList( const char *name ) const {
1197         int i, hash;
1198
1199         hash = varDefNameHash.GenerateKey( name, true );
1200         for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) {
1201                 if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) {
1202                         return varDefNames[i]->GetDefs();
1203                 }
1204         }
1205         return NULL;
1206 }
1207
1208 /*
1209 ============
1210 idProgram::AddDefToNameList
1211 ============
1212 */
1213 void idProgram::AddDefToNameList( idVarDef *def, const char *name ) {
1214         int i, hash;
1215
1216         hash = varDefNameHash.GenerateKey( name, true );
1217         for ( i = varDefNameHash.First( hash ); i != -1; i = varDefNameHash.Next( i ) ) {
1218                 if ( idStr::Cmp( varDefNames[i]->Name(), name ) == 0 ) {
1219                         break;
1220                 }
1221         }
1222         if ( i == -1 ) {
1223                 i = varDefNames.Append( new idVarDefName( name ) );
1224                 varDefNameHash.Add( hash, i );
1225         }
1226         varDefNames[i]->AddDef( def );
1227 }
1228
1229 /*
1230 ============
1231 idProgram::AllocDef
1232 ============
1233 */
1234 idVarDef *idProgram::AllocDef( idTypeDef *type, const char *name, idVarDef *scope, bool constant ) {
1235         idVarDef        *def;
1236         idStr           element;
1237         idVarDef        *def_x;
1238         idVarDef        *def_y;
1239         idVarDef        *def_z;
1240
1241         // allocate a new def
1242         def = new idVarDef( type );
1243         def->scope              = scope;
1244         def->numUsers   = 1;
1245         def->num                = varDefs.Append( def );
1246
1247         // add the def to the list with defs with this name and set the name pointer
1248         AddDefToNameList( def, name );
1249
1250         if ( ( type->Type() == ev_vector ) || ( ( type->Type() == ev_field ) && ( type->FieldType()->Type() == ev_vector ) ) ) {
1251                 //
1252                 // vector
1253                 //
1254                 if ( !strcmp( name, RESULT_STRING ) ) {
1255                         // <RESULT> vector defs don't need the _x, _y and _z components
1256                         assert( scope->Type() == ev_function );
1257                         def->value.stackOffset  = scope->value.functionPtr->locals;
1258                         def->initialized                = idVarDef::stackVariable;
1259                         scope->value.functionPtr->locals += type->Size();
1260                 } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
1261                         idTypeDef       newtype( ev_field, NULL, "float field", 0, &type_float );
1262                         idTypeDef       *type = GetType( newtype, true );
1263
1264                         // set the value to the variable's position in the object
1265                         def->value.ptrOffset = scope->TypeDef()->Size();
1266
1267                         // make automatic defs for the vectors elements
1268                         // origin can be accessed as origin_x, origin_y, and origin_z
1269                         sprintf( element, "%s_x", def->Name() );
1270                         def_x = AllocDef( type, element, scope, constant );
1271
1272                         sprintf( element, "%s_y", def->Name() );
1273                         def_y = AllocDef( type, element, scope, constant );
1274                         def_y->value.ptrOffset = def_x->value.ptrOffset + type_float.Size();
1275
1276                         sprintf( element, "%s_z", def->Name() );
1277                         def_z = AllocDef( type, element, scope, constant );
1278                         def_z->value.ptrOffset = def_y->value.ptrOffset + type_float.Size();
1279                 } else {
1280                         // make automatic defs for the vectors elements
1281                         // origin can be accessed as origin_x, origin_y, and origin_z
1282                         sprintf( element, "%s_x", def->Name() );
1283                         def_x = AllocDef( &type_float, element, scope, constant );
1284
1285                         sprintf( element, "%s_y", def->Name() );
1286                         def_y = AllocDef( &type_float, element, scope, constant );
1287
1288                         sprintf( element, "%s_z", def->Name() );
1289                         def_z = AllocDef( &type_float, element, scope, constant );
1290
1291                         // point the vector def to the x coordinate
1292                         def->value                      = def_x->value;
1293                         def->initialized        = def_x->initialized;
1294                 }
1295         } else if ( scope->TypeDef()->Inherits( &type_object ) ) {
1296                 //
1297                 // object variable
1298                 //
1299                 // set the value to the variable's position in the object
1300                 def->value.ptrOffset = scope->TypeDef()->Size();
1301         } else if ( scope->Type() == ev_function ) {
1302                 //
1303                 // stack variable
1304                 //
1305                 // since we don't know how many local variables there are,
1306                 // we have to have them go backwards on the stack
1307                 def->value.stackOffset  = scope->value.functionPtr->locals;
1308                 def->initialized                = idVarDef::stackVariable;
1309
1310                 if ( type->Inherits( &type_object ) ) {
1311                         // objects only have their entity number on the stack, not the entire object
1312                         scope->value.functionPtr->locals += type_object.Size();
1313                 } else {
1314                         scope->value.functionPtr->locals += type->Size();
1315                 }
1316         } else {
1317                 //
1318                 // global variable
1319                 //
1320                 def->value.bytePtr = &variables[ numVariables ];
1321                 numVariables += def->TypeDef()->Size();
1322                 if ( numVariables > sizeof( variables ) ) {
1323                         throw idCompileError( va( "Exceeded global memory size (%d bytes)", sizeof( variables ) ) );
1324                 }
1325
1326                 memset( def->value.bytePtr, 0, def->TypeDef()->Size() );
1327         }
1328
1329         return def;
1330 }
1331
1332 /*
1333 ============
1334 idProgram::GetDef
1335
1336 If type is NULL, it will match any type
1337 ============
1338 */
1339 idVarDef *idProgram::GetDef( const idTypeDef *type, const char *name, const idVarDef *scope ) const {
1340         idVarDef                *def;
1341         idVarDef                *bestDef;
1342         int                             bestDepth;
1343         int                             depth;
1344
1345         bestDepth = 0;
1346         bestDef = NULL;
1347         for( def = GetDefList( name ); def != NULL; def = def->Next() ) {
1348                 if ( def->scope->Type() == ev_namespace ) {
1349                         depth = def->DepthOfScope( scope );
1350                         if ( !depth ) {
1351                                 // not in the same namespace
1352                                 continue;
1353                         }
1354                 } else if ( def->scope != scope ) {
1355                         // in a different function
1356                         continue;
1357                 } else {
1358                         depth = 1;
1359                 }
1360
1361                 if ( !bestDef || ( depth < bestDepth ) ) {
1362                         bestDepth = depth;
1363                         bestDef = def;
1364                 }
1365         }
1366
1367         // see if the name is already in use for another type
1368         if ( bestDef && type && ( bestDef->TypeDef() != type ) ) {
1369                 throw idCompileError( va( "Type mismatch on redeclaration of %s", name ) );
1370         }
1371
1372         return bestDef;
1373 }
1374
1375 /*
1376 ============
1377 idProgram::FreeDef
1378 ============
1379 */
1380 void idProgram::FreeDef( idVarDef *def, const idVarDef *scope ) {
1381         idVarDef *e;
1382         int i;
1383
1384         if ( def->Type() == ev_vector ) {
1385                 idStr name;
1386
1387                 sprintf( name, "%s_x", def->Name() );
1388                 e = GetDef( NULL, name, scope );
1389                 if ( e ) {
1390                         FreeDef( e, scope );
1391                 }
1392
1393                 sprintf( name, "%s_y", def->Name() );
1394                 e = GetDef( NULL, name, scope );
1395                 if ( e ) {
1396                         FreeDef( e, scope );
1397                 }
1398
1399                 sprintf( name, "%s_z", def->Name() );
1400                 e = GetDef( NULL, name, scope );
1401                 if ( e ) {
1402                         FreeDef( e, scope );
1403                 }
1404         }
1405
1406         varDefs.RemoveIndex( def->num );
1407         for( i = def->num; i < varDefs.Num(); i++ ) {
1408                 varDefs[ i ]->num = i;
1409         }
1410
1411         delete def;
1412 }
1413
1414 /*
1415 ============
1416 idProgram::FindFreeResultDef
1417 ============
1418 */
1419 idVarDef *idProgram::FindFreeResultDef( idTypeDef *type, const char *name, idVarDef *scope, const idVarDef *a, const idVarDef *b ) {
1420         idVarDef *def;
1421         
1422         for( def = GetDefList( name ); def != NULL; def = def->Next() ) {
1423                 if ( def == a || def == b ) {
1424                         continue;
1425                 }
1426                 if ( def->TypeDef() != type ) {
1427                         continue;
1428                 }
1429                 if ( def->scope != scope ) {
1430                         continue;
1431                 }
1432                 if ( def->numUsers <= 1 ) {
1433                         continue;
1434                 }
1435                 return def;
1436         }
1437
1438         return AllocDef( type, name, scope, false );
1439 }
1440
1441 /*
1442 ================
1443 idProgram::FindFunction
1444
1445 Searches for the specified function in the currently loaded script.  A full namespace should be
1446 specified if not in the global namespace.
1447
1448 Returns 0 if function not found.
1449 Returns >0 if function found.
1450 ================
1451 */
1452 function_t *idProgram::FindFunction( const char *name ) const {
1453         int                     start;
1454         int                     pos;
1455         idVarDef        *namespaceDef;
1456         idVarDef        *def;
1457
1458         assert( name );
1459
1460         idStr fullname = name;
1461         start = 0;
1462         namespaceDef = &def_namespace;
1463         do {
1464                 pos = fullname.Find( "::", true, start );
1465                 if ( pos < 0 ) {
1466                         break;
1467                 }
1468
1469                 idStr namespaceName = fullname.Mid( start, pos - start );
1470                 def = GetDef( NULL, namespaceName, namespaceDef );
1471                 if ( !def ) {
1472                         // couldn't find namespace
1473                         return NULL;
1474                 }
1475                 namespaceDef = def;
1476
1477                 // skip past the ::
1478                 start = pos + 2;
1479         } while( def->Type() == ev_namespace );
1480
1481         idStr funcName = fullname.Right( fullname.Length() - start );
1482         def = GetDef( NULL, funcName, namespaceDef );
1483         if ( !def ) {
1484                 // couldn't find function
1485                 return NULL;
1486         }
1487
1488         if ( ( def->Type() == ev_function ) && ( def->value.functionPtr->eventdef == NULL ) ) {
1489                 return def->value.functionPtr;
1490         }
1491
1492         // is not a function, or is an eventdef
1493         return NULL;
1494 }
1495
1496 /*
1497 ================
1498 idProgram::FindFunction
1499
1500 Searches for the specified object function in the currently loaded script.
1501
1502 Returns 0 if function not found.
1503 Returns >0 if function found.
1504 ================
1505 */
1506 function_t *idProgram::FindFunction( const char *name, const idTypeDef *type ) const {
1507         const idVarDef  *tdef;
1508         const idVarDef  *def;
1509
1510         // look for the function
1511         def = NULL;
1512         for( tdef = type->def; tdef != &def_object; tdef = tdef->TypeDef()->SuperClass()->def ) {
1513                 def = GetDef( NULL, name, tdef );
1514                 if ( def ) {
1515                         return def->value.functionPtr;
1516                 }
1517         }
1518
1519         return NULL;
1520 }
1521
1522 /*
1523 ================
1524 idProgram::AllocFunction
1525 ================
1526 */
1527 function_t &idProgram::AllocFunction( idVarDef *def ) {
1528         if ( functions.Num() >= functions.Max() ) {
1529                 throw idCompileError( va( "Exceeded maximum allowed number of functions (%d)", functions.Max() ) );
1530         }
1531
1532         // fill in the dfunction
1533         function_t &func        = *functions.Alloc();
1534         func.eventdef           = NULL;
1535         func.def                        = def;
1536         func.type                       = def->TypeDef();
1537         func.firstStatement     = 0;
1538         func.numStatements      = 0;
1539         func.parmTotal          = 0;
1540         func.locals                     = 0;
1541         func.filenum            = filenum;
1542         func.parmSize.SetGranularity( 1 );
1543         func.SetName( def->GlobalName() );
1544
1545         def->SetFunction( &func );
1546
1547         return func;
1548 }
1549
1550 /*
1551 ================
1552 idProgram::SetEntity
1553 ================
1554 */
1555 void idProgram::SetEntity( const char *name, idEntity *ent ) {
1556         idVarDef        *def;
1557         idStr           defName( "$" );
1558
1559         defName += name;
1560
1561         def = GetDef( &type_entity, defName, &def_namespace );
1562         if ( def && ( def->initialized != idVarDef::stackVariable ) ) {
1563                 // 0 is reserved for NULL entity
1564                 if ( !ent ) {
1565                         *def->value.entityNumberPtr = 0;
1566                 } else {
1567                         *def->value.entityNumberPtr = ent->entityNumber + 1;
1568                 }
1569         }
1570 }
1571
1572 /*
1573 ================
1574 idProgram::AllocStatement
1575 ================
1576 */
1577 statement_t *idProgram::AllocStatement( void ) {
1578         if ( statements.Num() >= statements.Max() ) {
1579                 throw idCompileError( va( "Exceeded maximum allowed number of statements (%d)", statements.Max() ) );
1580         }
1581         return statements.Alloc();
1582 }
1583
1584 /*
1585 ==============
1586 idProgram::BeginCompilation
1587
1588 called before compiling a batch of files, clears the pr struct
1589 ==============
1590 */
1591 void idProgram::BeginCompilation( void ) {
1592         statement_t     *statement;
1593
1594         FreeData();
1595
1596         try {
1597                 // make the first statement a return for a "NULL" function
1598                 statement = AllocStatement();
1599                 statement->linenumber   = 0;
1600                 statement->file                 = 0;
1601                 statement->op                   = OP_RETURN;
1602                 statement->a                    = NULL;
1603                 statement->b                    = NULL;
1604                 statement->c                    = NULL;
1605
1606                 // define NULL
1607                 //AllocDef( &type_void, "<NULL>", &def_namespace, true );
1608
1609                 // define the return def
1610                 returnDef = AllocDef( &type_vector, "<RETURN>", &def_namespace, false );
1611
1612                 // define the return def for strings
1613                 returnStringDef = AllocDef( &type_string, "<RETURN>", &def_namespace, false );
1614
1615                 // define the sys object
1616                 sysDef = AllocDef( &type_void, "sys", &def_namespace, true );
1617         }
1618
1619         catch( idCompileError &err ) {
1620                 gameLocal.Error( "%s", err.error );
1621         }
1622 }
1623
1624 /*
1625 ==============
1626 idProgram::DisassembleStatement
1627 ==============
1628 */
1629 void idProgram::DisassembleStatement( idFile *file, int instructionPointer ) const {
1630         opcode_t                        *op;
1631         const statement_t       *statement;
1632
1633         statement = &statements[ instructionPointer ];
1634         op = &idCompiler::opcodes[ statement->op ];
1635         file->Printf( "%20s(%d):\t%6d: %15s\t", fileList[ statement->file ].c_str(), statement->linenumber, instructionPointer, op->opname );
1636
1637         if ( statement->a ) {
1638                 file->Printf( "\ta: " );
1639                 statement->a->PrintInfo( file, instructionPointer );
1640         }
1641
1642         if ( statement->b ) {
1643                 file->Printf( "\tb: " );
1644                 statement->b->PrintInfo( file, instructionPointer );
1645         }
1646
1647         if ( statement->c ) {
1648                 file->Printf( "\tc: " );
1649                 statement->c->PrintInfo( file, instructionPointer );
1650         }
1651
1652         file->Printf( "\n" );
1653 }
1654
1655 /*
1656 ==============
1657 idProgram::Disassemble
1658 ==============
1659 */
1660 void idProgram::Disassemble( void ) const {
1661         int                                     i;
1662         int                                     instructionPointer;
1663         const function_t        *func;
1664         idFile                          *file;
1665
1666         file = fileSystem->OpenFileByMode( "script/disasm.txt", FS_WRITE );
1667
1668         for( i = 0; i < functions.Num(); i++ ) {
1669                 func = &functions[ i ];
1670                 if ( func->eventdef ) {
1671                         // skip eventdefs
1672                         continue;
1673                 }
1674
1675                 file->Printf( "\nfunction %s() %d stack used, %d parms, %d locals {\n", func->Name(), func->locals, func->parmTotal, func->locals - func->parmTotal );
1676
1677                 for( instructionPointer = 0; instructionPointer < func->numStatements; instructionPointer++ ) {
1678                         DisassembleStatement( file, func->firstStatement + instructionPointer );
1679                 }
1680         
1681                 file->Printf( "}\n" );
1682         }
1683
1684         fileSystem->CloseFile( file );
1685 }
1686
1687 /*
1688 ==============
1689 idProgram::FinishCompilation
1690
1691 Called after all files are compiled to check for errors
1692 ==============
1693 */
1694 void idProgram::FinishCompilation( void ) {
1695         int     i;
1696
1697         top_functions   = functions.Num();
1698         top_statements  = statements.Num();
1699         top_types               = types.Num();
1700         top_defs                = varDefs.Num();
1701         top_files               = fileList.Num();
1702
1703         variableDefaults.Clear();
1704         variableDefaults.SetNum( numVariables );
1705
1706         for( i = 0; i < numVariables; i++ ) {
1707                 variableDefaults[ i ] = variables[ i ];
1708         }
1709 }
1710
1711 /*
1712 ==============
1713 idProgram::CompileStats
1714
1715 called after all files are compiled to report memory usage.
1716 ==============
1717 */
1718 void idProgram::CompileStats( void ) {
1719         int     memused;
1720         int     memallocated;
1721         int     numdefs;
1722         int     stringspace;
1723         int funcMem;
1724         int     i;
1725
1726         gameLocal.Printf( "---------- Compile stats ----------\n" );
1727         gameLocal.DPrintf( "Files loaded:\n" );
1728
1729         stringspace = 0;
1730         for( i = 0; i < fileList.Num(); i++ ) {
1731                 gameLocal.DPrintf( "   %s\n", fileList[ i ].c_str() );
1732                 stringspace += fileList[ i ].Allocated();
1733         }
1734         stringspace += fileList.Size();
1735
1736         numdefs = varDefs.Num();
1737         memused = varDefs.Num() * sizeof( idVarDef );
1738         memused += types.Num() * sizeof( idTypeDef );
1739         memused += stringspace;
1740
1741         for( i = 0; i < types.Num(); i++ ) {
1742                 memused += types[ i ]->Allocated();
1743         }
1744
1745         funcMem = functions.MemoryUsed();
1746         for( i = 0; i < functions.Num(); i++ ) {
1747                 funcMem += functions[ i ].Allocated();
1748         }
1749
1750         memallocated = funcMem + memused + sizeof( idProgram );
1751
1752         memused += statements.MemoryUsed();
1753         memused += functions.MemoryUsed();      // name and filename of functions are shared, so no need to include them
1754         memused += sizeof( variables );
1755
1756         gameLocal.Printf( "\nMemory usage:\n" );
1757         gameLocal.Printf( "     Strings: %d, %d bytes\n", fileList.Num(), stringspace );
1758         gameLocal.Printf( "  Statements: %d, %d bytes\n", statements.Num(), statements.MemoryUsed() );
1759         gameLocal.Printf( "   Functions: %d, %d bytes\n", functions.Num(), funcMem );
1760         gameLocal.Printf( "   Variables: %d bytes\n", numVariables );
1761         gameLocal.Printf( "    Mem used: %d bytes\n", memused );
1762         gameLocal.Printf( " Static data: %d bytes\n", sizeof( idProgram ) );
1763         gameLocal.Printf( "   Allocated: %d bytes\n", memallocated );
1764         gameLocal.Printf( " Thread size: %d bytes\n\n", sizeof( idThread ) );
1765 }
1766
1767 /*
1768 ================
1769 idProgram::CompileText
1770 ================
1771 */
1772 bool idProgram::CompileText( const char *source, const char *text, bool console ) {
1773         idCompiler      compiler;
1774         int                     i;
1775         idVarDef        *def;
1776         idStr           ospath;
1777
1778         // use a full os path for GetFilenum since it calls OSPathToRelativePath to convert filenames from the parser
1779         ospath = fileSystem->RelativePathToOSPath( source );
1780         filenum = GetFilenum( ospath );
1781
1782         try {
1783                 compiler.CompileFile( text, filename, console );
1784
1785                 // check to make sure all functions prototyped have code
1786                 for( i = 0; i < varDefs.Num(); i++ ) {
1787                         def = varDefs[ i ];
1788                         if ( ( def->Type() == ev_function ) && ( ( def->scope->Type() == ev_namespace ) || def->scope->TypeDef()->Inherits( &type_object ) ) ) {
1789                                 if ( !def->value.functionPtr->eventdef && !def->value.functionPtr->firstStatement ) {
1790                                         throw idCompileError( va( "function %s was not defined\n", def->GlobalName() ) );
1791                                 }
1792                         }
1793                 }
1794         }
1795         
1796         catch( idCompileError &err ) {
1797                 if ( console ) {
1798                         gameLocal.Printf( "%s\n", err.error );
1799                         return false;
1800                 } else {
1801                         gameLocal.Error( "%s\n", err.error );
1802                 }
1803         };
1804
1805         if ( !console ) {
1806                 CompileStats();
1807         }
1808
1809         return true;
1810 }
1811
1812 /*
1813 ================
1814 idProgram::CompileFunction
1815 ================
1816 */
1817 const function_t *idProgram::CompileFunction( const char *functionName, const char *text ) {
1818         bool result;
1819
1820         result = CompileText( functionName, text, false );
1821
1822         if ( g_disasm.GetBool() ) {
1823                 Disassemble();
1824         }
1825
1826         if ( !result ) {
1827                 gameLocal.Error( "Compile failed." );
1828         }
1829
1830         return FindFunction( functionName );
1831 }
1832
1833 /*
1834 ================
1835 idProgram::CompileFile
1836 ================
1837 */
1838 void idProgram::CompileFile( const char *filename ) {
1839         char *src;
1840         bool result;
1841
1842         if ( fileSystem->ReadFile( filename, ( void ** )&src, NULL ) < 0 ) {
1843                 gameLocal.Error( "Couldn't load %s\n", filename );
1844         }
1845
1846         result = CompileText( filename, src, false );
1847
1848         fileSystem->FreeFile( src );
1849
1850         if ( g_disasm.GetBool() ) {
1851                 Disassemble();
1852         }
1853
1854         if ( !result ) {
1855                 gameLocal.Error( "Compile failed in file %s.", filename );
1856         }
1857 }
1858
1859 /*
1860 ================
1861 idProgram::FreeData
1862 ================
1863 */
1864 void idProgram::FreeData( void ) {
1865         int i;
1866
1867         // free the defs
1868         varDefs.DeleteContents( true );
1869         varDefNames.DeleteContents( true );
1870         varDefNameHash.Free();
1871
1872         returnDef               = NULL;
1873         returnStringDef = NULL;
1874         sysDef                  = NULL;
1875
1876         // free any special types we've created
1877         types.DeleteContents( true );
1878
1879         filenum = 0;
1880
1881         numVariables = 0;
1882         memset( variables, 0, sizeof( variables ) );
1883
1884         // clear all the strings in the functions so that it doesn't look like we're leaking memory.
1885         for( i = 0; i < functions.Num(); i++ ) {
1886                 functions[ i ].Clear();
1887         }
1888
1889         filename.Clear();
1890         fileList.Clear();
1891         statements.Clear();
1892         functions.Clear();
1893
1894         top_functions   = 0;
1895         top_statements  = 0;
1896         top_types               = 0;
1897         top_defs                = 0;
1898         top_files               = 0;
1899
1900         filename = "";
1901 }
1902
1903 /*
1904 ================
1905 idProgram::Startup
1906 ================
1907 */
1908 void idProgram::Startup( const char *defaultScript ) {
1909         gameLocal.Printf( "Initializing scripts\n" );
1910
1911         // make sure all data is freed up
1912         idThread::Restart();
1913
1914         // get ready for loading scripts
1915         BeginCompilation();
1916
1917         // load the default script
1918         if ( defaultScript && *defaultScript ) {
1919                 CompileFile( defaultScript );
1920         }
1921
1922         FinishCompilation();
1923 }
1924
1925 /*
1926 ================
1927 idProgram::Save
1928 ================
1929 */
1930 void idProgram::Save( idSaveGame *savefile ) const {
1931         int i;
1932         int currentFileNum = top_files;
1933
1934         savefile->WriteInt( (fileList.Num() - currentFileNum) );
1935         while ( currentFileNum < fileList.Num() ) {
1936                 savefile->WriteString( fileList[ currentFileNum ] );
1937                 currentFileNum++;
1938         }
1939
1940         for ( i = 0; i < variableDefaults.Num(); i++ ) {
1941                 if ( variables[i] != variableDefaults[i] ) {
1942                         savefile->WriteInt( i );
1943                         savefile->WriteByte( variables[i] );
1944                 }
1945         }
1946         // Mark the end of the diff with default variables with -1
1947         savefile->WriteInt( -1 );
1948
1949         savefile->WriteInt( numVariables );
1950         for ( i = variableDefaults.Num(); i < numVariables; i++ ) {
1951                 savefile->WriteByte( variables[i] );
1952         }
1953
1954         int checksum = CalculateChecksum();
1955         savefile->WriteInt( checksum );
1956 }
1957
1958 /*
1959 ================
1960 idProgram::Restore
1961 ================
1962 */
1963 bool idProgram::Restore( idRestoreGame *savefile ) {
1964         int i, num, index;
1965         bool result = true;
1966         idStr scriptname;
1967
1968         savefile->ReadInt( num );
1969         for ( i = 0; i < num; i++ ) {
1970                 savefile->ReadString( scriptname );
1971                 CompileFile( scriptname );
1972         }
1973
1974         savefile->ReadInt( index );
1975         while( index >= 0 ) {
1976                 savefile->ReadByte( variables[index] );
1977                 savefile->ReadInt( index );
1978         }
1979
1980         savefile->ReadInt( num );
1981         for ( i = variableDefaults.Num(); i < num; i++ ) {
1982                 savefile->ReadByte( variables[i] );
1983         }
1984
1985         int saved_checksum, checksum;
1986
1987         savefile->ReadInt( saved_checksum );
1988         checksum = CalculateChecksum();
1989
1990         if ( saved_checksum != checksum ) {
1991                 result = false;
1992         }
1993
1994         return result;
1995 }
1996
1997 /*
1998 ================
1999 idProgram::CalculateChecksum
2000 ================
2001 */
2002 int idProgram::CalculateChecksum( void ) const {
2003         int i, result;
2004
2005         typedef struct {
2006                 unsigned short  op;
2007                 int                             a;
2008                 int                             b;
2009                 int                             c;
2010                 unsigned short  linenumber;
2011                 unsigned short  file;
2012         } statementBlock_t;
2013
2014         statementBlock_t        *statementList = new statementBlock_t[ statements.Num() ];
2015
2016         memset( statementList, 0, ( sizeof(statementBlock_t) * statements.Num() ) );
2017
2018         // Copy info into new list, using the variable numbers instead of a pointer to the variable
2019         for( i = 0; i < statements.Num(); i++ ) {
2020                 statementList[i].op = statements[i].op;
2021
2022                 if ( statements[i].a ) {
2023                         statementList[i].a = statements[i].a->num;
2024                 } else {
2025                         statementList[i].a = -1;
2026                 }
2027                 if ( statements[i].b ) {
2028                         statementList[i].b = statements[i].b->num;
2029                 } else {
2030                         statementList[i].b = -1;
2031                 }
2032                 if ( statements[i].c ) {
2033                         statementList[i].c = statements[i].c->num;
2034                 } else {
2035                         statementList[i].c = -1;
2036                 }
2037
2038                 statementList[i].linenumber = statements[i].linenumber;
2039                 statementList[i].file = statements[i].file;
2040         }
2041
2042         result = MD4_BlockChecksum( statementList, ( sizeof(statementBlock_t) * statements.Num() ) );
2043
2044         delete [] statementList;
2045
2046         return result;
2047 }
2048
2049 /*
2050 ==============
2051 idProgram::Restart
2052
2053 Restores all variables to their initial value
2054 ==============
2055 */
2056 void idProgram::Restart( void ) {
2057         int i;
2058
2059         idThread::Restart();
2060
2061         //
2062         // since there may have been a script loaded by the map or the user may
2063         // have typed "script" from the console, free up any types and vardefs that
2064         // have been allocated after the initial startup
2065         //
2066         for( i = top_types; i < types.Num(); i++ ) {
2067                 delete types[ i ];
2068         }
2069         types.SetNum( top_types, false );
2070
2071         for( i = top_defs; i < varDefs.Num(); i++ ) {
2072                 delete varDefs[ i ];
2073         }
2074         varDefs.SetNum( top_defs, false );
2075
2076         for( i = top_functions; i < functions.Num(); i++ ) {
2077                 functions[ i ].Clear();
2078         }
2079         functions.SetNum( top_functions );
2080
2081         statements.SetNum( top_statements );
2082         fileList.SetNum( top_files, false );
2083         filename.Clear();
2084         
2085         // reset the variables to their default values
2086         numVariables = variableDefaults.Num();
2087         for( i = 0; i < numVariables; i++ ) {
2088                 variables[ i ] = variableDefaults[ i ];
2089         }
2090 }
2091
2092 /*
2093 ================
2094 idProgram::GetFilenum
2095 ================
2096 */
2097 int idProgram::GetFilenum( const char *name ) {
2098         if ( filename == name ) {
2099                 return filenum;
2100         }
2101
2102         idStr strippedName;
2103         strippedName = fileSystem->OSPathToRelativePath( name );
2104         if ( !strippedName.Length() ) {
2105                 // not off the base path so just use the full path
2106                 filenum = fileList.AddUnique( name );
2107         } else {
2108                 filenum = fileList.AddUnique( strippedName );
2109         }
2110
2111         // save the unstripped name so that we don't have to strip the incoming name every time we call GetFilenum
2112         filename = name;
2113
2114         return filenum;
2115 }
2116
2117 /*
2118 ================
2119 idProgram::idProgram
2120 ================
2121 */
2122 idProgram::idProgram() {
2123         FreeData();
2124 }
2125
2126 /*
2127 ================
2128 idProgram::~idProgram
2129 ================
2130 */
2131 idProgram::~idProgram() {
2132         FreeData();
2133 }
2134
2135 /*
2136 ================
2137 idProgram::ReturnEntity
2138 ================
2139 */
2140 void idProgram::ReturnEntity( idEntity *ent ) {
2141         if ( ent ) {
2142                 *returnDef->value.entityNumberPtr = ent->entityNumber + 1;
2143         } else {
2144                 *returnDef->value.entityNumberPtr = 0;
2145         }
2146 }