DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Class.cpp (26285B)


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