mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 23:01:50 +00:00
Merge branch 'master' into floatcvt
# Conflicts: # src/dobjtype.cpp # src/dobjtype.h # src/version.h
This commit is contained in:
commit
fd27c8db9e
13 changed files with 1221 additions and 102 deletions
101
src/dobject.cpp
101
src/dobject.cpp
|
@ -257,46 +257,50 @@ DObject::DObject (PClass *inClass)
|
|||
|
||||
DObject::~DObject ()
|
||||
{
|
||||
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
|
||||
if (!PClass::bShutdown)
|
||||
{
|
||||
DObject **probe;
|
||||
PClass *type = GetClass();
|
||||
|
||||
if (!(ObjectFlags & OF_YesReallyDelete))
|
||||
if (!(ObjectFlags & OF_Cleanup) && !PClass::bShutdown)
|
||||
{
|
||||
Printf ("Warning: '%s' is freed outside the GC process.\n",
|
||||
type != NULL ? type->TypeName.GetChars() : "==some object==");
|
||||
}
|
||||
DObject **probe;
|
||||
|
||||
// Find all pointers that reference this object and NULL them.
|
||||
StaticPointerSubstitution(this, NULL);
|
||||
|
||||
// Now unlink this object from the GC list.
|
||||
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
|
||||
{
|
||||
if (*probe == this)
|
||||
if (!(ObjectFlags & OF_YesReallyDelete))
|
||||
{
|
||||
*probe = ObjNext;
|
||||
if (&ObjNext == GC::SweepPos)
|
||||
{
|
||||
GC::SweepPos = probe;
|
||||
}
|
||||
break;
|
||||
Printf("Warning: '%s' is freed outside the GC process.\n",
|
||||
type != NULL ? type->TypeName.GetChars() : "==some object==");
|
||||
}
|
||||
}
|
||||
|
||||
// If it's gray, also unlink it from the gray list.
|
||||
if (this->IsGray())
|
||||
{
|
||||
for (probe = &GC::Gray; *probe != NULL; probe = &((*probe)->GCNext))
|
||||
// Find all pointers that reference this object and NULL them.
|
||||
StaticPointerSubstitution(this, NULL);
|
||||
|
||||
// Now unlink this object from the GC list.
|
||||
for (probe = &GC::Root; *probe != NULL; probe = &((*probe)->ObjNext))
|
||||
{
|
||||
if (*probe == this)
|
||||
{
|
||||
*probe = GCNext;
|
||||
*probe = ObjNext;
|
||||
if (&ObjNext == GC::SweepPos)
|
||||
{
|
||||
GC::SweepPos = probe;
|
||||
}
|
||||
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())
|
||||
{
|
||||
// Write all user variables.
|
||||
for (; symt != NULL; symt = symt->ParentSymbolTable)
|
||||
{
|
||||
PSymbolTable::MapType::Iterator it(symt->Symbols);
|
||||
PSymbolTable::MapType::Pair *pair;
|
||||
|
||||
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;
|
||||
// Write all fields that aren't serialized by native code.
|
||||
GetClass()->WriteValue(arc, this);
|
||||
}
|
||||
else if (SaveVersion >= 4535)
|
||||
{
|
||||
GetClass()->ReadValue(arc, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
{ // Old version that only deals with ints
|
||||
// Read user variables until 'None' is encountered.
|
||||
arc << varname;
|
||||
while (varname != NAME_None)
|
||||
|
|
979
src/dobjtype.cpp
979
src/dobjtype.cpp
File diff suppressed because it is too large
Load diff
111
src/dobjtype.h
111
src/dobjtype.h
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "vm.h"
|
||||
|
||||
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
|
||||
|
||||
// Variable/parameter/field flags -------------------------------------------
|
||||
|
||||
// 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);
|
||||
|
||||
// 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)
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
|
@ -321,6 +353,9 @@ class PInt : public PBasicType
|
|||
public:
|
||||
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, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
|
@ -347,6 +382,9 @@ class PFloat : public PBasicType
|
|||
public:
|
||||
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, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
|
@ -381,6 +419,12 @@ public:
|
|||
PString();
|
||||
|
||||
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 ----------------------------------------------
|
||||
|
@ -390,6 +434,9 @@ class PName : public PInt
|
|||
DECLARE_CLASS(PName, PInt);
|
||||
public:
|
||||
PName();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
};
|
||||
|
||||
class PSound : public PInt
|
||||
|
@ -397,6 +444,9 @@ class PSound : public PInt
|
|||
DECLARE_CLASS(PSound, PInt);
|
||||
public:
|
||||
PSound();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
};
|
||||
|
||||
class PColor : public PInt
|
||||
|
@ -414,6 +464,9 @@ class PStatePointer : public PBasicType
|
|||
public:
|
||||
PStatePointer();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
|
||||
virtual int GetStoreOp() const;
|
||||
virtual int GetLoadOp() const;
|
||||
virtual int GetRegType() const;
|
||||
|
@ -434,6 +487,10 @@ public:
|
|||
|
||||
virtual bool IsMatch(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:
|
||||
PPointer();
|
||||
};
|
||||
|
@ -500,6 +557,12 @@ public:
|
|||
|
||||
virtual bool IsMatch(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:
|
||||
PArray();
|
||||
};
|
||||
|
@ -554,9 +617,16 @@ public:
|
|||
|
||||
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();
|
||||
|
||||
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:
|
||||
PStruct();
|
||||
};
|
||||
|
@ -614,11 +684,16 @@ class PClass : public PStruct
|
|||
protected:
|
||||
// We unravel _WITH_META here just as we did for PType.
|
||||
enum { MetaClassNum = CLASSREG_PClassClass };
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
virtual void Derive(PClass *newclass);
|
||||
void InitializeSpecials(void *addr) const;
|
||||
public:
|
||||
typedef PClassClass MetaClass;
|
||||
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) {}
|
||||
static void StaticInit();
|
||||
static void StaticShutdown();
|
||||
|
@ -639,10 +714,10 @@ public:
|
|||
void InsertIntoHash();
|
||||
DObject *CreateNew() const;
|
||||
PClass *CreateDerivedClass(FName name, unsigned int size);
|
||||
unsigned int Extend(unsigned int extension, unsigned int alignment);
|
||||
unsigned int Extend(const PType *type) { return Extend(type->Size, type->Align); }
|
||||
PField *AddField(FName name, PType *type, DWORD flags=0) override;
|
||||
void InitializeActorInfo();
|
||||
void BuildFlatPointers();
|
||||
void DestroySpecials(void *addr) const;
|
||||
const PClass *NativeClass() const;
|
||||
|
||||
// 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.
|
||||
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 FString &name) { return FindClass(FName(name, true)); }
|
||||
static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); }
|
||||
|
@ -810,4 +888,31 @@ public:
|
|||
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (m_Storing)
|
||||
|
@ -868,7 +899,7 @@ FArchive &FArchive::operator<< (FString &str)
|
|||
{
|
||||
if (m_Storing)
|
||||
{
|
||||
WriteString (str.GetChars());
|
||||
WriteString (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -883,8 +914,7 @@ FArchive &FArchive::operator<< (FString &str)
|
|||
char *str2 = (char *)alloca(size*sizeof(char));
|
||||
size--;
|
||||
Read (str2, size);
|
||||
str2[size] = 0;
|
||||
str = str2;
|
||||
str = FString(str2, size);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
|
|
@ -166,7 +166,14 @@ public:
|
|||
virtual void Write (const void *mem, unsigned int len);
|
||||
virtual void Read (void *mem, unsigned int len);
|
||||
|
||||
void WriteString(const FString &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);
|
||||
DWORD ReadCount ();
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePistol)
|
|||
return 0;
|
||||
|
||||
P_SetPsprite (self->player, ps_flash, weapon->FindState(NAME_Flash));
|
||||
self->player->psprites[ps_flash].processPending = true;
|
||||
}
|
||||
self->player->mo->PlayAttacking2 ();
|
||||
|
||||
|
@ -274,6 +275,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun)
|
|||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1))
|
||||
return 0;
|
||||
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
|
||||
self->player->psprites[ps_flash].processPending = true;
|
||||
}
|
||||
player->mo->PlayAttacking2 ();
|
||||
|
||||
|
@ -310,6 +312,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2)
|
|||
if (!weapon->DepleteAmmo (weapon->bAltFire, true, 2))
|
||||
return 0;
|
||||
P_SetPsprite (player, ps_flash, weapon->FindState(NAME_Flash));
|
||||
self->player->psprites[ps_flash].processPending = true;
|
||||
}
|
||||
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
|
||||
P_SetPsprite (player, ps_flash, flashstate + index);
|
||||
player->psprites[ps_flash].processPending = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// oh, no! The state is beyond the end of the state table so use the original flash state.
|
||||
P_SetPsprite (player, ps_flash, flashstate);
|
||||
player->psprites[ps_flash].processPending = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -404,6 +409,7 @@ void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int i
|
|||
index = 0;
|
||||
}
|
||||
P_SetPsprite (player, ps_flash, flashstate + index);
|
||||
player->psprites[ps_flash].processPending = true;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -708,6 +708,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireGrenade)
|
|||
return 0;
|
||||
|
||||
P_SetPsprite (player, ps_flash, flash);
|
||||
self->player->psprites[ps_flash].processPending = true;
|
||||
|
||||
if (grenadetype != NULL)
|
||||
{
|
||||
|
|
|
@ -5144,7 +5144,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo
|
|||
points *= thing->GetClass()->RDFactor;
|
||||
|
||||
// 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
|
||||
double vz;
|
||||
double thrust;
|
||||
|
|
14
src/tarray.h
14
src/tarray.h
|
@ -94,17 +94,23 @@ public:
|
|||
{
|
||||
return &Array[0];
|
||||
}
|
||||
const_iterator begin() const
|
||||
{
|
||||
return &Array[0];
|
||||
}
|
||||
const_iterator cbegin() const
|
||||
{
|
||||
return &Array[0];
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return &Array[Count];
|
||||
}
|
||||
|
||||
const_iterator cbegin() const
|
||||
const_iterator end() const
|
||||
{
|
||||
return &Array[0];
|
||||
return &Array[Count];
|
||||
}
|
||||
|
||||
const_iterator cend() const
|
||||
{
|
||||
return &Array[Count];
|
||||
|
|
|
@ -2745,6 +2745,22 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LogInt)
|
|||
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
|
||||
|
|
|
@ -2995,10 +2995,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
|||
}
|
||||
|
||||
ValueType = arraytype->ElementType;
|
||||
if (ValueType->GetRegType() != REGT_INT)
|
||||
if (ValueType->GetRegType() != REGT_INT && ValueType->GetRegType() != REGT_FLOAT)
|
||||
{
|
||||
// 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;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -3015,7 +3015,10 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
|||
ExpEmit FxArrayElement::Emit(VMFunctionBuilder *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)
|
||||
{
|
||||
ExpEmit tmpstart(build, REGT_POINTER);
|
||||
|
@ -3025,19 +3028,30 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
|||
if (index->isConstant())
|
||||
{
|
||||
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");
|
||||
}
|
||||
indexval <<= 2;
|
||||
build->Emit(OP_LW, dest.RegNum, start.RegNum, build->GetConstantInt(indexval));
|
||||
indexval *= arraytype->ElementSize;
|
||||
build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum,
|
||||
start.RegNum, build->GetConstantInt(indexval));
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpEmit indexv(index->Emit(build));
|
||||
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, 2);
|
||||
build->Emit(OP_BOUND, indexv.RegNum, static_cast<PArray*>(Array->ValueType)->ElementCount);
|
||||
build->Emit(OP_LW_R, dest.RegNum, start.RegNum, indexv.RegNum);
|
||||
int shiftbits = 0;
|
||||
while (1u << shiftbits < arraytype->ElementSize)
|
||||
{
|
||||
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);
|
||||
}
|
||||
start.Free(build);
|
||||
|
|
|
@ -525,12 +525,17 @@ static void ParseUserVariable (FScanner &sc, PSymbolTable *symt, PClassActor *cl
|
|||
|
||||
// Read the type and make sure it's acceptable.
|
||||
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++;
|
||||
break;
|
||||
}
|
||||
type = sc.TokenType == TK_Int ? (PType *)TypeSInt32 : (PType *)TypeFloat64;
|
||||
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
// 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(';');
|
||||
|
||||
PField *sym = new PField(symname, type, 0);
|
||||
sym->Offset = cls->Extend(type);
|
||||
if (symt->AddSymbol(sym) == NULL)
|
||||
PField *sym = cls->AddField(symname, type, 0);
|
||||
if (cls == NULL)
|
||||
{
|
||||
delete sym;
|
||||
sc.ScriptMessage ("'%s' is already defined in '%s'.",
|
||||
symname.GetChars(), cls ? cls->TypeName.GetChars() : "Global");
|
||||
FScriptPosition::ErrorCounter++;
|
||||
|
|
|
@ -203,6 +203,7 @@ ACTOR Actor native //: Thinker
|
|||
action native A_PrintBold(string whattoprint, float time = 0, name fontname = "");
|
||||
action native A_Log(string 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_FadeIn(float reduce = 0.1, int flags = 0);
|
||||
action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true
|
||||
|
|
Loading…
Reference in a new issue