mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-17 09:41:21 +00:00
6695e255ce
using duplicate DoomEdNums and will affect all attempts to spawn the replaced actor. However, because this happens for all spawns and not just at map load, the replacing actor must be compatible with the replaced actor, which means that an actor can only serve as a replacement for one of its baseclasses. For example, if you want to use a modified imp, you can use this DECORATE: actor MyImp : DoomImp replaces DoompImp { // Put changed properties here } - New: The IWAD dialog now remembers the last IWAD you picked and automatically highlights it the next time you run the game. This also applies if you check "Don't ask me this again": The IWAD selected will be the one that gets automatically loaded, not the one located first. (Using the -iwad parameter will not change the default IWAD.) In addition, you can now bring the dialog up even if you disable it by holding down SHIFT during startup. - Changed ExtractFilePath() and ExtractFileBase() to return FStrings instead of writing to a provided output buffer. ExtractFileBase() can also optionally keep the file's extension in the result. - Removed the -heapsize parameter entirely. The informational message should no longer be needed. - Removed -maxdemo parameter. There's no point to having it around since the demo buffer grows automatically. SVN r238 (trunk)
270 lines
6.4 KiB
C++
270 lines
6.4 KiB
C++
#include "dobject.h"
|
|
#include "i_system.h"
|
|
#include "actor.h"
|
|
#include "autosegs.h"
|
|
|
|
TArray<PClass *> PClass::m_RuntimeActors;
|
|
TArray<PClass *> PClass::m_Types;
|
|
PClass *PClass::TypeHash[PClass::HASH_SIZE];
|
|
|
|
// A harmless non_NULL FlatPointer for classes without pointers.
|
|
static const size_t TheEnd = ~0;
|
|
|
|
void PClass::StaticInit ()
|
|
{
|
|
atterm (StaticShutdown);
|
|
|
|
TAutoSegIterator<ClassReg *, &CRegHead, &CRegTail> probe;
|
|
|
|
while (++probe != NULL)
|
|
{
|
|
probe->RegisterClass ();
|
|
}
|
|
}
|
|
|
|
void PClass::StaticShutdown ()
|
|
{
|
|
TArray<size_t *> uniqueFPs(64);
|
|
unsigned int i, j;
|
|
|
|
for (i = 0; i < PClass::m_Types.Size(); ++i)
|
|
{
|
|
PClass *type = PClass::m_Types[i];
|
|
PClass::m_Types[i] = NULL;
|
|
if (type->FlatPointers != &TheEnd && type->FlatPointers != type->Pointers)
|
|
{
|
|
// FlatPointers are shared by many classes, so we must check for
|
|
// duplicates and only delete those that are unique.
|
|
for (j = 0; j < uniqueFPs.Size(); ++j)
|
|
{
|
|
if (type->FlatPointers == uniqueFPs[j])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (j == uniqueFPs.Size())
|
|
{
|
|
uniqueFPs.Push(const_cast<size_t *>(type->FlatPointers));
|
|
}
|
|
}
|
|
// For runtime classes, this call will also delete the PClass.
|
|
PClass::StaticFreeData (type);
|
|
}
|
|
for (i = 0; i < uniqueFPs.Size(); ++i)
|
|
{
|
|
delete[] uniqueFPs[i];
|
|
}
|
|
}
|
|
|
|
void PClass::StaticFreeData (PClass *type)
|
|
{
|
|
if (type->Defaults != NULL)
|
|
{
|
|
delete[] type->Defaults;
|
|
type->Defaults = NULL;
|
|
}
|
|
if (type->bRuntimeClass)
|
|
{
|
|
if (type->ActorInfo != NULL)
|
|
{
|
|
if (type->ActorInfo->OwnedStates != NULL)
|
|
{
|
|
delete[] type->ActorInfo->OwnedStates;
|
|
type->ActorInfo->OwnedStates = NULL;
|
|
}
|
|
delete type->ActorInfo;
|
|
type->ActorInfo = NULL;
|
|
}
|
|
delete type;
|
|
}
|
|
}
|
|
|
|
void ClassReg::RegisterClass ()
|
|
{
|
|
assert (MyClass != NULL);
|
|
|
|
// Add type to list
|
|
MyClass->ClassIndex = PClass::m_Types.Push (MyClass);
|
|
|
|
MyClass->TypeName = FName(Name+1);
|
|
MyClass->ParentClass = ParentType;
|
|
MyClass->Size = SizeOf;
|
|
MyClass->Pointers = Pointers;
|
|
MyClass->ConstructNative = ConstructNative;
|
|
MyClass->InsertIntoHash ();
|
|
}
|
|
|
|
void PClass::InsertIntoHash ()
|
|
{
|
|
// Add class to hash table. Classes are inserted into each bucket
|
|
// in ascending order by name index.
|
|
unsigned int bucket = TypeName % HASH_SIZE;
|
|
PClass **hashpos = &TypeHash[bucket];
|
|
while (*hashpos != NULL)
|
|
{
|
|
int lexx = int(TypeName) - int((*hashpos)->TypeName);
|
|
|
|
if (lexx > 0)
|
|
{ // This type should come later in the chain
|
|
hashpos = &((*hashpos)->HashNext);
|
|
}
|
|
else if (lexx == 0)
|
|
{ // This type has already been inserted
|
|
I_FatalError ("Tried to register class '%s' more than once.", TypeName.GetChars());
|
|
}
|
|
else
|
|
{ // Type comes right here
|
|
break;
|
|
}
|
|
}
|
|
HashNext = *hashpos;
|
|
*hashpos = this;
|
|
}
|
|
|
|
// Find a type, passed the name as a string
|
|
const PClass *PClass::FindClass (const char *zaname)
|
|
{
|
|
FName namename (zaname, true);
|
|
|
|
if (namename == NAME_None)
|
|
{
|
|
return NULL;
|
|
}
|
|
return FindClass (namename);
|
|
}
|
|
|
|
// Find a type, passed the name as a name
|
|
const PClass *PClass::FindClass (FName zaname)
|
|
{
|
|
PClass *cls = TypeHash[zaname % HASH_SIZE];
|
|
|
|
while (cls != 0)
|
|
{
|
|
int lexx = int(zaname) - int(cls->TypeName);
|
|
if (lexx > 0)
|
|
{
|
|
cls = cls->HashNext;
|
|
}
|
|
else if (lexx == 0)
|
|
{
|
|
return cls;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Create a new object that this class represents
|
|
DObject *PClass::CreateNew () const
|
|
{
|
|
BYTE *mem = (BYTE *)M_Malloc (Size);
|
|
|
|
// Set this object's defaults before constructing it.
|
|
if (Defaults!=NULL)
|
|
memcpy (mem, Defaults, Size);
|
|
else
|
|
memset (mem, 0, Size);
|
|
|
|
ConstructNative (mem);
|
|
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
|
|
return (DObject *)mem;
|
|
}
|
|
|
|
// Create a new class based on an existing class
|
|
PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
|
|
{
|
|
assert (size >= Size);
|
|
|
|
PClass *type = new PClass;
|
|
|
|
type->TypeName = name;
|
|
type->ParentClass = this;
|
|
type->Size = size;
|
|
type->Pointers = NULL;
|
|
type->ConstructNative = ConstructNative;
|
|
type->ClassIndex = m_Types.Push (type);
|
|
type->InsertIntoHash();
|
|
type->Meta = Meta;
|
|
type->Defaults = new BYTE[size];
|
|
memcpy (type->Defaults, Defaults, Size);
|
|
if (size > Size)
|
|
{
|
|
memset (type->Defaults + Size, 0, size - Size);
|
|
}
|
|
type->FlatPointers = NULL;
|
|
type->bRuntimeClass = true;
|
|
|
|
// If this class has an actor info, then any classes derived from it
|
|
// also need an actor info.
|
|
if (this->ActorInfo != NULL)
|
|
{
|
|
FActorInfo *info = type->ActorInfo = new FActorInfo;
|
|
info->Class = type;
|
|
info->GameFilter = GAME_Any;
|
|
info->SpawnID = 0;
|
|
info->DoomEdNum = -1;
|
|
info->OwnedStates = NULL;
|
|
info->NumOwnedStates = 0;
|
|
info->Replacement = NULL;
|
|
m_RuntimeActors.Push (type);
|
|
}
|
|
else
|
|
{
|
|
type->ActorInfo = NULL;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
// Create the FlatPointers array, if it doesn't exist already.
|
|
// It comprises all the Pointers from superclasses plus this class's own Pointers.
|
|
// If this class does not define any new Pointers, then FlatPointers will be set
|
|
// to the same array as the super class's.
|
|
void PClass::BuildFlatPointers ()
|
|
{
|
|
if (FlatPointers != NULL)
|
|
{ // Already built: Do nothing.
|
|
return;
|
|
}
|
|
else if (ParentClass == NULL)
|
|
{ // No parent: FlatPointers is the same as Pointers.
|
|
if (Pointers == NULL)
|
|
{ // No pointers: Make FlatPointers a harmless non-NULL.
|
|
FlatPointers = &TheEnd;
|
|
}
|
|
else
|
|
{
|
|
FlatPointers = Pointers;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ParentClass->BuildFlatPointers ();
|
|
if (Pointers == NULL)
|
|
{ // No new pointers: Just use the same FlatPointers as the parent.
|
|
FlatPointers = ParentClass->FlatPointers;
|
|
}
|
|
else
|
|
{ // New pointers: Create a new FlatPointers array and add them.
|
|
int numPointers, numSuperPointers;
|
|
|
|
// Count pointers defined by this class.
|
|
for (numPointers = 0; Pointers[numPointers] != ~(size_t)0; numPointers++)
|
|
{ }
|
|
// Count pointers defined by superclasses.
|
|
for (numSuperPointers = 0; ParentClass->FlatPointers[numSuperPointers] != ~(size_t)0; numSuperPointers++)
|
|
{ }
|
|
|
|
// Concatenate them into a new array
|
|
size_t *flat = new size_t[numPointers + numSuperPointers + 1];
|
|
if (numSuperPointers > 0)
|
|
{
|
|
memcpy (flat, ParentClass->FlatPointers, sizeof(size_t)*numSuperPointers);
|
|
}
|
|
memcpy (flat + numSuperPointers, Pointers, sizeof(size_t)*(numPointers+1));
|
|
FlatPointers = flat;
|
|
}
|
|
}
|
|
}
|