891 lines
19 KiB
C++
891 lines
19 KiB
C++
|
//-----------------------------------------------------------------------------
|
||
|
//
|
||
|
// $Logfile:: /Code/DLLs/game/class.cpp $
|
||
|
// $Revision:: 17 $
|
||
|
// $Author:: Steven $
|
||
|
// $Date:: 10/13/03 9:43a $
|
||
|
//
|
||
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
||
|
// All rights reserved.
|
||
|
//
|
||
|
// This source is may not be distributed and/or modified without
|
||
|
// expressly written permission by Ritual Entertainment, Inc.
|
||
|
//
|
||
|
//
|
||
|
// DESCRIPTION:
|
||
|
// Base class that all classes that are used in conjunction with the game should
|
||
|
// be based off of. Class gives run-time type information about any class
|
||
|
// derived from it. This is really handy when you have a pointer to an object
|
||
|
// that you need to know if it supports certain behaviour.
|
||
|
//
|
||
|
// WARNING: This file is shared between game, cgame and possibly the user interface.
|
||
|
// It is instanced in each one of these directories because of the way that SourceSafe works.
|
||
|
//
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdarg.h>
|
||
|
|
||
|
|
||
|
#if defined( GAME_DLL )
|
||
|
|
||
|
#include "g_local.h"
|
||
|
|
||
|
#elif defined ( CGAME_DLL )
|
||
|
|
||
|
#include "cg_local.h"
|
||
|
#include "listener.h"
|
||
|
#include <qcommon/qcommon.h>
|
||
|
|
||
|
#else
|
||
|
|
||
|
#include "listener.h"
|
||
|
#include <qcommon/qcommon.h>
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#include "class.h"
|
||
|
#include "Linklist.h"
|
||
|
#include <qcommon/output.h>
|
||
|
|
||
|
int totalmemallocated = 0;
|
||
|
int numclassesallocated = 0;
|
||
|
|
||
|
static ClassDef *classlist = NULL;
|
||
|
|
||
|
|
||
|
ClassDef::ClassDef()
|
||
|
{
|
||
|
this->classname = NULL;
|
||
|
this->classID = NULL;
|
||
|
this->superclass = NULL;
|
||
|
this->responses = NULL;
|
||
|
this->numEvents = 0;
|
||
|
this->responseLookup = NULL;
|
||
|
this->newInstance = NULL;
|
||
|
this->classSize = 0;
|
||
|
this->super = NULL;
|
||
|
this->prev = this;
|
||
|
this->next = this;
|
||
|
}
|
||
|
|
||
|
ClassDef::ClassDef( const char *classname, const char *classID, const char *superclass, ResponseDef<Class> *responses,
|
||
|
void *( *newInstance )( void ), int classSize )
|
||
|
{
|
||
|
ClassDef *node;
|
||
|
|
||
|
if ( classlist == NULL )
|
||
|
{
|
||
|
classlist = new ClassDef;
|
||
|
}
|
||
|
|
||
|
this->classname = classname;
|
||
|
this->classID = classID;
|
||
|
this->superclass = superclass;
|
||
|
this->responses = responses;
|
||
|
this->numEvents = 0;
|
||
|
this->responseLookup = NULL;
|
||
|
this->newInstance = newInstance;
|
||
|
this->classSize = classSize;
|
||
|
this->super = getClass( superclass );
|
||
|
|
||
|
// It's not uncommon for classes to not have a class id, so just set it
|
||
|
// to an empty string so that we're not checking for it all the time.
|
||
|
if ( !classID )
|
||
|
{
|
||
|
this->classID = "";
|
||
|
}
|
||
|
|
||
|
// Check if any subclasses were initialized before their superclass
|
||
|
for( node = classlist->next; node != classlist; node = node->next )
|
||
|
{
|
||
|
if ( ( node->super == NULL ) && ( !Q_stricmp( node->superclass, this->classname ) ) &&
|
||
|
( Q_stricmp( node->classname, "Class" ) ) )
|
||
|
{
|
||
|
node->super = this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add to front of list
|
||
|
LL_Add( classlist, this, prev, next );
|
||
|
}
|
||
|
|
||
|
void ClassDef::Shutdown( void )
|
||
|
{
|
||
|
if ( responseLookup )
|
||
|
{
|
||
|
delete[] responseLookup;
|
||
|
responseLookup = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ClassDef::~ClassDef()
|
||
|
{
|
||
|
ClassDef *node;
|
||
|
|
||
|
if ( classlist != this )
|
||
|
{
|
||
|
LL_Remove( this, prev, next );
|
||
|
|
||
|
// Check if any subclasses were initialized before their superclass
|
||
|
for( node = classlist->next; node != classlist; node = node->next )
|
||
|
{
|
||
|
if ( node->super == this )
|
||
|
{
|
||
|
node->super = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// If the head of the list is deleted before the list is cleared, then we may have problems
|
||
|
assert( this->next == this->prev );
|
||
|
}
|
||
|
|
||
|
if ( responseLookup )
|
||
|
{
|
||
|
delete[] responseLookup;
|
||
|
responseLookup = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ClassDef::BuildResponseList( void )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
ResponseDef<Class> *r;
|
||
|
int ev;
|
||
|
int i;
|
||
|
qboolean *set;
|
||
|
int num;
|
||
|
|
||
|
if ( responseLookup )
|
||
|
{
|
||
|
delete[] responseLookup;
|
||
|
responseLookup = NULL;
|
||
|
}
|
||
|
|
||
|
num = Event::NumEventCommands();
|
||
|
responseLookup = ( Response ** )new char[ sizeof( Response * ) * num ];
|
||
|
memset( responseLookup, 0, sizeof( Response * ) * num );
|
||
|
|
||
|
set = new qboolean[ num ];
|
||
|
memset( set, 0, sizeof( qboolean ) * num );
|
||
|
|
||
|
this->numEvents = num;
|
||
|
|
||
|
for( c = this; c != NULL; c = c->super )
|
||
|
{
|
||
|
r = c->responses;
|
||
|
if ( r )
|
||
|
{
|
||
|
for( i = 0; r[ i ].event != NULL; i++ )
|
||
|
{
|
||
|
ev = ( int )*r[ i ].event;
|
||
|
if ( !set[ ev ] )
|
||
|
{
|
||
|
set[ ev ] = true;
|
||
|
if ( r[ i ].response )
|
||
|
{
|
||
|
responseLookup[ ev ] = &r[ i ].response;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
responseLookup[ ev ] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete[] set;
|
||
|
}
|
||
|
|
||
|
void BuildEventResponses( void )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
int amount;
|
||
|
int numclasses;
|
||
|
|
||
|
amount = 0;
|
||
|
numclasses = 0;
|
||
|
for( c = classlist->next; c != classlist; c = c->next )
|
||
|
{
|
||
|
c->BuildResponseList();
|
||
|
|
||
|
amount += c->numEvents * sizeof( Response * );
|
||
|
numclasses++;
|
||
|
}
|
||
|
|
||
|
CLASS_DPrintf( "\n------------------\nEvent system initialized: "
|
||
|
"%d classes %d events %d total memory in response list\n\n", numclasses, Event::NumEventCommands(), amount );
|
||
|
}
|
||
|
|
||
|
ClassDef *getClassForID( const char *name )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
|
||
|
for( c = classlist->next; c != classlist; c = c->next )
|
||
|
{
|
||
|
if ( c->classID && !Q_stricmp( c->classID, name ) )
|
||
|
{
|
||
|
return c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ClassDef *getClass( const char *name )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
|
||
|
for( c = classlist->next; c != classlist; c = c->next )
|
||
|
{
|
||
|
if ( !Q_stricmp( c->classname, name ) )
|
||
|
{
|
||
|
return c;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ClassDef *getClassList( void )
|
||
|
{
|
||
|
return classlist;
|
||
|
}
|
||
|
|
||
|
void listAllClasses( void )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
|
||
|
for( c = classlist->next; c != classlist; c = c->next )
|
||
|
{
|
||
|
CLASS_DPrintf( "%s\n", c->classname );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void listInheritanceOrder( const char *classname )
|
||
|
{
|
||
|
ClassDef *cls;
|
||
|
ClassDef *c;
|
||
|
|
||
|
cls = getClass( classname );
|
||
|
if ( !cls )
|
||
|
{
|
||
|
CLASS_WDPrintf( "Unknown class: %s\n", classname );
|
||
|
return;
|
||
|
}
|
||
|
for( c = cls; c != NULL; c = c->super )
|
||
|
{
|
||
|
CLASS_DPrintf( "%s\n", c->classname );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
qboolean checkInheritance( const ClassDef *superclass, const ClassDef *subclass )
|
||
|
{
|
||
|
const ClassDef *c;
|
||
|
|
||
|
for( c = subclass; c != NULL; c = c->super )
|
||
|
{
|
||
|
if ( c == superclass )
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
qboolean checkInheritance( ClassDef *superclass, const char *subclass )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
|
||
|
c = getClass( subclass );
|
||
|
if ( c == NULL )
|
||
|
{
|
||
|
CLASS_WDPrintf( "Unknown class: %s\n", subclass );
|
||
|
return false;
|
||
|
}
|
||
|
return checkInheritance( superclass, c );
|
||
|
}
|
||
|
|
||
|
qboolean checkInheritance( const char *superclass, const char *subclass )
|
||
|
{
|
||
|
ClassDef *c1;
|
||
|
ClassDef *c2;
|
||
|
|
||
|
c1 = getClass( superclass );
|
||
|
c2 = getClass( subclass );
|
||
|
if ( c1 == NULL )
|
||
|
{
|
||
|
CLASS_WDPrintf( "Unknown class: %s\n", superclass );
|
||
|
return false;
|
||
|
}
|
||
|
if ( c2 == NULL )
|
||
|
{
|
||
|
CLASS_WDPrintf( "Unknown class: %s\n", subclass );
|
||
|
return false;
|
||
|
}
|
||
|
return checkInheritance( c1, c2 );
|
||
|
}
|
||
|
|
||
|
void CLASS_Print( FILE *class_file, const char *fmt, ... )
|
||
|
{
|
||
|
va_list argptr;
|
||
|
char text[ 1024 ];
|
||
|
|
||
|
va_start( argptr, fmt );
|
||
|
vsprintf( text, fmt, argptr );
|
||
|
va_end( argptr );
|
||
|
|
||
|
if ( class_file )
|
||
|
fprintf( class_file, text );
|
||
|
else
|
||
|
CLASS_DPrintf( text );
|
||
|
}
|
||
|
|
||
|
CLASS_DECLARATION( NULL, Class, NULL )
|
||
|
{
|
||
|
{ NULL, NULL }
|
||
|
};
|
||
|
|
||
|
#ifdef NDEBUG
|
||
|
|
||
|
void * Class::operator new( size_t s )
|
||
|
{
|
||
|
int *p;
|
||
|
|
||
|
if ( s == 0 )
|
||
|
return 0;
|
||
|
|
||
|
s += sizeof( int );
|
||
|
#if defined( GAME_DLL )
|
||
|
p = ( int * )gi.Malloc( s );
|
||
|
#elif defined( CGAME_DLL )
|
||
|
p = ( int * )cgi.Malloc( s );
|
||
|
#else
|
||
|
p = ( int * )Z_TagMalloc( s, TAG_CLIENT );
|
||
|
#endif
|
||
|
*p = s;
|
||
|
totalmemallocated += s;
|
||
|
numclassesallocated++;
|
||
|
return p + 1;
|
||
|
}
|
||
|
|
||
|
void Class::operator delete( void *ptr )
|
||
|
{
|
||
|
int *p;
|
||
|
|
||
|
p = ( ( int * )ptr ) - 1;
|
||
|
totalmemallocated -= *p;
|
||
|
numclassesallocated--;
|
||
|
#if defined( GAME_DLL )
|
||
|
gi.Free( p );
|
||
|
#elif defined( CGAME_DLL )
|
||
|
cgi.Free( p );
|
||
|
#else
|
||
|
Z_Free( p );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
#ifdef MEMORY_LEAK_TEST
|
||
|
int classindex = 0;
|
||
|
#endif
|
||
|
|
||
|
void * Class::operator new( size_t s )
|
||
|
{
|
||
|
int *p;
|
||
|
|
||
|
s += sizeof( int ) * 3;
|
||
|
#if defined( GAME_DLL )
|
||
|
p = ( int * )gi.Malloc( s );
|
||
|
#elif defined( CGAME_DLL )
|
||
|
p = ( int * )cgi.Malloc( s );
|
||
|
#else
|
||
|
p = ( int * )Z_TagMalloc( s, TAG_CLIENT );
|
||
|
#endif
|
||
|
// set memory to a known wrong number
|
||
|
memset( p, 0xaa, s );
|
||
|
#ifdef MEMORY_LEAK_TEST
|
||
|
p[ 0 ] = classindex++;
|
||
|
#else
|
||
|
p[ 0 ] = 0x12348765;
|
||
|
#endif
|
||
|
*( int * )( ((byte *)p) + s - sizeof( int ) ) = 0x56784321;
|
||
|
p[ 1 ] = s;
|
||
|
totalmemallocated += s;
|
||
|
numclassesallocated++;
|
||
|
return p + 2;
|
||
|
}
|
||
|
|
||
|
void Class::operator delete( void *ptr )
|
||
|
{
|
||
|
int *p;
|
||
|
|
||
|
p = ( ( int * )ptr ) - 2;
|
||
|
#ifndef MEMORY_LEAK_TEST
|
||
|
assert( p[ 0 ] == 0x12348765 );
|
||
|
#endif
|
||
|
assert( *( int * )( ((byte *)p) + p[ 1 ] - sizeof( int ) ) == 0x56784321 );
|
||
|
|
||
|
totalmemallocated -= p[ 1 ];
|
||
|
numclassesallocated--;
|
||
|
#if defined( GAME_DLL )
|
||
|
gi.Free( p );
|
||
|
#elif defined( CGAME_DLL )
|
||
|
cgi.Free( p );
|
||
|
#else
|
||
|
Z_Free( p );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void DisplayMemoryUsage( void )
|
||
|
{
|
||
|
CLASS_Printf( "Classes %-5d Class memory used: %d\n", numclassesallocated, totalmemallocated );
|
||
|
}
|
||
|
|
||
|
Class::Class()
|
||
|
{
|
||
|
SafePtrList = NULL;
|
||
|
}
|
||
|
|
||
|
Class::~Class()
|
||
|
{
|
||
|
ClearSafePointers();
|
||
|
}
|
||
|
|
||
|
#ifdef GAME_DLL
|
||
|
|
||
|
void Class::Archive( Archiver &arc )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void Class::ClearSafePointers( void )
|
||
|
{
|
||
|
while( SafePtrList != NULL )
|
||
|
{
|
||
|
SafePtrList->Clear();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void Class::warning( const char *function, const char *fmt, ... )
|
||
|
{
|
||
|
va_list argptr;
|
||
|
char text[ 1024 ];
|
||
|
|
||
|
va_start( argptr, fmt );
|
||
|
vsprintf( text, fmt, argptr );
|
||
|
va_end( argptr );
|
||
|
|
||
|
if ( getClassID() )
|
||
|
{
|
||
|
CLASS_WDPrintf( "%s::%s : %s\n", getClassID(), function, text );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CLASS_WDPrintf( "%s::%s : %s\n", getClassname(), function, text );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Class::error( const char *function, const char *fmt, ... )
|
||
|
{
|
||
|
va_list argptr;
|
||
|
char text[ 1024 ];
|
||
|
|
||
|
va_start( argptr, fmt );
|
||
|
vsprintf( text, fmt, argptr );
|
||
|
va_end( argptr );
|
||
|
|
||
|
if ( getClassID() )
|
||
|
{
|
||
|
CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassID(), function, text );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassname(), function, text );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
qboolean Class::inheritsFrom( const char *name ) const
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
|
||
|
c = getClass( name );
|
||
|
if ( c == NULL )
|
||
|
{
|
||
|
CLASS_WDPrintf( "Unknown class: %s\n", name );
|
||
|
return false;
|
||
|
}
|
||
|
return checkInheritance( c, classinfo() );
|
||
|
}
|
||
|
|
||
|
qboolean Class::isInheritedBy( const char *name ) const
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
|
||
|
c = getClass( name );
|
||
|
if ( c == NULL )
|
||
|
{
|
||
|
CLASS_WDPrintf( "Unknown class: %s\n", name );
|
||
|
return false;
|
||
|
}
|
||
|
return checkInheritance( classinfo(), c );
|
||
|
}
|
||
|
|
||
|
const char *Class::getClassname( void )
|
||
|
{
|
||
|
ClassDef *cls;
|
||
|
|
||
|
cls = classinfo();
|
||
|
return cls->classname;
|
||
|
}
|
||
|
|
||
|
const char *Class::getClassID( void )
|
||
|
{
|
||
|
ClassDef *cls;
|
||
|
|
||
|
cls = classinfo();
|
||
|
return cls->classID;
|
||
|
}
|
||
|
|
||
|
const char *Class::getSuperclass( void )
|
||
|
{
|
||
|
ClassDef *cls;
|
||
|
|
||
|
cls = classinfo();
|
||
|
return cls->superclass;
|
||
|
}
|
||
|
|
||
|
void *Class::newInstance( void )
|
||
|
{
|
||
|
ClassDef *cls;
|
||
|
|
||
|
cls = classinfo();
|
||
|
return cls->newInstance();
|
||
|
}
|
||
|
|
||
|
#define MAX_INHERITANCE 64
|
||
|
void ClassEvents( const char *classname, qboolean print_to_disk )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
ResponseDef<Class> *r;
|
||
|
int ev;
|
||
|
int i, j;
|
||
|
qboolean *set;
|
||
|
int num, orderNum;
|
||
|
Event **events;
|
||
|
byte *order;
|
||
|
FILE *class_file;
|
||
|
str classNames[ MAX_INHERITANCE ];
|
||
|
str class_filename;
|
||
|
|
||
|
c = getClass( classname );
|
||
|
if ( !c )
|
||
|
{
|
||
|
CLASS_WDPrintf( "Unknown class: %s\n", classname );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
class_file = NULL;
|
||
|
|
||
|
if ( print_to_disk )
|
||
|
{
|
||
|
class_filename = str ( classname ) + ".txt";
|
||
|
class_file = fopen( class_filename.c_str(), "w" );
|
||
|
if ( class_file == NULL )
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
num = Event::NumEventCommands();
|
||
|
|
||
|
set = new qboolean[ num ];
|
||
|
memset( set, 0, sizeof( qboolean ) * num );
|
||
|
|
||
|
events = new Event *[ num ];
|
||
|
memset( events, 0, sizeof( Event * ) * num );
|
||
|
|
||
|
order = new byte[ num ];
|
||
|
memset( order, 0, sizeof( byte ) * num );
|
||
|
|
||
|
orderNum = 0;
|
||
|
for( ; c != NULL; c = c->super )
|
||
|
{
|
||
|
if ( orderNum < MAX_INHERITANCE )
|
||
|
{
|
||
|
classNames[ orderNum ] = c->classname;
|
||
|
}
|
||
|
r = c->responses;
|
||
|
if ( r )
|
||
|
{
|
||
|
for( i = 0; r[ i ].event != NULL; i++ )
|
||
|
{
|
||
|
ev = ( int )*r[ i ].event;
|
||
|
if ( !set[ ev ] )
|
||
|
{
|
||
|
set[ ev ] = true;
|
||
|
|
||
|
if ( r[ i ].response )
|
||
|
{
|
||
|
events[ ev ] = r[ i ].event;
|
||
|
order[ ev ] = orderNum;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
orderNum++;
|
||
|
}
|
||
|
|
||
|
CLASS_Print( class_file, "********************************************************\n" );
|
||
|
CLASS_Print( class_file, "********************************************************\n" );
|
||
|
CLASS_Print( class_file, "* All Events For Class: %s\n", classname );
|
||
|
CLASS_Print( class_file, "********************************************************\n" );
|
||
|
CLASS_Print( class_file, "********************************************************\n\n" );
|
||
|
|
||
|
for( j = orderNum - 1; j >= 0; j-- )
|
||
|
{
|
||
|
CLASS_Print( class_file, "\n********************************************************\n" );
|
||
|
CLASS_Print( class_file, "* Class: %s\n", classNames[ j ].c_str() );
|
||
|
CLASS_Print( class_file, "********************************************************\n\n" );
|
||
|
for( i = 1; i < num; i++ )
|
||
|
{
|
||
|
int index;
|
||
|
|
||
|
index = Event::MapSortedEventIndex( i );
|
||
|
if ( events[ index ] && ( order[ index ] == j ) )
|
||
|
{
|
||
|
Event::PrintEventDocumentation( events[ index ], class_file );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( class_file != NULL )
|
||
|
{
|
||
|
CLASS_DPrintf( "Printed class info to file %s\n", class_filename.c_str() );
|
||
|
fclose( class_file );
|
||
|
}
|
||
|
|
||
|
delete[] events;
|
||
|
delete[] order;
|
||
|
delete[] set;
|
||
|
}
|
||
|
|
||
|
static int dump_numclasses;
|
||
|
static int dump_numevents;
|
||
|
void DumpClass( FILE * class_file, const char * className, int typeFlag )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
ResponseDef<Class> *r;
|
||
|
int ev;
|
||
|
int i;
|
||
|
int num;
|
||
|
Event **events;
|
||
|
|
||
|
c = getClass( className );
|
||
|
if ( !c )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
num = Event::NumEventCommands();
|
||
|
|
||
|
events = new Event *[ num ];
|
||
|
memset( events, 0, sizeof( Event * ) * num );
|
||
|
|
||
|
// gather event responses for this class
|
||
|
r = c->responses;
|
||
|
if ( r )
|
||
|
{
|
||
|
for( i = 0; r[ i ].event != NULL; i++ )
|
||
|
{
|
||
|
ev = ( int )*r[ i ].event;
|
||
|
if ( r[ i ].response )
|
||
|
{
|
||
|
events[ ev ] = r[ i ].event;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CLASS_Print( class_file, "\n");
|
||
|
if ( c->classID[ 0 ] )
|
||
|
{
|
||
|
CLASS_Print( class_file, "<h2> <a name=\"%s\">%s (<i>%s</i>)</a>", c->classname, c->classname, c->classID );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CLASS_Print( class_file, "<h2> <a name=\"%s\">%s</a>", c->classname, c->classname );
|
||
|
}
|
||
|
|
||
|
// print out lineage
|
||
|
for( c = c->super; c != NULL; c = c->super )
|
||
|
{
|
||
|
CLASS_Print( class_file, " -> <a href=\"#%s\">%s</a>", c->classname, c->classname );
|
||
|
}
|
||
|
CLASS_Print( class_file, "</h2>\n");
|
||
|
|
||
|
dump_numclasses++;
|
||
|
|
||
|
CLASS_Print( class_file, "<BLOCKQUOTE>\n");
|
||
|
for( i = 1; i < num; i++ )
|
||
|
{
|
||
|
int index;
|
||
|
|
||
|
index = Event::MapSortedEventIndex( i );
|
||
|
if ( events[ index ] )
|
||
|
{
|
||
|
Event::PrintEventDocumentation( events[ index ], class_file, true, typeFlag );
|
||
|
dump_numevents++;
|
||
|
}
|
||
|
}
|
||
|
CLASS_Print( class_file, "</BLOCKQUOTE>\n");
|
||
|
delete[] events;
|
||
|
}
|
||
|
|
||
|
void DumpAllClasses( int typeFlag, int outputType, const char *filename )
|
||
|
{
|
||
|
str defaultname;
|
||
|
#if defined( GAME_DLL )
|
||
|
defaultname = "g_allclasses";
|
||
|
#elif defined( CGAME_DLL )
|
||
|
defaultname = "cg_allclasses";
|
||
|
#else
|
||
|
defaultname = "cl_allclasses";
|
||
|
#endif
|
||
|
|
||
|
if ( outputType == OUTPUT_HTML || !outputType )
|
||
|
{
|
||
|
HTMLDocFileOutput *hdout = new HTMLDocFileOutput();
|
||
|
if ( filename )
|
||
|
hdout->Write(filename, classlist, typeFlag);
|
||
|
else
|
||
|
hdout->Write(defaultname, classlist, typeFlag);
|
||
|
delete hdout;
|
||
|
}
|
||
|
|
||
|
if ( outputType == OUTPUT_CMD || !outputType )
|
||
|
{
|
||
|
ToolDocFileOutput *dout = new ToolDocFileOutput();
|
||
|
if ( filename )
|
||
|
dout->Write(filename, classlist, typeFlag);
|
||
|
else
|
||
|
dout->Write(defaultname, classlist, typeFlag);
|
||
|
delete dout;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
int i, j, num, smallest;
|
||
|
ClassDef *c;
|
||
|
FILE * class_file;
|
||
|
str class_filename;
|
||
|
str class_title;
|
||
|
str classes[ MAX_CLASSES ];
|
||
|
|
||
|
#if defined( GAME_DLL )
|
||
|
class_filename = "g_allclasses.html";
|
||
|
class_title = "Game Module";
|
||
|
#elif defined( CGAME_DLL )
|
||
|
class_filename = "cg_allclasses.html";
|
||
|
class_title = "Client Game Module";
|
||
|
#else
|
||
|
class_filename = "cl_allclasses.html";
|
||
|
class_title = "Client Module";
|
||
|
#endif
|
||
|
|
||
|
class_file = fopen( class_filename.c_str(), "w" );
|
||
|
if ( class_file == NULL )
|
||
|
return;
|
||
|
|
||
|
// construct the HTML header for the document
|
||
|
CLASS_Print( class_file, "<HTML>\n");
|
||
|
CLASS_Print( class_file, "<HEAD>\n");
|
||
|
CLASS_Print( class_file, "<Title>%s Classes</Title>\n", class_title.c_str() );
|
||
|
CLASS_Print( class_file, "</HEAD>\n");
|
||
|
CLASS_Print( class_file, "<BODY>\n");
|
||
|
CLASS_Print( class_file, "<H1>\n");
|
||
|
CLASS_Print( class_file, "<center>%s Classes</center>\n", class_title.c_str() );
|
||
|
CLASS_Print( class_file, "</H1>\n");
|
||
|
#if defined( GAME_DLL )
|
||
|
//
|
||
|
// print out some commonly used classnames
|
||
|
//
|
||
|
CLASS_Print( class_file, "<h2>" );
|
||
|
CLASS_Print( class_file, "<a href=\"#Actor\">Actor</a>, " );
|
||
|
CLASS_Print( class_file, "<a href=\"#Animate\">Animate</a>, " );
|
||
|
CLASS_Print( class_file, "<a href=\"#Entity\">Entity</a>, " );
|
||
|
CLASS_Print( class_file, "<a href=\"#ScriptSlave\">ScriptSlave</a>, " );
|
||
|
CLASS_Print( class_file, "<a href=\"#ScriptThread\">ScriptThread</a>, " );
|
||
|
CLASS_Print( class_file, "<a href=\"#Sentient\">Sentient</a>, " );
|
||
|
CLASS_Print( class_file, "<a href=\"#Trigger\">Trigger</a>, " );
|
||
|
CLASS_Print( class_file, "<a href=\"#World\">World</a>" );
|
||
|
CLASS_Print( class_file, "</h2>" );
|
||
|
#endif
|
||
|
|
||
|
dump_numclasses = 0;
|
||
|
dump_numevents = 0;
|
||
|
|
||
|
// get all the classes
|
||
|
num = 0;
|
||
|
for( c = classlist->next; c != classlist; c = c->next )
|
||
|
{
|
||
|
if ( num < MAX_CLASSES )
|
||
|
{
|
||
|
classes[ num++ ] = c->classname;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// go through and process each class from smallest to greatest
|
||
|
for( i = 0; i < num; i++ )
|
||
|
{
|
||
|
smallest = -1;
|
||
|
for( j = 0; j < num; j++ )
|
||
|
{
|
||
|
if ( classes[ j ].length() > 1 )
|
||
|
{
|
||
|
if ( smallest >= 0 )
|
||
|
{
|
||
|
if ( classes[ j ].icmp( classes[ smallest ] ) < 0 )
|
||
|
{
|
||
|
smallest = j;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
smallest = j;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
DumpClass( class_file, classes[ smallest ], typeFlag );
|
||
|
// delete the name from the list
|
||
|
classes[ smallest ] = "";
|
||
|
}
|
||
|
|
||
|
if ( class_file != NULL )
|
||
|
{
|
||
|
CLASS_Print( class_file, "<H2>\n");
|
||
|
CLASS_Print( class_file, "%d %s Classes.<BR>%d %s Events.\n", dump_numclasses, class_title.c_str(), dump_numevents, class_title.c_str() );
|
||
|
CLASS_Print( class_file, "</H2>\n");
|
||
|
CLASS_Print( class_file, "</BODY>\n");
|
||
|
CLASS_Print( class_file, "</HTML>\n");
|
||
|
CLASS_DPrintf( "Dumped all classes to file %s\n", class_filename.c_str() );
|
||
|
fclose( class_file );
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
void ShutdownClasses( void )
|
||
|
{
|
||
|
ClassDef *c;
|
||
|
|
||
|
for( c = classlist->next; c != classlist; c = c->next )
|
||
|
{
|
||
|
c->Shutdown();
|
||
|
}
|
||
|
}
|