diff --git a/src/dobjtype.h b/src/dobjtype.h index 156818147a..dd240e0718 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -639,6 +639,19 @@ protected: PProperty(); }; +class PPropFlag : public PSymbol +{ + DECLARE_CLASS(PPropFlag, PSymbol); +public: + PPropFlag(FName name, PField *offset, int bitval); + + PField *Offset; + int bitval; + +protected: + PPropFlag(); +}; + // Compound types ----------------------------------------------------------- class PEnum : public PNamedType diff --git a/src/g_inventory/a_artifacts.cpp b/src/g_inventory/a_artifacts.cpp index 8b57d4fe25..6e5b03cc3b 100644 --- a/src/g_inventory/a_artifacts.cpp +++ b/src/g_inventory/a_artifacts.cpp @@ -123,25 +123,7 @@ DEFINE_FIELD(APowerup, EffectTics) DEFINE_FIELD(APowerup, BlendColor) DEFINE_FIELD(APowerup, Mode) DEFINE_FIELD(APowerup, Strength) - -//=========================================================================== -// -// APowerup :: Tick -// -//=========================================================================== - -void APowerup::Tick () -{ - // Powerups cannot exist outside an inventory - if (Owner == NULL) - { - Destroy (); - } - if (EffectTics > 0 && --EffectTics == 0) - { - Destroy (); - } -} +DEFINE_FIELD(APowerup, Colormap) //=========================================================================== // @@ -156,257 +138,8 @@ void APowerup::Serialize(FSerializer &arc) arc("effecttics", EffectTics, def->EffectTics) ("blendcolor", BlendColor, def->BlendColor) ("mode", Mode, def->Mode) - ("strength", Strength, def->Strength); -} - -//=========================================================================== -// -// APowerup :: GetBlend -// -//=========================================================================== - -PalEntry APowerup::GetBlend () -{ - if (isBlinking()) - return 0; - - if (IsSpecialColormap(BlendColor)) return 0; - return BlendColor; -} - -//=========================================================================== -// -// APowerup :: InitEffect -// -//=========================================================================== - -void APowerup::InitEffect () -{ -} - -DEFINE_ACTION_FUNCTION(APowerup, InitEffect) -{ - PARAM_SELF_PROLOGUE(APowerup); - self->InitEffect(); - return 0; -} - -void APowerup::CallInitEffect() -{ - IFVIRTUAL(APowerup, InitEffect) - { - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } - else InitEffect(); -} - -//=========================================================================== -// -// APowerup :: isBlinking (todo: make this virtual so that child classes can configure their blinking) -// -//=========================================================================== - -bool APowerup::isBlinking() const -{ - return (EffectTics <= BLINKTHRESHOLD && (EffectTics & 8) && !(ItemFlags & IF_NOSCREENBLINK)); -} - -DEFINE_ACTION_FUNCTION(APowerup, isBlinking) -{ - PARAM_SELF_PROLOGUE(APowerup); - ACTION_RETURN_BOOL(self->isBlinking()); -} - -//=========================================================================== -// -// APowerup :: DoEffect -// -//=========================================================================== - -void APowerup::DoEffect () -{ - if (Owner == NULL || Owner->player == NULL) - { - return; - } - - if (EffectTics > 0) - { - int Colormap = GetSpecialColormap(BlendColor); - - if (Colormap != NOFIXEDCOLORMAP) - { - if (!isBlinking()) - { - Owner->player->fixedcolormap = Colormap; - } - else if (Owner->player->fixedcolormap == Colormap) - { - // only unset if the fixed colormap comes from this item - Owner->player->fixedcolormap = NOFIXEDCOLORMAP; - } - } - } -} - -//=========================================================================== -// -// APowerup :: EndEffect -// -//=========================================================================== - -void APowerup::EndEffect () -{ - int colormap = GetSpecialColormap(BlendColor); - - if (colormap != NOFIXEDCOLORMAP && Owner && Owner->player && Owner->player->fixedcolormap == colormap) - { // only unset if the fixed colormap comes from this item - Owner->player->fixedcolormap = NOFIXEDCOLORMAP; - } -} - -DEFINE_ACTION_FUNCTION(APowerup, EndEffect) -{ - PARAM_SELF_PROLOGUE(APowerup); - self->EndEffect(); - return 0; -} - -void APowerup::CallEndEffect() -{ - IFVIRTUAL(APowerup, EndEffect) - { - VMValue params[1] = { (DObject*)this }; - VMFrameStack stack; - GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); - } - else EndEffect(); -} - - -//=========================================================================== -// -// APowerup :: Destroy -// -//=========================================================================== - -void APowerup::OnDestroy () -{ - CallEndEffect (); - Super::OnDestroy(); -} - -//=========================================================================== -// -// APowerup :: DrawPowerup -// -//=========================================================================== - -bool APowerup::DrawPowerup (int x, int y) -{ - if (!Icon.isValid()) - { - return false; - } - if (!isBlinking()) - { - FTexture *pic = TexMan(Icon); - screen->DrawTexture (pic, x, y, - DTA_HUDRules, HUD_Normal, -// DTA_TopOffset, pic->GetHeight()/2, -// DTA_LeftOffset, pic->GetWidth()/2, - TAG_DONE); - } - return true; -} - -//=========================================================================== -// -// APowerup :: HandlePickup -// -//=========================================================================== - -bool APowerup::HandlePickup (AInventory *item) -{ - if (item->GetClass() == GetClass()) - { - APowerup *power = static_cast(item); - if (power->EffectTics == 0) - { - power->ItemFlags |= IF_PICKUPGOOD; - return true; - } - // Color gets transferred if the new item has an effect. - - // Increase the effect's duration. - if (power->ItemFlags & IF_ADDITIVETIME) - { - EffectTics += power->EffectTics; - BlendColor = power->BlendColor; - } - // If it's not blinking yet, you can't replenish the power unless the - // powerup is required to be picked up. - else if (EffectTics > BLINKTHRESHOLD && !(power->ItemFlags & IF_ALWAYSPICKUP)) - { - return true; - } - // Reset the effect duration. - else if (power->EffectTics > EffectTics) - { - EffectTics = power->EffectTics; - BlendColor = power->BlendColor; - } - power->ItemFlags |= IF_PICKUPGOOD; - return true; - } - return false; -} - -//=========================================================================== -// -// APowerup :: CreateCopy -// -//=========================================================================== - -AInventory *APowerup::CreateCopy (AActor *other) -{ - // Get the effective effect time. - EffectTics = abs (EffectTics); - // Abuse the Owner field to tell the - // InitEffect method who started it; - // this should be cleared afterwards, - // as this powerup instance is not - // properly attached to anything yet. - Owner = other; - // Actually activate the powerup. - CallInitEffect (); - // Clear the Owner field, unless it was - // changed by the activation, for example, - // if this instance is a morph powerup; - // the flag tells the caller that the - // ownership has changed so that they - // can properly handle the situation. - if (!(ItemFlags & IF_CREATECOPYMOVED)) - { - Owner = NULL; - } - // All done. - return this; -} - -//=========================================================================== -// -// APowerup :: CreateTossable -// -// Powerups are never droppable, even without IF_UNDROPPABLE set. -// -//=========================================================================== - -AInventory *APowerup::CreateTossable () -{ - return NULL; + ("strength", Strength, def->Strength) + ("colormap", Colormap, def->Colormap); } //=========================================================================== @@ -422,24 +155,6 @@ void APowerup::OwnerDied () Destroy (); } -// Speed Powerup ------------------------------------------------------------- - -IMPLEMENT_CLASS(APowerSpeed, false, false) - -DEFINE_FIELD(APowerSpeed, SpeedFlags) - -//=========================================================================== -// -// APowerSpeed :: Serialize -// -//=========================================================================== - -void APowerSpeed::Serialize(FSerializer &arc) -{ - Super::Serialize (arc); - arc("speedflags", SpeedFlags); -} - // Morph powerup ------------------------------------------------------ IMPLEMENT_CLASS(APowerMorph, false, true) diff --git a/src/g_inventory/a_artifacts.h b/src/g_inventory/a_artifacts.h index 89088a0be6..f17299d468 100644 --- a/src/g_inventory/a_artifacts.h +++ b/src/g_inventory/a_artifacts.h @@ -11,31 +11,16 @@ class APowerup : public AInventory { DECLARE_CLASS (APowerup, AInventory) public: - virtual void Tick () override; - virtual void OnDestroy() override; - virtual bool HandlePickup (AInventory *item) override; - virtual AInventory *CreateCopy (AActor *other) override; - virtual AInventory *CreateTossable () override; virtual void Serialize(FSerializer &arc) override; virtual void OwnerDied () override; - virtual PalEntry GetBlend () override; - virtual bool DrawPowerup (int x, int y) override; int EffectTics; PalEntry BlendColor; FNameNoInit Mode; double Strength; + int Colormap; public: - virtual void InitEffect (); - virtual void DoEffect () override; - virtual void EndEffect (); - bool isBlinking() const; - -protected: - void CallInitEffect(); - void CallEndEffect(); - friend void EndAllPowerupEffects(AInventory *item); friend void InitAllPowerupEffects(AInventory *item); }; @@ -57,17 +42,6 @@ public: double Strength; // Meaning depends on powerup - currently used only by Invisibility }; -class APowerSpeed : public APowerup -{ - DECLARE_CLASS (APowerSpeed, APowerup) -protected: - virtual void Serialize(FSerializer &arc) override; -public: - int SpeedFlags; -}; - -#define PSF_NOTRAIL 1 - class APowerMorph : public APowerup { DECLARE_CLASS( APowerMorph, APowerup ) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index d18ec7e029..40e6e420b6 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -17,6 +17,7 @@ #include "a_armor.h" #include "r_data/sprites.h" #include "g_levellocals.h" +#include "virtual.h" static FRandom pr_morphmonst ("MorphMonster"); @@ -597,7 +598,12 @@ void EndAllPowerupEffects(AInventory *item) { if (item->IsKindOf(RUNTIME_CLASS(APowerup))) { - static_cast(item)->CallEndEffect(); + IFVIRTUALPTR(item, APowerup, EndEffect) + { + VMValue params[1] = { item }; + VMFrameStack stack; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } item = item->Inventory; } @@ -617,7 +623,12 @@ void InitAllPowerupEffects(AInventory *item) { if (item->IsKindOf(RUNTIME_CLASS(APowerup))) { - static_cast(item)->CallInitEffect(); + IFVIRTUALPTR(item, APowerup, InitEffect) + { + VMValue params[1] = { item }; + VMFrameStack stack; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } } item = item->Inventory; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 5355b10a08..50dc1eb7a7 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -87,6 +87,7 @@ #include "a_ammo.h" #include "r_data/colormaps.h" #include "g_levellocals.h" +#include "stats.h" extern FILE *Logfile; @@ -2974,8 +2975,12 @@ void DACSThinker::Serialize(FSerializer &arc) } } +cycle_t ACSTime; + void DACSThinker::Tick () { + ACSTime.Reset(); + ACSTime.Clock(); DLevelScript *script = Scripts; while (script) @@ -2993,6 +2998,7 @@ void DACSThinker::Tick () ACS_StringBuilderStack.Clear(); I_Error("Error: %d garbage entries on ACS string builder stack.", size); } + ACSTime.Unclock(); } void DACSThinker::StopScriptsFor (AActor *actor) @@ -10269,3 +10275,8 @@ CCMD(acsprofile) ShowProfileData(ScriptProfiles, limit, sorter, false); ShowProfileData(FuncProfiles, limit, sorter, true); } + +ADD_STAT(ACS) +{ + return FStringf("ACS time: %f ms", ACSTime.TimeMS()); +} diff --git a/src/r_data/colormaps.h b/src/r_data/colormaps.h index 9db564b604..03f705b2ba 100644 --- a/src/r_data/colormaps.h +++ b/src/r_data/colormaps.h @@ -63,16 +63,6 @@ inline uint32 MakeSpecialColormap(int index) return index | SPECIALCOLORMAP_MASK; } -inline bool IsSpecialColormap(uint32 map) -{ - return (map & 0xFFFF0000) == SPECIALCOLORMAP_MASK; -} - -inline int GetSpecialColormap(int blend) -{ - return IsSpecialColormap(blend) ? blend & 0xFFFF : NOFIXEDCOLORMAP; -} - int AddSpecialColormap(float r1, float g1, float b1, float r2, float g2, float b2); diff --git a/src/scripting/thingdef.h b/src/scripting/thingdef.h index 9d41b5265b..20d25dd8e6 100644 --- a/src/scripting/thingdef.h +++ b/src/scripting/thingdef.h @@ -187,6 +187,7 @@ enum DEPF_HEXENBOUNCE, DEPF_DOOMBOUNCE, DEPF_INTERHUBSTRIP, + DEPF_NOTRAIL, }; // Types of old style decorations diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 8caa07292f..20e210f801 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -462,7 +462,7 @@ static FFlagDef PlayerPawnFlagDefs[] = static FFlagDef PowerSpeedFlagDefs[] = { // PowerSpeed flags - DEFINE_FLAG(PSF, NOTRAIL, APowerSpeed, SpeedFlags), + DEFINE_DEPRECATED_FLAG(NOTRAIL), }; static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int NumDefs; int Use; } FlagLists[] = @@ -473,7 +473,6 @@ static const struct FFlagList { const PClass * const *Type; FFlagDef *Defs; int { &RUNTIME_CLASS_CASTLESS(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, - { &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs), 1 }, }; #define NUM_FLAG_LISTS (countof(FlagLists)) @@ -548,6 +547,12 @@ FFlagDef *FindFlag (const PClass *type, const char *part1, const char *part2, bo } } } + + // Handle that lone PowerSpeed flag - this should be more generalized but it's just this one flag and unlikely to become more so an explicit check will do. + if ((!stricmp(part1, "NOTRAIL") && !strict) || (!stricmp(part1, "POWERSPEED") && !stricmp(part2, "NOTRAIL"))) + { + return &PowerSpeedFlagDefs[0]; + } return NULL; } diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index db24349cb2..487763d9aa 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -354,6 +354,23 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in break; case DEPF_INTERHUBSTRIP: // Old system was 0 or 1, so if the flag is cleared, assume 1. static_cast(defaults)->InterHubAmount = set ? 0 : 1; + break; + case DEPF_NOTRAIL: + { + FString propname = "@property@powerspeed.notrail"; + FName name(propname, true); + if (name != NAME_None) + { + auto propp = dyn_cast(info->Symbols.FindSymbol(name, true)); + if (propp != nullptr) + { + *((char*)defaults + propp->Variables[0]->Offset) = set ? 1 : 0; + } + } + break; + } + + default: break; // silence GCC } diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index 3b97eb614f..7615a4f0f1 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -36,6 +36,7 @@ #include "dobject.h" #include "v_text.h" #include "stats.h" +#include "templates.h" cycle_t VMCycles[10]; int VMCalls[10]; @@ -605,11 +606,16 @@ ADD_STAT(VM) { double added = 0; int addedc = 0; - for (auto d : VMCycles) added += d.TimeMS(); + double peak = 0; + for (auto d : VMCycles) + { + added += d.TimeMS(); + peak = MAX(peak, d.TimeMS()); + } for (auto d : VMCalls) addedc += d; memmove(&VMCycles[1], &VMCycles[0], 9 * sizeof(cycle_t)); memmove(&VMCalls[1], &VMCalls[0], 9 * sizeof(int)); VMCycles[0].Reset(); VMCalls[0] = 0; - return FStringf("VM time in last 10 tics: %f ms, %d calls", added, addedc); + return FStringf("VM time in last 10 tics: %f ms, %d calls, peak = %f ms", added, addedc, peak); } diff --git a/wadsrc/static/zscript/inventory/powerups.txt b/wadsrc/static/zscript/inventory/powerups.txt index 8ad8bdac19..af20ed628b 100644 --- a/wadsrc/static/zscript/inventory/powerups.txt +++ b/wadsrc/static/zscript/inventory/powerups.txt @@ -22,13 +22,232 @@ class Powerup : Inventory native native color BlendColor; native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility native double Strength; // Meaning depends on powerup - currently used only by Invisibility + native int Colormap; + const SPECIALCOLORMAP_MASK = 0x00b60000; // Note, that while this is an inventory flag, it only has meaning on an active powerup. - override bool GetNoTeleportFreeze() { return bNoTeleportFreeze; } + override bool GetNoTeleportFreeze() + { + return bNoTeleportFreeze; + } + + //=========================================================================== + // + // APowerup :: Tick + // + //=========================================================================== + + override void Tick () + { + // Powerups cannot exist outside an inventory + if (Owner == NULL) + { + Destroy (); + } + if (EffectTics > 0 && --EffectTics == 0) + { + Destroy (); + } + } + + //=========================================================================== + // + // APowerup :: HandlePickup + // + //=========================================================================== + + override bool HandlePickup (Inventory item) + { + if (item.GetClass() == GetClass()) + { + let power = Powerup(item); + if (power.EffectTics == 0) + { + power.bPickupGood = true; + return true; + } + // Color gets transferred if the new item has an effect. + + // Increase the effect's duration. + if (power.bAdditiveTime) + { + EffectTics += power.EffectTics; + BlendColor = power.BlendColor; + } + // If it's not blinking yet, you can't replenish the power unless the + // powerup is required to be picked up. + else if (EffectTics > BLINKTHRESHOLD && !power.bAlwaysPickup) + { + return true; + } + // Reset the effect duration. + else if (power.EffectTics > EffectTics) + { + EffectTics = power.EffectTics; + BlendColor = power.BlendColor; + } + power.bPickupGood = true; + return true; + } + return false; + } + + //=========================================================================== + // + // APowerup :: CreateCopy + // + //=========================================================================== + + override Inventory CreateCopy (Actor other) + { + // Get the effective effect time. + EffectTics = abs (EffectTics); + // Abuse the Owner field to tell the + // InitEffect method who started it; + // this should be cleared afterwards, + // as this powerup instance is not + // properly attached to anything yet. + Owner = other; + // Actually activate the powerup. + InitEffect (); + // Clear the Owner field, unless it was + // changed by the activation, for example, + // if this instance is a morph powerup; + // the flag tells the caller that the + // ownership has changed so that they + // can properly handle the situation. + if (!bCreateCopyMoved) + { + Owner = NULL; + } + // All done. + return self; + } + + //=========================================================================== + // + // APowerup :: CreateTossable + // + // Powerups are never droppable, even without IF_UNDROPPABLE set. + // + //=========================================================================== + + override Inventory CreateTossable () + { + return NULL; + } + + //=========================================================================== + // + // APowerup :: InitEffect + // + //=========================================================================== + + virtual void InitEffect() + { + // initialize this only once instead of recalculating repeatedly. + Colormap = ((BlendColor & 0xFFFF0000) == SPECIALCOLORMAP_MASK)? BlendColor & 0xffff : PlayerInfo.NOFIXEDCOLORMAP; + } + + //=========================================================================== + // + // APowerup :: DoEffect + // + //=========================================================================== + + override void DoEffect () + { + if (Owner == NULL || Owner.player == NULL) + { + return; + } + + if (EffectTics > 0) + { + if (Colormap != PlayerInfo.NOFIXEDCOLORMAP) + { + if (!isBlinking()) + { + Owner.player.fixedcolormap = Colormap; + } + else if (Owner.player.fixedcolormap == Colormap) + { + // only unset if the fixed colormap comes from this item + Owner.player.fixedcolormap = PlayerInfo.NOFIXEDCOLORMAP; + } + } + } + } + + //=========================================================================== + // + // APowerup :: EndEffect + // + //=========================================================================== + + virtual void EndEffect () + { + if (colormap != PlayerInfo.NOFIXEDCOLORMAP && Owner && Owner.player && Owner.player.fixedcolormap == colormap) + { // only unset if the fixed colormap comes from this item + Owner.player.fixedcolormap = PlayerInfo.NOFIXEDCOLORMAP; + } + } + + //=========================================================================== + // + // APowerup :: Destroy + // + //=========================================================================== + + override void OnDestroy () + { + EndEffect (); + Super.OnDestroy(); + } + + //=========================================================================== + // + // APowerup :: GetBlend + // + //=========================================================================== + + override color GetBlend () + { + if (Colormap != Player.NOFIXEDCOLORMAP) return 0; + if (isBlinking()) return 0; + return BlendColor; + } + + //=========================================================================== + // + // APowerup :: DrawPowerup + // + //=========================================================================== + + override bool DrawPowerup (int x, int y) + { + if (!Icon.isValid()) + { + return false; + } + if (!isBlinking()) + { + screen.DrawHUDTexture(Icon, x, y); + } + return true; + } + + //=========================================================================== + // + // APowerup :: isBlinking + // + //=========================================================================== + + virtual bool isBlinking() + { + return (EffectTics <= BLINKTHRESHOLD && (EffectTics & 8) && !bNoScreenBlink); + } - native virtual void InitEffect(); - native virtual void EndEffect(); - native bool isBlinking(); } @@ -881,13 +1100,12 @@ class PowerWeaponLevel2 : Powerup // //=========================================================================== -class PowerSpeed : Powerup native +class PowerSpeed : Powerup { - native int SpeedFlags; + int NoTrail; + + Property NoTrail: NoTrail; - const PSF_NOTRAIL = 1; - - Default { Powerup.Duration -45; @@ -917,7 +1135,7 @@ class PowerSpeed : Powerup native if (Owner.player.cheats & CF_PREDICTING) return; - if (SpeedFlags & PSF_NOTRAIL) + if (NoTrail) return; if (level.time & 1) @@ -928,7 +1146,7 @@ class PowerSpeed : Powerup native for (Inventory item = Inv; item != NULL; item = item.Inv) { let sitem = PowerSpeed(item); - if (sitem != null && !(sitem.SpeedFlags & PSF_NOTRAIL)) + if (sitem != null && !NoTrail) { return; } @@ -1678,7 +1896,7 @@ class PowerMorph : Powerup native native Class MorphFlash, UnMorphFlash; native int MorphStyle; native PlayerInfo MorphedPlayer; - + Default { Powerup.Duration -40;