2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 2015 the OpenMoHAA team
|
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA 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 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA 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 OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// class.cpp: General class.
|
|
|
|
|
2023-01-29 20:59:31 +01:00
|
|
|
#include "class.h"
|
|
|
|
#include "listener.h"
|
2023-06-17 01:24:20 +02:00
|
|
|
#include "q_shared.h"
|
2023-01-29 20:59:31 +01:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
#if defined(GAME_DLL)
|
2023-04-30 20:36:22 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
# include "../fgame/g_local.h"
|
2023-04-30 20:36:22 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
# define CLASS_Printf gi.Printf
|
|
|
|
# define CLASS_DPrintf gi.DPrintf
|
|
|
|
# define CLASS_Error gi.Error
|
2023-04-30 20:36:22 +02:00
|
|
|
|
|
|
|
#elif defined(CGAME_DLL)
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
# include "../cgame/cg_local.h"
|
2023-04-30 20:36:22 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
# define CLASS_Printf cgi.Printf
|
|
|
|
# define CLASS_DPrintf cgi.DPrintf
|
|
|
|
# define CLASS_Error cgi.Error
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-01-29 20:59:31 +01:00
|
|
|
#else
|
2023-04-30 20:36:22 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
# define CLASS_Printf Com_Printf
|
|
|
|
# define CLASS_DPrintf Com_DPrintf
|
|
|
|
# define CLASS_Error Com_Error
|
2023-04-30 20:36:22 +02:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2023-05-29 01:33:07 +02:00
|
|
|
#ifdef WITH_SCRIPT_ENGINE
|
2023-04-30 20:36:22 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
# include "../fgame/scriptmaster.h"
|
2023-04-30 20:36:22 +02:00
|
|
|
|
2023-01-29 20:59:31 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
ClassDef *ClassDef::classlist;
|
2023-07-05 21:23:39 +02:00
|
|
|
int ClassDef::numclasses;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
int ClassDef::dump_numclasses;
|
|
|
|
int ClassDef::dump_numevents;
|
|
|
|
Container<int> ClassDef::sortedList;
|
|
|
|
Container<ClassDef *> ClassDef::sortedClassList;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
int ClassDef::compareClasses(const void *arg1, const void *arg2)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c1 = *(ClassDef **)arg1;
|
|
|
|
ClassDef *c2 = *(ClassDef **)arg2;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return Q_stricmp(c1->classname, c2->classname);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void ClassDef::SortClassList(Container<ClassDef *> *sortedList)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
sortedList->Resize(numclasses);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (c = classlist->next; c != classlist; c = c->next) {
|
|
|
|
sortedList->AddObject(c);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qsort(
|
|
|
|
(void *)sortedList->AddressOfObjectAt(1), (size_t)sortedList->NumObjects(), sizeof(ClassDef *), compareClasses
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *getClassForID(const char *name)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *classlist = ClassDef::classlist;
|
|
|
|
ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (c = classlist->next; c != classlist; c = c->next) {
|
|
|
|
if (c->classID && !Q_stricmp(c->classID, name)) {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *getClass(const char *name)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
if (name == NULL || !*name) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *list = ClassDef::classlist;
|
|
|
|
ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (c = list->next; c != list; c = c->next) {
|
|
|
|
if (Q_stricmp(c->classname, name) == 0) {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *getClassList(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return ClassDef::classlist;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void listAllClasses(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c;
|
|
|
|
ClassDef *list = ClassDef::classlist;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (c = list->next; c != list; c = c->next) {
|
|
|
|
CLASS_DPrintf("%s\n", c->classname);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void listInheritanceOrder(const char *classname)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *cls;
|
|
|
|
ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
cls = getClass(classname);
|
|
|
|
if (!cls) {
|
|
|
|
CLASS_DPrintf("Unknown class: %s\n", classname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (c = cls; c != NULL; c = c->super) {
|
|
|
|
CLASS_DPrintf("%s\n", c->classname);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qboolean checkInheritance(const ClassDef *superclass, const ClassDef *subclass)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
const ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (c = subclass; c != NULL; c = c->super) {
|
|
|
|
if (c == superclass) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qboolean checkInheritance(ClassDef *superclass, const char *subclass)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
c = getClass(subclass);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (c == NULL) {
|
|
|
|
CLASS_DPrintf("Unknown class: %s\n", subclass);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return checkInheritance(superclass, c);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qboolean checkInheritance(const char *superclass, const char *subclass)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c1;
|
|
|
|
ClassDef *c2;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
c1 = getClass(superclass);
|
|
|
|
c2 = getClass(subclass);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (c1 == NULL) {
|
|
|
|
CLASS_DPrintf("Unknown class: %s\n", superclass);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (c2 == NULL) {
|
|
|
|
CLASS_DPrintf("Unknown class: %s\n", subclass);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return checkInheritance(c1, c2);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void CLASS_Print(FILE *class_file, const char *fmt, ...)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
va_list argptr;
|
|
|
|
char text[1024];
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
va_start(argptr, fmt);
|
|
|
|
vsprintf(text, fmt, argptr);
|
|
|
|
va_end(argptr);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (class_file) {
|
|
|
|
fprintf(class_file, "%s", text);
|
|
|
|
} else {
|
|
|
|
CLASS_DPrintf("%s", text);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-19 12:13:43 +01:00
|
|
|
|
2016-03-27 11:49:47 +02:00
|
|
|
Class::Class()
|
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
SafePtrList = NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Class::~Class()
|
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClearSafePointers();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void Class::Archive(Archiver& arc) {}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void Class::ClearSafePointers(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
while (SafePtrList != NULL) {
|
|
|
|
SafePtrList->Clear();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-08-09 01:53:45 +02:00
|
|
|
void Class::warning(const char *function, const char *format, ...) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
char buffer[MAX_STRING_CHARS];
|
|
|
|
const char *classname;
|
|
|
|
va_list va;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
va_start(va, format);
|
|
|
|
vsprintf(buffer, format, va);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
classname = classinfo()->classname;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
#ifdef GAME_DLL
|
2023-07-05 21:23:39 +02:00
|
|
|
gi.DPrintf(
|
2016-03-27 11:49:47 +02:00
|
|
|
#elif defined CGAME_DLL
|
2023-07-05 21:23:39 +02:00
|
|
|
cgi.DPrintf(
|
2016-03-27 11:49:47 +02:00
|
|
|
#else
|
2023-07-05 21:23:39 +02:00
|
|
|
Com_DPrintf(
|
2016-03-27 11:49:47 +02:00
|
|
|
#endif
|
2023-07-05 21:23:39 +02:00
|
|
|
"%s::%s : %s\n", classname, function, buffer
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-08-09 01:53:45 +02:00
|
|
|
void Class::error(const char *function, const char *fmt, ...) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
va_list argptr;
|
|
|
|
char text[1024];
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
va_start(argptr, fmt);
|
|
|
|
vsprintf(text, fmt, argptr);
|
|
|
|
va_end(argptr);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
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);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ClassDef::ClassDef()
|
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
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;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-05-29 01:33:07 +02:00
|
|
|
#ifdef WITH_SCRIPT_ENGINE
|
2023-07-05 21:23:39 +02:00
|
|
|
this->waitTillSet = NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef::ClassDef(
|
|
|
|
const char *classname,
|
|
|
|
const char *classID,
|
|
|
|
const char *superclass,
|
|
|
|
ResponseDef<Class> *responses,
|
|
|
|
void *(*newInstance)(void),
|
|
|
|
int classSize
|
|
|
|
)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *node;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (classlist == NULL) {
|
|
|
|
classlist = new ClassDef;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
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);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-05-29 01:33:07 +02:00
|
|
|
#ifdef WITH_SCRIPT_ENGINE
|
2023-07-05 21:23:39 +02:00
|
|
|
this->waitTillSet = NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
#endif
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (!classID) {
|
|
|
|
this->classID = "";
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
// Add to front of list
|
|
|
|
LL_AddFirst(classlist, this, prev, next);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
numclasses++;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ClassDef::~ClassDef()
|
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
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;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-05-29 01:33:07 +02:00
|
|
|
#ifdef WITH_SCRIPT_ENGINE
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void ClassDef::AddWaitTill(str s)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return AddWaitTill(Director.AddString(s));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void ClassDef::AddWaitTill(const_str s)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
if (!waitTillSet) {
|
|
|
|
waitTillSet = new con_set<const_str, const_str>;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
waitTillSet->addKeyValue(s) = s;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void ClassDef::RemoveWaitTill(str s)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return RemoveWaitTill(Director.AddString(s));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void ClassDef::RemoveWaitTill(const_str s)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
if (waitTillSet) {
|
|
|
|
waitTillSet->remove(s);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
bool ClassDef::WaitTillDefined(str s)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return WaitTillDefined(Director.AddString(s));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
bool ClassDef::WaitTillDefined(const_str s)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
if (!waitTillSet) {
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return waitTillSet->findKeyValue(s) != NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
EventDef *ClassDef::GetDef(int eventnum)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ResponseDef<Class> *r = responseLookup[eventnum];
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (r) {
|
|
|
|
return r->def;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
int ClassDef::GetFlags(Event *event)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
EventDef *def = GetDef(event->eventnum);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (def) {
|
|
|
|
return def->flags;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void ClassDef::BuildResponseList(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c;
|
|
|
|
ResponseDef<Class> *r;
|
|
|
|
int ev;
|
|
|
|
int i;
|
|
|
|
qboolean *set;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
if (responseLookup) {
|
|
|
|
delete[] responseLookup;
|
|
|
|
responseLookup = NULL;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
num = Event::NumEventCommands(
|
|
|
|
); //size will be total event count, because it WAS faster to look for an event via eventnum
|
|
|
|
//nowadays there's not much overhead in performance, TODO: change size to appropriate.
|
|
|
|
responseLookup = (ResponseDef<Class> **)new char[sizeof(ResponseDef<Class> *) * num];
|
|
|
|
memset(responseLookup, 0, sizeof(ResponseDef<Class> *) * num);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
set = new qboolean[num];
|
|
|
|
memset(set, 0, sizeof(qboolean) * num);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
this->numEvents = num;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (c = this; c != NULL; c = c->super) {
|
|
|
|
r = c->responses;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (r) {
|
|
|
|
for (i = 0; r[i].event != NULL; i++) {
|
|
|
|
ev = (int)r[i].event->eventnum;
|
|
|
|
r[i].def = r[i].event->getInfo();
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (!set[ev]) {
|
|
|
|
set[ev] = true;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (r[i].response) {
|
|
|
|
responseLookup[ev] = &r[i];
|
|
|
|
} else {
|
|
|
|
responseLookup[ev] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
delete[] set;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void ClassDef::BuildEventResponses(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c;
|
|
|
|
int amount;
|
|
|
|
int numclasses;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
amount = 0;
|
|
|
|
numclasses = 0;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (c = classlist->next; c != classlist; c = c->next) {
|
|
|
|
c->BuildResponseList();
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
amount += c->numEvents * sizeof(Response *);
|
|
|
|
numclasses++;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
CLASS_DPrintf(
|
|
|
|
"\n------------------\nEvent system initialized: "
|
|
|
|
"%d classes %d events %d total memory in response list\n\n",
|
|
|
|
numclasses,
|
|
|
|
Event::NumEventCommands(),
|
|
|
|
amount
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
const char *Class::getClassID(void) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return classinfo()->classID;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
const char *Class::getClassname(void) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return classinfo()->classname;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
const char *Class::getSuperclass(void) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return classinfo()->superclass;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#define MAX_INHERITANCE 64
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
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_DPrintf("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->eventnum;
|
|
|
|
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 = ClassDef::sortedList.ObjectAt(i);
|
|
|
|
if (events[index] && (order[index] == j)) {
|
|
|
|
Event::eventDefList[events[index]].PrintEventDocumentation(class_file, qfalse);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DumpClass(FILE *class_file, const char *className)
|
|
|
|
{
|
|
|
|
ClassDef *c;
|
|
|
|
ResponseDef<Class> *r;
|
|
|
|
int ev;
|
|
|
|
int i;
|
|
|
|
int num, num2;
|
|
|
|
Event **events;
|
|
|
|
|
|
|
|
c = getClass(className);
|
|
|
|
if (!c) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
num = Event::commandList.size();
|
|
|
|
num2 = Event::NumEventCommands();
|
|
|
|
|
|
|
|
events = new Event *[num2];
|
|
|
|
memset(events, 0, sizeof(Event *) * num2);
|
|
|
|
|
|
|
|
// gather event responses for this class
|
|
|
|
r = c->responses;
|
|
|
|
if (r) {
|
|
|
|
for (i = 0; r[i].event != NULL; i++) {
|
|
|
|
ev = (int)r[i].event->eventnum;
|
|
|
|
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");
|
|
|
|
|
|
|
|
ClassDef::dump_numclasses++;
|
|
|
|
|
|
|
|
CLASS_Print(class_file, "<BLOCKQUOTE>\n");
|
|
|
|
for (i = 1; i < num; i++) {
|
|
|
|
int index;
|
|
|
|
|
|
|
|
index = ClassDef::sortedList.ObjectAt(i);
|
|
|
|
if (events[index]) {
|
|
|
|
Event::eventDefList[events[index]].PrintEventDocumentation(class_file, qtrue);
|
|
|
|
ClassDef::dump_numevents++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CLASS_Print(class_file, "</BLOCKQUOTE>\n");
|
|
|
|
delete[] events;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
|
|
|
#define MAX_CLASSES 1024
|
2023-07-05 21:23:39 +02:00
|
|
|
|
|
|
|
void DumpAllClasses(void)
|
|
|
|
{
|
|
|
|
int i, num;
|
|
|
|
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";
|
2016-03-27 11:49:47 +02:00
|
|
|
#else
|
2023-07-05 21:23:39 +02:00
|
|
|
class_filename = "cl_allclasses.html";
|
|
|
|
class_title = "Client Module";
|
2016-03-27 11:49:47 +02:00
|
|
|
#endif
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
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=\"#StateMap\">StateMap</a>, ");
|
|
|
|
CLASS_Print(class_file, "<a href=\"#Trigger\">Trigger</a>, ");
|
|
|
|
CLASS_Print(class_file, "<a href=\"#World\">World</a>");
|
|
|
|
CLASS_Print(class_file, "</h2>");
|
2016-03-27 11:49:47 +02:00
|
|
|
#endif
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef::dump_numclasses = 0;
|
|
|
|
ClassDef::dump_numevents = 0;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef::sortedList.ClearObjectList();
|
|
|
|
ClassDef::sortedClassList.ClearObjectList();
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
Event::SortEventList(&ClassDef::sortedList);
|
|
|
|
ClassDef::SortClassList(&ClassDef::sortedClassList);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
num = ClassDef::sortedClassList.NumObjects();
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
// go through and process each class from smallest to greatest
|
|
|
|
for (i = 1; i <= num; i++) {
|
|
|
|
c = ClassDef::sortedClassList.ObjectAt(i);
|
|
|
|
DumpClass(class_file, c->classname);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (class_file != NULL) {
|
|
|
|
CLASS_Print(class_file, "<H2>\n");
|
|
|
|
CLASS_Print(
|
|
|
|
class_file,
|
|
|
|
"%d %s Classes.<BR>%d %s Events.\n",
|
|
|
|
ClassDef::dump_numclasses,
|
|
|
|
class_title.c_str(),
|
|
|
|
ClassDef::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);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qboolean Class::inheritsFrom(ClassDef *c) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return checkInheritance(c, classinfo());
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qboolean Class::inheritsFrom(const char *name) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
c = getClass(name);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (c == NULL) {
|
|
|
|
CLASS_Printf("Unknown class: %s\n", name);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return checkInheritance(c, classinfo());
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qboolean Class::isInheritedBy(const char *name) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *c;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
c = getClass(name);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
if (c == NULL) {
|
|
|
|
CLASS_DPrintf("Unknown class: %s\n", name);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return checkInheritance(classinfo(), c);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
qboolean Class::isInheritedBy(ClassDef *c) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return checkInheritance(classinfo(), c);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ClassDefHook::ClassDefHook()
|
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
this->classdef = NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef
|
|
|
|
Class::ClassInfo("Class", NULL, NULL, (ResponseDef<Class> *)Class::Responses, Class::_newInstance, sizeof(Class));
|
2023-01-31 19:28:10 +01:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void *Class::_newInstance(void)
|
2023-01-31 19:28:10 +01:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return new Class();
|
2023-01-31 19:28:10 +01:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ClassDef *Class::classinfo(void) const
|
2023-01-31 19:28:10 +01:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return &(Class::ClassInfo);
|
2023-01-31 19:28:10 +01:00
|
|
|
}
|
2023-07-05 21:23:39 +02:00
|
|
|
|
|
|
|
ClassDef *Class::classinfostatic(void)
|
2023-01-31 19:28:10 +01:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
return &(Class::ClassInfo);
|
2023-01-31 19:28:10 +01:00
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
ResponseDef<Class> Class::Responses[] = {
|
|
|
|
{NULL, NULL}
|
2023-01-31 19:28:10 +01:00
|
|
|
};
|