]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/game/gamesys/Class.cpp
hello world
[icculus/iodoom3.git] / neo / game / gamesys / Class.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
30 Base class for all C++ objects.  Provides fast run-time type checking and run-time
31 instancing of objects.
32
33 */
34
35 #include "../../idlib/precompiled.h"
36 #pragma hdrstop
37
38 #include "../Game_local.h"
39
40 #include "TypeInfo.h"
41
42
43 /***********************************************************************
44
45   idTypeInfo
46
47 ***********************************************************************/
48
49 // this is the head of a singly linked list of all the idTypes
50 static idTypeInfo                               *typelist = NULL;
51 static idHierarchy<idTypeInfo>  classHierarchy;
52 static int                                              eventCallbackMemory     = 0;
53
54 /*
55 ================
56 idTypeInfo::idClassType()
57
58 Constructor for class.  Should only be called from CLASS_DECLARATION macro.
59 Handles linking class definition into class hierarchy.  This should only happen
60 at startup as idTypeInfos are statically defined.  Since static variables can be
61 initialized in any order, the constructor must handle the case that subclasses
62 are initialized before superclasses.
63 ================
64 */
65 idTypeInfo::idTypeInfo( const char *classname, const char *superclass, idEventFunc<idClass> *eventCallbacks, idClass *( *CreateInstance )( void ), 
66         void ( idClass::*Spawn )( void ), void ( idClass::*Save )( idSaveGame *savefile ) const, void ( idClass::*Restore )( idRestoreGame *savefile ) ) {
67
68         idTypeInfo *type;
69         idTypeInfo **insert;
70
71         this->classname                 = classname;
72         this->superclass                = superclass;
73         this->eventCallbacks    = eventCallbacks;
74         this->eventMap                  = NULL;
75         this->Spawn                             = Spawn;
76         this->Save                              = Save;
77         this->Restore                   = Restore;
78         this->CreateInstance    = CreateInstance;
79         this->super                             = idClass::GetClass( superclass );
80         this->freeEventMap              = false;
81         typeNum                                 = 0;
82         lastChild                               = 0;
83
84         // Check if any subclasses were initialized before their superclass
85         for( type = typelist; type != NULL; type = type->next ) {
86                 if ( ( type->super == NULL ) && !idStr::Cmp( type->superclass, this->classname ) && 
87                         idStr::Cmp( type->classname, "idClass" ) ) {
88                         type->super     = this;
89                 }
90         }
91
92         // Insert sorted
93         for ( insert = &typelist; *insert; insert = &(*insert)->next ) {
94                 assert( idStr::Cmp( classname, (*insert)->classname ) );
95                 if ( idStr::Cmp( classname, (*insert)->classname ) < 0 ) {
96                         next = *insert;
97                         *insert = this;
98                         break;
99                 }
100         }
101         if ( !*insert ) {
102                 *insert = this;
103                 next = NULL;
104         }
105 }
106
107 /*
108 ================
109 idTypeInfo::~idTypeInfo
110 ================
111 */
112 idTypeInfo::~idTypeInfo() {
113         Shutdown();
114 }
115
116 /*
117 ================
118 idTypeInfo::Init
119
120 Initializes the event callback table for the class.  Creates a 
121 table for fast lookups of event functions.  Should only be called once.
122 ================
123 */
124 void idTypeInfo::Init( void ) {
125         idTypeInfo                              *c;
126         idEventFunc<idClass>    *def;
127         int                                             ev;
128         int                                             i;
129         bool                                    *set;
130         int                                             num;
131
132         if ( eventMap ) {
133                 // we've already been initialized by a subclass
134                 return;
135         }
136
137         // make sure our superclass is initialized first
138         if ( super && !super->eventMap ) {
139                 super->Init();
140         }
141
142         // add to our node hierarchy
143         if ( super ) {
144                 node.ParentTo( super->node );
145         } else {
146                 node.ParentTo( classHierarchy );
147         }
148         node.SetOwner( this );
149
150         // keep track of the number of children below each class
151         for( c = super; c != NULL; c = c->super ) {
152                 c->lastChild++;
153         }
154
155         // if we're not adding any new event callbacks, we can just use our superclass's table
156         if ( ( !eventCallbacks || !eventCallbacks->event ) && super ) {
157                 eventMap = super->eventMap;
158                 return;
159         }
160
161         // set a flag so we know to delete the eventMap table
162         freeEventMap = true;
163
164         // Allocate our new table.  It has to have as many entries as there
165         // are events.  NOTE: could save some space by keeping track of the maximum
166         // event that the class responds to and doing range checking.
167         num = idEventDef::NumEventCommands();
168         eventMap = new eventCallback_t[ num ];
169         memset( eventMap, 0, sizeof( eventCallback_t ) * num );
170         eventCallbackMemory += sizeof( eventCallback_t ) * num;
171
172         // allocate temporary memory for flags so that the subclass's event callbacks
173         // override the superclass's event callback
174         set = new bool[ num ];
175         memset( set, 0, sizeof( bool ) * num );
176
177         // go through the inheritence order and copies the event callback function into
178         // a list indexed by the event number.  This allows fast lookups of
179         // event functions.
180         for( c = this; c != NULL; c = c->super ) {
181                 def = c->eventCallbacks;
182                 if ( !def ) {
183                         continue;
184                 }
185
186                 // go through each entry until we hit the NULL terminator
187                 for( i = 0; def[ i ].event != NULL; i++ )       {
188                         ev = def[ i ].event->GetEventNum();
189
190                         if ( set[ ev ] ) {
191                                 continue;
192                         }
193                         set[ ev ] = true;
194                         eventMap[ ev ] = def[ i ].function;
195                 }
196         }
197
198         delete[] set;
199 }
200
201 /*
202 ================
203 idTypeInfo::Shutdown
204
205 Should only be called when DLL or EXE is being shutdown.
206 Although it cleans up any allocated memory, it doesn't bother to remove itself 
207 from the class list since the program is shutting down.
208 ================
209 */
210 void idTypeInfo::Shutdown() {
211         // free up the memory used for event lookups
212         if ( eventMap ) {
213                 if ( freeEventMap ) {
214                         delete[] eventMap;
215                 }
216                 eventMap = NULL;
217         }
218         typeNum = 0;
219         lastChild = 0;
220 }
221
222
223 /***********************************************************************
224
225   idClass
226
227 ***********************************************************************/
228
229 const idEventDef EV_Remove( "<immediateremove>", NULL );
230 const idEventDef EV_SafeRemove( "remove", NULL );
231
232 ABSTRACT_DECLARATION( NULL, idClass )
233         EVENT( EV_Remove,                               idClass::Event_Remove )
234         EVENT( EV_SafeRemove,                   idClass::Event_SafeRemove )
235 END_CLASS
236
237 // alphabetical order
238 idList<idTypeInfo *>    idClass::types;
239 // typenum order
240 idList<idTypeInfo *>    idClass::typenums;
241
242 bool    idClass::initialized    = false;
243 int             idClass::typeNumBits    = 0;
244 int             idClass::memused                = 0;
245 int             idClass::numobjects             = 0;
246
247 /*
248 ================
249 idClass::CallSpawn
250 ================
251 */
252 void idClass::CallSpawn( void ) {
253         idTypeInfo *type;
254
255         type = GetType();
256         CallSpawnFunc( type );
257 }
258
259 /*
260 ================
261 idClass::CallSpawnFunc
262 ================
263 */
264 classSpawnFunc_t idClass::CallSpawnFunc( idTypeInfo *cls ) {
265         classSpawnFunc_t func;
266
267         if ( cls->super ) {
268                 func = CallSpawnFunc( cls->super );
269                 if ( func == cls->Spawn ) {
270                         // don't call the same function twice in a row.
271                         // this can happen when subclasses don't have their own spawn function.
272                         return func;
273                 }
274         }
275
276         ( this->*cls->Spawn )();
277
278         return cls->Spawn;
279 }
280
281 /*
282 ================
283 idClass::FindUninitializedMemory
284 ================
285 */
286 void idClass::FindUninitializedMemory( void ) {
287 #ifdef ID_DEBUG_UNINITIALIZED_MEMORY
288         unsigned long *ptr = ( ( unsigned long * )this ) - 1;
289         int size = *ptr;
290         assert( ( size & 3 ) == 0 );
291         size >>= 2;
292         for ( int i = 0; i < size; i++ ) {
293                 if ( ptr[i] == 0xcdcdcdcd ) {
294                         const char *varName = GetTypeVariableName( GetClassname(), i << 2 );
295                         gameLocal.Warning( "type '%s' has uninitialized variable %s (offset %d)", GetClassname(), varName, i << 2 );
296                 }
297         }
298 #endif
299 }
300
301 /*
302 ================
303 idClass::Spawn
304 ================
305 */
306 void idClass::Spawn( void ) {
307 }
308
309 /*
310 ================
311 idClass::~idClass
312
313 Destructor for object.  Cancels any events that depend on this object.
314 ================
315 */
316 idClass::~idClass() {
317         idEvent::CancelEvents( this );
318 }
319
320 /*
321 ================
322 idClass::DisplayInfo_f
323 ================
324 */
325 void idClass::DisplayInfo_f( const idCmdArgs &args ) {
326         gameLocal.Printf( "Class memory status: %i bytes allocated in %i objects\n", memused, numobjects );
327 }
328
329 /*
330 ================
331 idClass::ListClasses_f
332 ================
333 */
334 void idClass::ListClasses_f( const idCmdArgs &args ) {
335         int                     i;
336         idTypeInfo *type;
337
338         gameLocal.Printf( "%-24s %-24s %-6s %-6s\n", "Classname", "Superclass", "Type", "Subclasses" );
339         gameLocal.Printf( "----------------------------------------------------------------------\n" );
340
341         for( i = 0; i < types.Num(); i++ ) {
342                 type = types[ i ];
343                 gameLocal.Printf( "%-24s %-24s %6d %6d\n", type->classname, type->superclass, type->typeNum, type->lastChild - type->typeNum );
344         }
345
346         gameLocal.Printf( "...%d classes", types.Num() );
347 }
348
349 /*
350 ================
351 idClass::CreateInstance
352 ================
353 */
354 idClass *idClass::CreateInstance( const char *name ) {
355         const idTypeInfo        *type;
356         idClass                         *obj;
357
358         type = idClass::GetClass( name );
359         if ( !type ) {
360                 return NULL;
361         }
362
363         obj = type->CreateInstance();
364         return obj;
365 }
366
367 /*
368 ================
369 idClass::Init
370
371 Should be called after all idTypeInfos are initialized, so must be called
372 manually upon game code initialization.  Tells all the idTypeInfos to initialize
373 their event callback table for the associated class.  This should only be called
374 once during the execution of the program or DLL.
375 ================
376 */
377 void idClass::Init( void ) {
378         idTypeInfo      *c;
379         int                     num;
380
381         gameLocal.Printf( "Initializing class hierarchy\n" );
382
383         if ( initialized ) {
384                 gameLocal.Printf( "...already initialized\n" );
385                 return;
386         }
387
388         // init the event callback tables for all the classes
389         for( c = typelist; c != NULL; c = c->next ) {
390                 c->Init();
391         }
392
393         // number the types according to the class hierarchy so we can quickly determine if a class
394         // is a subclass of another
395         num = 0;
396         for( c = classHierarchy.GetNext(); c != NULL; c = c->node.GetNext(), num++ ) {
397         c->typeNum = num;
398                 c->lastChild += num;
399         }
400
401         // number of bits needed to send types over network
402         typeNumBits = idMath::BitsForInteger( num );
403
404         // create a list of the types so we can do quick lookups
405         // one list in alphabetical order, one in typenum order
406         types.SetGranularity( 1 );
407         types.SetNum( num );
408         typenums.SetGranularity( 1 );
409         typenums.SetNum( num );
410         num = 0;
411         for( c = typelist; c != NULL; c = c->next, num++ ) {
412                 types[ num ] = c;
413                 typenums[ c->typeNum ] = c;
414         }
415
416         initialized = true;
417
418         gameLocal.Printf( "...%i classes, %i bytes for event callbacks\n", types.Num(), eventCallbackMemory );
419 }
420
421 /*
422 ================
423 idClass::Shutdown
424 ================
425 */
426 void idClass::Shutdown( void ) {
427         idTypeInfo      *c;
428
429         for( c = typelist; c != NULL; c = c->next ) {
430                 c->Shutdown();
431         }
432         types.Clear();
433         typenums.Clear();
434
435         initialized = false;
436 }
437
438 /*
439 ================
440 idClass::new
441 ================
442 */
443 #ifdef ID_DEBUG_MEMORY
444 #undef new
445 #endif
446
447 void * idClass::operator new( size_t s ) {
448         int *p;
449
450         s += sizeof( int );
451         p = (int *)Mem_Alloc( s );
452         *p = s;
453         memused += s;
454         numobjects++;
455
456 #ifdef ID_DEBUG_UNINITIALIZED_MEMORY
457         unsigned long *ptr = (unsigned long *)p;
458         int size = s;
459         assert( ( size & 3 ) == 0 );
460         size >>= 3;
461         for ( int i = 1; i < size; i++ ) {
462                 ptr[i] = 0xcdcdcdcd;
463         }
464 #endif
465
466         return p + 1;
467 }
468
469 void * idClass::operator new( size_t s, int, int, char *, int ) {
470         int *p;
471
472         s += sizeof( int );
473         p = (int *)Mem_Alloc( s );
474         *p = s;
475         memused += s;
476         numobjects++;
477
478 #ifdef ID_DEBUG_UNINITIALIZED_MEMORY
479         unsigned long *ptr = (unsigned long *)p;
480         int size = s;
481         assert( ( size & 3 ) == 0 );
482         size >>= 3;
483         for ( int i = 1; i < size; i++ ) {
484                 ptr[i] = 0xcdcdcdcd;
485         }
486 #endif
487
488         return p + 1;
489 }
490
491 #ifdef ID_DEBUG_MEMORY
492 #define new ID_DEBUG_NEW
493 #endif
494
495 /*
496 ================
497 idClass::delete
498 ================
499 */
500 void idClass::operator delete( void *ptr ) {
501         int *p;
502
503         if ( ptr ) {
504                 p = ( ( int * )ptr ) - 1;
505                 memused -= *p;
506                 numobjects--;
507         Mem_Free( p );
508         }
509 }
510
511 void idClass::operator delete( void *ptr, int, int, char *, int ) {
512         int *p;
513
514         if ( ptr ) {
515                 p = ( ( int * )ptr ) - 1;
516                 memused -= *p;
517                 numobjects--;
518         Mem_Free( p );
519         }
520 }
521
522 /*
523 ================
524 idClass::GetClass
525
526 Returns the idTypeInfo for the name of the class passed in.  This is a static function
527 so it must be called as idClass::GetClass( classname )
528 ================
529 */
530 idTypeInfo *idClass::GetClass( const char *name ) {
531         idTypeInfo      *c;
532         int                     order;
533         int                     mid;
534         int                     min;
535         int                     max;
536
537         if ( !initialized ) {
538                 // idClass::Init hasn't been called yet, so do a slow lookup
539                 for( c = typelist; c != NULL; c = c->next ) {
540                         if ( !idStr::Cmp( c->classname, name ) ) {
541                                 return c;
542                         }
543                 }
544         } else {
545                 // do a binary search through the list of types
546                 min = 0;
547                 max = types.Num() - 1;
548                 while( min <= max ) {
549                         mid = ( min + max ) / 2;
550                         c = types[ mid ];
551                         order = idStr::Cmp( c->classname, name );
552                         if ( !order ) {
553                                 return c;
554                         } else if ( order > 0 ) {
555                                 max = mid - 1;
556                         } else {
557                                 min = mid + 1;
558                         }
559                 }
560         }
561
562         return NULL;
563 }
564
565 /*
566 ================
567 idClass::GetType
568 ================
569 */
570 idTypeInfo *idClass::GetType( const int typeNum ) {
571         idTypeInfo *c;
572
573         if ( !initialized ) {
574                 for( c = typelist; c != NULL; c = c->next ) {
575                         if ( c->typeNum == typeNum ) {
576                                 return c;
577                         }
578                 }
579         } else if ( ( typeNum >= 0 ) && ( typeNum < types.Num() ) ) {
580                 return typenums[ typeNum ];
581         }
582
583         return NULL;
584 }
585
586 /*
587 ================
588 idClass::GetClassname
589
590 Returns the text classname of the object.
591 ================
592 */
593 const char *idClass::GetClassname( void ) const {
594         idTypeInfo *type;
595
596         type = GetType();
597         return type->classname;
598 }
599
600 /*
601 ================
602 idClass::GetSuperclass
603
604 Returns the text classname of the superclass.
605 ================
606 */
607 const char *idClass::GetSuperclass( void ) const {
608         idTypeInfo *cls;
609
610         cls = GetType();
611         return cls->superclass;
612 }
613
614 /*
615 ================
616 idClass::CancelEvents
617 ================
618 */
619 void idClass::CancelEvents( const idEventDef *ev ) {
620         idEvent::CancelEvents( this, ev );
621 }
622
623 /*
624 ================
625 idClass::PostEventArgs
626 ================
627 */
628 bool idClass::PostEventArgs( const idEventDef *ev, int time, int numargs, ... ) {
629         idTypeInfo      *c;
630         idEvent         *event;
631         va_list         args;
632         
633         assert( ev );
634         
635         if ( !idEvent::initialized ) {
636                 return false;
637         }
638
639         c = GetType();
640         if ( !c->eventMap[ ev->GetEventNum() ] ) {
641                 // we don't respond to this event, so ignore it
642                 return false;
643         }
644
645         // we service events on the client to avoid any bad code filling up the event pool
646         // we don't want them processed usually, unless when the map is (re)loading.
647         // we allow threads to run fine, though.
648         if ( gameLocal.isClient && ( gameLocal.GameState() != GAMESTATE_STARTUP ) && !IsType( idThread::Type ) ) {
649                 return true;
650         }
651
652         va_start( args, numargs );
653         event = idEvent::Alloc( ev, numargs, args );
654         va_end( args );
655
656         event->Schedule( this, c, time );
657
658         return true;
659 }
660
661 /*
662 ================
663 idClass::PostEventMS
664 ================
665 */
666 bool idClass::PostEventMS( const idEventDef *ev, int time ) {
667         return PostEventArgs( ev, time, 0 );
668 }
669
670 /*
671 ================
672 idClass::PostEventMS
673 ================
674 */
675 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1 ) {
676         return PostEventArgs( ev, time, 1, &arg1 );
677 }
678
679 /*
680 ================
681 idClass::PostEventMS
682 ================
683 */
684 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2 ) {
685         return PostEventArgs( ev, time, 2, &arg1, &arg2 );
686 }
687
688 /*
689 ================
690 idClass::PostEventMS
691 ================
692 */
693 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) {
694         return PostEventArgs( ev, time, 3, &arg1, &arg2, &arg3 );
695 }
696
697 /*
698 ================
699 idClass::PostEventMS
700 ================
701 */
702 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) {
703         return PostEventArgs( ev, time, 4, &arg1, &arg2, &arg3, &arg4 );
704 }
705
706 /*
707 ================
708 idClass::PostEventMS
709 ================
710 */
711 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) {
712         return PostEventArgs( ev, time, 5, &arg1, &arg2, &arg3, &arg4, &arg5 );
713 }
714
715 /*
716 ================
717 idClass::PostEventMS
718 ================
719 */
720 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) {
721         return PostEventArgs( ev, time, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 );
722 }
723
724 /*
725 ================
726 idClass::PostEventMS
727 ================
728 */
729 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) {
730         return PostEventArgs( ev, time, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 );
731 }
732
733 /*
734 ================
735 idClass::PostEventMS
736 ================
737 */
738 bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) {
739         return PostEventArgs( ev, time, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 );
740 }
741
742 /*
743 ================
744 idClass::PostEventSec
745 ================
746 */
747 bool idClass::PostEventSec( const idEventDef *ev, float time ) {
748         return PostEventArgs( ev, SEC2MS( time ), 0 );
749 }
750
751 /*
752 ================
753 idClass::PostEventSec
754 ================
755 */
756 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1 ) {
757         return PostEventArgs( ev, SEC2MS( time ), 1, &arg1 );
758 }
759
760 /*
761 ================
762 idClass::PostEventSec
763 ================
764 */
765 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2 ) {
766         return PostEventArgs( ev, SEC2MS( time ), 2, &arg1, &arg2 );
767 }
768
769 /*
770 ================
771 idClass::PostEventSec
772 ================
773 */
774 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) {
775         return PostEventArgs( ev, SEC2MS( time ), 3, &arg1, &arg2, &arg3 );
776 }
777
778 /*
779 ================
780 idClass::PostEventSec
781 ================
782 */
783 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) {
784         return PostEventArgs( ev, SEC2MS( time ), 4, &arg1, &arg2, &arg3, &arg4 );
785 }
786
787 /*
788 ================
789 idClass::PostEventSec
790 ================
791 */
792 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) {
793         return PostEventArgs( ev, SEC2MS( time ), 5, &arg1, &arg2, &arg3, &arg4, &arg5 );
794 }
795
796 /*
797 ================
798 idClass::PostEventSec
799 ================
800 */
801 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) {
802         return PostEventArgs( ev, SEC2MS( time ), 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 );
803 }
804
805 /*
806 ================
807 idClass::PostEventSec
808 ================
809 */
810 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) {
811         return PostEventArgs( ev, SEC2MS( time ), 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 );
812 }
813
814 /*
815 ================
816 idClass::PostEventSec
817 ================
818 */
819 bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) {
820         return PostEventArgs( ev, SEC2MS( time ), 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 );
821 }
822
823 /*
824 ================
825 idClass::ProcessEventArgs
826 ================
827 */
828 bool idClass::ProcessEventArgs( const idEventDef *ev, int numargs, ... ) {
829         idTypeInfo      *c;
830         int                     num;
831         int                     data[ D_EVENT_MAXARGS ];
832         va_list         args;
833         
834         assert( ev );
835         assert( idEvent::initialized );
836
837         c = GetType();
838         num = ev->GetEventNum();
839         if ( !c->eventMap[ num ] ) {
840                 // we don't respond to this event, so ignore it
841                 return false;
842         }
843
844         va_start( args, numargs );
845         idEvent::CopyArgs( ev, numargs, args, data );
846         va_end( args );
847
848         ProcessEventArgPtr( ev, data );
849
850         return true;
851 }
852
853 /*
854 ================
855 idClass::ProcessEvent
856 ================
857 */
858 bool idClass::ProcessEvent( const idEventDef *ev ) {
859         return ProcessEventArgs( ev, 0 );
860 }
861
862 /*
863 ================
864 idClass::ProcessEvent
865 ================
866 */
867 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1 ) {
868         return ProcessEventArgs( ev, 1, &arg1 );
869 }
870
871 /*
872 ================
873 idClass::ProcessEvent
874 ================
875 */
876 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2 ) {
877         return ProcessEventArgs( ev, 2, &arg1, &arg2 );
878 }
879
880 /*
881 ================
882 idClass::ProcessEvent
883 ================
884 */
885 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) {
886         return ProcessEventArgs( ev, 3, &arg1, &arg2, &arg3 );
887 }
888
889 /*
890 ================
891 idClass::ProcessEvent
892 ================
893 */
894 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) {
895         return ProcessEventArgs( ev, 4, &arg1, &arg2, &arg3, &arg4 );
896 }
897
898 /*
899 ================
900 idClass::ProcessEvent
901 ================
902 */
903 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) {
904         return ProcessEventArgs( ev, 5, &arg1, &arg2, &arg3, &arg4, &arg5 );
905 }
906
907 /*
908 ================
909 idClass::ProcessEvent
910 ================
911 */
912 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) {
913         return ProcessEventArgs( ev, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 );
914 }
915
916 /*
917 ================
918 idClass::ProcessEvent
919 ================
920 */
921 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) {
922         return ProcessEventArgs( ev, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 );
923 }
924
925 /*
926 ================
927 idClass::ProcessEvent
928 ================
929 */
930 bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) {
931         return ProcessEventArgs( ev, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 );
932 }
933
934 /*
935 ================
936 idClass::ProcessEventArgPtr
937 ================
938 */
939 bool idClass::ProcessEventArgPtr( const idEventDef *ev, int *data ) {
940         idTypeInfo      *c;
941         int                     num;
942         eventCallback_t callback;
943
944         assert( ev );
945         assert( idEvent::initialized );
946
947         if ( g_debugTriggers.GetBool() && ( ev == &EV_Activate ) && IsType( idEntity::Type ) ) {
948                 const idEntity *ent = *reinterpret_cast<idEntity **>( data );
949                 gameLocal.Printf( "%d: '%s' activated by '%s'\n", gameLocal.framenum, static_cast<idEntity *>( this )->GetName(), ent ? ent->GetName() : "NULL" );
950         }
951
952         c = GetType();
953         num = ev->GetEventNum();
954         if ( !c->eventMap[ num ] ) {
955                 // we don't respond to this event, so ignore it
956                 return false;
957         }
958
959         callback = c->eventMap[ num ];
960
961 #if !CPU_EASYARGS
962
963 /*
964 on ppc architecture, floats are passed in a seperate set of registers
965 the function prototypes must have matching float declaration
966
967 http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/2rt_powerpc_abi/chapter_9_section_5.html
968 */
969
970         switch( ev->GetFormatspecIndex() ) {
971         case 1 << D_EVENT_MAXARGS :
972                 ( this->*callback )();
973                 break;
974
975 // generated file - see CREATE_EVENT_CODE
976 #include "Callbacks.cpp"
977
978         default:
979                 gameLocal.Warning( "Invalid formatspec on event '%s'", ev->GetName() );
980                 break;
981         }
982
983 #else
984
985         assert( D_EVENT_MAXARGS == 8 );
986
987         switch( ev->GetNumArgs() ) {
988         case 0 :
989                 ( this->*callback )();
990                 break;
991
992         case 1 :
993                 typedef void ( idClass::*eventCallback_1_t )( const int );
994                 ( this->*( eventCallback_1_t )callback )( data[ 0 ] );
995                 break;
996
997         case 2 :
998                 typedef void ( idClass::*eventCallback_2_t )( const int, const int );
999                 ( this->*( eventCallback_2_t )callback )( data[ 0 ], data[ 1 ] );
1000                 break;
1001
1002         case 3 :
1003                 typedef void ( idClass::*eventCallback_3_t )( const int, const int, const int );
1004                 ( this->*( eventCallback_3_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ] );
1005                 break;
1006
1007         case 4 :
1008                 typedef void ( idClass::*eventCallback_4_t )( const int, const int, const int, const int );
1009                 ( this->*( eventCallback_4_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ] );
1010                 break;
1011
1012         case 5 :
1013                 typedef void ( idClass::*eventCallback_5_t )( const int, const int, const int, const int, const int );
1014                 ( this->*( eventCallback_5_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ] );
1015                 break;
1016
1017         case 6 :
1018                 typedef void ( idClass::*eventCallback_6_t )( const int, const int, const int, const int, const int, const int );
1019                 ( this->*( eventCallback_6_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ] );
1020                 break;
1021
1022         case 7 :
1023                 typedef void ( idClass::*eventCallback_7_t )( const int, const int, const int, const int, const int, const int, const int );
1024                 ( this->*( eventCallback_7_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ] );
1025                 break;
1026
1027         case 8 :
1028                 typedef void ( idClass::*eventCallback_8_t )( const int, const int, const int, const int, const int, const int, const int, const int );
1029                 ( this->*( eventCallback_8_t )callback )( data[ 0 ], data[ 1 ], data[ 2 ], data[ 3 ], data[ 4 ], data[ 5 ], data[ 6 ], data[ 7 ] );
1030                 break;
1031
1032         default:
1033                 gameLocal.Warning( "Invalid formatspec on event '%s'", ev->GetName() );
1034                 break;
1035         }
1036
1037 #endif
1038
1039         return true;
1040 }
1041
1042 /*
1043 ================
1044 idClass::Event_Remove
1045 ================
1046 */
1047 void idClass::Event_Remove( void ) {
1048         delete this;
1049 }
1050
1051 /*
1052 ================
1053 idClass::Event_SafeRemove
1054 ================
1055 */
1056 void idClass::Event_SafeRemove( void ) {
1057         // Forces the remove to be done at a safe time
1058         PostEventMS( &EV_Remove, 0 );
1059 }