mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-07 09:01:57 +00:00
- added property definitions to the ZScript parser. This will allow defining custom properties for the default block in custom base classes. See 'Health' for an example.
- support transient object member variables for information that does not need to be put in a savegame. - fixed: special initialization of objects needs to pass the proper defaults along, otherwise the parent classes will use their own, inappropriate one.
This commit is contained in:
parent
0c3aab794f
commit
179b6e1a39
21 changed files with 313 additions and 109 deletions
|
@ -360,7 +360,7 @@ void DBot::WhatToGet (AActor *item)
|
||||||
}
|
}
|
||||||
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
|
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
|
||||||
return;
|
return;
|
||||||
else if (item->IsKindOf (RUNTIME_CLASS(AHealth)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina)
|
else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((dest == NULL ||
|
if ((dest == NULL ||
|
||||||
|
|
|
@ -1971,21 +1971,21 @@ static int PatchMisc (int dummy)
|
||||||
barmor->MaxSaveAmount = deh.MaxArmor;
|
barmor->MaxSaveAmount = deh.MaxArmor;
|
||||||
}
|
}
|
||||||
|
|
||||||
AHealth *health;
|
AInventory *health;
|
||||||
health = static_cast<AHealth *> (GetDefaultByName ("HealthBonus"));
|
health = static_cast<AInventory *> (GetDefaultByName ("HealthBonus"));
|
||||||
if (health!=NULL)
|
if (health!=NULL)
|
||||||
{
|
{
|
||||||
health->MaxAmount = 2 * deh.MaxHealth;
|
health->MaxAmount = 2 * deh.MaxHealth;
|
||||||
}
|
}
|
||||||
|
|
||||||
health = static_cast<AHealth *> (GetDefaultByName ("Soulsphere"));
|
health = static_cast<AInventory *> (GetDefaultByName ("Soulsphere"));
|
||||||
if (health!=NULL)
|
if (health!=NULL)
|
||||||
{
|
{
|
||||||
health->Amount = deh.SoulsphereHealth;
|
health->Amount = deh.SoulsphereHealth;
|
||||||
health->MaxAmount = deh.MaxSoulsphere;
|
health->MaxAmount = deh.MaxSoulsphere;
|
||||||
}
|
}
|
||||||
|
|
||||||
health = static_cast<AHealth *> (GetDefaultByName ("MegasphereHealth"));
|
health = static_cast<AInventory *> (GetDefaultByName ("MegasphereHealth"));
|
||||||
if (health!=NULL)
|
if (health!=NULL)
|
||||||
{
|
{
|
||||||
health->Amount = health->MaxAmount = deh.MegasphereHealth;
|
health->Amount = health->MaxAmount = deh.MegasphereHealth;
|
||||||
|
|
|
@ -566,3 +566,16 @@ DEFINE_ACTION_FUNCTION(DObject, GetClassName)
|
||||||
PARAM_SELF_PROLOGUE(DObject);
|
PARAM_SELF_PROLOGUE(DObject);
|
||||||
ACTION_RETURN_INT(self->GetClass()->TypeName);
|
ACTION_RETURN_INT(self->GetClass()->TypeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *DObject::ScriptVar(FName field, PType *type)
|
||||||
|
{
|
||||||
|
auto sym = dyn_cast<PField>(GetClass()->Symbols.FindSymbol(field, true));
|
||||||
|
if (sym && sym->Type == type)
|
||||||
|
{
|
||||||
|
return (((char*)this) + sym->Offset);
|
||||||
|
}
|
||||||
|
// This is only for internal use so I_Error is fine.
|
||||||
|
I_Error("Variable %s not found in %s\n", field.GetChars(), GetClass()->TypeName.GetChars());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#include "i_system.h"
|
#include "i_system.h"
|
||||||
|
|
||||||
class PClass;
|
class PClass;
|
||||||
|
class PType;
|
||||||
class FSerializer;
|
class FSerializer;
|
||||||
|
|
||||||
class DObject;
|
class DObject;
|
||||||
|
@ -94,7 +94,6 @@ enum
|
||||||
CLASSREG_PClass,
|
CLASSREG_PClass,
|
||||||
CLASSREG_PClassActor,
|
CLASSREG_PClassActor,
|
||||||
CLASSREG_PClassInventory,
|
CLASSREG_PClassInventory,
|
||||||
CLASSREG_PClassHealth,
|
|
||||||
CLASSREG_PClassPuzzleItem,
|
CLASSREG_PClassPuzzleItem,
|
||||||
CLASSREG_PClassWeapon,
|
CLASSREG_PClassWeapon,
|
||||||
CLASSREG_PClassPlayerPawn,
|
CLASSREG_PClassPlayerPawn,
|
||||||
|
@ -453,6 +452,8 @@ public:
|
||||||
DObject *GCNext; // Next object in this collection list
|
DObject *GCNext; // Next object in this collection list
|
||||||
uint32 ObjectFlags; // Flags for this object
|
uint32 ObjectFlags; // Flags for this object
|
||||||
|
|
||||||
|
void *ScriptVar(FName field, PType *type);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DObject ();
|
DObject ();
|
||||||
DObject (PClass *inClass);
|
DObject (PClass *inClass);
|
||||||
|
@ -476,6 +477,10 @@ public:
|
||||||
virtual void OnDestroy() {}
|
virtual void OnDestroy() {}
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
|
// Add other types as needed.
|
||||||
|
int &IntVar(FName field);
|
||||||
|
double &FloatVar(FName field);
|
||||||
|
|
||||||
// If you need to replace one object with another and want to
|
// If you need to replace one object with another and want to
|
||||||
// change any pointers from the old object to the new object,
|
// change any pointers from the old object to the new object,
|
||||||
// use this method.
|
// use this method.
|
||||||
|
|
|
@ -2609,6 +2609,27 @@ PField::PField(FName name, PType *type, DWORD flags, size_t offset, int bitvalue
|
||||||
else BitValue = -1;
|
else BitValue = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PProperty *****************************************************************/
|
||||||
|
|
||||||
|
IMPLEMENT_CLASS(PProperty, false, false)
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// PField - Default Constructor
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
PProperty::PProperty()
|
||||||
|
: PSymbol(NAME_None)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PProperty::PProperty(FName name, TArray<PField *> &fields)
|
||||||
|
: PSymbol(name)
|
||||||
|
{
|
||||||
|
Variables = std::move(fields);
|
||||||
|
}
|
||||||
|
|
||||||
/* PPrototype *************************************************************/
|
/* PPrototype *************************************************************/
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PPrototype, false, false)
|
IMPLEMENT_CLASS(PPrototype, false, false)
|
||||||
|
@ -3094,7 +3115,6 @@ PClass *ClassReg::RegisterClass()
|
||||||
&PClass::RegistrationInfo,
|
&PClass::RegistrationInfo,
|
||||||
&PClassActor::RegistrationInfo,
|
&PClassActor::RegistrationInfo,
|
||||||
&PClassInventory::RegistrationInfo,
|
&PClassInventory::RegistrationInfo,
|
||||||
&PClassHealth::RegistrationInfo,
|
|
||||||
&PClassPuzzleItem::RegistrationInfo,
|
&PClassPuzzleItem::RegistrationInfo,
|
||||||
&PClassWeapon::RegistrationInfo,
|
&PClassWeapon::RegistrationInfo,
|
||||||
&PClassPlayerPawn::RegistrationInfo,
|
&PClassPlayerPawn::RegistrationInfo,
|
||||||
|
@ -3234,7 +3254,7 @@ DObject *PClass::CreateNew() const
|
||||||
|
|
||||||
ConstructNative (mem);
|
ConstructNative (mem);
|
||||||
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
|
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
|
||||||
InitializeSpecials(mem);
|
InitializeSpecials(mem, Defaults);
|
||||||
return (DObject *)mem;
|
return (DObject *)mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3246,7 +3266,7 @@ DObject *PClass::CreateNew() const
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void PClass::InitializeSpecials(void *addr) const
|
void PClass::InitializeSpecials(void *addr, void *defaults) const
|
||||||
{
|
{
|
||||||
// Once we reach a native class, we can stop going up the family tree,
|
// Once we reach a native class, we can stop going up the family tree,
|
||||||
// since native classes handle initialization natively.
|
// since native classes handle initialization natively.
|
||||||
|
@ -3255,10 +3275,10 @@ void PClass::InitializeSpecials(void *addr) const
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(ParentClass != NULL);
|
assert(ParentClass != NULL);
|
||||||
ParentClass->InitializeSpecials(addr);
|
ParentClass->InitializeSpecials(addr, defaults);
|
||||||
for (auto tao : SpecialInits)
|
for (auto tao : SpecialInits)
|
||||||
{
|
{
|
||||||
tao.first->InitializeValue((BYTE*)addr + tao.second, Defaults == nullptr? nullptr : Defaults + tao.second);
|
tao.first->InitializeValue((char*)addr + tao.second, defaults == nullptr? nullptr : ((char*)defaults) + tao.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3332,7 +3352,7 @@ void PClass::InitializeDefaults()
|
||||||
{
|
{
|
||||||
// Copy parent values from the parent defaults.
|
// Copy parent values from the parent defaults.
|
||||||
assert(ParentClass != NULL);
|
assert(ParentClass != NULL);
|
||||||
ParentClass->InitializeSpecials(Defaults);
|
ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
|
||||||
|
|
||||||
for (const PField *field : Fields)
|
for (const PField *field : Fields)
|
||||||
{
|
{
|
||||||
|
@ -3923,6 +3943,13 @@ PSymbol *PSymbolTable::AddSymbol (PSymbol *sym)
|
||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PSymbolTable::RemoveSymbol(PSymbol *sym)
|
||||||
|
{
|
||||||
|
auto mysym = Symbols.CheckKey(sym->SymbolName);
|
||||||
|
if (mysym == nullptr || *mysym != sym) return;
|
||||||
|
Symbols.Remove(sym->SymbolName);
|
||||||
|
}
|
||||||
|
|
||||||
PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym)
|
PSymbol *PSymbolTable::ReplaceSymbol(PSymbol *newsym)
|
||||||
{
|
{
|
||||||
// If a symbol with a matching name exists, take its place and return it.
|
// If a symbol with a matching name exists, take its place and return it.
|
||||||
|
|
|
@ -29,11 +29,12 @@ enum
|
||||||
VARF_In = (1<<10),
|
VARF_In = (1<<10),
|
||||||
VARF_Out = (1<<11),
|
VARF_Out = (1<<11),
|
||||||
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures)
|
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures)
|
||||||
VARF_Static = (1<<13), // static class data (by necessity read only.)
|
VARF_Static = (1<<13),
|
||||||
VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code.
|
VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code.
|
||||||
VARF_Override = (1<<15), // overrides a virtual function from the parent class.
|
VARF_Override = (1<<15), // overrides a virtual function from the parent class.
|
||||||
VARF_Ref = (1<<16), // argument is passed by reference.
|
VARF_Ref = (1<<16), // argument is passed by reference.
|
||||||
VARF_Transient = (1<<17) // don't auto serialize field.
|
VARF_Transient = (1<<17), // don't auto serialize field.
|
||||||
|
VARF_Meta = (1<<18), // static class data (by necessity read only.)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Symbol information -------------------------------------------------------
|
// Symbol information -------------------------------------------------------
|
||||||
|
@ -137,6 +138,8 @@ struct PSymbolTable
|
||||||
// to be in the table with this name, if any.
|
// to be in the table with this name, if any.
|
||||||
PSymbol *ReplaceSymbol(PSymbol *sym);
|
PSymbol *ReplaceSymbol(PSymbol *sym);
|
||||||
|
|
||||||
|
void RemoveSymbol(PSymbol *sym);
|
||||||
|
|
||||||
// Frees all symbols from this table.
|
// Frees all symbols from this table.
|
||||||
void ReleaseSymbols();
|
void ReleaseSymbols();
|
||||||
|
|
||||||
|
@ -621,6 +624,21 @@ protected:
|
||||||
PField();
|
PField();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Struct/class fields ------------------------------------------------------
|
||||||
|
|
||||||
|
// A PField describes a symbol that takes up physical space in the struct.
|
||||||
|
class PProperty : public PSymbol
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(PProperty, PSymbol);
|
||||||
|
public:
|
||||||
|
PProperty(FName name, TArray<PField *> &variables);
|
||||||
|
|
||||||
|
TArray<PField *> Variables;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PProperty();
|
||||||
|
};
|
||||||
|
|
||||||
// Compound types -----------------------------------------------------------
|
// Compound types -----------------------------------------------------------
|
||||||
|
|
||||||
class PEnum : public PNamedType
|
class PEnum : public PNamedType
|
||||||
|
@ -807,7 +825,7 @@ protected:
|
||||||
enum { MetaClassNum = CLASSREG_PClassClass };
|
enum { MetaClassNum = CLASSREG_PClassClass };
|
||||||
TArray<FTypeAndOffset> SpecialInits;
|
TArray<FTypeAndOffset> SpecialInits;
|
||||||
void Derive(PClass *newclass, FName name);
|
void Derive(PClass *newclass, FName name);
|
||||||
void InitializeSpecials(void *addr) const;
|
void InitializeSpecials(void *addr, void *defaults) const;
|
||||||
void SetSuper();
|
void SetSuper();
|
||||||
public:
|
public:
|
||||||
typedef PClassClass MetaClass;
|
typedef PClassClass MetaClass;
|
||||||
|
@ -1041,4 +1059,15 @@ enum ETypeVal : BYTE
|
||||||
VAL_Class,
|
VAL_Class,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline int &DObject::IntVar(FName field)
|
||||||
|
{
|
||||||
|
return *(int*)ScriptVar(field, TypeSInt32);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double &DObject::FloatVar(FName field)
|
||||||
|
{
|
||||||
|
return *(double*)ScriptVar(field, TypeFloat64);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,42 +45,7 @@
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
IMPLEMENT_CLASS(PClassHealth, false, false)
|
|
||||||
IMPLEMENT_CLASS(AHealth, false, false)
|
|
||||||
DEFINE_FIELD(AHealth, PrevHealth)
|
|
||||||
DEFINE_FIELD(PClassHealth, LowHealth)
|
|
||||||
DEFINE_FIELD(PClassHealth, LowHealthMessage)
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// PClassHealth Constructor
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
PClassHealth::PClassHealth()
|
|
||||||
{
|
|
||||||
LowHealth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//===========================================================================
|
|
||||||
//
|
|
||||||
// PClassHealth :: DeriveData
|
|
||||||
//
|
|
||||||
//===========================================================================
|
|
||||||
|
|
||||||
void PClassHealth::DeriveData(PClass *newclass)
|
|
||||||
{
|
|
||||||
assert(newclass->IsKindOf(RUNTIME_CLASS(PClassHealth)));
|
|
||||||
Super::DeriveData(newclass);
|
|
||||||
PClassHealth *newc = static_cast<PClassHealth *>(newclass);
|
|
||||||
|
|
||||||
newc->LowHealth = LowHealth;
|
|
||||||
newc->LowHealthMessage = LowHealthMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS(AHealthPickup, false, false)
|
IMPLEMENT_CLASS(AHealthPickup, false, false)
|
||||||
|
|
||||||
DEFINE_FIELD(AHealthPickup, autousemode)
|
DEFINE_FIELD(AHealthPickup, autousemode)
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
|
@ -2,27 +2,6 @@
|
||||||
|
|
||||||
#include "a_pickups.h"
|
#include "a_pickups.h"
|
||||||
|
|
||||||
// Health is some item that gives the player health when picked up.
|
|
||||||
class PClassHealth : public PClassInventory
|
|
||||||
{
|
|
||||||
DECLARE_CLASS(PClassHealth, PClassInventory)
|
|
||||||
protected:
|
|
||||||
public:
|
|
||||||
PClassHealth();
|
|
||||||
virtual void DeriveData(PClass *newclass);
|
|
||||||
|
|
||||||
FString LowHealthMessage;
|
|
||||||
int LowHealth;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AHealth : public AInventory
|
|
||||||
{
|
|
||||||
DECLARE_CLASS_WITH_META(AHealth, AInventory, PClassHealth)
|
|
||||||
|
|
||||||
public:
|
|
||||||
int PrevHealth;
|
|
||||||
};
|
|
||||||
|
|
||||||
// HealthPickup is some item that gives the player health when used.
|
// HealthPickup is some item that gives the player health when used.
|
||||||
class AHealthPickup : public AInventory
|
class AHealthPickup : public AInventory
|
||||||
{
|
{
|
||||||
|
|
|
@ -2400,7 +2400,7 @@ static bool DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (item->IsKindOf(RUNTIME_CLASS(AHealth)))
|
if (item->IsKindOf(PClass::FindActor(NAME_Health)))
|
||||||
{
|
{
|
||||||
item->Amount *= amount;
|
item->Amount *= amount;
|
||||||
}
|
}
|
||||||
|
@ -5655,7 +5655,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo
|
||||||
if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
|
if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
|
||||||
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
|
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
|
||||||
AInventory *gift = static_cast<AInventory *>(Spawn(item));
|
AInventory *gift = static_cast<AInventory *>(Spawn(item));
|
||||||
if (gift->IsKindOf(RUNTIME_CLASS(AHealth)))
|
if (gift->IsKindOf(PClass::FindActor(NAME_Health)))
|
||||||
{
|
{
|
||||||
gift->Amount *= amount;
|
gift->Amount *= amount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1341,7 +1341,7 @@ bool P_GiveBody(AActor *actor, int num, int max)
|
||||||
if (player != NULL)
|
if (player != NULL)
|
||||||
{
|
{
|
||||||
// Max is 0 by default, preserving default behavior for P_GiveBody()
|
// Max is 0 by default, preserving default behavior for P_GiveBody()
|
||||||
// calls while supporting AHealth.
|
// calls while supporting health pickups.
|
||||||
if (max <= 0)
|
if (max <= 0)
|
||||||
{
|
{
|
||||||
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
|
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
|
||||||
|
@ -1396,7 +1396,7 @@ bool P_GiveBody(AActor *actor, int num, int max)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Parameter value for max is ignored on monsters, preserving original
|
// Parameter value for max is ignored on monsters, preserving original
|
||||||
// behaviour on AHealth as well as on existing calls to P_GiveBody().
|
// behaviour of health as well as on existing calls to P_GiveBody().
|
||||||
max = actor->SpawnHealth();
|
max = actor->SpawnHealth();
|
||||||
if (num < 0)
|
if (num < 0)
|
||||||
{
|
{
|
||||||
|
@ -5663,9 +5663,10 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
||||||
// [RH] Other things that shouldn't be spawned depending on dmflags
|
// [RH] Other things that shouldn't be spawned depending on dmflags
|
||||||
if (deathmatch || alwaysapplydmflags)
|
if (deathmatch || alwaysapplydmflags)
|
||||||
{
|
{
|
||||||
|
// Fixme: This needs to be done differently, it's quite broken.
|
||||||
if (dmflags & DF_NO_HEALTH)
|
if (dmflags & DF_NO_HEALTH)
|
||||||
{
|
{
|
||||||
if (i->IsDescendantOf (RUNTIME_CLASS(AHealth)))
|
if (i->IsDescendantOf (PClass::FindActor(NAME_Health)))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (i->TypeName == NAME_Berserk)
|
if (i->TypeName == NAME_Berserk)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -146,7 +146,7 @@ std2:
|
||||||
'instanceof' { RET(TK_InstanceOf); }
|
'instanceof' { RET(TK_InstanceOf); }
|
||||||
'auto' { RET(TK_Auto); }
|
'auto' { RET(TK_Auto); }
|
||||||
'exec' { RET(TK_Exec); }
|
'exec' { RET(TK_Exec); }
|
||||||
'defaultproperties' { RET(TK_DefaultProperties); }
|
'property' { RET(TK_Property); }
|
||||||
'native' { RET(TK_Native); }
|
'native' { RET(TK_Native); }
|
||||||
'var' { RET(TK_Var); }
|
'var' { RET(TK_Var); }
|
||||||
'out' { RET(TK_Out); }
|
'out' { RET(TK_Out); }
|
||||||
|
|
|
@ -67,6 +67,7 @@ xx(TK_Long, "'long'")
|
||||||
xx(TK_ULong, "'ulong'")
|
xx(TK_ULong, "'ulong'")
|
||||||
xx(TK_Void, "'void'")
|
xx(TK_Void, "'void'")
|
||||||
xx(TK_Struct, "'struct'")
|
xx(TK_Struct, "'struct'")
|
||||||
|
xx(TK_Property, "'property'")
|
||||||
xx(TK_Class, "'class'")
|
xx(TK_Class, "'class'")
|
||||||
xx(TK_Enum, "'enum'")
|
xx(TK_Enum, "'enum'")
|
||||||
xx(TK_Name, "'name'")
|
xx(TK_Name, "'name'")
|
||||||
|
|
|
@ -208,10 +208,6 @@ ExpEmit::ExpEmit(VMFunctionBuilder *build, int type, int count)
|
||||||
|
|
||||||
void ExpEmit::Free(VMFunctionBuilder *build)
|
void ExpEmit::Free(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
if (RegType == REGT_INT && RegNum == 0)
|
|
||||||
{
|
|
||||||
int a = 0;
|
|
||||||
}
|
|
||||||
if (!Fixed && !Konst && RegType <= REGT_TYPE)
|
if (!Fixed && !Konst && RegType <= REGT_TYPE)
|
||||||
{
|
{
|
||||||
build->Registers[RegType].Return(RegNum, RegCount);
|
build->Registers[RegType].Return(RegNum, RegCount);
|
||||||
|
@ -4447,10 +4443,6 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(expr, ctx);
|
SAFE_RESOLVE(expr, ctx);
|
||||||
if (expr->ExprType == EFX_GetDefaultByType)
|
|
||||||
{
|
|
||||||
int a = 0;
|
|
||||||
}
|
|
||||||
bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer *>(expr->ValueType)->IsConst;
|
bool constflag = expr->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer *>(expr->ValueType)->IsConst;
|
||||||
if (constflag)
|
if (constflag)
|
||||||
{
|
{
|
||||||
|
@ -6472,7 +6464,7 @@ FxStructMember::~FxStructMember()
|
||||||
bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
|
bool FxStructMember::RequestAddress(FCompileContext &ctx, bool *writable)
|
||||||
{
|
{
|
||||||
// Cannot take the address of metadata variables.
|
// Cannot take the address of metadata variables.
|
||||||
if (membervar->Flags & VARF_Static)
|
if (membervar->Flags & VARF_Meta)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -6615,7 +6607,7 @@ ExpEmit FxStructMember::Emit(VMFunctionBuilder *build)
|
||||||
obj = newobj;
|
obj = newobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (membervar->Flags & VARF_Static)
|
if (membervar->Flags & VARF_Meta)
|
||||||
{
|
{
|
||||||
obj.Free(build);
|
obj.Free(build);
|
||||||
ExpEmit meta(build, REGT_POINTER);
|
ExpEmit meta(build, REGT_POINTER);
|
||||||
|
|
|
@ -1969,18 +1969,6 @@ DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
|
||||||
static_cast<PClassInventory *>(info)->GiveQuest = i;
|
static_cast<PClassInventory *>(info)->GiveQuest = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
DEFINE_CLASS_PROPERTY(lowmessage, IT, Health)
|
|
||||||
{
|
|
||||||
PROP_INT_PARM(i, 0);
|
|
||||||
PROP_STRING_PARM(str, 1);
|
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassHealth)));
|
|
||||||
static_cast<PClassHealth *>(info)->LowHealth = i;
|
|
||||||
static_cast<PClassHealth *>(info)->LowHealthMessage = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -336,6 +336,16 @@ static void PrintStruct(FLispString &out, ZCC_TreeNode *node)
|
||||||
out.Close();
|
out.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void PrintProperty(FLispString &out, ZCC_TreeNode *node)
|
||||||
|
{
|
||||||
|
ZCC_Property *snode = (ZCC_Property *)node;
|
||||||
|
out.Break();
|
||||||
|
out.Open("property");
|
||||||
|
out.AddName(snode->NodeName);
|
||||||
|
PrintNodes(out, snode->Body, false, true);
|
||||||
|
out.Close();
|
||||||
|
}
|
||||||
|
|
||||||
static void PrintEnum(FLispString &out, ZCC_TreeNode *node)
|
static void PrintEnum(FLispString &out, ZCC_TreeNode *node)
|
||||||
{
|
{
|
||||||
ZCC_Enum *enode = (ZCC_Enum *)node;
|
ZCC_Enum *enode = (ZCC_Enum *)node;
|
||||||
|
@ -934,6 +944,7 @@ void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *
|
||||||
PrintVectorInitializer,
|
PrintVectorInitializer,
|
||||||
PrintDeclFlags,
|
PrintDeclFlags,
|
||||||
PrintExprClassCast,
|
PrintExprClassCast,
|
||||||
|
PrintProperty,
|
||||||
};
|
};
|
||||||
|
|
||||||
FString ZCC_PrintAST(ZCC_TreeNode *root)
|
FString ZCC_PrintAST(ZCC_TreeNode *root)
|
||||||
|
|
|
@ -209,7 +209,6 @@ class_ancestry(X) ::= COLON dottable_id(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; }
|
class_flags(X) ::= . { X.Flags = 0; X.Replaces = NULL; }
|
||||||
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; }
|
class_flags(X) ::= class_flags(A) ABSTRACT. { X.Flags = A.Flags | ZCC_Abstract; X.Replaces = A.Replaces; }
|
||||||
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; }
|
class_flags(X) ::= class_flags(A) NATIVE. { X.Flags = A.Flags | ZCC_Native; X.Replaces = A.Replaces; }
|
||||||
class_flags(X) ::= class_flags(A) ACTION. { X.Flags = A.Flags | ZCC_Action; X.Replaces = A.Replaces; }
|
|
||||||
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; }
|
class_flags(X) ::= class_flags(A) REPLACES dottable_id(B). { X.Flags = A.Flags; X.Replaces = B; }
|
||||||
|
|
||||||
/*----- Dottable Identifier -----*/
|
/*----- Dottable Identifier -----*/
|
||||||
|
@ -265,6 +264,7 @@ class_body(X) ::= LBRACE class_innards(A) RBRACE. { X = A; /*X-overwrites-A*/ }
|
||||||
class_innards(X) ::= . { X = NULL; }
|
class_innards(X) ::= . { X = NULL; }
|
||||||
class_innards(X) ::= class_innards(X) class_member(B). { SAFE_APPEND(X,B); }
|
class_innards(X) ::= class_innards(X) class_member(B). { SAFE_APPEND(X,B); }
|
||||||
|
|
||||||
|
%type property_def{ZCC_Property *}
|
||||||
%type struct_def{ZCC_Struct *}
|
%type struct_def{ZCC_Struct *}
|
||||||
%type enum_def {ZCC_Enum *}
|
%type enum_def {ZCC_Enum *}
|
||||||
%type states_def {ZCC_States *}
|
%type states_def {ZCC_States *}
|
||||||
|
@ -276,6 +276,7 @@ class_member(X) ::= struct_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_member(X) ::= states_def(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= states_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_member(X) ::= default_def(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= default_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
|
class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
class_member(X) ::= property_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
|
|
||||||
/*----- Struct Definition -----*/
|
/*----- Struct Definition -----*/
|
||||||
/* Structs can define variables and enums. */
|
/* Structs can define variables and enums. */
|
||||||
|
@ -283,6 +284,30 @@ class_member(X) ::= const_def(A). { X = A; /*X-overwrites-A*/ }
|
||||||
%type opt_struct_body{ZCC_TreeNode *}
|
%type opt_struct_body{ZCC_TreeNode *}
|
||||||
%type struct_body{ZCC_TreeNode *}
|
%type struct_body{ZCC_TreeNode *}
|
||||||
%type struct_member{ZCC_TreeNode *}
|
%type struct_member{ZCC_TreeNode *}
|
||||||
|
%type identifier_list{ZCC_Identifier *}
|
||||||
|
|
||||||
|
property_def(X) ::= PROPERTY(T) IDENTIFIER(A) COLON identifier_list(B) SEMICOLON.
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(Property,def,T);
|
||||||
|
def->NodeName = A.Name();
|
||||||
|
def->Body = B;
|
||||||
|
X = def;
|
||||||
|
}
|
||||||
|
|
||||||
|
identifier_list(X) ::= IDENTIFIER(A).
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(Identifier,id,A);
|
||||||
|
id->Id = A.Name();
|
||||||
|
X = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
identifier_list(X) ::= states_opt(A) COMMA IDENTIFIER(B).
|
||||||
|
{
|
||||||
|
NEW_AST_NODE(Identifier,id,B);
|
||||||
|
id->Id = B.Name();
|
||||||
|
X = A; /*X-overwrites-A*/
|
||||||
|
AppendTreeNodeSibling(X, id);
|
||||||
|
}
|
||||||
|
|
||||||
struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body(B) RBRACE opt_semicolon.
|
struct_def(X) ::= STRUCT(T) IDENTIFIER(A) struct_flags(S) LBRACE opt_struct_body(B) RBRACE opt_semicolon.
|
||||||
{
|
{
|
||||||
|
@ -747,7 +772,7 @@ type_name(X) ::= DOT dottable_id(A).
|
||||||
/* Type names can also be used as identifiers in contexts where type names
|
/* Type names can also be used as identifiers in contexts where type names
|
||||||
* are not normally allowed. */
|
* are not normally allowed. */
|
||||||
%fallback IDENTIFIER
|
%fallback IDENTIFIER
|
||||||
SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16.
|
SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR SOUND UINT8 INT8 UINT16 INT16 PROPERTY.
|
||||||
|
|
||||||
/* Aggregate types */
|
/* Aggregate types */
|
||||||
%type aggregate_type {ZCC_Type *}
|
%type aggregate_type {ZCC_Type *}
|
||||||
|
@ -964,6 +989,7 @@ decl_flag(X) ::= PROTECTED(T). { X.Int = ZCC_Protected; X.SourceLoc = T.SourceL
|
||||||
decl_flag(X) ::= LATENT(T). { X.Int = ZCC_Latent; X.SourceLoc = T.SourceLoc; }
|
decl_flag(X) ::= LATENT(T). { X.Int = ZCC_Latent; X.SourceLoc = T.SourceLoc; }
|
||||||
decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; }
|
decl_flag(X) ::= FINAL(T). { X.Int = ZCC_Final; X.SourceLoc = T.SourceLoc; }
|
||||||
decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; }
|
decl_flag(X) ::= META(T). { X.Int = ZCC_Meta; X.SourceLoc = T.SourceLoc; }
|
||||||
|
decl_flag(X) ::= TRANSIENT(T). { X.Int = ZCC_Transient; X.SourceLoc = T.SourceLoc; }
|
||||||
decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; }
|
decl_flag(X) ::= READONLY(T). { X.Int = ZCC_ReadOnly; X.SourceLoc = T.SourceLoc; }
|
||||||
decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; }
|
decl_flag(X) ::= DEPRECATED(T). { X.Int = ZCC_Deprecated; X.SourceLoc = T.SourceLoc; }
|
||||||
decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; }
|
decl_flag(X) ::= VIRTUAL(T). { X.Int = ZCC_Virtual; X.SourceLoc = T.SourceLoc; }
|
||||||
|
|
|
@ -120,6 +120,10 @@ void ZCCCompiler::ProcessClass(ZCC_Class *cnode, PSymbolTreeNode *treenode)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AST_Property:
|
||||||
|
cls->Properties.Push(static_cast<ZCC_Property *>(node));
|
||||||
|
break;
|
||||||
|
|
||||||
case AST_VarDeclarator:
|
case AST_VarDeclarator:
|
||||||
cls->Fields.Push(static_cast<ZCC_VarDeclarator *>(node));
|
cls->Fields.Push(static_cast<ZCC_VarDeclarator *>(node));
|
||||||
break;
|
break;
|
||||||
|
@ -396,6 +400,7 @@ int ZCCCompiler::Compile()
|
||||||
CreateStructTypes();
|
CreateStructTypes();
|
||||||
CompileAllConstants();
|
CompileAllConstants();
|
||||||
CompileAllFields();
|
CompileAllFields();
|
||||||
|
CompileAllProperties();
|
||||||
InitDefaults();
|
InitDefaults();
|
||||||
InitFunctions();
|
InitFunctions();
|
||||||
CompileStates();
|
CompileStates();
|
||||||
|
@ -1269,6 +1274,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
||||||
if (field->Flags & ZCC_Protected) varflags |= VARF_Protected;
|
if (field->Flags & ZCC_Protected) varflags |= VARF_Protected;
|
||||||
if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated;
|
if (field->Flags & ZCC_Deprecated) varflags |= VARF_Deprecated;
|
||||||
if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly;
|
if (field->Flags & ZCC_ReadOnly) varflags |= VARF_ReadOnly;
|
||||||
|
if (field->Flags & ZCC_Transient) varflags |= VARF_Transient;
|
||||||
|
|
||||||
if (field->Flags & ZCC_Native)
|
if (field->Flags & ZCC_Native)
|
||||||
{
|
{
|
||||||
|
@ -1277,7 +1283,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
||||||
|
|
||||||
if (field->Flags & ZCC_Meta)
|
if (field->Flags & ZCC_Meta)
|
||||||
{
|
{
|
||||||
varflags |= VARF_Static|VARF_ReadOnly; // metadata implies readonly
|
varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly
|
||||||
if (!(field->Flags & ZCC_Native))
|
if (!(field->Flags & ZCC_Native))
|
||||||
{
|
{
|
||||||
// Non-native meta data is not implemented yet and requires some groundwork in the class copy code.
|
// Non-native meta data is not implemented yet and requires some groundwork in the class copy code.
|
||||||
|
@ -1303,7 +1309,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
||||||
|
|
||||||
if (varflags & VARF_Native)
|
if (varflags & VARF_Native)
|
||||||
{
|
{
|
||||||
auto querytype = (varflags & VARF_Static) ? type->GetClass() : type;
|
auto querytype = (varflags & VARF_Meta) ? type->GetClass() : type;
|
||||||
fd = FindField(querytype, FName(name->Name).GetChars());
|
fd = FindField(querytype, FName(name->Name).GetChars());
|
||||||
if (fd == nullptr)
|
if (fd == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -1337,6 +1343,68 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
||||||
return Fields.Size() == 0;
|
return Fields.Size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ZCCCompiler :: CompileAllProperties
|
||||||
|
//
|
||||||
|
// builds the property lists of all actor classes
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void ZCCCompiler::CompileAllProperties()
|
||||||
|
{
|
||||||
|
for (auto c : Classes)
|
||||||
|
{
|
||||||
|
if (c->Properties.Size() > 0)
|
||||||
|
CompileProperties(c->Type(), c->Properties, c->Type()->TypeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// ZCCCompiler :: CompileProperties
|
||||||
|
//
|
||||||
|
// builds the internal structure of a single class or struct
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Properties, FName prefix)
|
||||||
|
{
|
||||||
|
if (!type->IsKindOf(RUNTIME_CLASS(PClassActor)))
|
||||||
|
{
|
||||||
|
Error(Properties[0], "Properties can only be defined for actors");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(auto p : Properties)
|
||||||
|
{
|
||||||
|
TArray<PField *> fields;
|
||||||
|
ZCC_Identifier *id = (ZCC_Identifier *)p->Body;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto f = dyn_cast<PField>(type->Symbols.FindSymbol(id->Id, true));
|
||||||
|
if (f == nullptr)
|
||||||
|
{
|
||||||
|
Error(id, "Variable %s not found in %s", FName(id->Id).GetChars(), type->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
fields.Push(f);
|
||||||
|
id = (ZCC_Identifier*)id->SiblingNext;
|
||||||
|
} while (id != p->Body);
|
||||||
|
|
||||||
|
FString qualifiedname;
|
||||||
|
// Store the full qualified name and prepend some 'garbage' to the name so that no conflicts with other symbol types can happen.
|
||||||
|
// All these will be removed from the symbol table after the compiler finishes to free up the allocated space.
|
||||||
|
if (prefix == NAME_None) qualifiedname.Format("@property@%s", FName(p->NodeName).GetChars());
|
||||||
|
else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), FName(p->NodeName).GetChars());
|
||||||
|
fields.ShrinkToFit();
|
||||||
|
if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields)))
|
||||||
|
{
|
||||||
|
Error(id, "Unable to add property %s to class %s", FName(p->NodeName).GetChars(), type->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// ZCCCompiler :: FieldFlagsToString
|
// ZCCCompiler :: FieldFlagsToString
|
||||||
|
@ -1841,6 +1909,73 @@ void ZCCCompiler::DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *proper
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// Parses an actor property's parameters and calls the handler
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *property, AActor *defaults, Baggage &bag)
|
||||||
|
{
|
||||||
|
unsigned parmcount = 1;
|
||||||
|
ZCC_TreeNode *x = property->Values;
|
||||||
|
while (x->SiblingNext != property->Values)
|
||||||
|
{
|
||||||
|
x = x->SiblingNext;
|
||||||
|
parmcount++;
|
||||||
|
}
|
||||||
|
if (parmcount != prop->Variables.Size())
|
||||||
|
{
|
||||||
|
Error(x, "Argument count mismatch: Got %u, expected %u", parmcount, prop->Variables.Size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto values = Simplify(property->Values, &bag.Info->Symbols, true); // need to do this before the loop so that we can find the head node again.
|
||||||
|
auto exp = values;
|
||||||
|
for (auto f : prop->Variables)
|
||||||
|
{
|
||||||
|
void *addr;
|
||||||
|
|
||||||
|
if (f->Flags & VARF_Meta)
|
||||||
|
{
|
||||||
|
addr = ((char*)bag.Info) + f->Offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addr = ((char*)defaults) + f->Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
|
||||||
|
{
|
||||||
|
static_cast<PInt*>(f->Type)->SetValue(addr, GetInt(exp));
|
||||||
|
}
|
||||||
|
else if (f->Type->IsKindOf(RUNTIME_CLASS(PFloat)))
|
||||||
|
{
|
||||||
|
static_cast<PFloat*>(f->Type)->SetValue(addr, GetDouble(exp));
|
||||||
|
}
|
||||||
|
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
|
||||||
|
{
|
||||||
|
*(FString*)addr = GetString(exp);
|
||||||
|
}
|
||||||
|
else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||||
|
{
|
||||||
|
auto cls = PClass::FindClass(GetString(exp));
|
||||||
|
*(PClass**)addr = cls;
|
||||||
|
if (!cls->IsDescendantOf(static_cast<PClassPointer*>(f->Type)->ClassRestriction))
|
||||||
|
{
|
||||||
|
Error(property, "class %s is not compatible with property type %s", cls->TypeName.GetChars(), static_cast<PClassPointer*>(f->Type)->ClassRestriction->TypeName.GetChars());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Error(property, "unhandled property type %s", f->Type->DescriptiveName());
|
||||||
|
}
|
||||||
|
exp->ToErrorNode(); // invalidate after processing.
|
||||||
|
exp = static_cast<ZCC_Expression *>(exp->SiblingNext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// Parses an actor property
|
// Parses an actor property
|
||||||
|
@ -1893,6 +2028,17 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
propname.Insert(0, "@property@");
|
||||||
|
FName name(propname, true);
|
||||||
|
if (name != NAME_None)
|
||||||
|
{
|
||||||
|
auto propp = dyn_cast<PProperty>(cls->Symbols.FindSymbol(name, true));
|
||||||
|
if (propp != nullptr)
|
||||||
|
{
|
||||||
|
DispatchScriptProperty(propp, prop, (AActor *)bag.Info->Defaults, bag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
Error(prop, "'%s' is an unknown actor property\n", propname.GetChars());
|
Error(prop, "'%s' is an unknown actor property\n", propname.GetChars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ struct ZCC_ClassWork : public ZCC_StructWork
|
||||||
ZCC_Class *cls;
|
ZCC_Class *cls;
|
||||||
TArray<ZCC_Default *> Defaults;
|
TArray<ZCC_Default *> Defaults;
|
||||||
TArray<ZCC_States *> States;
|
TArray<ZCC_States *> States;
|
||||||
|
TArray<ZCC_Property *> Properties;
|
||||||
|
|
||||||
ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n)
|
ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n)
|
||||||
{
|
{
|
||||||
|
@ -67,6 +68,12 @@ struct ZCC_ClassWork : public ZCC_StructWork
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZCC_PropertyWork
|
||||||
|
{
|
||||||
|
ZCC_Property *prop;
|
||||||
|
PSymbolTable *outputtable;
|
||||||
|
};
|
||||||
|
|
||||||
struct ZCC_ConstantWork
|
struct ZCC_ConstantWork
|
||||||
{
|
{
|
||||||
ZCC_ConstantDef *node;
|
ZCC_ConstantDef *node;
|
||||||
|
@ -92,6 +99,8 @@ private:
|
||||||
|
|
||||||
void CompileAllFields();
|
void CompileAllFields();
|
||||||
bool CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false);
|
bool CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct, bool hasnativechildren = false);
|
||||||
|
void CompileAllProperties();
|
||||||
|
bool CompileProperties(PClass *type, TArray<ZCC_Property *> &Properties, FName prefix);
|
||||||
FString FlagsToString(uint32_t flags);
|
FString FlagsToString(uint32_t flags);
|
||||||
PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember);
|
PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember);
|
||||||
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym);
|
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym);
|
||||||
|
@ -101,6 +110,7 @@ private:
|
||||||
void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg);
|
void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg);
|
||||||
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag);
|
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag);
|
||||||
void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
|
void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
|
||||||
|
void DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
|
||||||
int GetInt(ZCC_Expression *expr);
|
int GetInt(ZCC_Expression *expr);
|
||||||
double GetDouble(ZCC_Expression *expr);
|
double GetDouble(ZCC_Expression *expr);
|
||||||
const char *GetString(ZCC_Expression *expr, bool silent = false);
|
const char *GetString(ZCC_Expression *expr, bool silent = false);
|
||||||
|
@ -114,6 +124,7 @@ private:
|
||||||
TArray<ZCC_ConstantDef *> Constants;
|
TArray<ZCC_ConstantDef *> Constants;
|
||||||
TArray<ZCC_StructWork *> Structs;
|
TArray<ZCC_StructWork *> Structs;
|
||||||
TArray<ZCC_ClassWork *> Classes;
|
TArray<ZCC_ClassWork *> Classes;
|
||||||
|
TArray<ZCC_PropertyWork *> Properties;
|
||||||
|
|
||||||
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);
|
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,8 @@ static void InitTokenMap()
|
||||||
TOKENDEF ('{', ZCC_LBRACE);
|
TOKENDEF ('{', ZCC_LBRACE);
|
||||||
TOKENDEF ('}', ZCC_RBRACE);
|
TOKENDEF ('}', ZCC_RBRACE);
|
||||||
TOKENDEF (TK_Struct, ZCC_STRUCT);
|
TOKENDEF (TK_Struct, ZCC_STRUCT);
|
||||||
|
TOKENDEF (TK_Property, ZCC_PROPERTY);
|
||||||
|
TOKENDEF (TK_Transient, ZCC_TRANSIENT);
|
||||||
TOKENDEF (TK_Enum, ZCC_ENUM);
|
TOKENDEF (TK_Enum, ZCC_ENUM);
|
||||||
TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte);
|
TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte);
|
||||||
TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte);
|
TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte);
|
||||||
|
|
|
@ -35,6 +35,7 @@ enum
|
||||||
ZCC_Extension = 1 << 12,
|
ZCC_Extension = 1 << 12,
|
||||||
ZCC_Virtual = 1 << 13,
|
ZCC_Virtual = 1 << 13,
|
||||||
ZCC_Override = 1 << 14,
|
ZCC_Override = 1 << 14,
|
||||||
|
ZCC_Transient = 1 << 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function parameter modifiers
|
// Function parameter modifiers
|
||||||
|
@ -104,6 +105,7 @@ enum EZCCTreeNodeType
|
||||||
AST_DeclFlags,
|
AST_DeclFlags,
|
||||||
AST_ClassCast,
|
AST_ClassCast,
|
||||||
AST_StaticArrayStatement,
|
AST_StaticArrayStatement,
|
||||||
|
AST_Property,
|
||||||
|
|
||||||
NUM_AST_NODE_TYPES
|
NUM_AST_NODE_TYPES
|
||||||
};
|
};
|
||||||
|
@ -189,6 +191,11 @@ struct ZCC_Struct : ZCC_NamedNode
|
||||||
PStruct *Type;
|
PStruct *Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ZCC_Property : ZCC_NamedNode
|
||||||
|
{
|
||||||
|
ZCC_TreeNode *Body;
|
||||||
|
};
|
||||||
|
|
||||||
struct ZCC_Class : ZCC_Struct
|
struct ZCC_Class : ZCC_Struct
|
||||||
{
|
{
|
||||||
ZCC_Identifier *ParentName;
|
ZCC_Identifier *ParentName;
|
||||||
|
|
|
@ -33,11 +33,13 @@
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Health : Inventory native
|
class Health : Inventory
|
||||||
{
|
{
|
||||||
native int PrevHealth;
|
transient int PrevHealth;
|
||||||
native meta int LowHealth;
|
/*meta*/ int LowHealth;
|
||||||
native meta String LowHealthMessage;
|
/*meta*/ String LowHealthMessage;
|
||||||
|
|
||||||
|
property LowMessage: LowHealth, LowHealthMessage;
|
||||||
|
|
||||||
Default
|
Default
|
||||||
{
|
{
|
||||||
|
@ -56,7 +58,6 @@ class Health : Inventory native
|
||||||
if (PrevHealth < LowHealth)
|
if (PrevHealth < LowHealth)
|
||||||
{
|
{
|
||||||
String message = LowHealthMessage;
|
String message = LowHealthMessage;
|
||||||
|
|
||||||
if (message.Length() != 0)
|
if (message.Length() != 0)
|
||||||
{
|
{
|
||||||
return message;
|
return message;
|
||||||
|
|
Loading…
Reference in a new issue