mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-26 22:11:43 +00:00
This commit is contained in:
commit
d6169ea75e
44 changed files with 729 additions and 750 deletions
33
src/actor.h
33
src/actor.h
|
@ -817,32 +817,7 @@ public:
|
|||
void SetAngle(DAngle ang, bool interpolate);
|
||||
void SetRoll(DAngle roll, bool interpolate);
|
||||
|
||||
PClassActor *GetBloodType(int type = 0) const
|
||||
{
|
||||
PClassActor *bloodcls;
|
||||
if (type == 0)
|
||||
{
|
||||
bloodcls = PClass::FindActor(GetClass()->BloodType);
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
bloodcls = PClass::FindActor(GetClass()->BloodType2);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
bloodcls = PClass::FindActor(GetClass()->BloodType3);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bloodcls != NULL)
|
||||
{
|
||||
bloodcls = bloodcls->GetReplacement();
|
||||
}
|
||||
return bloodcls;
|
||||
}
|
||||
PClassActor *GetBloodType(int type = 0) const;
|
||||
|
||||
double Distance2DSquared(AActor *other, bool absolute = false)
|
||||
{
|
||||
|
@ -1048,6 +1023,12 @@ public:
|
|||
double renderradius;
|
||||
|
||||
double projectilepassheight; // height for clipping projectile movement against this actor
|
||||
double CameraHeight; // Height of camera when used as such
|
||||
|
||||
double RadiusDamageFactor; // Radius damage factor
|
||||
double SelfDamageFactor;
|
||||
double StealthAlpha; // Minmum alpha for MF_STEALTH.
|
||||
int WoundHealth; // Health needed to enter wound state
|
||||
|
||||
SDWORD tics; // state tic counter
|
||||
FState *state;
|
||||
|
|
|
@ -358,7 +358,7 @@ void DBot::WhatToGet (AActor *item)
|
|||
}
|
||||
else if ((typeis (Megasphere) || typeis (Soulsphere) || typeis (HealthBonus)) && player->mo->health >= deh.MaxSoulsphere)
|
||||
return;
|
||||
else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth() + player->mo->stamina)
|
||||
else if (item->IsKindOf (PClass::FindActor(NAME_Health)) && player->mo->health >= player->mo->GetMaxHealth(true))
|
||||
return;
|
||||
|
||||
if ((dest == NULL ||
|
||||
|
|
|
@ -732,34 +732,6 @@ CCMD (dir)
|
|||
chdir (curdir);
|
||||
}
|
||||
|
||||
CCMD (fov)
|
||||
{
|
||||
player_t *player = who ? who->player : &players[consoleplayer];
|
||||
|
||||
if (argv.argc() != 2)
|
||||
{
|
||||
Printf ("fov is %g\n", player->DesiredFOV);
|
||||
return;
|
||||
}
|
||||
else if (dmflags & DF_NO_FOV)
|
||||
{
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
Net_WriteByte (DEM_FOV);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("A setting controller has disabled FOV changes.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte (DEM_MYFOV);
|
||||
}
|
||||
Net_WriteByte (clamp (atoi (argv[1]), 5, 179));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CCMD warp
|
||||
|
|
|
@ -93,7 +93,7 @@ public:
|
|||
virtual bool UpdateWaterLevel (bool splash) override;
|
||||
|
||||
bool ResetAirSupply (bool playgasp = true);
|
||||
int GetMaxHealth() const;
|
||||
int GetMaxHealth(bool withupgrades = false) const;
|
||||
void TweakSpeeds (double &forwardmove, double &sidemove);
|
||||
void MorphPlayerThink ();
|
||||
void ActivateMorphWeapon ();
|
||||
|
@ -159,8 +159,6 @@ public:
|
|||
FNameNoInit Face; // Doom status bar face (when used)
|
||||
FNameNoInit Portrait;
|
||||
FNameNoInit Slot[10];
|
||||
FNameNoInit InvulMode;
|
||||
FNameNoInit HealingRadiusType;
|
||||
double HexenArmor[5];
|
||||
BYTE ColorRangeStart; // Skin color range
|
||||
BYTE ColorRangeEnd;
|
||||
|
@ -529,6 +527,9 @@ public:
|
|||
DPSprite *GetPSprite(PSPLayers layer);
|
||||
|
||||
bool GetPainFlash(FName type, PalEntry *color) const;
|
||||
|
||||
// [Nash] set player FOV
|
||||
void SetFOV(float fov);
|
||||
};
|
||||
|
||||
// Bookkeeping on players - state.
|
||||
|
|
|
@ -623,12 +623,20 @@ DEFINE_ACTION_FUNCTION(DObject, MSTime)
|
|||
|
||||
void *DObject::ScriptVar(FName field, PType *type)
|
||||
{
|
||||
auto sym = dyn_cast<PField>(GetClass()->Symbols.FindSymbol(field, true));
|
||||
auto cls = GetClass();
|
||||
auto sym = dyn_cast<PField>(cls->Symbols.FindSymbol(field, true));
|
||||
if (sym && (sym->Type == type || type == nullptr))
|
||||
{
|
||||
if (!(sym->Flags & VARF_Meta))
|
||||
{
|
||||
return (((char*)this) + sym->Offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (cls->Meta + 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());
|
||||
I_Error("Variable %s not found in %s\n", field.GetChars(), cls->TypeName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
class PClass;
|
||||
class PType;
|
||||
class FSerializer;
|
||||
class FSoundID;
|
||||
|
||||
class DObject;
|
||||
/*
|
||||
|
@ -483,9 +484,11 @@ public:
|
|||
// Add other types as needed.
|
||||
bool &BoolVar(FName field);
|
||||
int &IntVar(FName field);
|
||||
FSoundID &SoundVar(FName field);
|
||||
PalEntry &ColorVar(FName field);
|
||||
FName &NameVar(FName field);
|
||||
double &FloatVar(FName field);
|
||||
FString &StringVar(FName field);
|
||||
template<class T> T*& PointerVar(FName field);
|
||||
|
||||
// If you need to replace one object with another and want to
|
||||
|
|
115
src/dobjtype.cpp
115
src/dobjtype.cpp
|
@ -722,10 +722,6 @@ PBool::PBool()
|
|||
{
|
||||
mDescriptiveName = "Bool";
|
||||
MemberOnly = false;
|
||||
// Override the default max set by PInt's constructor
|
||||
PSymbolConstNumeric *maxsym = static_cast<PSymbolConstNumeric *>(Symbols.FindSymbol(NAME_Max, false));
|
||||
assert(maxsym != nullptr && maxsym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||
maxsym->Value = 1;
|
||||
}
|
||||
|
||||
/* PFloat *****************************************************************/
|
||||
|
@ -2892,6 +2888,7 @@ PClass::PClass()
|
|||
bExported = false;
|
||||
bDecorateClass = false;
|
||||
ConstructNative = nullptr;
|
||||
Meta = nullptr;
|
||||
mDescriptiveName = "Class";
|
||||
|
||||
PClass::AllClasses.Push(this);
|
||||
|
@ -2910,6 +2907,11 @@ PClass::~PClass()
|
|||
M_Free(Defaults);
|
||||
Defaults = nullptr;
|
||||
}
|
||||
if (Meta != nullptr)
|
||||
{
|
||||
M_Free(Meta);
|
||||
Meta = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3047,7 +3049,7 @@ PClass *PClass::FindClass (FName zaname)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
DObject *PClass::CreateNew() const
|
||||
DObject *PClass::CreateNew()
|
||||
{
|
||||
BYTE *mem = (BYTE *)M_Malloc (Size);
|
||||
assert (mem != nullptr);
|
||||
|
@ -3064,7 +3066,7 @@ DObject *PClass::CreateNew() const
|
|||
}
|
||||
ConstructNative (mem);
|
||||
((DObject *)mem)->SetClass (const_cast<PClass *>(this));
|
||||
InitializeSpecials(mem, Defaults);
|
||||
InitializeSpecials(mem, Defaults, &PClass::SpecialInits);
|
||||
return (DObject *)mem;
|
||||
}
|
||||
|
||||
|
@ -3076,17 +3078,16 @@ DObject *PClass::CreateNew() const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::InitializeSpecials(void *addr, void *defaults) const
|
||||
void PClass::InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits)
|
||||
{
|
||||
// Once we reach a native class, we can stop going up the family tree,
|
||||
// since native classes handle initialization natively.
|
||||
if (!bRuntimeClass)
|
||||
if ((!bRuntimeClass && Inits == &PClass::SpecialInits) || ParentClass == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
assert(ParentClass != nullptr);
|
||||
ParentClass->InitializeSpecials(addr, defaults);
|
||||
for (auto tao : SpecialInits)
|
||||
ParentClass->InitializeSpecials(addr, defaults, Inits);
|
||||
for (auto tao : (this->*Inits))
|
||||
{
|
||||
tao.first->InitializeValue((char*)addr + tao.second, defaults == nullptr? nullptr : ((char*)defaults) + tao.second);
|
||||
}
|
||||
|
@ -3101,7 +3102,7 @@ void PClass::InitializeSpecials(void *addr, void *defaults) const
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void PClass::DestroySpecials(void *addr) const
|
||||
void PClass::DestroySpecials(void *addr)
|
||||
{
|
||||
// Once we reach a native class, we can stop going up the family tree,
|
||||
// since native classes handle deinitialization natively.
|
||||
|
@ -3160,7 +3161,6 @@ void PClass::InitializeDefaults()
|
|||
optr->ObjNext = nullptr;
|
||||
optr->SetClass(this);
|
||||
|
||||
|
||||
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
|
||||
if (ParentClass->Defaults != nullptr)
|
||||
{
|
||||
|
@ -3174,21 +3174,53 @@ void PClass::InitializeDefaults()
|
|||
{
|
||||
memset(Defaults + sizeof(DObject), 0, Size - sizeof(DObject));
|
||||
}
|
||||
|
||||
assert(MetaSize >= ParentClass->MetaSize);
|
||||
if (MetaSize != 0)
|
||||
{
|
||||
Meta = (BYTE*)M_Malloc(MetaSize);
|
||||
|
||||
// Copy the defaults from the parent but leave the DObject part alone because it contains important data.
|
||||
if (ParentClass->Meta != nullptr)
|
||||
{
|
||||
memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize);
|
||||
if (MetaSize > ParentClass->MetaSize)
|
||||
{
|
||||
memset(Meta + ParentClass->MetaSize, 0, MetaSize - ParentClass->MetaSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(Meta, 0, MetaSize);
|
||||
}
|
||||
|
||||
if (MetaSize > 0) memcpy(Meta, ParentClass->Meta, ParentClass->MetaSize);
|
||||
else memset(Meta, 0, MetaSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (bRuntimeClass)
|
||||
{
|
||||
// Copy parent values from the parent defaults.
|
||||
assert(ParentClass != nullptr);
|
||||
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults);
|
||||
if (Defaults != nullptr) ParentClass->InitializeSpecials(Defaults, ParentClass->Defaults, &PClass::SpecialInits);
|
||||
if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits);
|
||||
for (const PField *field : Fields)
|
||||
{
|
||||
if (!(field->Flags & VARF_Native))
|
||||
if (!(field->Flags & VARF_Native) && !(field->Flags & VARF_Meta))
|
||||
{
|
||||
field->Type->SetDefaultValue(Defaults, unsigned(field->Offset), &SpecialInits);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Meta != nullptr) ParentClass->InitializeSpecials(Meta, ParentClass->Meta, &PClass::MetaInits);
|
||||
for (const PField *field : Fields)
|
||||
{
|
||||
if (!(field->Flags & VARF_Native) && (field->Flags & VARF_Meta))
|
||||
{
|
||||
field->Type->SetDefaultValue(Meta, unsigned(field->Offset), &MetaInits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3248,6 +3280,7 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
type->bRuntimeClass = true;
|
||||
Derive(type, name);
|
||||
type->Size = size;
|
||||
type->MetaSize = MetaSize;
|
||||
if (size != TentativeClass)
|
||||
{
|
||||
type->InitializeDefaults();
|
||||
|
@ -3264,6 +3297,39 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
return type;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: AddField
|
||||
//
|
||||
// Appends a new metadata field to the end of a struct. Returns either the new field
|
||||
// or nullptr if a symbol by that name already exists.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
PField *PClass::AddMetaField(FName name, PType *type, DWORD flags)
|
||||
{
|
||||
PField *field = new PField(name, type, flags);
|
||||
|
||||
// The new field is added to the end of this struct, alignment permitting.
|
||||
field->Offset = (MetaSize + (type->Align - 1)) & ~(type->Align - 1);
|
||||
|
||||
// Enlarge this struct to enclose the new field.
|
||||
MetaSize = unsigned(field->Offset + type->Size);
|
||||
|
||||
// This struct's alignment is the same as the largest alignment of any of
|
||||
// its fields.
|
||||
Align = MAX(Align, type->Align);
|
||||
|
||||
if (Symbols.AddSymbol(field) == nullptr)
|
||||
{ // name is already in use
|
||||
field->Destroy();
|
||||
return nullptr;
|
||||
}
|
||||
Fields.Push(field);
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: AddField
|
||||
|
@ -3272,6 +3338,8 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size)
|
|||
|
||||
PField *PClass::AddField(FName name, PType *type, DWORD flags)
|
||||
{
|
||||
if (!(flags & VARF_Meta))
|
||||
{
|
||||
unsigned oldsize = Size;
|
||||
PField *field = Super::AddField(name, type, flags);
|
||||
|
||||
|
@ -3284,6 +3352,22 @@ PField *PClass::AddField(FName name, PType *type, DWORD flags)
|
|||
memset(Defaults + oldsize, 0, Size - oldsize);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned oldsize = MetaSize;
|
||||
PField *field = AddMetaField(name, type, flags);
|
||||
|
||||
// Only initialize the defaults if they have already been created.
|
||||
// For ZScript this is not the case, it will first define all fields before
|
||||
// setting up any defaults for any class.
|
||||
if (field != nullptr && !(flags & VARF_Native) && Meta != nullptr)
|
||||
{
|
||||
Meta = (BYTE *)M_Realloc(Meta, MetaSize);
|
||||
memset(Meta + oldsize, 0, MetaSize - oldsize);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3313,6 +3397,7 @@ PClass *PClass::FindClassTentative(FName name)
|
|||
PClass *type = static_cast<PClass *>(GetClass()->CreateNew());
|
||||
DPrintf(DMSG_SPAMMY, "Creating placeholder class %s : %s\n", name.GetChars(), TypeName.GetChars());
|
||||
|
||||
assert(MetaSize == 0);
|
||||
Derive(type, name);
|
||||
type->Size = TentativeClass;
|
||||
TypeTable.AddType(type, RUNTIME_CLASS(PClass), 0, name, bucket);
|
||||
|
|
|
@ -557,12 +557,13 @@ enum
|
|||
class PClass : public PNativeStruct
|
||||
{
|
||||
DECLARE_CLASS(PClass, PNativeStruct);
|
||||
protected:
|
||||
// We unravel _WITH_META here just as we did for PType.
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
protected:
|
||||
TArray<FTypeAndOffset> MetaInits;
|
||||
void Derive(PClass *newclass, FName name);
|
||||
void InitializeSpecials(void *addr, void *defaults) const;
|
||||
void InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits);
|
||||
void SetSuper();
|
||||
PField *AddMetaField(FName name, PType *type, DWORD flags);
|
||||
public:
|
||||
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
|
||||
void WriteAllFields(FSerializer &ar, const void *addr) const;
|
||||
|
@ -577,11 +578,14 @@ public:
|
|||
static void StaticBootstrap();
|
||||
|
||||
// Per-class information -------------------------------------
|
||||
TArray<FTypeAndOffset> SpecialInits;
|
||||
PClass *ParentClass; // the class this class derives from
|
||||
const size_t *Pointers; // object pointers defined by this class *only*
|
||||
const size_t *FlatPointers; // object pointers defined by this class and all its superclasses; not initialized by default
|
||||
const size_t *ArrayPointers; // dynamic arrays containing object pointers.
|
||||
BYTE *Defaults;
|
||||
BYTE *Meta; // Per-class static script data
|
||||
unsigned MetaSize;
|
||||
bool bRuntimeClass; // class was defined at run-time, not compile-time
|
||||
bool bExported; // This type has been declared in a script
|
||||
bool bDecorateClass; // may be subject to some idiosyncracies due to DECORATE backwards compatibility
|
||||
|
@ -593,13 +597,14 @@ public:
|
|||
PClass();
|
||||
~PClass();
|
||||
void InsertIntoHash();
|
||||
DObject *CreateNew() const;
|
||||
DObject *CreateNew();
|
||||
PClass *CreateDerivedClass(FName name, unsigned int size);
|
||||
PField *AddField(FName name, PType *type, DWORD flags=0) override;
|
||||
void InitializeActorInfo();
|
||||
void BuildFlatPointers();
|
||||
void BuildArrayPointers();
|
||||
void DestroySpecials(void *addr) const;
|
||||
void InitMeta();
|
||||
void DestroySpecials(void *addr);
|
||||
const PClass *NativeClass() const;
|
||||
|
||||
// Returns true if this type is an ancestor of (or same as) the passed type.
|
||||
|
@ -723,6 +728,11 @@ inline int &DObject::IntVar(FName field)
|
|||
return *(int*)ScriptVar(field, TypeSInt32);
|
||||
}
|
||||
|
||||
inline FSoundID &DObject::SoundVar(FName field)
|
||||
{
|
||||
return *(FSoundID*)ScriptVar(field, TypeSound);
|
||||
}
|
||||
|
||||
inline PalEntry &DObject::ColorVar(FName field)
|
||||
{
|
||||
return *(PalEntry*)ScriptVar(field, TypeColor);
|
||||
|
@ -738,6 +748,11 @@ inline double &DObject::FloatVar(FName field)
|
|||
return *(double*)ScriptVar(field, TypeFloat64);
|
||||
}
|
||||
|
||||
inline FString &DObject::StringVar(FName field)
|
||||
{
|
||||
return *(FString*)ScriptVar(field, TypeString);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T *&DObject::PointerVar(FName field)
|
||||
{
|
||||
|
|
|
@ -50,8 +50,6 @@ DEFINE_FIELD(AInventory, DropTime)
|
|||
DEFINE_FIELD(AInventory, SpawnPointClass)
|
||||
DEFINE_FIELD(AInventory, PickupFlash)
|
||||
DEFINE_FIELD(AInventory, PickupSound)
|
||||
DEFINE_FIELD(AInventory, GiveQuest)
|
||||
DEFINE_FIELD(PClassActor, PickupMsg)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -115,8 +113,7 @@ void AInventory::Serialize(FSerializer &arc)
|
|||
("icon", Icon, def->Icon)
|
||||
("pickupsound", PickupSound, def->PickupSound)
|
||||
("spawnpointclass", SpawnPointClass, def->SpawnPointClass)
|
||||
("droptime", DropTime, def->DropTime)
|
||||
("givequest", GiveQuest, def->GiveQuest);
|
||||
("droptime", DropTime, def->DropTime);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -17,7 +17,7 @@ struct visstyle_t;
|
|||
|
||||
// A pickup is anything the player can pickup (i.e. weapons, ammo, powerups, etc)
|
||||
|
||||
enum
|
||||
enum ItemFlag
|
||||
{
|
||||
IF_ACTIVATABLE = 1<<0, // can be activated
|
||||
IF_ACTIVATED = 1<<1, // is currently activated
|
||||
|
@ -46,8 +46,14 @@ enum
|
|||
IF_TRANSFER = 1<<24, // All inventory items that the inventory item contains is also transfered to the pickuper
|
||||
IF_NOTELEPORTFREEZE = 1<<25, // does not 'freeze' the player right after teleporting.
|
||||
IF_NOSCREENBLINK = 1<<26, // Does not blink the screen overlay when expiring.
|
||||
IF_ISHEALTH = 1<<27, // for the DM flag so that it can recognize items that are not obviously health givers.
|
||||
IF_ISARMOR = 1<<28, // for the DM flag so that it can recognize items that are not obviously armor givers.
|
||||
};
|
||||
|
||||
typedef TFlags<ItemFlag> InvFlags;
|
||||
//typedef TFlags<ItemFlag2> ItemFlags2;
|
||||
DEFINE_TFLAGS_OPERATORS(InvFlags)
|
||||
//DEFINE_TFLAGS_OPERATORS(ItemFlags2)
|
||||
|
||||
class AInventory : public AActor
|
||||
{
|
||||
|
@ -87,10 +93,9 @@ public:
|
|||
FTextureID Icon; // Icon to show on status bar or HUD
|
||||
int DropTime; // Countdown after dropping
|
||||
PClassActor *SpawnPointClass; // For respawning like Heretic's mace
|
||||
int GiveQuest; // Optionally give one of the quest items.
|
||||
FTextureID AltHUDIcon;
|
||||
|
||||
DWORD ItemFlags;
|
||||
InvFlags ItemFlags;
|
||||
PClassActor *PickupFlash; // actor to spawn as pickup flash
|
||||
|
||||
FSoundIDNoInit PickupSound;
|
||||
|
|
|
@ -2744,7 +2744,7 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
max = 0;
|
||||
}
|
||||
else //default to the class's health
|
||||
max = statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->mo->stamina;
|
||||
max = statusBar->CPlayer->mo->GetMaxHealth(true);
|
||||
break;
|
||||
case ARMOR:
|
||||
value = statusBar->armor != NULL ? statusBar->armor->Amount : 0;
|
||||
|
@ -3251,7 +3251,7 @@ class CommandDrawGem : public SBarInfoCommand
|
|||
void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged)
|
||||
{
|
||||
goalValue = armor ? (statusBar->armor ? statusBar->armor->Amount : 0) : statusBar->CPlayer->mo->health;
|
||||
int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth() + statusBar->CPlayer->mo->stamina;
|
||||
int max = armor ? 100 : statusBar->CPlayer->mo->GetMaxHealth(true);
|
||||
if(max != 0 && goalValue > 0)
|
||||
{
|
||||
goalValue = (goalValue*100)/max;
|
||||
|
|
|
@ -56,6 +56,7 @@ DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mBackButton)
|
|||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenMapNameFont)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenEnteringFont)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, mStatscreenFinishedFont)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, gibfactor)
|
||||
|
||||
|
||||
const char *GameNames[17] =
|
||||
|
|
39
src/info.cpp
39
src/info.cpp
|
@ -251,22 +251,7 @@ PClassActor::PClassActor()
|
|||
DamageFactors = NULL;
|
||||
PainChances = NULL;
|
||||
|
||||
DeathHeight = -1;
|
||||
BurnHeight = -1;
|
||||
GibHealth = INT_MIN;
|
||||
WoundHealth = 6;
|
||||
FastSpeed = -1.;
|
||||
RDFactor = 1.;
|
||||
SelfDamageFactor = 1.;
|
||||
StealthAlpha = 0.;
|
||||
CameraHeight = INT_MIN;
|
||||
|
||||
DropItems = NULL;
|
||||
|
||||
DontHurtShooter = false;
|
||||
ExplosionRadius = -1;
|
||||
MeleeDamage = 0;
|
||||
|
||||
// Record this in the master list.
|
||||
AllActorClasses.Push(this);
|
||||
}
|
||||
|
@ -310,34 +295,11 @@ void PClassActor::DeriveData(PClass *newclass)
|
|||
PClassActor *newa = static_cast<PClassActor *>(newclass);
|
||||
|
||||
newa->DefaultStateUsage = DefaultStateUsage;
|
||||
newa->Obituary = Obituary;
|
||||
newa->HitObituary = HitObituary;
|
||||
newa->DeathHeight = DeathHeight;
|
||||
newa->BurnHeight = BurnHeight;
|
||||
newa->BloodColor = BloodColor;
|
||||
newa->GibHealth = GibHealth;
|
||||
newa->WoundHealth = WoundHealth;
|
||||
newa->FastSpeed = FastSpeed;
|
||||
newa->RDFactor = RDFactor;
|
||||
newa->SelfDamageFactor = SelfDamageFactor;
|
||||
newa->StealthAlpha = StealthAlpha;
|
||||
newa->CameraHeight = CameraHeight;
|
||||
newa->HowlSound = HowlSound;
|
||||
newa->BloodType = BloodType;
|
||||
newa->BloodType2 = BloodType2;
|
||||
newa->BloodType3 = BloodType3;
|
||||
newa->distancecheck = distancecheck;
|
||||
|
||||
newa->DropItems = DropItems;
|
||||
|
||||
newa->DontHurtShooter = DontHurtShooter;
|
||||
newa->ExplosionRadius = ExplosionRadius;
|
||||
newa->ExplosionDamage = ExplosionDamage;
|
||||
newa->MeleeDamage = MeleeDamage;
|
||||
newa->MeleeSound = MeleeSound;
|
||||
newa->MissileName = MissileName;
|
||||
newa->MissileHeight = MissileHeight;
|
||||
|
||||
newa->VisibleToPlayerClass = VisibleToPlayerClass;
|
||||
|
||||
if (DamageFactors != NULL)
|
||||
|
@ -354,7 +316,6 @@ void PClassActor::DeriveData(PClass *newclass)
|
|||
}
|
||||
|
||||
// Inventory stuff
|
||||
newa->PickupMsg = PickupMsg;
|
||||
newa->ForbiddenToPlayerClass = ForbiddenToPlayerClass;
|
||||
newa->RestrictedToPlayerClass = RestrictedToPlayerClass;
|
||||
|
||||
|
|
25
src/info.h
25
src/info.h
|
@ -290,38 +290,13 @@ public:
|
|||
|
||||
TArray<PClassActor *> VisibleToPlayerClass;
|
||||
|
||||
FString Obituary; // Player was killed by this actor
|
||||
FString HitObituary; // Player was killed by this actor in melee
|
||||
double DeathHeight; // Height on normal death
|
||||
double BurnHeight; // Height on burning death
|
||||
PalEntry BloodColor; // Colorized blood
|
||||
int GibHealth; // Negative health below which this monster dies an extreme death
|
||||
int WoundHealth; // Health needed to enter wound state
|
||||
double FastSpeed; // speed in fast mode
|
||||
double RDFactor; // Radius damage factor
|
||||
double SelfDamageFactor;
|
||||
double CameraHeight; // Height of camera when used as such
|
||||
double StealthAlpha; // Minmum alpha for MF_STEALTH.
|
||||
FSoundID HowlSound; // Sound being played when electrocuted or poisoned
|
||||
FName BloodType; // Blood replacement type
|
||||
FName BloodType2; // Bloopsplatter replacement type
|
||||
FName BloodType3; // AxeBlood replacement type
|
||||
|
||||
FDropItem *DropItems;
|
||||
FString SourceLumpName;
|
||||
FIntCVar *distancecheck;
|
||||
|
||||
// Old Decorate compatibility stuff
|
||||
bool DontHurtShooter;
|
||||
int ExplosionRadius;
|
||||
int ExplosionDamage;
|
||||
int MeleeDamage;
|
||||
FSoundID MeleeSound;
|
||||
FName MissileName;
|
||||
double MissileHeight;
|
||||
|
||||
// These are only valid for inventory items.
|
||||
FString PickupMsg;
|
||||
TArray<PClassActor *> RestrictedToPlayerClass;
|
||||
TArray<PClassActor *> ForbiddenToPlayerClass;
|
||||
|
||||
|
|
|
@ -58,15 +58,15 @@ enum EScrollDir
|
|||
};
|
||||
|
||||
// actions that don't create objects
|
||||
#define WIPER_ID ((const PClass*)intptr_t(-1))
|
||||
#define TITLE_ID ((const PClass*)intptr_t(-2))
|
||||
#define WIPER_ID ((PClass*)intptr_t(-1))
|
||||
#define TITLE_ID ((PClass*)intptr_t(-2))
|
||||
|
||||
//==========================================================================
|
||||
|
||||
struct FIntermissionAction
|
||||
{
|
||||
int mSize;
|
||||
const PClass *mClass;
|
||||
PClass *mClass;
|
||||
FString mMusic;
|
||||
int mMusicOrder;
|
||||
int mCdTrack;
|
||||
|
|
|
@ -472,7 +472,7 @@ void M_SetMenu(FName menu, int param)
|
|||
}
|
||||
else
|
||||
{
|
||||
const PClass *menuclass = PClass::FindClass(menu);
|
||||
PClass *menuclass = PClass::FindClass(menu);
|
||||
if (menuclass != nullptr)
|
||||
{
|
||||
if (menuclass->IsDescendantOf("GenericMenu"))
|
||||
|
|
|
@ -391,12 +391,19 @@ xx(Radius)
|
|||
xx(ReactionTime)
|
||||
xx(MeleeRange)
|
||||
xx(Speed)
|
||||
xx(FastSpeed)
|
||||
xx(HowlSound)
|
||||
xx(Clamp)
|
||||
xx(VisibleStartAngle)
|
||||
xx(VisibleStartPitch)
|
||||
xx(VisibleEndAngle)
|
||||
xx(VisibleEndPitch)
|
||||
xx(Format)
|
||||
xx(PickupMsg)
|
||||
xx(Respawnable)
|
||||
xx(ExplosionDamage)
|
||||
xx(ExplosionRadius)
|
||||
xx(DontHurtShooter)
|
||||
|
||||
// Various actor names which are used internally
|
||||
xx(MapSpot)
|
||||
|
|
|
@ -4232,7 +4232,7 @@ enum
|
|||
SOUND_Howl,
|
||||
};
|
||||
|
||||
static FSoundID GetActorSound(const AActor *actor, int soundtype)
|
||||
static FSoundID GetActorSound(AActor *actor, int soundtype)
|
||||
{
|
||||
switch (soundtype)
|
||||
{
|
||||
|
@ -4245,7 +4245,7 @@ static FSoundID GetActorSound(const AActor *actor, int soundtype)
|
|||
case SOUND_Bounce: return actor->BounceSound;
|
||||
case SOUND_WallBounce: return actor->WallBounceSound;
|
||||
case SOUND_CrushPain: return actor->CrushPainSound;
|
||||
case SOUND_Howl: return actor->GetClass()->HowlSound;
|
||||
case SOUND_Howl: return actor->SoundVar(NAME_HowlSound);
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
@ -4369,8 +4369,8 @@ enum EACSFunctions
|
|||
ACSF_GetActorFloorTerrain,
|
||||
ACSF_StrArg,
|
||||
ACSF_Floor,
|
||||
ACSF_Ceil,
|
||||
ACSF_Round,
|
||||
ACSF_Ceil,
|
||||
|
||||
|
||||
// OpenGL stuff
|
||||
|
|
|
@ -86,7 +86,6 @@ AActor *SingleActorFromTID(int tid, AActor *defactor);
|
|||
|
||||
|
||||
static FRandom pr_camissile ("CustomActorfire");
|
||||
static FRandom pr_camelee ("CustomMelee");
|
||||
static FRandom pr_cabullet ("CustomBullet");
|
||||
static FRandom pr_cajump ("CustomJump");
|
||||
static FRandom pr_cwbullet ("CustomWpBullet");
|
||||
|
@ -439,22 +438,6 @@ DEFINE_ACTION_FUNCTION(AActor, GetSpawnHealth)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// GetGibHealth
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetGibHealth)
|
||||
{
|
||||
if (numret > 0)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
ret->SetInt(self->GetGibHealth());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// GetSpriteAngle
|
||||
|
@ -924,86 +907,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_CopyFriendliness)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Customizable attack functions which use actor parameters.
|
||||
//
|
||||
//==========================================================================
|
||||
static void DoAttack (AActor *self, bool domelee, bool domissile,
|
||||
int MeleeDamage, FSoundID MeleeSound, PClassActor *MissileType,double MissileHeight)
|
||||
{
|
||||
if (self->target == NULL) return;
|
||||
|
||||
A_FaceTarget (self);
|
||||
if (domelee && MeleeDamage>0 && self->CheckMeleeRange ())
|
||||
{
|
||||
int damage = pr_camelee.HitDice(MeleeDamage);
|
||||
if (MeleeSound) S_Sound (self, CHAN_WEAPON, MeleeSound, 1, ATTN_NORM);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
}
|
||||
else if (domissile && MissileType != NULL)
|
||||
{
|
||||
// This seemingly senseless code is needed for proper aiming.
|
||||
double add = MissileHeight + self->GetBobOffset() - 32;
|
||||
self->AddZ(add);
|
||||
AActor *missile = P_SpawnMissileXYZ (self->PosPlusZ(32.), self, self->target, MissileType, false);
|
||||
self->AddZ(-add);
|
||||
|
||||
if (missile)
|
||||
{
|
||||
// automatic handling of seeker missiles
|
||||
if (missile->flags2&MF2_SEEKERMISSILE)
|
||||
{
|
||||
missile->tracer=self->target;
|
||||
}
|
||||
P_CheckMissileSpawn(missile, self->radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MeleeAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
int MeleeDamage = self->GetClass()->MeleeDamage;
|
||||
FSoundID MeleeSound = self->GetClass()->MeleeSound;
|
||||
DoAttack(self, true, false, MeleeDamage, MeleeSound, NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_MissileAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName);
|
||||
DoAttack(self, false, true, 0, 0, MissileType, self->GetClass()->MissileHeight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_ComboAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
int MeleeDamage = self->GetClass()->MeleeDamage;
|
||||
FSoundID MeleeSound = self->GetClass()->MeleeSound;
|
||||
PClassActor *MissileType = PClass::FindActor(self->GetClass()->MissileName);
|
||||
DoAttack(self, true, true, MeleeDamage, MeleeSound, MissileType, self->GetClass()->MissileHeight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_BasicAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_INT (melee_damage);
|
||||
PARAM_SOUND (melee_sound);
|
||||
PARAM_CLASS (missile_type, AActor);
|
||||
PARAM_FLOAT (missile_height);
|
||||
|
||||
if (missile_type != NULL)
|
||||
{
|
||||
DoAttack(self, true, true, melee_damage, melee_sound, missile_type, missile_height);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Custom sound functions.
|
||||
|
@ -1261,9 +1164,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_Explode)
|
|||
|
||||
if (damage < 0) // get parameters from metadata
|
||||
{
|
||||
damage = self->GetClass()->ExplosionDamage;
|
||||
distance = self->GetClass()->ExplosionRadius;
|
||||
flags = !self->GetClass()->DontHurtShooter;
|
||||
damage = self->IntVar(NAME_ExplosionDamage);
|
||||
distance = self->IntVar(NAME_ExplosionRadius);
|
||||
flags = !self->BoolVar(NAME_DontHurtShooter);
|
||||
alert = false;
|
||||
}
|
||||
if (distance <= 0) distance = damage;
|
||||
|
|
|
@ -3217,13 +3217,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_ActiveSound)
|
|||
//---------------------------------------------------------------------------
|
||||
void ModifyDropAmount(AInventory *inv, int dropamount)
|
||||
{
|
||||
int flagmask = IF_IGNORESKILL;
|
||||
auto flagmask = IF_IGNORESKILL;
|
||||
double dropammofactor = G_SkillProperty(SKILLP_DropAmmoFactor);
|
||||
// Default drop amount is half of regular amount * regular ammo multiplication
|
||||
if (dropammofactor == -1)
|
||||
{
|
||||
dropammofactor = 0.5;
|
||||
flagmask = 0;
|
||||
flagmask = ItemFlag(0);
|
||||
}
|
||||
|
||||
if (dropamount > 0)
|
||||
|
|
|
@ -62,7 +62,6 @@
|
|||
#include "g_levellocals.h"
|
||||
#include "events.h"
|
||||
|
||||
static FRandom pr_obituary ("Obituary");
|
||||
static FRandom pr_botrespawn ("BotRespawn");
|
||||
static FRandom pr_killmobj ("ActorDie");
|
||||
FRandom pr_damagemobj ("ActorTakeDamage");
|
||||
|
@ -186,14 +185,11 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
|||
const char *message;
|
||||
const char *messagename;
|
||||
char gendermessage[1024];
|
||||
int gender;
|
||||
|
||||
// No obituaries for non-players, voodoo dolls or when not wanted
|
||||
if (self->player == NULL || self->player->mo != self || !show_obituaries)
|
||||
return;
|
||||
|
||||
gender = self->player->userinfo.GetGender();
|
||||
|
||||
// Treat voodoo dolls as unknown deaths
|
||||
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
||||
MeansOfDeath = NAME_None;
|
||||
|
@ -217,93 +213,47 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
|||
}
|
||||
|
||||
FString obit = DamageTypeDefinition::GetObituary(mod);
|
||||
if (obit.IsNotEmpty()) messagename = obit;
|
||||
if (attacker == nullptr) messagename = obit;
|
||||
else
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case NAME_Suicide: messagename = "OB_SUICIDE"; break;
|
||||
case NAME_Falling: messagename = "OB_FALLING"; break;
|
||||
case NAME_Crush: messagename = "OB_CRUSH"; break;
|
||||
case NAME_Exit: messagename = "OB_EXIT"; break;
|
||||
case NAME_Drowning: messagename = "OB_WATER"; break;
|
||||
case NAME_Slime: messagename = "OB_SLIME"; break;
|
||||
case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break;
|
||||
case NAME_Suicide: message = "$OB_SUICIDE"; break;
|
||||
case NAME_Falling: message = "$OB_FALLING"; break;
|
||||
case NAME_Crush: message = "$OB_CRUSH"; break;
|
||||
case NAME_Exit: message = "$OB_EXIT"; break;
|
||||
case NAME_Drowning: message = "$OB_WATER"; break;
|
||||
case NAME_Slime: message = "$OB_SLIME"; break;
|
||||
case NAME_Fire: messagename = "$OB_LAVA"; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for being killed by a voodoo doll.
|
||||
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
||||
{
|
||||
messagename = "OB_VOODOO";
|
||||
messagename = "$OB_VOODOO";
|
||||
}
|
||||
|
||||
if (messagename != NULL)
|
||||
message = GStrings(messagename);
|
||||
|
||||
if (attacker != NULL && message == NULL)
|
||||
{
|
||||
if (attacker == self)
|
||||
{
|
||||
message = GStrings("OB_KILLEDSELF");
|
||||
}
|
||||
else if (attacker->player == NULL)
|
||||
{
|
||||
if (mod == NAME_Telefrag)
|
||||
{
|
||||
message = GStrings("OB_MONTELEFRAG");
|
||||
}
|
||||
else if (mod == NAME_Melee && attacker->GetClass()->HitObituary.IsNotEmpty())
|
||||
{
|
||||
message = attacker->GetClass()->HitObituary;
|
||||
}
|
||||
else if (attacker->GetClass()->Obituary.IsNotEmpty())
|
||||
{
|
||||
message = attacker->GetClass()->Obituary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message == NULL && attacker != NULL && attacker->player != NULL)
|
||||
{
|
||||
if (self->player != attacker->player && self->IsTeammate(attacker))
|
||||
{
|
||||
self = attacker;
|
||||
gender = self->player->userinfo.GetGender();
|
||||
mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3));
|
||||
message = GStrings(gendermessage);
|
||||
message = "$OB_KILLEDSELF";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG");
|
||||
if (message == NULL)
|
||||
IFVIRTUALPTR(attacker, AActor, GetObituary)
|
||||
{
|
||||
if (inflictor != NULL && inflictor->GetClass()->Obituary.IsNotEmpty())
|
||||
{
|
||||
message = inflictor->GetClass()->Obituary;
|
||||
}
|
||||
if (message == NULL && (dmgflags & DMG_PLAYERATTACK) && attacker->player->ReadyWeapon != NULL)
|
||||
{
|
||||
message = attacker->player->ReadyWeapon->GetClass()->Obituary;
|
||||
}
|
||||
if (message == NULL)
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case NAME_BFGSplash: messagename = "OB_MPBFG_SPLASH"; break;
|
||||
case NAME_Railgun: messagename = "OB_RAILGUN"; break;
|
||||
}
|
||||
if (messagename != NULL)
|
||||
message = GStrings(messagename);
|
||||
}
|
||||
if (message == NULL)
|
||||
{
|
||||
message = attacker->GetClass()->Obituary;
|
||||
VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) };
|
||||
FString ret;
|
||||
VMReturn rett(&ret);
|
||||
GlobalVMStack.Call(func, params, countof(params), &rett, 1);
|
||||
if (ret.IsNotEmpty()) message = ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else attacker = self; // for the message creation
|
||||
if (message == nullptr) message = messagename; // fallback to defaults if possible.
|
||||
if (attacker->player == nullptr) attacker = self; // for the message creation
|
||||
|
||||
if (message != NULL && message[0] == '$')
|
||||
{
|
||||
|
@ -319,7 +269,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
|||
if (message == NULL || strlen(message) <= 0)
|
||||
return;
|
||||
|
||||
SexMessage (message, gendermessage, gender,
|
||||
SexMessage (message, gendermessage, self->player->userinfo.GetGender(),
|
||||
self->player->userinfo.GetName(), attacker->player->userinfo.GetName());
|
||||
Printf (PRINT_MEDIUM, "%s\n", gendermessage);
|
||||
}
|
||||
|
@ -411,23 +361,11 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
|
|||
}
|
||||
flags6 |= MF6_KILLED;
|
||||
|
||||
// [RH] Allow the death height to be overridden using metadata.
|
||||
double metaheight = -1;
|
||||
if (DamageType == NAME_Fire)
|
||||
IFVIRTUAL(AActor, GetDeathHeight)
|
||||
{
|
||||
metaheight = GetClass()->BurnHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
metaheight = GetClass()->DeathHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
Height *= 0.25;
|
||||
}
|
||||
else
|
||||
{
|
||||
Height = MAX<double> (metaheight, 0);
|
||||
VMValue params[] = { (DObject*)this };
|
||||
VMReturn ret(&Height);
|
||||
GlobalVMStack.Call(func, params, 1, &ret, 1);
|
||||
}
|
||||
|
||||
// [RH] If the thing has a special, execute and remove it
|
||||
|
@ -1022,7 +960,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
|||
}
|
||||
if (target == source && damage < TELEFRAG_DAMAGE)
|
||||
{
|
||||
damage = int(damage * target->GetClass()->SelfDamageFactor);
|
||||
damage = int(damage * target->SelfDamageFactor);
|
||||
}
|
||||
|
||||
// [MC] Changed it to check rawdamage here for consistency, even though that doesn't actually do anything
|
||||
|
@ -1536,7 +1474,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
|
|||
woundstate = target->FindState(NAME_Wound, mod);
|
||||
if (woundstate != NULL)
|
||||
{
|
||||
int woundhealth = target->GetClass()->WoundHealth;
|
||||
int woundhealth = target->WoundHealth;
|
||||
|
||||
if (target->health <= woundhealth)
|
||||
{
|
||||
|
|
|
@ -5680,7 +5680,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
|
|||
{
|
||||
points = points * splashfactor;
|
||||
}
|
||||
points *= thing->GetClass()->RDFactor;
|
||||
points *= thing->RadiusDamageFactor;
|
||||
|
||||
double check = int(points) * bombdamage;
|
||||
// points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.)
|
||||
|
@ -5759,7 +5759,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom
|
|||
dist = clamp<double>(dist - fulldamagedistance, 0, dist);
|
||||
int damage = Scale(bombdamage, bombdistance - int(dist), bombdistance);
|
||||
|
||||
double factor = splashfactor * thing->GetClass()->RDFactor;
|
||||
double factor = splashfactor * thing->RadiusDamageFactor;
|
||||
damage = int(damage * factor);
|
||||
if (damage > 0 || (bombspot->flags7 & MF7_FORCEZERORADIUSDMG))
|
||||
{
|
||||
|
|
128
src/p_mobj.cpp
128
src/p_mobj.cpp
|
@ -311,30 +311,13 @@ DEFINE_FIELD(AActor, ConversationRoot)
|
|||
DEFINE_FIELD(AActor, Conversation)
|
||||
DEFINE_FIELD(AActor, DecalGenerator)
|
||||
DEFINE_FIELD(AActor, fountaincolor)
|
||||
DEFINE_FIELD(AActor, CameraHeight)
|
||||
DEFINE_FIELD(AActor, RadiusDamageFactor)
|
||||
DEFINE_FIELD(AActor, SelfDamageFactor)
|
||||
DEFINE_FIELD(AActor, StealthAlpha)
|
||||
DEFINE_FIELD(AActor, WoundHealth)
|
||||
|
||||
DEFINE_FIELD(PClassActor, Obituary)
|
||||
DEFINE_FIELD(PClassActor, HitObituary)
|
||||
DEFINE_FIELD(PClassActor, DeathHeight)
|
||||
DEFINE_FIELD(PClassActor, BurnHeight)
|
||||
DEFINE_FIELD(PClassActor, BloodColor)
|
||||
DEFINE_FIELD(PClassActor, GibHealth)
|
||||
DEFINE_FIELD(PClassActor, WoundHealth)
|
||||
DEFINE_FIELD(PClassActor, FastSpeed)
|
||||
DEFINE_FIELD(PClassActor, RDFactor)
|
||||
DEFINE_FIELD(PClassActor, SelfDamageFactor)
|
||||
DEFINE_FIELD(PClassActor, StealthAlpha)
|
||||
DEFINE_FIELD(PClassActor, CameraHeight)
|
||||
DEFINE_FIELD(PClassActor, HowlSound)
|
||||
DEFINE_FIELD(PClassActor, BloodType)
|
||||
DEFINE_FIELD(PClassActor, BloodType2)
|
||||
DEFINE_FIELD(PClassActor, BloodType3)
|
||||
DEFINE_FIELD(PClassActor, DontHurtShooter)
|
||||
DEFINE_FIELD(PClassActor, ExplosionRadius)
|
||||
DEFINE_FIELD(PClassActor, ExplosionDamage)
|
||||
DEFINE_FIELD(PClassActor, MeleeDamage)
|
||||
DEFINE_FIELD(PClassActor, MeleeSound)
|
||||
DEFINE_FIELD(PClassActor, MissileName)
|
||||
DEFINE_FIELD(PClassActor, MissileHeight)
|
||||
//DEFINE_FIELD(PClassActor, BloodColor)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
@ -495,11 +478,17 @@ void AActor::Serialize(FSerializer &arc)
|
|||
A("spriteangle", SpriteAngle)
|
||||
A("spriterotation", SpriteRotation)
|
||||
("alternative", alternative)
|
||||
A("cameraheight", CameraHeight)
|
||||
A("tag", Tag)
|
||||
A("visiblestartangle",VisibleStartAngle)
|
||||
A("visibleendangle",VisibleEndAngle)
|
||||
A("visiblestartpitch",VisibleStartPitch)
|
||||
A("visibleendpitch",VisibleEndPitch);
|
||||
A("visibleendpitch",VisibleEndPitch)
|
||||
A("woundhealth", WoundHealth)
|
||||
A("rdfactor", RadiusDamageFactor)
|
||||
A("selfdamagefactor", SelfDamageFactor)
|
||||
A("stealthalpha", StealthAlpha);
|
||||
|
||||
}
|
||||
|
||||
#undef A
|
||||
|
@ -1341,7 +1330,7 @@ bool P_GiveBody(AActor *actor, int num, int max)
|
|||
// calls while supporting health pickups.
|
||||
if (max <= 0)
|
||||
{
|
||||
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->mo->stamina;
|
||||
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth(true);
|
||||
// [MH] First step in predictable generic morph effects
|
||||
if (player->morphTics)
|
||||
{
|
||||
|
@ -3521,7 +3510,7 @@ int AActor::GetMissileDamage (int mask, int add)
|
|||
|
||||
void AActor::Howl ()
|
||||
{
|
||||
FSoundID howl = GetClass()->HowlSound;
|
||||
FSoundID howl = IntVar(NAME_HowlSound);
|
||||
if (!S_IsActorPlayingSomething(this, CHAN_BODY, howl))
|
||||
{
|
||||
S_Sound (this, CHAN_BODY, howl, 1, ATTN_NORM);
|
||||
|
@ -3823,6 +3812,19 @@ void AActor::SetRoll(DAngle r, bool interpolate)
|
|||
}
|
||||
}
|
||||
|
||||
PClassActor *AActor::GetBloodType(int type) const
|
||||
{
|
||||
IFVIRTUAL(AActor, GetBloodType)
|
||||
{
|
||||
VMValue params[] = { (DObject*)this, type };
|
||||
PClassActor *res;
|
||||
VMReturn ret((void**)&res);
|
||||
GlobalVMStack.Call(func, params, countof(params), &ret, 1);
|
||||
return res;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
DVector3 AActor::GetPortalTransition(double byoffset, sector_t **pSec)
|
||||
{
|
||||
|
@ -4101,9 +4103,9 @@ void AActor::Tick ()
|
|||
else if (visdir < 0)
|
||||
{
|
||||
Alpha -= 1.5/TICRATE;
|
||||
if (Alpha < GetClass()->StealthAlpha)
|
||||
if (Alpha < StealthAlpha)
|
||||
{
|
||||
Alpha = GetClass()->StealthAlpha;
|
||||
Alpha = StealthAlpha;
|
||||
visdir = 0;
|
||||
}
|
||||
}
|
||||
|
@ -4824,8 +4826,11 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a
|
|||
actor->renderflags = (actor->renderflags & ~RF_FULLBRIGHT) | ActorRenderFlags::FromInt (st->GetFullbright());
|
||||
actor->touching_sectorlist = nullptr; // NULL head of sector list // phares 3/13/98
|
||||
actor->touching_rendersectors = nullptr;
|
||||
if (G_SkillProperty(SKILLP_FastMonsters) && actor->GetClass()->FastSpeed >= 0)
|
||||
actor->Speed = actor->GetClass()->FastSpeed;
|
||||
if (G_SkillProperty(SKILLP_FastMonsters))
|
||||
{
|
||||
double f = actor->FloatVar(NAME_FastSpeed);
|
||||
if (f >= 0) actor->Speed = f;
|
||||
}
|
||||
|
||||
// set subsector and/or block links
|
||||
actor->LinkToWorld (nullptr, SpawningMapThing);
|
||||
|
@ -5305,6 +5310,7 @@ DEFINE_ACTION_FUNCTION(AActor, AdjustFloorClip)
|
|||
//
|
||||
EXTERN_CVAR (Bool, chasedemo)
|
||||
EXTERN_CVAR(Bool, sv_singleplayerrespawn)
|
||||
EXTERN_CVAR(Float, fov)
|
||||
|
||||
extern bool demonew;
|
||||
|
||||
|
@ -5442,7 +5448,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
|
|||
mobj->sprite = Skins[p->userinfo.GetSkin()].sprite;
|
||||
}
|
||||
|
||||
p->DesiredFOV = p->FOV = 90.f;
|
||||
p->DesiredFOV = p->FOV = fov;
|
||||
p->camera = p->mo;
|
||||
p->playerstate = PST_LIVE;
|
||||
p->refire = 0;
|
||||
|
@ -5815,27 +5821,23 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
|
|||
// [RH] Other things that shouldn't be spawned depending on dmflags
|
||||
if (deathmatch || alwaysapplydmflags)
|
||||
{
|
||||
// Fixme: This needs to be done differently, it's quite broken.
|
||||
if (i->IsDescendantOf(RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
auto it = static_cast<AInventory*>(GetDefaultByType(i));
|
||||
|
||||
if (dmflags & DF_NO_HEALTH)
|
||||
{
|
||||
if (i->IsDescendantOf (PClass::FindActor(NAME_Health)))
|
||||
return NULL;
|
||||
if (i->TypeName == NAME_Berserk)
|
||||
return NULL;
|
||||
if (i->TypeName == NAME_Megasphere)
|
||||
return NULL;
|
||||
if (it->ItemFlags & IF_ISHEALTH) return nullptr;
|
||||
}
|
||||
if (dmflags & DF_NO_ITEMS)
|
||||
{
|
||||
// if (i->IsDescendantOf (RUNTIME_CLASS(AArtifact)))
|
||||
// return;
|
||||
// if (i->IsDescendantOf (RUNTIME_CLASS(AArtifact)))
|
||||
// return;
|
||||
}
|
||||
if (dmflags & DF_NO_ARMOR)
|
||||
{
|
||||
if (i->IsDescendantOf (PClass::FindActor(NAME_Armor)))
|
||||
return NULL;
|
||||
if (i->TypeName == NAME_Megasphere)
|
||||
return NULL;
|
||||
if (it->ItemFlags & IF_ISARMOR) return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6697,10 +6699,14 @@ static double GetDefaultSpeed(PClassActor *type)
|
|||
{
|
||||
if (type == NULL)
|
||||
return 0;
|
||||
else if (G_SkillProperty(SKILLP_FastMonsters) && type->FastSpeed >= 0)
|
||||
return type->FastSpeed;
|
||||
else
|
||||
return GetDefaultByType(type)->Speed;
|
||||
|
||||
auto def = GetDefaultByType(type);
|
||||
if (G_SkillProperty(SKILLP_FastMonsters))
|
||||
{
|
||||
double f = def->FloatVar(NAME_FastSpeed);
|
||||
if (f >= 0) return f;
|
||||
}
|
||||
return def->Speed;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetDefaultSpeed)
|
||||
|
@ -7466,9 +7472,10 @@ void AActor::Crash()
|
|||
{
|
||||
FState *crashstate = NULL;
|
||||
|
||||
int gibh = GetGibHealth();
|
||||
if (DamageType != NAME_None)
|
||||
{
|
||||
if (health < GetGibHealth())
|
||||
if (health < gibh)
|
||||
{ // Extreme death
|
||||
FName labels[] = { NAME_Crash, NAME_Extreme, DamageType };
|
||||
crashstate = FindState (3, labels, true);
|
||||
|
@ -7480,7 +7487,7 @@ void AActor::Crash()
|
|||
}
|
||||
if (crashstate == NULL)
|
||||
{
|
||||
if (health < GetGibHealth())
|
||||
if (health < gibh)
|
||||
{ // Extreme death
|
||||
crashstate = FindState(NAME_Crash, NAME_Extreme);
|
||||
}
|
||||
|
@ -7586,21 +7593,20 @@ void AActor::Revive()
|
|||
|
||||
int AActor::GetGibHealth() const
|
||||
{
|
||||
int gibhealth = GetClass()->GibHealth;
|
||||
|
||||
if (gibhealth != INT_MIN)
|
||||
IFVIRTUAL(AActor, GetGibHealth)
|
||||
{
|
||||
return -abs(gibhealth);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -int(SpawnHealth() * gameinfo.gibfactor);
|
||||
VMValue params[] = { (DObject*)this };
|
||||
int h;
|
||||
VMReturn ret(&h);
|
||||
GlobalVMStack.Call(func, params, 1, &ret, 1);
|
||||
return h;
|
||||
}
|
||||
return -SpawnHealth();
|
||||
}
|
||||
|
||||
double AActor::GetCameraHeight() const
|
||||
{
|
||||
return GetClass()->CameraHeight == INT_MIN ? Height / 2 : GetClass()->CameraHeight;
|
||||
return CameraHeight == INT_MIN ? Height / 2 : CameraHeight;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetCameraHeight)
|
||||
|
@ -8279,9 +8285,9 @@ void PrintMiscActorInfo(AActor *query)
|
|||
query->args[0], query->args[1], query->args[2], query->args[3],
|
||||
query->args[4], query->special1, query->special2);
|
||||
Printf("\nTID: %d", query->tid);
|
||||
Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f.",
|
||||
Printf("\nCoord= x: %f, y: %f, z:%f, floor:%f, ceiling:%f, height= %f",
|
||||
query->X(), query->Y(), query->Z(),
|
||||
query->floorz, query->ceilingz);
|
||||
query->floorz, query->ceilingz, query->Height);
|
||||
Printf("\nSpeed= %f, velocity= x:%f, y:%f, z:%f, combined:%f.\n",
|
||||
query->Speed, query->Vel.X, query->Vel.Y, query->Vel.Z, query->Vel.Length());
|
||||
Printf("Scale: x:%f, y:%f\n", query->Scale.X, query->Scale.Y);
|
||||
|
|
|
@ -88,6 +88,13 @@ CUSTOM_CVAR(Float, cl_predict_lerpthreshold, 2.00f, CVAR_ARCHIVE | CVAR_GLOBALCO
|
|||
ColorSetList ColorSets;
|
||||
PainFlashList PainFlashes;
|
||||
|
||||
// [Nash] FOV cvar setting
|
||||
CUSTOM_CVAR(Float, fov, 90.f, CVAR_ARCHIVE | CVAR_USERINFO | CVAR_NOINITCALL)
|
||||
{
|
||||
player_t *p = &players[consoleplayer];
|
||||
p->SetFOV(fov);
|
||||
}
|
||||
|
||||
struct PredictPos
|
||||
{
|
||||
int gametic;
|
||||
|
@ -550,6 +557,40 @@ int player_t::GetSpawnClass()
|
|||
return static_cast<APlayerPawn*>(GetDefaultByType(type))->SpawnMask;
|
||||
}
|
||||
|
||||
// [Nash] Set FOV
|
||||
void player_t::SetFOV(float fov)
|
||||
{
|
||||
player_t *p = &players[consoleplayer];
|
||||
if (p != nullptr && p->mo != nullptr)
|
||||
{
|
||||
if (dmflags & DF_NO_FOV)
|
||||
{
|
||||
if (consoleplayer == Net_Arbitrator)
|
||||
{
|
||||
Net_WriteByte(DEM_MYFOV);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf("A setting controller has disabled FOV changes.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Net_WriteByte(DEM_MYFOV);
|
||||
}
|
||||
Net_WriteByte((BYTE)clamp<float>(fov, 5.f, 179.f));
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, SetFOV)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
PARAM_FLOAT(fov);
|
||||
self->SetFOV((float)fov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// EnumColorsets
|
||||
|
@ -1309,15 +1350,18 @@ const char *APlayerPawn::GetSoundClass() const
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
int APlayerPawn::GetMaxHealth() const
|
||||
int APlayerPawn::GetMaxHealth(bool withupgrades) const
|
||||
{
|
||||
return MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth);
|
||||
int ret = MaxHealth > 0? MaxHealth : ((i_compatflags&COMPATF_DEHHEALTH)? 100 : deh.MaxHealth);
|
||||
if (withupgrades) ret += stamina;
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(APlayerPawn, GetMaxHealth)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(APlayerPawn);
|
||||
ACTION_RETURN_INT(self->GetMaxHealth());
|
||||
PARAM_BOOL_DEF(withupgrades);
|
||||
ACTION_RETURN_INT(self->GetMaxHealth(withupgrades));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -2829,7 +2873,7 @@ void P_PlayerThink (player_t *player)
|
|||
// Apply degeneration.
|
||||
if (dmflags2 & DF2_YES_DEGENERATION)
|
||||
{
|
||||
int maxhealth = player->mo->GetMaxHealth() + player->mo->stamina;
|
||||
int maxhealth = player->mo->GetMaxHealth(true);
|
||||
if ((level.time % TICRATE) == 0 && player->health > maxhealth)
|
||||
{
|
||||
if (player->health - 5 < maxhealth)
|
||||
|
@ -3326,19 +3370,14 @@ DEFINE_FIELD(APlayerPawn, FlechetteType)
|
|||
DEFINE_FIELD(APlayerPawn, DamageFade)
|
||||
DEFINE_FIELD(APlayerPawn, ViewBob)
|
||||
DEFINE_FIELD(APlayerPawn, FullHeight)
|
||||
|
||||
DEFINE_FIELD(APlayerPawn, HealingRadiusType)
|
||||
DEFINE_FIELD(APlayerPawn, SoundClass)
|
||||
DEFINE_FIELD(APlayerPawn, Face)
|
||||
DEFINE_FIELD(APlayerPawn, Portrait)
|
||||
DEFINE_FIELD(APlayerPawn, Slot)
|
||||
DEFINE_FIELD(APlayerPawn, InvulMode)
|
||||
DEFINE_FIELD(APlayerPawn, HexenArmor)
|
||||
DEFINE_FIELD(APlayerPawn, ColorRangeStart)
|
||||
DEFINE_FIELD(APlayerPawn, ColorRangeEnd)
|
||||
|
||||
DEFINE_FIELD(PClassActor, DisplayName)
|
||||
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, mo)
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, playerstate)
|
||||
DEFINE_FIELD_X(PlayerInfo, player_t, original_oldbuttons)
|
||||
|
|
|
@ -6088,19 +6088,85 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
|||
|
||||
if (Object->ExprType == EFX_Identifier)
|
||||
{
|
||||
auto id = static_cast<FxIdentifier *>(Object)->Identifier;
|
||||
// If the left side is a class name for a static member function call it needs to be resolved manually
|
||||
// because the resulting value type would cause problems in nearly every other place where identifiers are being used.
|
||||
ccls = FindStructType(static_cast<FxIdentifier *>(Object)->Identifier, ctx);
|
||||
if (ccls != nullptr) static_cast<FxIdentifier *>(Object)->noglobal = true;
|
||||
ccls = FindStructType(id, ctx);
|
||||
if (ccls != nullptr)
|
||||
{
|
||||
static_cast<FxIdentifier *>(Object)->noglobal = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PType *type;
|
||||
// Another special case to deal with here is constants assigned to non-struct types. The code below cannot deal with them so it needs to be done here explicitly.
|
||||
// Thanks to the messed up search logic of the type system, which doesn't allow any search by type name for the basic types at all,
|
||||
// we have to do this manually, though and check for all types that may have values attached explicitly.
|
||||
// (What's the point of attached fields to types if you cannot even search for the types...???)
|
||||
switch (id)
|
||||
{
|
||||
default:
|
||||
type = nullptr;
|
||||
break;
|
||||
|
||||
case NAME_Byte:
|
||||
case NAME_uint8:
|
||||
type = TypeUInt8;
|
||||
break;
|
||||
|
||||
case NAME_sByte:
|
||||
case NAME_int8:
|
||||
type = TypeSInt8;
|
||||
break;
|
||||
|
||||
case NAME_uShort:
|
||||
case NAME_uint16:
|
||||
type = TypeUInt16;
|
||||
break;
|
||||
|
||||
case NAME_Short:
|
||||
case NAME_int16:
|
||||
type = TypeSInt16;
|
||||
break;
|
||||
|
||||
case NAME_Int:
|
||||
type = TypeSInt32;
|
||||
break;
|
||||
|
||||
case NAME_uInt:
|
||||
type = TypeUInt32;
|
||||
break;
|
||||
|
||||
case NAME_Float:
|
||||
type = TypeFloat32;
|
||||
break;
|
||||
|
||||
case NAME_Double:
|
||||
type = TypeFloat64;
|
||||
break;
|
||||
}
|
||||
if (type != nullptr)
|
||||
{
|
||||
auto sym = type->Symbols.FindSymbol(Identifier, true);
|
||||
if (sym != nullptr)
|
||||
{
|
||||
// non-struct symbols must be constant numbers and can only be defined internally.
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolConstNumeric)));
|
||||
auto sn = static_cast<PSymbolConstNumeric*>(sym);
|
||||
|
||||
VMValue vmv;
|
||||
if (sn->ValueType->IsKindOf(RUNTIME_CLASS(PInt))) vmv = sn->Value;
|
||||
else vmv = sn->Float;
|
||||
auto x = new FxConstant(sn->ValueType, vmv, ScriptPosition);
|
||||
delete this;
|
||||
return x->Resolve(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SAFE_RESOLVE(Object, ctx);
|
||||
|
||||
if (Identifier == FName("allmap"))
|
||||
{
|
||||
int a = 2;
|
||||
}
|
||||
|
||||
// check for class or struct constants if the left side is a type name.
|
||||
if (Object->ValueType == TypeError)
|
||||
{
|
||||
|
@ -6371,7 +6437,7 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
|
|||
ExpEmit ob = obj->Emit(build);
|
||||
ob.Free(build);
|
||||
ExpEmit meta(build, REGT_POINTER);
|
||||
build->Emit(OP_META, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_CLSS, meta.RegNum, ob.RegNum);
|
||||
build->Emit(OP_LOS, meta.RegNum, meta.RegNum, build->GetConstantInt(myoffsetof(PClass, Defaults)));
|
||||
return meta;
|
||||
|
||||
|
@ -8832,7 +8898,7 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build)
|
|||
ExpEmit op = Self->Emit(build);
|
||||
op.Free(build);
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_META, to.RegNum, op.RegNum);
|
||||
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
|
||||
return to;
|
||||
}
|
||||
|
||||
|
@ -8873,7 +8939,7 @@ ExpEmit FxGetParentClass::Emit(VMFunctionBuilder *build)
|
|||
if (Self->IsObject())
|
||||
{
|
||||
ExpEmit to(build, REGT_POINTER);
|
||||
build->Emit(OP_META, to.RegNum, op.RegNum);
|
||||
build->Emit(OP_CLSS, to.RegNum, op.RegNum);
|
||||
op = to;
|
||||
op.Free(build);
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
|
|||
{
|
||||
extra.DeathHeight = ((AActor*)(type->Defaults))->Height;
|
||||
}
|
||||
type->DeathHeight = extra.DeathHeight;
|
||||
((AActor*)(type->Defaults))->FloatVar("DeathHeight") = extra.DeathHeight;
|
||||
}
|
||||
bag.statedef.SetStateLabel("Death", &type->OwnedStates[extra.DeathStart]);
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def, PNamespace *ns)
|
|||
}
|
||||
|
||||
if (extra.BurnHeight == 0) extra.BurnHeight = ((AActor*)(type->Defaults))->Height;
|
||||
type->BurnHeight = extra.BurnHeight;
|
||||
((AActor*)(type->Defaults))->FloatVar("BurnHeight") = extra.BurnHeight;
|
||||
|
||||
bag.statedef.SetStateLabel("Burn", &type->OwnedStates[extra.FireDeathStart]);
|
||||
}
|
||||
|
@ -445,18 +445,18 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
|||
else if (def == DEF_Projectile && sc.Compare ("ExplosionRadius"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
bag.Info->ExplosionRadius = sc.Number;
|
||||
defaults->IntVar(NAME_ExplosionRadius) = sc.Number;
|
||||
extra.bExplosive = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("ExplosionDamage"))
|
||||
{
|
||||
sc.MustGetNumber ();
|
||||
bag.Info->ExplosionDamage = sc.Number;
|
||||
defaults->IntVar(NAME_ExplosionDamage) = sc.Number;
|
||||
extra.bExplosive = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("DoNotHurtShooter"))
|
||||
{
|
||||
bag.Info->DontHurtShooter = true;
|
||||
defaults->BoolVar(NAME_DontHurtShooter) = true;
|
||||
}
|
||||
else if (def == DEF_Projectile && sc.Compare ("Damage"))
|
||||
{
|
||||
|
@ -541,11 +541,11 @@ static void ParseInsideDecoration (Baggage &bag, AActor *defaults,
|
|||
else if (def == DEF_Pickup && sc.Compare ("PickupMessage"))
|
||||
{
|
||||
sc.MustGetString ();
|
||||
bag.Info->PickupMsg = sc.String;
|
||||
inv->StringVar(NAME_PickupMsg) = sc.String;
|
||||
}
|
||||
else if (def == DEF_Pickup && sc.Compare ("Respawns"))
|
||||
{
|
||||
inv->BoolVar("Respawnable") = true;
|
||||
inv->BoolVar(NAME_Respawnable) = true;
|
||||
}
|
||||
else if (def == DEF_BreakableDecoration && sc.Compare ("SolidOnDeath"))
|
||||
{
|
||||
|
|
|
@ -827,7 +827,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
|
|||
if (i > 0) sc.MustGetStringName(",");
|
||||
if (f->Flags & VARF_Meta)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
addr = ((char*)bag.Info->Meta) + f->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -867,7 +867,7 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
|
|||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PString)))
|
||||
{
|
||||
sc.MustGetString();
|
||||
*(FString*)addr = sc.String;
|
||||
*(FString*)addr = strbin1(sc.String);
|
||||
}
|
||||
else if (f->Type->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||
{
|
||||
|
|
|
@ -430,6 +430,8 @@ static FFlagDef InventoryFlagDefs[] =
|
|||
DEFINE_FLAG(IF, TRANSFER, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, NOTELEPORTFREEZE, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, NOSCREENBLINK, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, ISARMOR, AInventory, ItemFlags),
|
||||
DEFINE_FLAG(IF, ISHEALTH, AInventory, ItemFlags),
|
||||
|
||||
DEFINE_DUMMY_FLAG(FORCERESPAWNINSURVIVAL, false),
|
||||
|
||||
|
|
|
@ -592,24 +592,13 @@ DEFINE_PROPERTY(health, I, Actor)
|
|||
defaults->health=id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(gibhealth, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->GibHealth = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(woundhealth, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->WoundHealth = id;
|
||||
defaults->WoundHealth = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -888,16 +877,6 @@ DEFINE_PROPERTY(activesound, S, Actor)
|
|||
defaults->ActiveSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(howlsound, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->HowlSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -981,75 +960,6 @@ DEFINE_PROPERTY(alpha, F, Actor)
|
|||
defaults->Alpha = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(obituary, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->Obituary = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(hitobituary, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->HitObituary = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(donthurtshooter, 0, Actor)
|
||||
{
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->DontHurtShooter = true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(explosionradius, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->ExplosionRadius = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(explosiondamage, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->ExplosionDamage = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(deathheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(h, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->DeathHeight = MAX(0., h);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(burnheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(h, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->BurnHeight = MAX(0., h);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1068,16 +978,6 @@ DEFINE_PROPERTY(meleethreshold, F, Actor)
|
|||
defaults->meleethreshold = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(meleedamage, I, Actor)
|
||||
{
|
||||
PROP_INT_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MeleeDamage = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1087,36 +987,6 @@ DEFINE_PROPERTY(meleerange, F, Actor)
|
|||
defaults->meleerange = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(meleesound, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MeleeSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(missiletype, S, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MissileName = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(missileheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(id, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->MissileHeight = id;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1190,37 +1060,6 @@ DEFINE_PROPERTY(bloodcolor, C, Actor)
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(bloodtype, Sss, Actor)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0)
|
||||
PROP_STRING_PARM(str1, 1)
|
||||
PROP_STRING_PARM(str2, 2)
|
||||
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
PClassActor *ainfo = static_cast<PClassActor *>(info);
|
||||
|
||||
FName blood = str;
|
||||
// normal blood
|
||||
ainfo->BloodType = blood;
|
||||
|
||||
if (PROP_PARM_COUNT > 1)
|
||||
{
|
||||
blood = str1;
|
||||
}
|
||||
// blood splatter
|
||||
ainfo->BloodType2 = blood;
|
||||
|
||||
if (PROP_PARM_COUNT > 2)
|
||||
{
|
||||
blood = str2;
|
||||
}
|
||||
// axe blood
|
||||
ainfo->BloodType3 = blood;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1410,24 +1249,13 @@ DEFINE_PROPERTY(poisondamagetype, S, Actor)
|
|||
defaults->PoisonDamageType = poisondamagetype;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(fastspeed, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->FastSpeed = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->RDFactor = i;
|
||||
defaults->RadiusDamageFactor = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1436,8 +1264,7 @@ DEFINE_PROPERTY(radiusdamagefactor, F, Actor)
|
|||
DEFINE_PROPERTY(selfdamagefactor, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->SelfDamageFactor = i;
|
||||
defaults->SelfDamageFactor = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1446,8 +1273,7 @@ DEFINE_PROPERTY(selfdamagefactor, F, Actor)
|
|||
DEFINE_PROPERTY(stealthalpha, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->StealthAlpha = i;
|
||||
defaults->StealthAlpha = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1456,8 +1282,7 @@ DEFINE_PROPERTY(stealthalpha, F, Actor)
|
|||
DEFINE_PROPERTY(cameraheight, F, Actor)
|
||||
{
|
||||
PROP_DOUBLE_PARM(i, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->CameraHeight = i;
|
||||
defaults->CameraHeight = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -1831,16 +1656,6 @@ DEFINE_CLASS_PROPERTY(pickupflash, S, Inventory)
|
|||
defaults->PickupFlash = FindClassTentative(str, RUNTIME_CLASS(AActor));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(pickupmessage, T, Inventory)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
||||
static_cast<PClassActor *>(info)->PickupMsg = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -1875,15 +1690,6 @@ DEFINE_CLASS_PROPERTY(usesound, S, Inventory)
|
|||
defaults->UseSound = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(givequest, I, Inventory)
|
||||
{
|
||||
PROP_INT_PARM(i, 0);
|
||||
defaults->GiveQuest = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -2718,24 +2524,6 @@ DEFINE_CLASS_PROPERTY_PREFIX(player, startitem, S_i, PlayerPawn)
|
|||
bag.DropItemList = di;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY_PREFIX(player, invulnerabilitymode, S, PlayerPawn)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
defaults->InvulMode = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY_PREFIX(player, healradiustype, S, PlayerPawn)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
defaults->HealingRadiusType = str;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
|
|
@ -109,12 +109,18 @@ begin:
|
|||
reg.atag[a] = ATAG_GENERIC; // using ATAG_FRAMEPOINTER will cause endless asserts.
|
||||
NEXTOP;
|
||||
|
||||
OP(META):
|
||||
OP(CLSS):
|
||||
ASSERTA(a); ASSERTO(B);
|
||||
reg.a[a] = ((DObject*)reg.a[B])->GetClass(); // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
|
||||
OP(META):
|
||||
ASSERTA(a); ASSERTO(B);
|
||||
reg.a[a] = ((DObject*)reg.a[B])->GetClass()->Meta; // I wish this could be done without a special opcode but there's really no good way to guarantee initialization of the Class pointer...
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
|
||||
OP(LB):
|
||||
ASSERTD(a); ASSERTA(B); ASSERTKD(C);
|
||||
GETADDR(PB,KC,X_READ_NIL);
|
||||
|
|
|
@ -23,7 +23,8 @@ xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed
|
|||
xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed
|
||||
xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed
|
||||
xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer
|
||||
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta class address
|
||||
xx(META, meta, RPRP, NOP, 0, 0), // load a class's meta data address
|
||||
xx(CLSS, clss, RPRP, NOP, 0, 0), // load a class's descriptor address
|
||||
|
||||
// Load from memory. rA = *(rB + rkC)
|
||||
xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte
|
||||
|
|
|
@ -1007,6 +1007,11 @@ void ZCCCompiler::CompileAllFields()
|
|||
type->Size = Classes[i]->Type()->ParentClass->Size;
|
||||
}
|
||||
}
|
||||
if (Classes[i]->Type()->ParentClass)
|
||||
type->MetaSize = Classes[i]->Type()->ParentClass->MetaSize;
|
||||
else
|
||||
type->MetaSize = 0;
|
||||
|
||||
if (CompileFields(type, Classes[i]->Fields, nullptr, &Classes[i]->TreeNodes, false, !!HasNativeChildren.CheckKey(type)))
|
||||
{
|
||||
// Remove from the list if all fields got compiled.
|
||||
|
@ -1070,11 +1075,6 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
if (field->Flags & ZCC_Meta)
|
||||
{
|
||||
varflags |= VARF_Meta | VARF_Static | VARF_ReadOnly; // metadata implies readonly
|
||||
if (!(field->Flags & ZCC_Native))
|
||||
{
|
||||
// Non-native meta data is not implemented yet and requires some groundwork in the class copy code.
|
||||
Error(field, "Metadata member %s must be native", FName(field->Names->Name).GetChars());
|
||||
}
|
||||
}
|
||||
|
||||
if (field->Type->ArraySize != nullptr)
|
||||
|
@ -1095,8 +1095,13 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
|
||||
if (varflags & VARF_Native)
|
||||
{
|
||||
auto querytype = (varflags & VARF_Meta) ? type->GetClass() : type;
|
||||
fd = FindField(querytype, FName(name->Name).GetChars());
|
||||
if (varflags & VARF_Meta)
|
||||
{
|
||||
Error(field, "Native meta variable %s not allowed", FName(name->Name).GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = FindField(type, FName(name->Name).GetChars());
|
||||
if (fd == nullptr)
|
||||
{
|
||||
Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars());
|
||||
|
@ -1113,6 +1118,7 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fiel
|
|||
type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hasnativechildren)
|
||||
{
|
||||
Error(field, "Cannot add field %s to %s. %s has native children which means it size may not change.", FName(name->Name).GetChars(), type->TypeName.GetChars(), type->TypeName.GetChars());
|
||||
|
@ -1188,8 +1194,10 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray<ZCC_Property *> &Proper
|
|||
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());
|
||||
FName name = FName(p->NodeName);
|
||||
if (prefix == NAME_None) qualifiedname.Format("@property@%s", name.GetChars());
|
||||
else qualifiedname.Format("@property@%s.%s", prefix.GetChars(), name.GetChars());
|
||||
|
||||
fields.ShrinkToFit();
|
||||
if (!type->Symbols.AddSymbol(new PProperty(qualifiedname, fields)))
|
||||
{
|
||||
|
@ -1692,7 +1700,7 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
|
|||
|
||||
if (f->Flags & VARF_Meta)
|
||||
{
|
||||
addr = ((char*)bag.Info) + f->Offset;
|
||||
addr = ((char*)bag.Info->Meta) + f->Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -281,6 +281,7 @@ static void ParseSingleFile(const char *filename, int lump, void *parser, ZCCPar
|
|||
tokentype = ZCC_FLOATCONST;
|
||||
break;
|
||||
|
||||
case TK_None: // 'NONE' is a token for SBARINFO but not here.
|
||||
case TK_Identifier:
|
||||
value.Int = FName(sc.String);
|
||||
tokentype = ZCC_IDENTIFIER;
|
||||
|
|
|
@ -189,29 +189,47 @@ class Actor : Thinker native
|
|||
native State MissileState;
|
||||
native voidptr /*DecalBase*/ DecalGenerator;
|
||||
native uint8 fountaincolor;
|
||||
native double CameraHeight; // Height of camera when used as such
|
||||
native double RadiusDamageFactor; // Radius damage factor
|
||||
native double SelfDamageFactor;
|
||||
native double StealthAlpha;
|
||||
native int WoundHealth; // Health needed to enter wound state
|
||||
//native color BloodColor; // won't be accessible for now because it needs refactoring to remove the 255-translations limit.
|
||||
|
||||
native meta String Obituary; // Player was killed by this actor
|
||||
native meta String HitObituary; // Player was killed by this actor in melee
|
||||
native meta double DeathHeight; // Height on normal death
|
||||
native meta double BurnHeight; // Height on burning death
|
||||
native meta color BloodColor; // Colorized blood
|
||||
native meta int GibHealth; // Negative health below which this monster dies an extreme death
|
||||
native meta int WoundHealth; // Health needed to enter wound state
|
||||
native meta double FastSpeed; // speed in fast mode
|
||||
native meta double RDFactor; // Radius damage factor
|
||||
native meta double CameraHeight; // Height of camera when used as such
|
||||
native meta Sound HowlSound; // Sound being played when electrocuted or poisoned
|
||||
native meta Name BloodType; // Blood replacement type
|
||||
native meta Name BloodType2; // Bloopsplatter replacement type
|
||||
native meta Name BloodType3; // AxeBlood replacement type
|
||||
native meta bool DontHurtShooter;
|
||||
native meta int ExplosionRadius;
|
||||
native meta int ExplosionDamage;
|
||||
native meta int MeleeDamage;
|
||||
native meta Sound MeleeSound;
|
||||
native meta Name MissileName;
|
||||
native meta double MissileHeight;
|
||||
meta String Obituary; // Player was killed by this actor
|
||||
meta String HitObituary; // Player was killed by this actor in melee
|
||||
meta double DeathHeight; // Height on normal death
|
||||
meta double BurnHeight; // Height on burning death
|
||||
meta int GibHealth; // Negative health below which this monster dies an extreme death
|
||||
meta Sound HowlSound; // Sound being played when electrocuted or poisoned
|
||||
meta Name BloodType; // Blood replacement type
|
||||
meta Name BloodType2; // Bloopsplatter replacement type
|
||||
meta Name BloodType3; // AxeBlood replacement type
|
||||
meta bool DontHurtShooter;
|
||||
meta int ExplosionRadius;
|
||||
meta int ExplosionDamage;
|
||||
meta int MeleeDamage;
|
||||
meta Sound MeleeSound;
|
||||
meta double MissileHeight;
|
||||
meta Name MissileName;
|
||||
meta double FastSpeed; // speed in fast mode
|
||||
|
||||
Property prefix: none;
|
||||
Property Obituary: Obituary;
|
||||
Property HitObituary: HitObituary;
|
||||
Property MeleeDamage: MeleeDamage;
|
||||
Property MeleeSound: MeleeSound;
|
||||
Property MissileHeight: MissileHeight;
|
||||
Property MissileType: MissileName;
|
||||
Property DontHurtShooter: DontHurtShooter;
|
||||
Property ExplosionRadius: ExplosionRadius;
|
||||
Property ExplosionDamage: ExplosionDamage;
|
||||
Property BloodType: BloodType, BloodType2, BloodType3;
|
||||
Property FastSpeed: FastSpeed;
|
||||
Property HowlSound: HowlSound;
|
||||
Property GibHealth: GibHealth;
|
||||
Property DeathHeight: DeathHeight;
|
||||
Property BurnHeight: BurnHeight;
|
||||
|
||||
// need some definition work first
|
||||
//FRenderStyle RenderStyle;
|
||||
|
@ -271,6 +289,7 @@ class Actor : Thinker native
|
|||
DefThreshold 100;
|
||||
BloodType "Blood", "BloodSplatter", "AxeBlood";
|
||||
ExplosionDamage 128;
|
||||
ExplosionRadius -1; // i.e. use ExplosionDamage value
|
||||
MissileHeight 32;
|
||||
SpriteAngle 0;
|
||||
SpriteRotation 0;
|
||||
|
@ -278,6 +297,15 @@ class Actor : Thinker native
|
|||
VisibleAngles 0, 0;
|
||||
VisiblePitch 0, 0;
|
||||
DefaultStateUsage SUF_ACTOR|SUF_OVERLAY;
|
||||
CameraHeight int.min;
|
||||
FastSpeed -1;
|
||||
RadiusDamageFactor 1;
|
||||
SelfDamageFactor 1;
|
||||
StealthAlpha 0;
|
||||
WoundHealth 6;
|
||||
GibHealth int.min;
|
||||
DeathHeight -1;
|
||||
BurnHeight -1;
|
||||
}
|
||||
|
||||
// Functions
|
||||
|
@ -310,7 +338,7 @@ class Actor : Thinker native
|
|||
virtual native void Touch(Actor toucher);
|
||||
virtual native void MarkPrecacheSounds();
|
||||
|
||||
// Called by PIT_CheckThing to check if two actos actually can collide.
|
||||
// Called by PIT_CheckThing to check if two actors actually can collide.
|
||||
virtual bool CanCollideWith(Actor other, bool passive)
|
||||
{
|
||||
return true;
|
||||
|
@ -335,6 +363,81 @@ class Actor : Thinker native
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual class<Actor> GetBloodType(int type)
|
||||
{
|
||||
Class<Actor> bloodcls;
|
||||
if (type == 0)
|
||||
{
|
||||
bloodcls = BloodType;
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
bloodcls = BloodType2;
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
bloodcls = BloodType3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bloodcls != NULL)
|
||||
{
|
||||
bloodcls = GetReplacement(bloodcls);
|
||||
}
|
||||
return bloodcls;
|
||||
}
|
||||
|
||||
virtual int GetGibHealth()
|
||||
{
|
||||
if (GibHealth != int.min)
|
||||
{
|
||||
return -abs(GibHealth);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -int(GetSpawnHealth() * gameinfo.gibfactor);
|
||||
}
|
||||
}
|
||||
|
||||
virtual double GetDeathHeight()
|
||||
{
|
||||
// [RH] Allow the death height to be overridden using metadata.
|
||||
double metaheight = -1;
|
||||
if (DamageType == 'Fire')
|
||||
{
|
||||
metaheight = BurnHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
metaheight = DeathHeight;
|
||||
}
|
||||
if (metaheight < 0)
|
||||
{
|
||||
return Height * 0.25;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MAX(metaheight, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||
{
|
||||
if (mod == 'Telefrag')
|
||||
{
|
||||
return "$OB_MONTELEFRAG";
|
||||
}
|
||||
else if (mod == 'Melee' && HitObituary.Length() > 0)
|
||||
{
|
||||
return HitObituary;
|
||||
}
|
||||
return Obituary;
|
||||
}
|
||||
|
||||
|
||||
native static class<Actor> GetReplacement(class<Actor> cls);
|
||||
native static class<Actor> GetReplacee(class<Actor> cls);
|
||||
native static int GetSpriteIndex(name sprt);
|
||||
|
@ -510,7 +613,6 @@ class Actor : Thinker native
|
|||
native double GetAngle(int flags, int ptr = AAPTR_TARGET);
|
||||
native double GetZAt(double px = 0, double py = 0, double angle = 0, int flags = 0, int pick_pointer = AAPTR_DEFAULT);
|
||||
native int GetSpawnHealth();
|
||||
native int GetGibHealth();
|
||||
native double GetCrouchFactor(int ptr = AAPTR_PLAYER1);
|
||||
native double GetCVar(string cvar);
|
||||
native int GetPlayerInput(int inputnum, int ptr = AAPTR_DEFAULT);
|
||||
|
@ -726,6 +828,68 @@ class Actor : Thinker native
|
|||
native bool A_LineEffect(int boomspecial = 0, int tag = 0);
|
||||
// End of MBF redundant functions.
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// old customizable attack functions which use actor parameters.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
private void DoAttack (bool domelee, bool domissile, int MeleeDamage, Sound MeleeSound, Class<Actor> MissileType,double MissileHeight)
|
||||
{
|
||||
if (target == NULL) return;
|
||||
|
||||
A_FaceTarget ();
|
||||
if (domelee && MeleeDamage>0 && CheckMeleeRange ())
|
||||
{
|
||||
int damage = random[CustomMelee](1, 8) * MeleeDamage;
|
||||
if (MeleeSound) A_PlaySound (MeleeSound, CHAN_WEAPON);
|
||||
int newdam = target.DamageMobj (self, self, damage, 'Melee');
|
||||
target.TraceBleed (newdam > 0 ? newdam : damage, self);
|
||||
}
|
||||
else if (domissile && MissileType != NULL)
|
||||
{
|
||||
// This seemingly senseless code is needed for proper aiming.
|
||||
double add = MissileHeight + GetBobOffset() - 32;
|
||||
AddZ(add);
|
||||
Actor missile = SpawnMissileXYZ (Pos + (0, 0, 32), target, MissileType, false);
|
||||
AddZ(-add);
|
||||
|
||||
if (missile)
|
||||
{
|
||||
// automatic handling of seeker missiles
|
||||
if (missile.bSeekerMissile)
|
||||
{
|
||||
missile.tracer = target;
|
||||
}
|
||||
missile.CheckMissileSpawn(radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deprecated void A_MeleeAttack()
|
||||
{
|
||||
DoAttack(true, false, MeleeDamage, MeleeSound, NULL, 0);
|
||||
}
|
||||
|
||||
deprecated void A_MissileAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(false, true, 0, 0, MissileType, MissileHeight);
|
||||
}
|
||||
|
||||
deprecated void A_ComboAttack()
|
||||
{
|
||||
Class<Actor> MissileType = MissileName;
|
||||
DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight);
|
||||
}
|
||||
|
||||
void A_BasicAttack(int melee_damage, sound melee_sound, class<actor> missile_type, double missile_height)
|
||||
{
|
||||
DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height);
|
||||
}
|
||||
|
||||
|
||||
native void A_MonsterRail();
|
||||
native void A_Pain();
|
||||
native void A_NoBlocking(bool drop = true);
|
||||
|
@ -754,9 +918,6 @@ class Actor : Thinker native
|
|||
native void A_Wander(int flags = 0);
|
||||
native void A_Look2();
|
||||
|
||||
deprecated native void A_MissileAttack();
|
||||
deprecated native void A_MeleeAttack();
|
||||
deprecated native void A_ComboAttack();
|
||||
deprecated native void A_BulletAttack();
|
||||
native void A_WolfAttack(int flags = 0, sound whattoplay = "weapons/pistol", double snipe = 1.0, int maxdamage = 64, int blocksize = 128, int pointblank = 2, int longrange = 4, double runspeed = 160.0, class<Actor> pufftype = "BulletPuff");
|
||||
native void A_PlaySound(sound whattoplay = "weapons/pistol", int slot = CHAN_BODY, double volume = 1.0, bool looping = false, double attenuation = ATTN_NORM, bool local = false);
|
||||
|
@ -794,7 +955,6 @@ class Actor : Thinker native
|
|||
native void A_RaiseMaster(int flags = 0);
|
||||
native void A_RaiseChildren(int flags = 0);
|
||||
native void A_RaiseSiblings(int flags = 0);
|
||||
deprecated native void A_BasicAttack(int meleedamage, sound meleesound, class<actor> missiletype, double missileheight);
|
||||
action native bool, Actor A_ThrowGrenade(class<Actor> itemtype, double zheight = 0, double xyvel = 0, double zvel = 0, bool useammo = true);
|
||||
native void A_Weave(int xspeed, int yspeed, double xdist, double ydist);
|
||||
native bool A_Morph(class<Actor> type, int duration = 0, int flags = 0, class<Actor> enter_flash = null, class<Actor> exit_flash = null);
|
||||
|
|
|
@ -310,6 +310,7 @@ struct GameInfoStruct native
|
|||
native GIFont mStatscreenMapNameFont;
|
||||
native GIFont mStatscreenEnteringFont;
|
||||
native GIFont mStatscreenFinishedFont;
|
||||
native double gibfactor;
|
||||
}
|
||||
|
||||
class Object native
|
||||
|
|
|
@ -72,6 +72,8 @@ class Megasphere : CustomInventory
|
|||
{
|
||||
+COUNTITEM
|
||||
+INVENTORY.ALWAYSPICKUP
|
||||
+INVENTORY.ISHEALTH
|
||||
+INVENTORY.ISARMOR
|
||||
Inventory.PickupMessage "$GOTMSPHERE";
|
||||
Inventory.PickupSound "misc/p_pkup";
|
||||
}
|
||||
|
@ -183,6 +185,7 @@ class Berserk : CustomInventory
|
|||
{
|
||||
+COUNTITEM
|
||||
+INVENTORY.ALWAYSPICKUP
|
||||
+INVENTORY.ISHEALTH
|
||||
Inventory.PickupMessage "$GOTBERSERK";
|
||||
Inventory.PickupSound "misc/p_pkup";
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class Ammo : Inventory
|
|||
{
|
||||
int BackpackAmount;
|
||||
int BackpackMaxAmount;
|
||||
/*meta*/ int DropAmount;
|
||||
meta int DropAmount;
|
||||
|
||||
property BackpackAmount: BackpackAmount;
|
||||
property BackpackMaxAmount: BackpackMaxAmount;
|
||||
|
|
|
@ -38,6 +38,7 @@ class Armor : Inventory
|
|||
Default
|
||||
{
|
||||
Inventory.PickupSound "misc/armor_pkup";
|
||||
+INVENTORY.ISARMOR
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,13 +36,14 @@
|
|||
class Health : Inventory
|
||||
{
|
||||
transient int PrevHealth;
|
||||
/*meta*/ int LowHealth;
|
||||
/*meta*/ String LowHealthMessage;
|
||||
meta int LowHealth;
|
||||
meta String LowHealthMessage;
|
||||
|
||||
property LowMessage: LowHealth, LowHealthMessage;
|
||||
|
||||
Default
|
||||
{
|
||||
+INVENTORY.ISHEALTH
|
||||
Inventory.Amount 1;
|
||||
Inventory.MaxAmount 0;
|
||||
Inventory.PickupSound "misc/health_pkup";
|
||||
|
@ -99,6 +100,7 @@ class HealthPickup : Inventory
|
|||
{
|
||||
Inventory.DefMaxAmount;
|
||||
+INVENTORY.INVBAR
|
||||
+INVENTORY.ISHEALTH
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
@ -87,8 +87,8 @@ class MapRevealer : Inventory
|
|||
|
||||
class PuzzleItem : Inventory
|
||||
{
|
||||
/*meta*/ int PuzzleItemNumber;
|
||||
/*meta*/ String PuzzFailMessage;
|
||||
meta int PuzzleItemNumber;
|
||||
meta String PuzzFailMessage;
|
||||
|
||||
property Number: PuzzleItemNumber;
|
||||
property FailMessage: PuzzFailMessage;
|
||||
|
|
|
@ -23,8 +23,11 @@ class Inventory : Actor native
|
|||
native bool bPickupGood;
|
||||
native bool bCreateCopyMoved;
|
||||
native bool bInitEffectFailed;
|
||||
native meta String PickupMsg;
|
||||
native /*meta*/ int GiveQuest;
|
||||
meta String PickupMsg;
|
||||
meta int GiveQuest;
|
||||
|
||||
Property PickupMessage: PickupMsg;
|
||||
Property GiveQuest: GiveQuest;
|
||||
|
||||
Default
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@ class Weapon : StateProvider native
|
|||
native float FOVScale;
|
||||
native int Crosshair; // 0 to use player's crosshair
|
||||
native bool GivenAsMorphWeapon;
|
||||
native bool bAltFire; // Set when self weapon's alternate fire is used.
|
||||
native bool bAltFire; // Set when this weapon's alternate fire is used.
|
||||
native readonly bool bDehAmmo;
|
||||
|
||||
Default
|
||||
|
@ -89,6 +89,12 @@ class Weapon : StateProvider native
|
|||
return s;
|
||||
}
|
||||
|
||||
override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||
{
|
||||
// Weapons may never return HitObituary by default. Override this if it is needed.
|
||||
return Obituary;
|
||||
}
|
||||
|
||||
action void A_GunFlash(statelabel flashlabel = null, int flags = 0)
|
||||
{
|
||||
let player = player;
|
||||
|
|
|
@ -8,17 +8,13 @@ class PlayerPawn : Actor native
|
|||
native int PlayerFlags;
|
||||
native Inventory InvFirst; // first inventory item displayed on inventory bar
|
||||
native Inventory InvSel; // selected inventory item
|
||||
native meta String DisplayName; // Display name (used in menus, etc.)
|
||||
|
||||
native /*meta*/ Name SoundClass; // Sound class
|
||||
native /*meta*/ Name Face; // Doom status bar face (when used)
|
||||
native /*meta*/ Name Portrait;
|
||||
native /*meta*/ Name Slot[10];
|
||||
native /*meta*/ Name InvulMode;
|
||||
native /*meta*/ Name HealingRadiusType;
|
||||
native /*meta*/ double HexenArmor[5];
|
||||
native /*meta*/ uint8 ColorRangeStart; // Skin color range
|
||||
native /*meta*/ uint8 ColorRangeEnd;
|
||||
native Name SoundClass; // Sound class
|
||||
native Name Face; // Doom status bar face (when used)
|
||||
native Name Portrait;
|
||||
native Name Slot[10];
|
||||
native double HexenArmor[5];
|
||||
native uint8 ColorRangeStart; // Skin color range
|
||||
native uint8 ColorRangeEnd;
|
||||
|
||||
// [GRB] Player class properties
|
||||
native double JumpZ;
|
||||
|
@ -38,6 +34,13 @@ class PlayerPawn : Actor native
|
|||
native double ViewBob; // [SP] ViewBob Multiplier
|
||||
native double FullHeight;
|
||||
|
||||
meta Name HealingRadiusType;
|
||||
meta Name InvulMode;
|
||||
|
||||
Property prefix: Player;
|
||||
Property HealRadiusType: HealingradiusType;
|
||||
Property InvulnerabilityMode: InvulMode;
|
||||
|
||||
Default
|
||||
{
|
||||
Health 100;
|
||||
|
@ -115,6 +118,36 @@ class PlayerPawn : Actor native
|
|||
}
|
||||
}
|
||||
|
||||
override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||
{
|
||||
if (victim.player != player && victim.IsTeammate(self))
|
||||
{
|
||||
victim = self;
|
||||
return String.Format("$OB_FRIENDLY%c", random[Obituary](49, 53));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mod == 'Telefrag') return "$OB_MPTELEFRAG";
|
||||
|
||||
String message;
|
||||
if (inflictor != NULL)
|
||||
{
|
||||
message = inflictor.GetObituary(victim, inflictor, mod, playerattack);
|
||||
}
|
||||
if (message.Length() == 0 && playerattack && player.ReadyWeapon != NULL)
|
||||
{
|
||||
message = player.ReadyWeapon.GetObituary(victim, inflictor, mod, playerattack);
|
||||
}
|
||||
if (message.Length() == 0)
|
||||
{
|
||||
if (mod == 'BFGSplash') return "$OB_MPBFG_SPLASH";
|
||||
if (mod == 'Railgun') return "$OB_RAILGUN";
|
||||
message = Obituary;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
// This is for SBARINFO.
|
||||
int, int GetEffectTicsForItem(class<Inventory> item)
|
||||
{
|
||||
|
@ -133,7 +166,7 @@ class PlayerPawn : Actor native
|
|||
return -1, -1;
|
||||
}
|
||||
|
||||
native int GetMaxHealth();
|
||||
native int GetMaxHealth(bool withupgrades = false);
|
||||
native bool ResetAirSupply (bool playgasp = false);
|
||||
native void CheckWeaponSwitch(class<Inventory> item);
|
||||
native static String GetPrintableDisplayName(Class<Actor> cls);
|
||||
|
@ -322,6 +355,7 @@ usercmd_t original_cmd;
|
|||
native int GetGender();
|
||||
native int GetTeam();
|
||||
native float GetAutoaim();
|
||||
native void SetFOV(float fov);
|
||||
}
|
||||
|
||||
struct PlayerClass native
|
||||
|
|
|
@ -76,7 +76,7 @@ extend class PlayerPawn
|
|||
}
|
||||
else
|
||||
{
|
||||
player.health = health = GetMaxHealth();
|
||||
player.health = health = GetMaxHealth(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue