diff --git a/src/actor.h b/src/actor.h index 2ed0047405..739f08f4ab 100644 --- a/src/actor.h +++ b/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,7 +1023,13 @@ 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; //VMFunction *Damage; // For missiles and monster railgun diff --git a/src/b_think.cpp b/src/b_think.cpp index da3fb61246..f286dd30f5 100644 --- a/src/b_think.cpp +++ b/src/b_think.cpp @@ -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 || diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 7e0a66c4b1..4bdca624a2 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -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 diff --git a/src/d_player.h b/src/d_player.h index 2d7d439c57..2787df231d 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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. diff --git a/src/dobject.cpp b/src/dobject.cpp index 747c1f9bfa..b8097f5498 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -623,12 +623,20 @@ DEFINE_ACTION_FUNCTION(DObject, MSTime) void *DObject::ScriptVar(FName field, PType *type) { - auto sym = dyn_cast(GetClass()->Symbols.FindSymbol(field, true)); + auto cls = GetClass(); + auto sym = dyn_cast(cls->Symbols.FindSymbol(field, true)); if (sym && (sym->Type == type || type == nullptr)) { - return (((char*)this) + sym->Offset); + 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; } diff --git a/src/dobject.h b/src/dobject.h index 41b5e2824d..d99fbee2b8 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -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 T*& PointerVar(FName field); // If you need to replace one object with another and want to diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 75193b868b..cd128b6560 100644 --- a/src/dobjtype.cpp +++ b/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(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(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 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,18 +3338,36 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) PField *PClass::AddField(FName name, PType *type, DWORD flags) { - unsigned oldsize = Size; - PField *field = Super::AddField(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) && Defaults != nullptr) + if (!(flags & VARF_Meta)) { - Defaults = (BYTE *)M_Realloc(Defaults, Size); - memset(Defaults + oldsize, 0, Size - oldsize); + unsigned oldsize = Size; + PField *field = Super::AddField(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) && Defaults != nullptr) + { + Defaults = (BYTE *)M_Realloc(Defaults, Size); + 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; } - return field; } //========================================================================== @@ -3313,6 +3397,7 @@ PClass *PClass::FindClassTentative(FName name) PClass *type = static_cast(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); diff --git a/src/dobjtype.h b/src/dobjtype.h index 0151e6c119..f589b4e489 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -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 SpecialInits; +protected: + TArray MetaInits; void Derive(PClass *newclass, FName name); - void InitializeSpecials(void *addr, void *defaults) const; + void InitializeSpecials(void *addr, void *defaults, TArray 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 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 inline T *&DObject::PointerVar(FName field) { diff --git a/src/g_inventory/a_pickups.cpp b/src/g_inventory/a_pickups.cpp index 53e7d84ed7..df6679d41a 100644 --- a/src/g_inventory/a_pickups.cpp +++ b/src/g_inventory/a_pickups.cpp @@ -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); } //=========================================================================== diff --git a/src/g_inventory/a_pickups.h b/src/g_inventory/a_pickups.h index 817fcf1769..9b2fc1cc1a 100644 --- a/src/g_inventory/a_pickups.h +++ b/src/g_inventory/a_pickups.h @@ -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 InvFlags; +//typedef TFlags 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; diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index ae6ba5b000..ad2da961d4 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -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; diff --git a/src/gi.cpp b/src/gi.cpp index 672ca3263a..ad5c5a0eea 100644 --- a/src/gi.cpp +++ b/src/gi.cpp @@ -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] = diff --git a/src/info.cpp b/src/info.cpp index 7cac3569d9..d51cad1155 100644 --- a/src/info.cpp +++ b/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(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; diff --git a/src/info.h b/src/info.h index 6d6329f88f..d5e3eff481 100644 --- a/src/info.h +++ b/src/info.h @@ -290,38 +290,13 @@ public: TArray 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 RestrictedToPlayerClass; TArray ForbiddenToPlayerClass; diff --git a/src/intermission/intermission.h b/src/intermission/intermission.h index cdc100d888..f0b423150c 100644 --- a/src/intermission/intermission.h +++ b/src/intermission/intermission.h @@ -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; diff --git a/src/menu/menu.cpp b/src/menu/menu.cpp index 8b0bf35e97..1c8e0b39bb 100644 --- a/src/menu/menu.cpp +++ b/src/menu/menu.cpp @@ -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")) diff --git a/src/namedef.h b/src/namedef.h index bb42fc76df..91fd28626e 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -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) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index baf15c1105..5ea7dfa075 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -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 diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 54a577e5b9..b75949f01b 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -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; diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 5841e6b994..dde4fce29c 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -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) diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 4c23c8123c..b4cb5d16f5 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -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"); + message = "$OB_KILLEDSELF"; } - else if (attacker->player == NULL) + else { - if (mod == NAME_Telefrag) + IFVIRTUALPTR(attacker, AActor, GetObituary) { - 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; + 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; } } } - - 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); - } - else - { - if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG"); - if (message == NULL) - { - 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; - } - } - } - } - 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 (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) { diff --git a/src/p_map.cpp b/src/p_map.cpp index 70b18df7fa..7e110dcbf4 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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(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)) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f38ac12bb3..b4affd5394 100644 --- a/src/p_mobj.cpp +++ b/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(actor)->GetMaxHealth() + player->mo->stamina; + max = static_cast(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 (dmflags & DF_NO_HEALTH) + if (i->IsDescendantOf(RUNTIME_CLASS(AInventory))) { - if (i->IsDescendantOf (PClass::FindActor(NAME_Health))) - return NULL; - if (i->TypeName == NAME_Berserk) - return NULL; - if (i->TypeName == NAME_Megasphere) - return NULL; - } - if (dmflags & DF_NO_ITEMS) - { -// 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; + auto it = static_cast(GetDefaultByType(i)); + + if (dmflags & DF_NO_HEALTH) + { + if (it->ItemFlags & IF_ISHEALTH) return nullptr; + } + if (dmflags & DF_NO_ITEMS) + { + // if (i->IsDescendantOf (RUNTIME_CLASS(AArtifact))) + // return; + } + if (dmflags & DF_NO_ARMOR) + { + 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); diff --git a/src/p_user.cpp b/src/p_user.cpp index b607b28a1b..528ab482df 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -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(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(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) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index cc93c22156..8e41f44ab4 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -6088,19 +6088,85 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx) if (Object->ExprType == EFX_Identifier) { + auto id = static_cast(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(Object)->Identifier, ctx); - if (ccls != nullptr) static_cast(Object)->noglobal = true; + ccls = FindStructType(id, ctx); + if (ccls != nullptr) + { + static_cast(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(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); } diff --git a/src/scripting/decorate/olddecorations.cpp b/src/scripting/decorate/olddecorations.cpp index 50e8f9c6a8..7370ddb54f 100644 --- a/src/scripting/decorate/olddecorations.cpp +++ b/src/scripting/decorate/olddecorations.cpp @@ -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")) { diff --git a/src/scripting/decorate/thingdef_parse.cpp b/src/scripting/decorate/thingdef_parse.cpp index e444d30a9f..72cac7cde7 100644 --- a/src/scripting/decorate/thingdef_parse.cpp +++ b/src/scripting/decorate/thingdef_parse.cpp @@ -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))) { diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 265dc079b4..4b65e6413e 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -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), diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index cf70b19aee..e41523b8cf 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -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(info)->GibHealth = id; -} - //========================================================================== // //========================================================================== DEFINE_PROPERTY(woundhealth, I, Actor) { PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(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(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(info)->Obituary = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(hitobituary, S, Actor) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->HitObituary = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(donthurtshooter, 0, Actor) -{ - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->DontHurtShooter = true; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(explosionradius, I, Actor) -{ - PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->ExplosionRadius = id; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(explosiondamage, I, Actor) -{ - PROP_INT_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->ExplosionDamage = id; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(deathheight, F, Actor) -{ - PROP_DOUBLE_PARM(h, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->DeathHeight = MAX(0., h); -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(burnheight, F, Actor) -{ - PROP_DOUBLE_PARM(h, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(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(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(info)->MeleeSound = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(missiletype, S, Actor) -{ - PROP_STRING_PARM(str, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(info)->MissileName = str; -} - -//========================================================================== -// -//========================================================================== -DEFINE_PROPERTY(missileheight, F, Actor) -{ - PROP_DOUBLE_PARM(id, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(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(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(info)->FastSpeed = i; -} - //========================================================================== // //========================================================================== DEFINE_PROPERTY(radiusdamagefactor, F, Actor) { PROP_DOUBLE_PARM(i, 0); - assert(info->IsKindOf(RUNTIME_CLASS(PClassActor))); - static_cast(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(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(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(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(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; -} - //========================================================================== // //========================================================================== diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 3082abf802..c37e29cbf1 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -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); diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index b058dc94b6..3d503932aa 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -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 diff --git a/src/scripting/zscript/zcc_compile.cpp b/src/scripting/zscript/zcc_compile.cpp index b28226efbb..5574fcc187 100644 --- a/src/scripting/zscript/zcc_compile.cpp +++ b/src/scripting/zscript/zcc_compile.cpp @@ -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 &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,22 +1095,28 @@ bool ZCCCompiler::CompileFields(PStruct *type, TArray &Fiel if (varflags & VARF_Native) { - auto querytype = (varflags & VARF_Meta) ? type->GetClass() : type; - fd = FindField(querytype, FName(name->Name).GetChars()); - if (fd == nullptr) + if (varflags & VARF_Meta) { - Error(field, "The member variable '%s.%s' has not been exported from the executable.", type->TypeName.GetChars(), FName(name->Name).GetChars()); + Error(field, "Native meta variable %s not allowed", FName(name->Name).GetChars()); } - else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0) - { - Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); - } - // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. else { - // for bit fields the type must point to the source variable. - if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; - type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + 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()); + } + else if (thisfieldtype->Size != fd->FieldSize && fd->BitValue == 0) + { + Error(field, "The member variable '%s.%s' has mismatching sizes in internal and external declaration. (Internal = %d, External = %d)", type->TypeName.GetChars(), FName(name->Name).GetChars(), fd->FieldSize, thisfieldtype->Size); + } + // Q: Should we check alignment, too? A mismatch may be an indicator for bad assumptions. + else + { + // for bit fields the type must point to the source variable. + if (fd->BitValue != 0) thisfieldtype = fd->FieldSize == 1 ? TypeUInt8 : fd->FieldSize == 2 ? TypeUInt16 : TypeUInt32; + type->AddNativeField(name->Name, thisfieldtype, fd->FieldOffset, varflags, fd->BitValue); + } } } else if (hasnativechildren) @@ -1188,8 +1194,10 @@ bool ZCCCompiler::CompileProperties(PClass *type, TArray &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 { diff --git a/src/scripting/zscript/zcc_parser.cpp b/src/scripting/zscript/zcc_parser.cpp index 501a7b2ea8..439b495b4c 100644 --- a/src/scripting/zscript/zcc_parser.cpp +++ b/src/scripting/zscript/zcc_parser.cpp @@ -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; diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index d22eac8000..2ed1623820 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -189,30 +189,48 @@ class Actor : Thinker native native State MissileState; native voidptr /*DecalBase*/ DecalGenerator; native uint8 fountaincolor; - - 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; - + 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. + 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; //int ConversationRoot; // THe root of the current dialogue @@ -239,7 +257,7 @@ class Actor : Thinker native Health DEFAULT_HEALTH; Reactiontime 8; Radius 20; - RenderRadius 0; + RenderRadius 0; Height 16; Mass 100; RenderStyle 'Normal'; @@ -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; @@ -334,6 +362,81 @@ class Actor : Thinker native { return false; } + + virtual class GetBloodType(int type) + { + Class 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 GetReplacement(class cls); native static class GetReplacee(class cls); @@ -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); @@ -725,6 +827,68 @@ class Actor : Thinker native // Meh, MBF redundant functions. Only for DeHackEd support. 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 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 MissileType = MissileName; + DoAttack(false, true, 0, 0, MissileType, MissileHeight); + } + + deprecated void A_ComboAttack() + { + Class MissileType = MissileName; + DoAttack(true, true, MeleeDamage, MeleeSound, MissileType, MissileHeight); + } + + void A_BasicAttack(int melee_damage, sound melee_sound, class missile_type, double missile_height) + { + DoAttack(true, true, melee_damage, melee_sound, missile_type, missile_height); + } + native void A_MonsterRail(); native void A_Pain(); @@ -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 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 missiletype, double missileheight); action native bool, Actor A_ThrowGrenade(class 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 type, int duration = 0, int flags = 0, class enter_flash = null, class exit_flash = null); diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index d8fed2f28a..f5eda90227 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -310,6 +310,7 @@ struct GameInfoStruct native native GIFont mStatscreenMapNameFont; native GIFont mStatscreenEnteringFont; native GIFont mStatscreenFinishedFont; + native double gibfactor; } class Object native diff --git a/wadsrc/static/zscript/doom/doomartifacts.txt b/wadsrc/static/zscript/doom/doomartifacts.txt index ad5e304c66..a6996cb886 100644 --- a/wadsrc/static/zscript/doom/doomartifacts.txt +++ b/wadsrc/static/zscript/doom/doomartifacts.txt @@ -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"; } diff --git a/wadsrc/static/zscript/inventory/ammo.txt b/wadsrc/static/zscript/inventory/ammo.txt index e742e806d9..092a93846b 100644 --- a/wadsrc/static/zscript/inventory/ammo.txt +++ b/wadsrc/static/zscript/inventory/ammo.txt @@ -37,7 +37,7 @@ class Ammo : Inventory { int BackpackAmount; int BackpackMaxAmount; - /*meta*/ int DropAmount; + meta int DropAmount; property BackpackAmount: BackpackAmount; property BackpackMaxAmount: BackpackMaxAmount; diff --git a/wadsrc/static/zscript/inventory/armor.txt b/wadsrc/static/zscript/inventory/armor.txt index ae9ab562e2..600c4e5265 100644 --- a/wadsrc/static/zscript/inventory/armor.txt +++ b/wadsrc/static/zscript/inventory/armor.txt @@ -38,6 +38,7 @@ class Armor : Inventory Default { Inventory.PickupSound "misc/armor_pkup"; + +INVENTORY.ISARMOR } } diff --git a/wadsrc/static/zscript/inventory/health.txt b/wadsrc/static/zscript/inventory/health.txt index 230b3575be..e64bbfd4a9 100644 --- a/wadsrc/static/zscript/inventory/health.txt +++ b/wadsrc/static/zscript/inventory/health.txt @@ -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 } //=========================================================================== diff --git a/wadsrc/static/zscript/inventory/inv_misc.txt b/wadsrc/static/zscript/inventory/inv_misc.txt index 441566786c..ce4bf805b4 100644 --- a/wadsrc/static/zscript/inventory/inv_misc.txt +++ b/wadsrc/static/zscript/inventory/inv_misc.txt @@ -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; diff --git a/wadsrc/static/zscript/inventory/inventory.txt b/wadsrc/static/zscript/inventory/inventory.txt index 06caedad73..cac9b9b8f2 100644 --- a/wadsrc/static/zscript/inventory/inventory.txt +++ b/wadsrc/static/zscript/inventory/inventory.txt @@ -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 { diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index c76aaef54c..860d387e27 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -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; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index a4a7742311..98cede7a55 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -8,18 +8,14 @@ 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 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; - 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; - // [GRB] Player class properties native double JumpZ; native double GruntSpeed; @@ -37,6 +33,13 @@ class PlayerPawn : Actor native native color DamageFade; // [CW] Fades for when you are being damaged. 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 { @@ -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 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 item); native static String GetPrintableDisplayName(Class 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 diff --git a/wadsrc/static/zscript/shared/player_cheat.txt b/wadsrc/static/zscript/shared/player_cheat.txt index 2aaa01ba87..15bad043cf 100644 --- a/wadsrc/static/zscript/shared/player_cheat.txt +++ b/wadsrc/static/zscript/shared/player_cheat.txt @@ -76,7 +76,7 @@ extend class PlayerPawn } else { - player.health = health = GetMaxHealth(); + player.health = health = GetMaxHealth(true); } }