- Made several DECORATE errors which do not involve parsing non-fatal.

- Added a static error counter to FScriptPosition class.
- Changed initialization of actor class type properties: fuglyname is gone as
  is the postprocessing in FinishThingdef. Instead an empty placeholder class
  is now created when a class is first referenced and this placeholder is later
  filled in. 
- Added option to replace backslash with '^' in state frame definitions because
  the backslash is just causing too many problems because it's also an escape
  character.


SVN r1334 (trunk)
This commit is contained in:
Christoph Oelckers 2008-12-29 23:03:38 +00:00
parent 8f686a5e02
commit f8c38e5f54
12 changed files with 211 additions and 186 deletions

View file

@ -1,3 +1,14 @@
December 30, 2008 (Changes by Graf Zahl)
- Made several DECORATE errors which do not involve parsing non-fatal.
- Added a static error counter to FScriptPosition class.
- Changed initialization of actor class type properties: fuglyname is gone as
is the postprocessing in FinishThingdef. Instead an empty placeholder class
is now created when a class is first referenced and this placeholder is later
filled in.
- Added option to replace backslash with '^' in state frame definitions because
the backslash is just causing too many problems because it's also an escape
character.
December 28, 2008 (Changes by Graf Zahl) December 28, 2008 (Changes by Graf Zahl)
- Added Karate Chris's new DMFlags submission. - Added Karate Chris's new DMFlags submission.

View file

@ -216,7 +216,7 @@ const PClass *PClass::FindClass (FName zaname)
} }
else if (lexx == 0) else if (lexx == 0)
{ {
return cls; return cls->Size<0? NULL : cls;
} }
else else
{ {
@ -247,15 +247,34 @@ DObject *PClass::CreateNew () const
PClass *PClass::CreateDerivedClass (FName name, unsigned int size) PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
{ {
assert (size >= Size); assert (size >= Size);
PClass *type;
bool notnew;
PClass *type = new PClass; const PClass *existclass = FindClass(name);
// This is a placeholder so fill it in
if (existclass != NULL && existclass->Size == -1)
{
type = const_cast<PClass*>(existclass);
if (!IsDescendantOf(type->ParentClass))
{
I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars());
}
Printf("Defining placeholder class %s\n", name.GetChars());
notnew = true;
}
else
{
type = new PClass;
notnew = false;
}
type->TypeName = name; type->TypeName = name;
type->ParentClass = this; type->ParentClass = this;
type->Size = size; type->Size = size;
type->Pointers = NULL; type->Pointers = NULL;
type->ConstructNative = ConstructNative; type->ConstructNative = ConstructNative;
type->ClassIndex = m_Types.Push (type); if (!notnew) type->ClassIndex = m_Types.Push (type);
type->Meta = Meta; type->Meta = Meta;
type->Defaults = new BYTE[size]; type->Defaults = new BYTE[size];
memcpy (type->Defaults, Defaults, Size); memcpy (type->Defaults, Defaults, Size);
@ -267,7 +286,7 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
type->bRuntimeClass = true; type->bRuntimeClass = true;
type->ActorInfo = NULL; type->ActorInfo = NULL;
type->Symbols.SetParentTable (&this->Symbols); type->Symbols.SetParentTable (&this->Symbols);
type->InsertIntoHash(); if (!notnew) type->InsertIntoHash();
// If this class has an actor info, then any classes derived from it // If this class has an actor info, then any classes derived from it
// also need an actor info. // also need an actor info.
@ -290,6 +309,51 @@ PClass *PClass::CreateDerivedClass (FName name, unsigned int size)
return type; return type;
} }
// Like FindClass but creates a placeholder if no class
// is found. CreateDerivedClass will automatcally fill in
// the placeholder when the actual class is defined.
const PClass *PClass::FindClassTentative (FName name)
{
if (name == NAME_None)
{
return NULL;
}
PClass *cls = TypeHash[name % HASH_SIZE];
while (cls != 0)
{
int lexx = int(name) - int(cls->TypeName);
if (lexx > 0)
{
cls = cls->HashNext;
}
else if (lexx == 0)
{
return cls;
}
else
{
break;
}
}
PClass *type = new PClass;
Printf("Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars());
type->TypeName = name;
type->ParentClass = this;
type->Size = -1;
type->Pointers = NULL;
type->ConstructNative = NULL;
type->ClassIndex = m_Types.Push (type);
type->Defaults = NULL;
type->FlatPointers = NULL;
type->bRuntimeClass = true;
type->ActorInfo = NULL;
type->InsertIntoHash();
return type;
}
// This is used by DECORATE to assign ActorInfos to internal classes // This is used by DECORATE to assign ActorInfos to internal classes
void PClass::InitializeActorInfo () void PClass::InitializeActorInfo ()
{ {

View file

@ -169,6 +169,7 @@ struct PClass
static const PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); } static const PClass *FindClass (const FString &name) { return FindClass (FName (name, true)); }
static const PClass *FindClass (ENamedName name) { return FindClass (FName (name)); } static const PClass *FindClass (ENamedName name) { return FindClass (FName (name)); }
static const PClass *FindClass (FName name); static const PClass *FindClass (FName name);
const PClass *FindClassTentative (FName name); // not static!
static TArray<PClass *> m_Types; static TArray<PClass *> m_Types;
static TArray<PClass *> m_RuntimeActors; static TArray<PClass *> m_RuntimeActors;

View file

@ -826,8 +826,14 @@ bool FStateDefinitions::AddStates(FState *state, const char *framechars)
bool error = false; bool error = false;
while (*framechars) while (*framechars)
{ {
int frame=((*framechars++)&223)-'A'; int frame;
if (*framechars == '^')
frame = '\\'-'A';
else
frame = ((*framechars)&223)-'A';
framechars++;
if (frame<0 || frame>28) if (frame<0 || frame>28)
{ {
frame = 0; frame = 0;

View file

@ -1030,6 +1030,7 @@ void FScanner::CheckOpen()
// a class that remembers a parser position // a class that remembers a parser position
// //
//========================================================================== //==========================================================================
int FScriptPosition::ErrorCounter;
FScriptPosition::FScriptPosition(const FScriptPosition &other) FScriptPosition::FScriptPosition(const FScriptPosition &other)
{ {
@ -1092,6 +1093,7 @@ void STACK_ARGS FScriptPosition::Message (int severity, const char *message, ...
break; break;
case MSG_ERROR: case MSG_ERROR:
ErrorCounter++;
type = "error"; type = "error";
break; break;

View file

@ -238,6 +238,7 @@ enum
struct FScriptPosition struct FScriptPosition
{ {
static int ErrorCounter;
FString FileName; FString FileName;
int ScriptLine; int ScriptLine;
@ -250,6 +251,10 @@ struct FScriptPosition
FScriptPosition(FScanner &sc); FScriptPosition(FScanner &sc);
FScriptPosition &operator=(const FScriptPosition &other); FScriptPosition &operator=(const FScriptPosition &other);
void Message(int severity, const char *message,...) const; void Message(int severity, const char *message,...) const;
static void ResetErrorCounter()
{
ErrorCounter = 0;
}
}; };

View file

@ -184,7 +184,8 @@ void SetReplacement(FActorInfo *info, FName replaceName)
void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag) void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag)
{ {
AActor *defaults = (AActor*)info->Class->Defaults; PClass *ti = info->Class;
AActor *defaults = (AActor*)ti->Defaults;
try try
{ {
@ -192,7 +193,9 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag)
} }
catch (CRecoverableError &err) catch (CRecoverableError &err)
{ {
sc.Message(MSG_FATAL, "%s", err.GetMessage()); sc.Message(MSG_ERROR, "%s", err.GetMessage());
bag.statedef.MakeStateDefines(NULL);
return;
} }
bag.statedef.InstallStates (info, defaults); bag.statedef.InstallStates (info, defaults);
bag.statedef.MakeStateDefines(NULL); bag.statedef.MakeStateDefines(NULL);
@ -200,69 +203,78 @@ void FinishActor(const FScriptPosition &sc, FActorInfo *info, Baggage &bag)
{ {
if (bag.DropItemList == NULL) if (bag.DropItemList == NULL)
{ {
if (info->Class->Meta.GetMetaInt (ACMETA_DropItems) != 0) if (ti->Meta.GetMetaInt (ACMETA_DropItems) != 0)
{ {
info->Class->Meta.SetMetaInt (ACMETA_DropItems, 0); ti->Meta.SetMetaInt (ACMETA_DropItems, 0);
} }
} }
else else
{ {
info->Class->Meta.SetMetaInt (ACMETA_DropItems, ti->Meta.SetMetaInt (ACMETA_DropItems,
StoreDropItemChain(bag.DropItemList)); StoreDropItemChain(bag.DropItemList));
} }
} }
if (info->Class->IsDescendantOf (RUNTIME_CLASS(AInventory))) if (ti->IsDescendantOf (RUNTIME_CLASS(AInventory)))
{ {
defaults->flags |= MF_SPECIAL; defaults->flags |= MF_SPECIAL;
} }
// Weapons must be checked for all relevant states. They may crash the game otherwise.
if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
{
FState * ready = ti->ActorInfo->FindState(NAME_Ready);
FState * select = ti->ActorInfo->FindState(NAME_Select);
FState * deselect = ti->ActorInfo->FindState(NAME_Deselect);
FState * fire = ti->ActorInfo->FindState(NAME_Fire);
// Consider any weapon without any valid state abstract and don't output a warning
// This is for creating base classes for weapon groups that only set up some properties.
if (ready || select || deselect || fire)
{
if (!ready)
{
sc.Message(MSG_ERROR, "Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars());
}
if (!select)
{
sc.Message(MSG_ERROR, "Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars());
}
if (!deselect)
{
sc.Message(MSG_ERROR, "Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars());
}
if (!fire)
{
sc.Message(MSG_ERROR, "Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars());
}
}
}
} }
//========================================================================== //==========================================================================
// //
// Do some postprocessing after everything has been defined // Do some postprocessing after everything has been defined
// This also processes all the internal actors to adjust the type
// fields in the weapons
// //
//========================================================================== //==========================================================================
static int ResolvePointer(const PClass **pPtr, const PClass *owner, const PClass *destclass, const char *description)
{
fuglyname v;
v = *pPtr;
if (v != NAME_None && v.IsValidName())
{
*pPtr = PClass::FindClass(v);
if (!*pPtr)
{
Printf("Unknown %s '%s' in '%s'\n", description, v.GetChars(), owner->TypeName.GetChars());
return 1;
}
else if (!(*pPtr)->IsDescendantOf(destclass))
{
*pPtr = NULL;
Printf("Invalid %s '%s' in '%s'\n", description, v.GetChars(), owner->TypeName.GetChars());
return 1;
}
}
return 0;
}
static void FinishThingdef() static void FinishThingdef()
{ {
unsigned int i; int errorcount = StateParams.ResolveAll();
int errorcount;
errorcount = StateParams.ResolveAll(); for (unsigned i = 0;i < PClass::m_Types.Size(); i++)
for (i = 0;i < PClass::m_Types.Size(); i++)
{ {
PClass * ti = PClass::m_Types[i]; PClass * ti = PClass::m_Types[i];
// Skip non-actors // Skip non-actors
if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue; if (!ti->IsDescendantOf(RUNTIME_CLASS(AActor))) continue;
if (ti->Size == -1)
{
Printf("Class %s referenced but not defined\n", ti->TypeName.GetChars());
errorcount++;
continue;
}
AActor *def = GetDefaultByType(ti); AActor *def = GetDefaultByType(ti);
if (!def) if (!def)
@ -271,100 +283,6 @@ static void FinishThingdef()
errorcount++; errorcount++;
continue; continue;
} }
// Friendlies never count as kills!
if (def->flags & MF_FRIENDLY)
{
def->flags &=~MF_COUNTKILL;
}
if (ti->IsDescendantOf(RUNTIME_CLASS(AInventory)))
{
AInventory * defaults=(AInventory *)def;
errorcount += ResolvePointer(&defaults->PickupFlash, ti, RUNTIME_CLASS(AActor), "pickup flash");
}
if (ti->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)) && ti != RUNTIME_CLASS(APowerupGiver))
{
FString typestr;
APowerupGiver * defaults=(APowerupGiver *)def;
fuglyname v;
v = defaults->PowerupType;
if (v != NAME_None && v.IsValidName())
{
typestr.Format ("Power%s", v.GetChars());
const PClass * powertype=PClass::FindClass(typestr);
if (!powertype) powertype=PClass::FindClass(v.GetChars());
if (!powertype)
{
Printf("Unknown powerup type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
errorcount++;
}
else if (!powertype->IsDescendantOf(RUNTIME_CLASS(APowerup)))
{
Printf("Invalid powerup type '%s' in '%s'\n", v.GetChars(), ti->TypeName.GetChars());
errorcount++;
}
else
{
defaults->PowerupType=powertype;
}
}
else if (v == NAME_None)
{
Printf("No powerup type specified in '%s'\n", ti->TypeName.GetChars());
errorcount++;
}
}
// the typeinfo properties of weapons have to be fixed here after all actors have been declared
if (ti->IsDescendantOf(RUNTIME_CLASS(AWeapon)))
{
AWeapon * defaults=(AWeapon *)def;
errorcount += ResolvePointer(&defaults->AmmoType1, ti, RUNTIME_CLASS(AAmmo), "ammo type");
errorcount += ResolvePointer(&defaults->AmmoType2, ti, RUNTIME_CLASS(AAmmo), "ammo type");
errorcount += ResolvePointer(&defaults->SisterWeaponType, ti, RUNTIME_CLASS(AWeapon), "sister weapon type");
FState * ready = ti->ActorInfo->FindState(NAME_Ready);
FState * select = ti->ActorInfo->FindState(NAME_Select);
FState * deselect = ti->ActorInfo->FindState(NAME_Deselect);
FState * fire = ti->ActorInfo->FindState(NAME_Fire);
// Consider any weapon without any valid state abstract and don't output a warning
// This is for creating base classes for weapon groups that only set up some properties.
if (ready || select || deselect || fire)
{
// Do some consistency checks. If these states are undefined the weapon cannot work!
if (!ready)
{
Printf("Weapon %s doesn't define a ready state.\n", ti->TypeName.GetChars());
errorcount++;
}
if (!select)
{
Printf("Weapon %s doesn't define a select state.\n", ti->TypeName.GetChars());
errorcount++;
}
if (!deselect)
{
Printf("Weapon %s doesn't define a deselect state.\n", ti->TypeName.GetChars());
errorcount++;
}
if (!fire)
{
Printf("Weapon %s doesn't define a fire state.\n", ti->TypeName.GetChars());
errorcount++;
}
}
}
// same for the weapon type of weapon pieces.
else if (ti->IsDescendantOf(RUNTIME_CLASS(AWeaponPiece)))
{
AWeaponPiece * defaults=(AWeaponPiece *)def;
errorcount += ResolvePointer(&defaults->WeaponClass, ti, RUNTIME_CLASS(AWeapon), "weapon type");
}
} }
if (errorcount > 0) if (errorcount > 0)
{ {
@ -378,7 +296,6 @@ static void FinishThingdef()
mysnprintf(fmt, countof(fmt), "QuestItem%d", i+1); mysnprintf(fmt, countof(fmt), "QuestItem%d", i+1);
QuestItemClasses[i] = PClass::FindClass(fmt); QuestItemClasses[i] = PClass::FindClass(fmt);
} }
} }
@ -395,6 +312,7 @@ void LoadActors ()
{ {
int lastlump, lump; int lastlump, lump;
FScriptPosition::ResetErrorCounter();
InitThingdef(); InitThingdef();
lastlump = 0; lastlump = 0;
while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1) while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1)
@ -402,6 +320,10 @@ void LoadActors ()
FScanner sc(lump); FScanner sc(lump);
ParseDecorate (sc); ParseDecorate (sc);
} }
if (FScriptPosition::ErrorCounter > 0)
{
I_Error("%d errors while parsing DECORATE scripts", FScriptPosition::ErrorCounter);
}
FinishThingdef(); FinishThingdef();
} }

View file

@ -27,31 +27,6 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2);
void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index); void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int index);
//==========================================================================
//
// This class is for storing a name inside a const PClass* field without
// generating compiler warnings. It does not manipulate data in any other
// way.
//
//==========================================================================
class fuglyname : public FName
{
public:
fuglyname() : FName() {}
fuglyname(const char *foo) : FName(foo) {}
operator const PClass *()
{
return reinterpret_cast<const PClass *>(size_t(int(*this)));
}
fuglyname &operator= (const PClass *foo)
{
FName *p = this;
*p = ENamedName(reinterpret_cast<size_t>(foo));
return *this;
}
};
//========================================================================== //==========================================================================
// //
// State parser // State parser

View file

@ -62,6 +62,12 @@ struct FCompileContext
bool lax; bool lax;
bool isconst; bool isconst;
FCompileContext(const PClass *_cls = NULL, bool _lax = false, bool _isconst = false)
{
cls = _cls;
lax = _lax;
isconst = _isconst;
}
PSymbol *FindInClass(FName identifier) PSymbol *FindInClass(FName identifier)
{ {

View file

@ -232,7 +232,7 @@ static ExpVal GetVariableValue (void *address, FExpressionType &type)
ExpVal FxExpression::EvalExpression (AActor *self) ExpVal FxExpression::EvalExpression (AActor *self)
{ {
I_Error("Unresolved expression found"); ScriptPosition.Message(MSG_ERROR, "Unresolved expression found");
ExpVal val; ExpVal val;
val.Type = VAL_Int; val.Type = VAL_Int;
@ -2635,23 +2635,27 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
} }
if (scope != NULL) if (scope != NULL)
{ {
FState *destination = NULL;
// If the label is class specific we can resolve it right here // If the label is class specific we can resolve it right here
if (scope->ActorInfo == NULL) if (names[1] != NAME_None)
{ {
ScriptPosition.Message(MSG_ERROR, "'%s' has no actorinfo", names[0].GetChars()); if (scope->ActorInfo == NULL)
delete this;
return NULL;
}
FState *destination = scope->ActorInfo->FindState(names.Size()-1, &names[1], false);
if (destination == NULL)
{
ScriptPosition.Message(ctx.lax? MSG_WARNING:MSG_ERROR, "Unknown state jump destination");
if (!ctx.lax)
{ {
ScriptPosition.Message(MSG_ERROR, "'%s' has no actorinfo", names[0].GetChars());
delete this; delete this;
return NULL; return NULL;
} }
return this; destination = scope->ActorInfo->FindState(names.Size()-1, &names[1], false);
if (destination == NULL)
{
ScriptPosition.Message(ctx.lax? MSG_WARNING:MSG_ERROR, "Unknown state jump destination");
if (!ctx.lax)
{
delete this;
return NULL;
}
return this;
}
} }
FxExpression *x = new FxConstant(destination, ScriptPosition); FxExpression *x = new FxConstant(destination, ScriptPosition);
delete this; delete this;
@ -2707,7 +2711,7 @@ FStateExpressions StateParams;
FStateExpressions::~FStateExpressions() FStateExpressions::~FStateExpressions()
{ {
for(int i=0; i<Size(); i++) for(unsigned i=0; i<Size(); i++)
{ {
if (expressions[i].expr != NULL && !expressions[i].cloned) if (expressions[i].expr != NULL && !expressions[i].cloned)
{ {
@ -2797,7 +2801,7 @@ int FStateExpressions::ResolveAll()
FCompileContext ctx; FCompileContext ctx;
ctx.lax = true; ctx.lax = true;
for(int i=0; i<Size(); i++) for(unsigned i=0; i<Size(); i++)
{ {
if (expressions[i].cloned) if (expressions[i].cloned)
{ {
@ -2822,7 +2826,7 @@ int FStateExpressions::ResolveAll()
} }
} }
for(int i=0; i<Size(); i++) for(unsigned i=0; i<Size(); i++)
{ {
if (expressions[i].expr != NULL) if (expressions[i].expr != NULL)
{ {

View file

@ -69,6 +69,25 @@
#include "colormatcher.h" #include "colormatcher.h"
#include "autosegs.h" #include "autosegs.h"
//==========================================================================
//
// Gets a class pointer and performs an error check for correct type
//
//==========================================================================
static const PClass *FindClassTentative(const char *name, const char *ancestor)
{
const PClass *anc = PClass::FindClass(ancestor);
assert(anc != NULL); // parent classes used here should always be natively defined
const PClass *cls = const_cast<PClass*>(anc)->FindClassTentative(name);
assert (cls != NULL); // cls can not ne NULL here
if (!cls->IsDescendantOf(anc))
{
I_Error("%s does not inherit from %s\n", name, ancestor);
}
return cls;
}
//=========================================================================== //===========================================================================
// //
// HandleDeprecatedFlags // HandleDeprecatedFlags
@ -107,7 +126,7 @@ void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int ind
case DEPF_PICKUPFLASH: case DEPF_PICKUPFLASH:
if (set) if (set)
{ {
static_cast<AInventory*>(defaults)->PickupFlash = fuglyname("PickupFlash"); static_cast<AInventory*>(defaults)->PickupFlash = FindClassTentative("PickupFlash", "Actor");
} }
else else
{ {
@ -1160,7 +1179,7 @@ DEFINE_CLASS_PROPERTY(defmaxamount, 0, Inventory)
DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory) DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
defaults->PickupFlash = fuglyname(str); defaults->PickupFlash = FindClassTentative(str, "Actor");
} }
//========================================================================== //==========================================================================
@ -1270,7 +1289,7 @@ DEFINE_CLASS_PROPERTY(ammogive2, I, Weapon)
DEFINE_CLASS_PROPERTY(ammotype, S, Weapon) DEFINE_CLASS_PROPERTY(ammotype, S, Weapon)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
defaults->AmmoType1 = fuglyname(str); defaults->AmmoType1 = FindClassTentative(str, "Ammo");
} }
//========================================================================== //==========================================================================
@ -1279,7 +1298,7 @@ DEFINE_CLASS_PROPERTY(ammotype, S, Weapon)
DEFINE_CLASS_PROPERTY(ammotype1, S, Weapon) DEFINE_CLASS_PROPERTY(ammotype1, S, Weapon)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
defaults->AmmoType1 = fuglyname(str); defaults->AmmoType1 = FindClassTentative(str, "Ammo");
} }
//========================================================================== //==========================================================================
@ -1288,7 +1307,7 @@ DEFINE_CLASS_PROPERTY(ammotype1, S, Weapon)
DEFINE_CLASS_PROPERTY(ammotype2, S, Weapon) DEFINE_CLASS_PROPERTY(ammotype2, S, Weapon)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
defaults->AmmoType2 = fuglyname(str); defaults->AmmoType2 = FindClassTentative(str, "Ammo");
} }
//========================================================================== //==========================================================================
@ -1359,7 +1378,7 @@ DEFINE_CLASS_PROPERTY(selectionorder, I, Weapon)
DEFINE_CLASS_PROPERTY(sisterweapon, S, Weapon) DEFINE_CLASS_PROPERTY(sisterweapon, S, Weapon)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
defaults->SisterWeaponType = fuglyname(str); defaults->SisterWeaponType = FindClassTentative(str, "Weapon");
} }
//========================================================================== //==========================================================================
@ -1395,7 +1414,7 @@ DEFINE_CLASS_PROPERTY(number, I, WeaponPiece)
DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece) DEFINE_CLASS_PROPERTY(weapon, S, WeaponPiece)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
defaults->WeaponClass = fuglyname(str); defaults->WeaponClass = FindClassTentative(str, "Weapon");
} }
//========================================================================== //==========================================================================
@ -1505,7 +1524,18 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, PowerupGiver)
DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver) DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
{ {
PROP_STRING_PARM(str, 0); PROP_STRING_PARM(str, 0);
defaults->PowerupType = fuglyname(str);
// Yuck! What was I thinking when I decided to prepend "Power" to the name?
// Now it's too late to change it...
const PClass *cls = PClass::FindClass(str);
if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
{
FString st;
st.Format("%s%s", strnicmp(str, "power", 5)? "Power" : "", str);
cls = FindClassTentative(st, "Powerup");
}
defaults->PowerupType = cls;
} }
//========================================================================== //==========================================================================

View file

@ -17,7 +17,6 @@ enum ExpValType
VAL_Pointer, // Dereferenced variable (only used for addressing arrays for now.) VAL_Pointer, // Dereferenced variable (only used for addressing arrays for now.)
VAL_Sound, // Sound identifier. Internally it's an int. VAL_Sound, // Sound identifier. Internally it's an int.
VAL_Name, // A Name VAL_Name, // A Name
VAL_MultiName, // Multiple names for multi-label states
VAL_Color, // A color. VAL_Color, // A color.
VAL_State, // A State pointer VAL_State, // A State pointer