Merge branch 'floatcvt' of https://github.com/rheit/zdoom into floatcvt

This commit is contained in:
Christoph Oelckers 2016-04-04 12:07:57 +02:00
commit 7486e24cd9
13 changed files with 1221 additions and 102 deletions

View file

@ -257,46 +257,50 @@ DObject::DObject (PClass *inClass)
DObject::~DObject () DObject::~DObject ()
{ {
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown) if (!PClass::bShutdown)
{ {
DObject **probe;
PClass *type = GetClass(); PClass *type = GetClass();
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
if (!(ObjectFlags & OF_YesReallyDelete))
{ {
Printf ("Warning: '%s' is freed outside the GC process.\n", DObject **probe;
type != NULL ? type->TypeName.GetChars() : "==some object==");
}
// Find all pointers that reference this object and NULL them. if (!(ObjectFlags & OF_YesReallyDelete))
StaticPointerSubstitution(this, NULL);
// Now unlink this object from the GC list.
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
{
if (*probe == this)
{ {
*probe = ObjNext; Printf("Warning: '%s' is freed outside the GC process.\n",
if (&ObjNext == GC::SweepPos) type != NULL ? type->TypeName.GetChars() : "==some object==");
{
GC::SweepPos = probe;
}
break;
} }
}
// If it's gray, also unlink it from the gray list. // Find all pointers that reference this object and NULL them.
if (this->IsGray()) StaticPointerSubstitution(this, NULL);
{
for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext)) // Now unlink this object from the GC list.
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
{ {
if (*probe == this) if (*probe == this)
{ {
*probe = GCNext; *probe = ObjNext;
if (&ObjNext == GC::SweepPos)
{
GC::SweepPos = probe;
}
break; break;
} }
} }
// If it's gray, also unlink it from the gray list.
if (this->IsGray())
{
for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext))
{
if (*probe == this)
{
*probe = GCNext;
break;
}
}
}
} }
type->DestroySpecials(this);
} }
} }
@ -417,46 +421,15 @@ void DObject::SerializeUserVars(FArchive &arc)
if (arc.IsStoring()) if (arc.IsStoring())
{ {
// Write all user variables. // Write all fields that aren't serialized by native code.
for (; symt != NULL; symt = symt->ParentSymbolTable) GetClass()->WriteValue(arc, this);
{ }
PSymbolTable::MapType::Iterator it(symt->Symbols); else if (SaveVersion >= 4535)
PSymbolTable::MapType::Pair *pair; {
GetClass()->ReadValue(arc, this);
while (it.NextPair(pair))
{
PField *var = dyn_cast<PField>(pair->Value);
if (var != NULL && !(var->Flags & VARF_Native))
{
PType *type = var->Type;
PArray *arraytype = dyn_cast<PArray>(type);
if (arraytype == NULL)
{
count = 1;
}
else
{
count = arraytype->ElementCount;
type = arraytype->ElementType;
}
assert(type == TypeSInt32);
varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->Offset);
arc << var->SymbolName;
arc.WriteCount(count);
for (j = 0; j < count; ++j)
{
arc << varloc[j];
}
}
}
}
// Write terminator.
varname = NAME_None;
arc << varname;
} }
else else
{ { // Old version that only deals with ints
// Read user variables until 'None' is encountered. // Read user variables until 'None' is encountered.
arc << varname; arc << varname;
while (varname != NAME_None) while (varname != NAME_None)

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,8 @@
#include "vm.h" #include "vm.h"
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
// Variable/parameter/field flags ------------------------------------------- // Variable/parameter/field flags -------------------------------------------
// Making all these different storage types use a common set of flags seems // Making all these different storage types use a common set of flags seems
@ -186,6 +188,36 @@ public:
int FindConversion(PType *target, const Conversion **slots, int numslots); int FindConversion(PType *target, const Conversion **slots, int numslots);
// Writes the value of a variable of this type at (addr) to an archive, preceded by
// a tag indicating its type. The tag is there so that variable types can be changed
// without completely breaking savegames, provided that the change isn't between
// totally unrelated types.
virtual void WriteValue(FArchive &ar, const void *addr) const;
// Returns true if the stored value was compatible. False otherwise.
// If the value was incompatible, then the memory at *addr is unchanged.
virtual bool ReadValue(FArchive &ar, void *addr) const;
// Skips over a value written with WriteValue
static void SkipValue(FArchive &ar);
static void SkipValue(FArchive &ar, int tag);
// Sets the default value for this type at (base + offset)
// If the default value is binary 0, then this function doesn't need
// to do anything, because PClass::Extend() takes care of that.
//
// The stroffs array is so that types that need special initialization
// and destruction (e.g. strings) can add their offsets to it for special
// initialization when the object is created and destruction when the
// object is destroyed.
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const;
// Initialize the value, if needed (e.g. strings)
virtual void InitializeValue(void *addr, const void *def) const;
// Destroy the value, if needed (e.g. strings)
virtual void DestroyValue(void *addr) const;
// Sets the value of a variable of this type at (addr) // Sets the value of a variable of this type at (addr)
virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val); virtual void SetValue(void *addr, double val);
@ -321,6 +353,9 @@ class PInt : public PBasicType
public: public:
PInt(unsigned int size, bool unsign); PInt(unsigned int size, bool unsign);
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val); virtual void SetValue(void *addr, double val);
virtual int GetValueInt(void *addr) const; virtual int GetValueInt(void *addr) const;
@ -347,6 +382,9 @@ class PFloat : public PBasicType
public: public:
PFloat(unsigned int size); PFloat(unsigned int size);
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val); virtual void SetValue(void *addr, double val);
virtual int GetValueInt(void *addr) const; virtual int GetValueInt(void *addr) const;
@ -381,6 +419,12 @@ public:
PString(); PString();
virtual int GetRegType() const; virtual int GetRegType() const;
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
}; };
// Variations of integer types ---------------------------------------------- // Variations of integer types ----------------------------------------------
@ -390,6 +434,9 @@ class PName : public PInt
DECLARE_CLASS(PName, PInt); DECLARE_CLASS(PName, PInt);
public: public:
PName(); PName();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
}; };
class PSound : public PInt class PSound : public PInt
@ -397,6 +444,9 @@ class PSound : public PInt
DECLARE_CLASS(PSound, PInt); DECLARE_CLASS(PSound, PInt);
public: public:
PSound(); PSound();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
}; };
class PColor : public PInt class PColor : public PInt
@ -414,6 +464,9 @@ class PStatePointer : public PBasicType
public: public:
PStatePointer(); PStatePointer();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
virtual int GetStoreOp() const; virtual int GetStoreOp() const;
virtual int GetLoadOp() const; virtual int GetLoadOp() const;
virtual int GetRegType() const; virtual int GetRegType() const;
@ -434,6 +487,10 @@ public:
virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
protected: protected:
PPointer(); PPointer();
}; };
@ -500,6 +557,12 @@ public:
virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) const override;
protected: protected:
PArray(); PArray();
}; };
@ -554,9 +617,16 @@ public:
TArray<PField *> Fields; TArray<PField *> Fields;
PField *AddField(FName name, PType *type, DWORD flags=0); virtual PField *AddField(FName name, PType *type, DWORD flags=0);
size_t PropagateMark(); size_t PropagateMark();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
static void WriteFields(FArchive &ar, const void *addr, const TArray<PField *> &fields);
bool ReadFields(FArchive &ar, void *addr) const;
protected: protected:
PStruct(); PStruct();
}; };
@ -614,11 +684,16 @@ class PClass : public PStruct
protected: protected:
// We unravel _WITH_META here just as we did for PType. // We unravel _WITH_META here just as we did for PType.
enum { MetaClassNum = CLASSREG_PClassClass }; enum { MetaClassNum = CLASSREG_PClassClass };
TArray<FTypeAndOffset> SpecialInits;
virtual void Derive(PClass *newclass); virtual void Derive(PClass *newclass);
void InitializeSpecials(void *addr) const;
public: public:
typedef PClassClass MetaClass; typedef PClassClass MetaClass;
MetaClass *GetClass() const; MetaClass *GetClass() const;
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
virtual void DeriveData(PClass *newclass) {} virtual void DeriveData(PClass *newclass) {}
static void StaticInit(); static void StaticInit();
static void StaticShutdown(); static void StaticShutdown();
@ -639,10 +714,10 @@ public:
void InsertIntoHash(); void InsertIntoHash();
DObject *CreateNew() const; DObject *CreateNew() const;
PClass *CreateDerivedClass(FName name, unsigned int size); PClass *CreateDerivedClass(FName name, unsigned int size);
unsigned int Extend(unsigned int extension, unsigned int alignment); PField *AddField(FName name, PType *type, DWORD flags=0) override;
unsigned int Extend(const PType *type) { return Extend(type->Size, type->Align); }
void InitializeActorInfo(); void InitializeActorInfo();
void BuildFlatPointers(); void BuildFlatPointers();
void DestroySpecials(void *addr) const;
const PClass *NativeClass() const; const PClass *NativeClass() const;
// Returns true if this type is an ancestor of (or same as) the passed type. // Returns true if this type is an ancestor of (or same as) the passed type.
@ -662,6 +737,9 @@ public:
} }
// Find a type, given its name. // Find a type, given its name.
const PClass *FindParentClass(FName name) const;
PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); }
static PClass *FindClass(const char *name) { return FindClass(FName(name, true)); } static PClass *FindClass(const char *name) { return FindClass(FName(name, true)); }
static PClass *FindClass(const FString &name) { return FindClass(FName(name, true)); } static PClass *FindClass(const FString &name) { return FindClass(FName(name, true)); }
static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); } static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); }
@ -810,4 +888,31 @@ public:
void ReleaseGlobalSymbols(); void ReleaseGlobalSymbols();
// Enumerations for serializing types in an archive -------------------------
enum ETypeVal : BYTE
{
VAL_Int8,
VAL_UInt8,
VAL_Int16,
VAL_UInt16,
VAL_Int32,
VAL_UInt32,
VAL_Int64,
VAL_UInt64,
VAL_Zero,
VAL_One,
VAL_Float32,
VAL_Float64,
VAL_Fixed,
VAL_BAM,
VAL_String,
VAL_Name,
VAL_Struct,
VAL_Array,
VAL_Object,
VAL_State,
VAL_Class,
};
#endif #endif

View file

@ -721,6 +721,29 @@ void FArchive::Close ()
} }
} }
void FArchive::WriteByte(BYTE val)
{
m_File->Write(&val, 1);
}
void FArchive::WriteInt16(WORD val)
{
WORD out = LittleShort(val);
m_File->Write(&out, 2);
}
void FArchive::WriteInt32(DWORD val)
{
int out = LittleLong(val);
m_File->Write(&out, 4);
}
void FArchive::WriteInt64(QWORD val)
{
long long out = SWAP_QWORD(val);
m_File->Write(&out, 8);
}
void FArchive::WriteCount (DWORD count) void FArchive::WriteCount (DWORD count)
{ {
BYTE out; BYTE out;
@ -832,6 +855,14 @@ void FArchive::WriteString (const char *str)
} }
} }
void FArchive::WriteString(const FString &str)
{
// The count includes the '\0' terminator, but we don't
// actually write it out.
WriteCount(str.Len() + 1);
Write(str, str.Len());
}
FArchive &FArchive::operator<< (char *&str) FArchive &FArchive::operator<< (char *&str)
{ {
if (m_Storing) if (m_Storing)
@ -868,7 +899,7 @@ FArchive &FArchive::operator<< (FString &str)
{ {
if (m_Storing) if (m_Storing)
{ {
WriteString (str.GetChars()); WriteString (str);
} }
else else
{ {
@ -883,8 +914,7 @@ FArchive &FArchive::operator<< (FString &str)
char *str2 = (char *)alloca(size*sizeof(char)); char *str2 = (char *)alloca(size*sizeof(char));
size--; size--;
Read (str2, size); Read (str2, size);
str2[size] = 0; str = FString(str2, size);
str = str2;
} }
} }
return *this; return *this;

View file

@ -166,7 +166,14 @@ public:
virtual void Write (const void *mem, unsigned int len); virtual void Write (const void *mem, unsigned int len);
virtual void Read (void *mem, unsigned int len); virtual void Read (void *mem, unsigned int len);
void WriteString(const FString &str);
void WriteString (const char *str); void WriteString (const char *str);
void WriteByte(BYTE val);
void WriteInt16(WORD val);
void WriteInt32(DWORD val);
void WriteInt64(QWORD val);
void WriteCount (DWORD count); void WriteCount (DWORD count);
DWORD ReadCount (); DWORD ReadCount ();

View file

@ -82,6 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol)
return 0; return 0;
P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash)); P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash));
self->player->psprites[ps_flash].processPending = true;
} }
self->player->mo->PlayAttacking2 (); self->player->mo->PlayAttacking2 ();
@ -274,6 +275,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun)
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
return 0; return 0;
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash)); P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
self->player->psprites[ps_flash].processPending = true;
} }
player->mo->PlayAttacking2 (); player->mo->PlayAttacking2 ();
@ -310,6 +312,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2)
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2)) if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2))
return 0; return 0;
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash)); P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
self->player->psprites[ps_flash].processPending = true;
} }
player->mo->PlayAttacking2 (); player->mo->PlayAttacking2 ();
@ -382,12 +385,14 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i
{ {
// we're ok so set the state // we're ok so set the state
P_SetPsprite (player, ps_flash, flashstate + index); P_SetPsprite (player, ps_flash, flashstate + index);
player->psprites[ps_flash].processPending = true;
return; return;
} }
else else
{ {
// oh, no! The state is beyond the end of the state table so use the original flash state. // oh, no! The state is beyond the end of the state table so use the original flash state.
P_SetPsprite (player, ps_flash, flashstate); P_SetPsprite (player, ps_flash, flashstate);
player->psprites[ps_flash].processPending = true;
return; return;
} }
} }
@ -404,6 +409,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i
index = 0; index = 0;
} }
P_SetPsprite (player, ps_flash, flashstate + index); P_SetPsprite (player, ps_flash, flashstate + index);
player->psprites[ps_flash].processPending = true;
} }
// //

View file

@ -708,6 +708,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade)
return 0; return 0;
P_SetPsprite (player, ps_flash, flash); P_SetPsprite (player, ps_flash, flash);
self->player->psprites[ps_flash].processPending = true;
if (grenadetype != NULL) if (grenadetype != NULL)
{ {

View file

@ -5144,7 +5144,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo
points *= thing->GetClass()->RDFactor; points *= thing->GetClass()->RDFactor;
// points and bombdamage should be the same sign // points and bombdamage should be the same sign
if (((points * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) if (((int(points) * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
{ // OK to damage; target is in direct path { // OK to damage; target is in direct path
double vz; double vz;
double thrust; double thrust;

View file

@ -94,17 +94,23 @@ public:
{ {
return &Array[0]; return &Array[0];
} }
const_iterator begin() const
{
return &Array[0];
}
const_iterator cbegin() const
{
return &Array[0];
}
iterator end() iterator end()
{ {
return &Array[Count]; return &Array[Count];
} }
const_iterator end() const
const_iterator cbegin() const
{ {
return &Array[0]; return &Array[Count];
} }
const_iterator cend() const const_iterator cend() const
{ {
return &Array[Count]; return &Array[Count];

View file

@ -2745,6 +2745,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt)
return 0; return 0;
} }
//=========================================================================
//
// A_LogFloat
//
//===========================================================================
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogFloat)
{
PARAM_ACTION_PROLOGUE;
PARAM_FLOAT(num);
IGNORE_FORMAT_PRE
Printf("%H\n", num);
IGNORE_FORMAT_POST
return 0;
}
//=========================================================================== //===========================================================================
// //
// A_SetTranslucent // A_SetTranslucent

View file

@ -2995,10 +2995,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
} }
ValueType = arraytype->ElementType; ValueType = arraytype->ElementType;
if (ValueType->GetRegType() != REGT_INT) if (ValueType->GetRegType() != REGT_INT && ValueType->GetRegType() != REGT_FLOAT)
{ {
// int arrays only for now // int arrays only for now
ScriptPosition.Message(MSG_ERROR, "Only integer arrays are supported."); ScriptPosition.Message(MSG_ERROR, "Only numeric arrays are supported.");
delete this; delete this;
return NULL; return NULL;
} }
@ -3015,7 +3015,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
{ {
ExpEmit start = Array->Emit(build); ExpEmit start = Array->Emit(build);
ExpEmit dest(build, REGT_INT); PArray *const arraytype = static_cast<PArray*>(Array->ValueType);
PType *const elementtype = arraytype->ElementType;
ExpEmit dest(build, elementtype->GetRegType());
if (start.Konst) if (start.Konst)
{ {
ExpEmit tmpstart(build, REGT_POINTER); ExpEmit tmpstart(build, REGT_POINTER);
@ -3025,19 +3028,30 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
if (index->isConstant()) if (index->isConstant())
{ {
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt(); unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
if (indexval >= static_cast<PArray*>(Array->ValueType)->ElementCount) if (indexval >= arraytype->ElementCount)
{ {
I_Error("Array index out of bounds"); I_Error("Array index out of bounds");
} }
indexval <<= 2; indexval *= arraytype->ElementSize;
build->Emit(OP_LW, dest.RegNum, start.RegNum, build->GetConstantInt(indexval)); build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum,
start.RegNum, build->GetConstantInt(indexval));
} }
else else
{ {
ExpEmit indexv(index->Emit(build)); ExpEmit indexv(index->Emit(build));
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2); int shiftbits = 0;
build->Emit(OP_BOUND, indexv.RegNum, static_cast<PArray*>(Array->ValueType)->ElementCount); while (1u << shiftbits < arraytype->ElementSize)
build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum); {
shiftbits++;
}
assert(1 << shiftbits == arraytype->ElementSize && "Element sizes other than power of 2 are not implemented");
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
if (shiftbits > 0)
{
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits);
}
build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that
dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register
indexv.Free(build); indexv.Free(build);
} }
start.Free(build); start.Free(build);

View file

@ -525,12 +525,17 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl
// Read the type and make sure it's acceptable. // Read the type and make sure it's acceptable.
sc.MustGetAnyToken(); sc.MustGetAnyToken();
if (sc.TokenType != TK_Int && sc.TokenType != TK_Float) switch (sc.TokenType)
{ {
sc.ScriptMessage("User variables must be of type 'int' or 'float'"); case TK_Int: type = TypeSInt32; break;
case TK_Float: type = TypeFloat64; break;
case TK_String: type = TypeString; break;
default:
type = TypeError;
sc.ScriptMessage("User variables must be of type 'int' or 'float' or 'string'");
FScriptPosition::ErrorCounter++; FScriptPosition::ErrorCounter++;
break;
} }
type = sc.TokenType == TK_Int ? (PType *)TypeSInt32 : (PType *)TypeFloat64;
sc.MustGetToken(TK_Identifier); sc.MustGetToken(TK_Identifier);
// For now, restrict user variables to those that begin with "user_" to guarantee // For now, restrict user variables to those that begin with "user_" to guarantee
@ -576,11 +581,9 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl
} }
sc.MustGetToken(';'); sc.MustGetToken(';');
PField *sym = new PField(symname, type, 0); PField *sym = cls->AddField(symname, type, 0);
sym->Offset = cls->Extend(type); if (cls == NULL)
if (symt->AddSymbol(sym) == NULL)
{ {
delete sym;
sc.ScriptMessage ("'%s' is already defined in '%s'.", sc.ScriptMessage ("'%s' is already defined in '%s'.",
symname.GetChars(), cls ? cls->TypeName.GetChars() : "Global"); symname.GetChars(), cls ? cls->TypeName.GetChars() : "Global");
FScriptPosition::ErrorCounter++; FScriptPosition::ErrorCounter++;

View file

@ -203,6 +203,7 @@ ACTOR Actor native //: Thinker
action native A_PrintBold(string whattoprint, float time = 0, name fontname = ""); action native A_PrintBold(string whattoprint, float time = 0, name fontname = "");
action native A_Log(string whattoprint); action native A_Log(string whattoprint);
action native A_LogInt(int whattoprint); action native A_LogInt(int whattoprint);
action native A_LogFloat(float whattoprint);
action native A_SetTranslucent(float alpha, int style = 0); action native A_SetTranslucent(float alpha, int style = 0);
action native A_FadeIn(float reduce = 0.1, int flags = 0); action native A_FadeIn(float reduce = 0.1, int flags = 0);
action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true