2011-11-22 21:28:15 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
|
|
|
|
Doom 3 GPL Source Code
|
2011-12-06 18:20:15 +00:00
|
|
|
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
2011-11-22 21:28:15 +00:00
|
|
|
|
2011-12-06 16:14:59 +00:00
|
|
|
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
|
2011-11-22 21:28:15 +00:00
|
|
|
|
|
|
|
Doom 3 Source Code is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Doom 3 Source Code is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
===========================================================================
|
|
|
|
*/
|
2011-12-16 22:28:29 +00:00
|
|
|
|
|
|
|
#include "sys/platform.h"
|
|
|
|
#include "gamesys/SysCvar.h"
|
|
|
|
#include "script/Script_Thread.h"
|
|
|
|
|
|
|
|
#include "Class.h"
|
|
|
|
|
2011-11-22 21:28:15 +00:00
|
|
|
/*
|
|
|
|
|
|
|
|
Base class for all C++ objects. Provides fast run-time type checking and run-time
|
|
|
|
instancing of objects.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
|
|
|
idTypeInfo
|
|
|
|
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
// this is the head of a singly linked list of all the idTypes
|
|
|
|
static idTypeInfo *typelist = NULL;
|
|
|
|
static idHierarchy<idTypeInfo> classHierarchy;
|
|
|
|
static int eventCallbackMemory = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idTypeInfo::idClassType()
|
|
|
|
|
|
|
|
Constructor for class. Should only be called from CLASS_DECLARATION macro.
|
|
|
|
Handles linking class definition into class hierarchy. This should only happen
|
|
|
|
at startup as idTypeInfos are statically defined. Since static variables can be
|
|
|
|
initialized in any order, the constructor must handle the case that subclasses
|
|
|
|
are initialized before superclasses.
|
|
|
|
================
|
|
|
|
*/
|
2011-12-06 18:20:15 +00:00
|
|
|
idTypeInfo::idTypeInfo( const char *classname, const char *superclass, idEventFunc<idClass> *eventCallbacks, idClass *( *CreateInstance )( void ),
|
2011-11-22 21:28:15 +00:00
|
|
|
void ( idClass::*Spawn )( void ), void ( idClass::*Save )( idSaveGame *savefile ) const, void ( idClass::*Restore )( idRestoreGame *savefile ) ) {
|
|
|
|
|
|
|
|
idTypeInfo *type;
|
|
|
|
idTypeInfo **insert;
|
|
|
|
|
|
|
|
this->classname = classname;
|
|
|
|
this->superclass = superclass;
|
|
|
|
this->eventCallbacks = eventCallbacks;
|
|
|
|
this->eventMap = NULL;
|
|
|
|
this->Spawn = Spawn;
|
|
|
|
this->Save = Save;
|
|
|
|
this->Restore = Restore;
|
|
|
|
this->CreateInstance = CreateInstance;
|
|
|
|
this->super = idClass::GetClass( superclass );
|
|
|
|
this->freeEventMap = false;
|
|
|
|
typeNum = 0;
|
|
|
|
lastChild = 0;
|
|
|
|
|
|
|
|
// Check if any subclasses were initialized before their superclass
|
|
|
|
for( type = typelist; type != NULL; type = type->next ) {
|
2011-12-06 18:20:15 +00:00
|
|
|
if ( ( type->super == NULL ) && !idStr::Cmp( type->superclass, this->classname ) &&
|
2011-11-22 21:28:15 +00:00
|
|
|
idStr::Cmp( type->classname, "idClass" ) ) {
|
|
|
|
type->super = this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert sorted
|
|
|
|
for ( insert = &typelist; *insert; insert = &(*insert)->next ) {
|
|
|
|
assert( idStr::Cmp( classname, (*insert)->classname ) );
|
|
|
|
if ( idStr::Cmp( classname, (*insert)->classname ) < 0 ) {
|
|
|
|
next = *insert;
|
|
|
|
*insert = this;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !*insert ) {
|
|
|
|
*insert = this;
|
|
|
|
next = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idTypeInfo::~idTypeInfo
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
idTypeInfo::~idTypeInfo() {
|
|
|
|
Shutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idTypeInfo::Init
|
|
|
|
|
2011-12-06 18:20:15 +00:00
|
|
|
Initializes the event callback table for the class. Creates a
|
2011-11-22 21:28:15 +00:00
|
|
|
table for fast lookups of event functions. Should only be called once.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idTypeInfo::Init( void ) {
|
|
|
|
idTypeInfo *c;
|
|
|
|
idEventFunc<idClass> *def;
|
|
|
|
int ev;
|
|
|
|
int i;
|
|
|
|
bool *set;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
if ( eventMap ) {
|
|
|
|
// we've already been initialized by a subclass
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure our superclass is initialized first
|
|
|
|
if ( super && !super->eventMap ) {
|
|
|
|
super->Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
// add to our node hierarchy
|
|
|
|
if ( super ) {
|
|
|
|
node.ParentTo( super->node );
|
|
|
|
} else {
|
|
|
|
node.ParentTo( classHierarchy );
|
|
|
|
}
|
|
|
|
node.SetOwner( this );
|
|
|
|
|
|
|
|
// keep track of the number of children below each class
|
|
|
|
for( c = super; c != NULL; c = c->super ) {
|
|
|
|
c->lastChild++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if we're not adding any new event callbacks, we can just use our superclass's table
|
|
|
|
if ( ( !eventCallbacks || !eventCallbacks->event ) && super ) {
|
|
|
|
eventMap = super->eventMap;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set a flag so we know to delete the eventMap table
|
|
|
|
freeEventMap = true;
|
|
|
|
|
|
|
|
// Allocate our new table. It has to have as many entries as there
|
|
|
|
// are events. NOTE: could save some space by keeping track of the maximum
|
|
|
|
// event that the class responds to and doing range checking.
|
|
|
|
num = idEventDef::NumEventCommands();
|
|
|
|
eventMap = new eventCallback_t[ num ];
|
|
|
|
memset( eventMap, 0, sizeof( eventCallback_t ) * num );
|
|
|
|
eventCallbackMemory += sizeof( eventCallback_t ) * num;
|
|
|
|
|
|
|
|
// allocate temporary memory for flags so that the subclass's event callbacks
|
|
|
|
// override the superclass's event callback
|
|
|
|
set = new bool[ num ];
|
|
|
|
memset( set, 0, sizeof( bool ) * num );
|
|
|
|
|
|
|
|
// go through the inheritence order and copies the event callback function into
|
|
|
|
// a list indexed by the event number. This allows fast lookups of
|
|
|
|
// event functions.
|
|
|
|
for( c = this; c != NULL; c = c->super ) {
|
|
|
|
def = c->eventCallbacks;
|
|
|
|
if ( !def ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// go through each entry until we hit the NULL terminator
|
|
|
|
for( i = 0; def[ i ].event != NULL; i++ ) {
|
|
|
|
ev = def[ i ].event->GetEventNum();
|
|
|
|
|
|
|
|
if ( set[ ev ] ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
set[ ev ] = true;
|
|
|
|
eventMap[ ev ] = def[ i ].function;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] set;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idTypeInfo::Shutdown
|
|
|
|
|
|
|
|
Should only be called when DLL or EXE is being shutdown.
|
2011-12-06 18:20:15 +00:00
|
|
|
Although it cleans up any allocated memory, it doesn't bother to remove itself
|
2011-11-22 21:28:15 +00:00
|
|
|
from the class list since the program is shutting down.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idTypeInfo::Shutdown() {
|
|
|
|
// free up the memory used for event lookups
|
|
|
|
if ( eventMap ) {
|
|
|
|
if ( freeEventMap ) {
|
|
|
|
delete[] eventMap;
|
|
|
|
}
|
|
|
|
eventMap = NULL;
|
|
|
|
}
|
|
|
|
typeNum = 0;
|
|
|
|
lastChild = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
|
|
|
idClass
|
|
|
|
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
const idEventDef EV_Remove( "<immediateremove>", NULL );
|
|
|
|
const idEventDef EV_SafeRemove( "remove", NULL );
|
|
|
|
|
|
|
|
ABSTRACT_DECLARATION( NULL, idClass )
|
|
|
|
EVENT( EV_Remove, idClass::Event_Remove )
|
|
|
|
EVENT( EV_SafeRemove, idClass::Event_SafeRemove )
|
|
|
|
END_CLASS
|
|
|
|
|
|
|
|
// alphabetical order
|
|
|
|
idList<idTypeInfo *> idClass::types;
|
|
|
|
// typenum order
|
|
|
|
idList<idTypeInfo *> idClass::typenums;
|
|
|
|
|
|
|
|
bool idClass::initialized = false;
|
|
|
|
int idClass::typeNumBits = 0;
|
|
|
|
int idClass::memused = 0;
|
|
|
|
int idClass::numobjects = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::CallSpawn
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::CallSpawn( void ) {
|
|
|
|
idTypeInfo *type;
|
|
|
|
|
|
|
|
type = GetType();
|
|
|
|
CallSpawnFunc( type );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::CallSpawnFunc
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
classSpawnFunc_t idClass::CallSpawnFunc( idTypeInfo *cls ) {
|
|
|
|
classSpawnFunc_t func;
|
|
|
|
|
|
|
|
if ( cls->super ) {
|
|
|
|
func = CallSpawnFunc( cls->super );
|
|
|
|
if ( func == cls->Spawn ) {
|
|
|
|
// don't call the same function twice in a row.
|
|
|
|
// this can happen when subclasses don't have their own spawn function.
|
|
|
|
return func;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
( this->*cls->Spawn )();
|
|
|
|
|
|
|
|
return cls->Spawn;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::FindUninitializedMemory
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::FindUninitializedMemory( void ) {
|
|
|
|
#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
|
|
|
|
unsigned long *ptr = ( ( unsigned long * )this ) - 1;
|
|
|
|
int size = *ptr;
|
|
|
|
assert( ( size & 3 ) == 0 );
|
|
|
|
size >>= 2;
|
|
|
|
for ( int i = 0; i < size; i++ ) {
|
|
|
|
if ( ptr[i] == 0xcdcdcdcd ) {
|
|
|
|
const char *varName = GetTypeVariableName( GetClassname(), i << 2 );
|
|
|
|
gameLocal.Warning( "type '%s' has uninitialized variable %s (offset %d)", GetClassname(), varName, i << 2 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::Spawn
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::Spawn( void ) {
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::~idClass
|
|
|
|
|
|
|
|
Destructor for object. Cancels any events that depend on this object.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
idClass::~idClass() {
|
|
|
|
idEvent::CancelEvents( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::DisplayInfo_f
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::DisplayInfo_f( const idCmdArgs &args ) {
|
|
|
|
gameLocal.Printf( "Class memory status: %i bytes allocated in %i objects\n", memused, numobjects );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ListClasses_f
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::ListClasses_f( const idCmdArgs &args ) {
|
|
|
|
int i;
|
|
|
|
idTypeInfo *type;
|
|
|
|
|
|
|
|
gameLocal.Printf( "%-24s %-24s %-6s %-6s\n", "Classname", "Superclass", "Type", "Subclasses" );
|
|
|
|
gameLocal.Printf( "----------------------------------------------------------------------\n" );
|
|
|
|
|
|
|
|
for( i = 0; i < types.Num(); i++ ) {
|
|
|
|
type = types[ i ];
|
|
|
|
gameLocal.Printf( "%-24s %-24s %6d %6d\n", type->classname, type->superclass, type->typeNum, type->lastChild - type->typeNum );
|
|
|
|
}
|
|
|
|
|
|
|
|
gameLocal.Printf( "...%d classes", types.Num() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::CreateInstance
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
idClass *idClass::CreateInstance( const char *name ) {
|
|
|
|
const idTypeInfo *type;
|
|
|
|
idClass *obj;
|
|
|
|
|
|
|
|
type = idClass::GetClass( name );
|
|
|
|
if ( !type ) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = type->CreateInstance();
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::Init
|
|
|
|
|
|
|
|
Should be called after all idTypeInfos are initialized, so must be called
|
|
|
|
manually upon game code initialization. Tells all the idTypeInfos to initialize
|
|
|
|
their event callback table for the associated class. This should only be called
|
|
|
|
once during the execution of the program or DLL.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::Init( void ) {
|
|
|
|
idTypeInfo *c;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
gameLocal.Printf( "Initializing class hierarchy\n" );
|
|
|
|
|
|
|
|
if ( initialized ) {
|
|
|
|
gameLocal.Printf( "...already initialized\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// init the event callback tables for all the classes
|
|
|
|
for( c = typelist; c != NULL; c = c->next ) {
|
|
|
|
c->Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
// number the types according to the class hierarchy so we can quickly determine if a class
|
|
|
|
// is a subclass of another
|
|
|
|
num = 0;
|
|
|
|
for( c = classHierarchy.GetNext(); c != NULL; c = c->node.GetNext(), num++ ) {
|
2011-12-06 18:20:15 +00:00
|
|
|
c->typeNum = num;
|
2011-11-22 21:28:15 +00:00
|
|
|
c->lastChild += num;
|
|
|
|
}
|
|
|
|
|
|
|
|
// number of bits needed to send types over network
|
|
|
|
typeNumBits = idMath::BitsForInteger( num );
|
|
|
|
|
|
|
|
// create a list of the types so we can do quick lookups
|
|
|
|
// one list in alphabetical order, one in typenum order
|
|
|
|
types.SetGranularity( 1 );
|
|
|
|
types.SetNum( num );
|
|
|
|
typenums.SetGranularity( 1 );
|
|
|
|
typenums.SetNum( num );
|
|
|
|
num = 0;
|
|
|
|
for( c = typelist; c != NULL; c = c->next, num++ ) {
|
|
|
|
types[ num ] = c;
|
|
|
|
typenums[ c->typeNum ] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
|
|
|
|
gameLocal.Printf( "...%i classes, %i bytes for event callbacks\n", types.Num(), eventCallbackMemory );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::Shutdown
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::Shutdown( void ) {
|
|
|
|
idTypeInfo *c;
|
|
|
|
|
|
|
|
for( c = typelist; c != NULL; c = c->next ) {
|
|
|
|
c->Shutdown();
|
|
|
|
}
|
|
|
|
types.Clear();
|
|
|
|
typenums.Clear();
|
|
|
|
|
|
|
|
initialized = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::new
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
#ifdef ID_DEBUG_MEMORY
|
|
|
|
#undef new
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void * idClass::operator new( size_t s ) {
|
|
|
|
int *p;
|
|
|
|
|
|
|
|
s += sizeof( int );
|
|
|
|
p = (int *)Mem_Alloc( s );
|
|
|
|
*p = s;
|
|
|
|
memused += s;
|
|
|
|
numobjects++;
|
|
|
|
|
|
|
|
#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
|
|
|
|
unsigned long *ptr = (unsigned long *)p;
|
|
|
|
int size = s;
|
|
|
|
assert( ( size & 3 ) == 0 );
|
|
|
|
size >>= 3;
|
|
|
|
for ( int i = 1; i < size; i++ ) {
|
|
|
|
ptr[i] = 0xcdcdcdcd;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return p + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void * idClass::operator new( size_t s, int, int, char *, int ) {
|
|
|
|
int *p;
|
|
|
|
|
|
|
|
s += sizeof( int );
|
|
|
|
p = (int *)Mem_Alloc( s );
|
|
|
|
*p = s;
|
|
|
|
memused += s;
|
|
|
|
numobjects++;
|
|
|
|
|
|
|
|
#ifdef ID_DEBUG_UNINITIALIZED_MEMORY
|
|
|
|
unsigned long *ptr = (unsigned long *)p;
|
|
|
|
int size = s;
|
|
|
|
assert( ( size & 3 ) == 0 );
|
|
|
|
size >>= 3;
|
|
|
|
for ( int i = 1; i < size; i++ ) {
|
|
|
|
ptr[i] = 0xcdcdcdcd;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return p + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ID_DEBUG_MEMORY
|
|
|
|
#define new ID_DEBUG_NEW
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::delete
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::operator delete( void *ptr ) {
|
|
|
|
int *p;
|
|
|
|
|
|
|
|
if ( ptr ) {
|
|
|
|
p = ( ( int * )ptr ) - 1;
|
|
|
|
memused -= *p;
|
|
|
|
numobjects--;
|
2011-12-06 18:20:15 +00:00
|
|
|
Mem_Free( p );
|
2011-11-22 21:28:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void idClass::operator delete( void *ptr, int, int, char *, int ) {
|
|
|
|
int *p;
|
|
|
|
|
|
|
|
if ( ptr ) {
|
|
|
|
p = ( ( int * )ptr ) - 1;
|
|
|
|
memused -= *p;
|
|
|
|
numobjects--;
|
2011-12-06 18:20:15 +00:00
|
|
|
Mem_Free( p );
|
2011-11-22 21:28:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::GetClass
|
|
|
|
|
|
|
|
Returns the idTypeInfo for the name of the class passed in. This is a static function
|
|
|
|
so it must be called as idClass::GetClass( classname )
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
idTypeInfo *idClass::GetClass( const char *name ) {
|
|
|
|
idTypeInfo *c;
|
|
|
|
int order;
|
|
|
|
int mid;
|
|
|
|
int min;
|
|
|
|
int max;
|
|
|
|
|
|
|
|
if ( !initialized ) {
|
|
|
|
// idClass::Init hasn't been called yet, so do a slow lookup
|
|
|
|
for( c = typelist; c != NULL; c = c->next ) {
|
|
|
|
if ( !idStr::Cmp( c->classname, name ) ) {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// do a binary search through the list of types
|
|
|
|
min = 0;
|
|
|
|
max = types.Num() - 1;
|
|
|
|
while( min <= max ) {
|
|
|
|
mid = ( min + max ) / 2;
|
|
|
|
c = types[ mid ];
|
|
|
|
order = idStr::Cmp( c->classname, name );
|
|
|
|
if ( !order ) {
|
|
|
|
return c;
|
|
|
|
} else if ( order > 0 ) {
|
|
|
|
max = mid - 1;
|
|
|
|
} else {
|
|
|
|
min = mid + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::GetType
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
idTypeInfo *idClass::GetType( const int typeNum ) {
|
|
|
|
idTypeInfo *c;
|
|
|
|
|
|
|
|
if ( !initialized ) {
|
|
|
|
for( c = typelist; c != NULL; c = c->next ) {
|
|
|
|
if ( c->typeNum == typeNum ) {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ( ( typeNum >= 0 ) && ( typeNum < types.Num() ) ) {
|
|
|
|
return typenums[ typeNum ];
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::GetClassname
|
|
|
|
|
|
|
|
Returns the text classname of the object.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
const char *idClass::GetClassname( void ) const {
|
|
|
|
idTypeInfo *type;
|
|
|
|
|
|
|
|
type = GetType();
|
|
|
|
return type->classname;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::GetSuperclass
|
|
|
|
|
|
|
|
Returns the text classname of the superclass.
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
const char *idClass::GetSuperclass( void ) const {
|
|
|
|
idTypeInfo *cls;
|
|
|
|
|
|
|
|
cls = GetType();
|
|
|
|
return cls->superclass;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::CancelEvents
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::CancelEvents( const idEventDef *ev ) {
|
|
|
|
idEvent::CancelEvents( this, ev );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventArgs
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventArgs( const idEventDef *ev, int time, int numargs, ... ) {
|
|
|
|
idTypeInfo *c;
|
|
|
|
idEvent *event;
|
|
|
|
va_list args;
|
2011-12-06 18:20:15 +00:00
|
|
|
|
2011-11-22 21:28:15 +00:00
|
|
|
assert( ev );
|
2011-12-06 18:20:15 +00:00
|
|
|
|
2011-11-22 21:28:15 +00:00
|
|
|
if ( !idEvent::initialized ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = GetType();
|
|
|
|
if ( !c->eventMap[ ev->GetEventNum() ] ) {
|
|
|
|
// we don't respond to this event, so ignore it
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we service events on the client to avoid any bad code filling up the event pool
|
|
|
|
// we don't want them processed usually, unless when the map is (re)loading.
|
|
|
|
// we allow threads to run fine, though.
|
|
|
|
if ( gameLocal.isClient && ( gameLocal.GameState() != GAMESTATE_STARTUP ) && !IsType( idThread::Type ) ) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
va_start( args, numargs );
|
|
|
|
event = idEvent::Alloc( ev, numargs, args );
|
|
|
|
va_end( args );
|
|
|
|
|
|
|
|
event->Schedule( this, c, time );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time ) {
|
|
|
|
return PostEventArgs( ev, time, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1 ) {
|
|
|
|
return PostEventArgs( ev, time, 1, &arg1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2 ) {
|
|
|
|
return PostEventArgs( ev, time, 2, &arg1, &arg2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) {
|
|
|
|
return PostEventArgs( ev, time, 3, &arg1, &arg2, &arg3 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) {
|
|
|
|
return PostEventArgs( ev, time, 4, &arg1, &arg2, &arg3, &arg4 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) {
|
|
|
|
return PostEventArgs( ev, time, 5, &arg1, &arg2, &arg3, &arg4, &arg5 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) {
|
|
|
|
return PostEventArgs( ev, time, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) {
|
|
|
|
return PostEventArgs( ev, time, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventMS
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventMS( const idEventDef *ev, int time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) {
|
|
|
|
return PostEventArgs( ev, time, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 1, &arg1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 2, &arg1, &arg2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 3, &arg1, &arg2, &arg3 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 4, &arg1, &arg2, &arg3, &arg4 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 5, &arg1, &arg2, &arg3, &arg4, &arg5 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::PostEventSec
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::PostEventSec( const idEventDef *ev, float time, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) {
|
|
|
|
return PostEventArgs( ev, SEC2MS( time ), 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEventArgs
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEventArgs( const idEventDef *ev, int numargs, ... ) {
|
|
|
|
idTypeInfo *c;
|
|
|
|
int num;
|
2011-12-01 18:03:17 +00:00
|
|
|
intptr_t data[ D_EVENT_MAXARGS ];
|
2011-11-22 21:28:15 +00:00
|
|
|
va_list args;
|
2011-12-06 18:20:15 +00:00
|
|
|
|
2011-11-22 21:28:15 +00:00
|
|
|
assert( ev );
|
|
|
|
assert( idEvent::initialized );
|
|
|
|
|
|
|
|
c = GetType();
|
|
|
|
num = ev->GetEventNum();
|
|
|
|
if ( !c->eventMap[ num ] ) {
|
|
|
|
// we don't respond to this event, so ignore it
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
va_start( args, numargs );
|
|
|
|
idEvent::CopyArgs( ev, numargs, args, data );
|
|
|
|
va_end( args );
|
|
|
|
|
|
|
|
ProcessEventArgPtr( ev, data );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev ) {
|
|
|
|
return ProcessEventArgs( ev, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1 ) {
|
|
|
|
return ProcessEventArgs( ev, 1, &arg1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2 ) {
|
|
|
|
return ProcessEventArgs( ev, 2, &arg1, &arg2 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3 ) {
|
|
|
|
return ProcessEventArgs( ev, 3, &arg1, &arg2, &arg3 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4 ) {
|
|
|
|
return ProcessEventArgs( ev, 4, &arg1, &arg2, &arg3, &arg4 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5 ) {
|
|
|
|
return ProcessEventArgs( ev, 5, &arg1, &arg2, &arg3, &arg4, &arg5 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6 ) {
|
|
|
|
return ProcessEventArgs( ev, 6, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7 ) {
|
|
|
|
return ProcessEventArgs( ev, 7, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEvent
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
bool idClass::ProcessEvent( const idEventDef *ev, idEventArg arg1, idEventArg arg2, idEventArg arg3, idEventArg arg4, idEventArg arg5, idEventArg arg6, idEventArg arg7, idEventArg arg8 ) {
|
|
|
|
return ProcessEventArgs( ev, 8, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8 );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::ProcessEventArgPtr
|
|
|
|
================
|
|
|
|
*/
|
2011-12-01 18:03:17 +00:00
|
|
|
bool idClass::ProcessEventArgPtr( const idEventDef *ev, intptr_t *data ) {
|
2011-11-22 21:28:15 +00:00
|
|
|
idTypeInfo *c;
|
|
|
|
int num;
|
|
|
|
eventCallback_t callback;
|
|
|
|
|
|
|
|
assert( ev );
|
|
|
|
assert( idEvent::initialized );
|
|
|
|
|
|
|
|
#ifdef _D3XP
|
|
|
|
SetTimeState ts;
|
|
|
|
|
|
|
|
if ( IsType( idEntity::Type ) ) {
|
|
|
|
idEntity *ent = (idEntity*)this;
|
|
|
|
ts.PushState( ent->timeGroup );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ( g_debugTriggers.GetBool() && ( ev == &EV_Activate ) && IsType( idEntity::Type ) ) {
|
|
|
|
const idEntity *ent = *reinterpret_cast<idEntity **>( data );
|
|
|
|
gameLocal.Printf( "%d: '%s' activated by '%s'\n", gameLocal.framenum, static_cast<idEntity *>( this )->GetName(), ent ? ent->GetName() : "NULL" );
|
|
|
|
}
|
|
|
|
|
|
|
|
c = GetType();
|
|
|
|
num = ev->GetEventNum();
|
|
|
|
if ( !c->eventMap[ num ] ) {
|
|
|
|
// we don't respond to this event, so ignore it
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
callback = c->eventMap[ num ];
|
|
|
|
|
|
|
|
switch( ev->GetFormatspecIndex() ) {
|
|
|
|
case 1 << D_EVENT_MAXARGS :
|
|
|
|
( this->*callback )();
|
|
|
|
break;
|
|
|
|
|
|
|
|
// generated file - see CREATE_EVENT_CODE
|
|
|
|
#include "Callbacks.cpp"
|
|
|
|
|
|
|
|
default:
|
|
|
|
gameLocal.Warning( "Invalid formatspec on event '%s'", ev->GetName() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::Event_Remove
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::Event_Remove( void ) {
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
idClass::Event_SafeRemove
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void idClass::Event_SafeRemove( void ) {
|
|
|
|
// Forces the remove to be done at a safe time
|
|
|
|
PostEventMS( &EV_Remove, 0 );
|
|
|
|
}
|