- scriptified APowerup.

This commit is contained in:
Christoph Oelckers 2017-01-17 01:50:31 +01:00
parent 0da1142bdb
commit 75d3f42d4f
11 changed files with 304 additions and 343 deletions

View file

@ -639,6 +639,19 @@ protected:
PProperty(); 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 ----------------------------------------------------------- // Compound types -----------------------------------------------------------
class PEnum : public PNamedType class PEnum : public PNamedType

View file

@ -123,25 +123,7 @@ DEFINE_FIELD(APowerup, EffectTics)
DEFINE_FIELD(APowerup, BlendColor) DEFINE_FIELD(APowerup, BlendColor)
DEFINE_FIELD(APowerup, Mode) DEFINE_FIELD(APowerup, Mode)
DEFINE_FIELD(APowerup, Strength) DEFINE_FIELD(APowerup, Strength)
DEFINE_FIELD(APowerup, Colormap)
//===========================================================================
//
// APowerup :: Tick
//
//===========================================================================
void APowerup::Tick ()
{
// Powerups cannot exist outside an inventory
if (Owner == NULL)
{
Destroy ();
}
if (EffectTics > 0 && --EffectTics == 0)
{
Destroy ();
}
}
//=========================================================================== //===========================================================================
// //
@ -156,257 +138,8 @@ void APowerup::Serialize(FSerializer &arc)
arc("effecttics", EffectTics, def->EffectTics) arc("effecttics", EffectTics, def->EffectTics)
("blendcolor", BlendColor, def->BlendColor) ("blendcolor", BlendColor, def->BlendColor)
("mode", Mode, def->Mode) ("mode", Mode, def->Mode)
("strength", Strength, def->Strength); ("strength", Strength, def->Strength)
} ("colormap", Colormap, def->Colormap);
//===========================================================================
//
// 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<APowerup*>(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;
} }
//=========================================================================== //===========================================================================
@ -422,24 +155,6 @@ void APowerup::OwnerDied ()
Destroy (); 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 ------------------------------------------------------ // Morph powerup ------------------------------------------------------
IMPLEMENT_CLASS(APowerMorph, false, true) IMPLEMENT_CLASS(APowerMorph, false, true)

View file

@ -11,31 +11,16 @@ class APowerup : public AInventory
{ {
DECLARE_CLASS (APowerup, AInventory) DECLARE_CLASS (APowerup, AInventory)
public: 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 Serialize(FSerializer &arc) override;
virtual void OwnerDied () override; virtual void OwnerDied () override;
virtual PalEntry GetBlend () override;
virtual bool DrawPowerup (int x, int y) override;
int EffectTics; int EffectTics;
PalEntry BlendColor; PalEntry BlendColor;
FNameNoInit Mode; FNameNoInit Mode;
double Strength; double Strength;
int Colormap;
public: 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 EndAllPowerupEffects(AInventory *item);
friend void InitAllPowerupEffects(AInventory *item); friend void InitAllPowerupEffects(AInventory *item);
}; };
@ -57,17 +42,6 @@ public:
double Strength; // Meaning depends on powerup - currently used only by Invisibility 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 class APowerMorph : public APowerup
{ {
DECLARE_CLASS( APowerMorph, APowerup ) DECLARE_CLASS( APowerMorph, APowerup )

View file

@ -17,6 +17,7 @@
#include "a_armor.h" #include "a_armor.h"
#include "r_data/sprites.h" #include "r_data/sprites.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "virtual.h"
static FRandom pr_morphmonst ("MorphMonster"); static FRandom pr_morphmonst ("MorphMonster");
@ -597,7 +598,12 @@ void EndAllPowerupEffects(AInventory *item)
{ {
if (item->IsKindOf(RUNTIME_CLASS(APowerup))) if (item->IsKindOf(RUNTIME_CLASS(APowerup)))
{ {
static_cast<APowerup *>(item)->CallEndEffect(); IFVIRTUALPTR(item, APowerup, EndEffect)
{
VMValue params[1] = { item };
VMFrameStack stack;
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
} }
item = item->Inventory; item = item->Inventory;
} }
@ -617,7 +623,12 @@ void InitAllPowerupEffects(AInventory *item)
{ {
if (item->IsKindOf(RUNTIME_CLASS(APowerup))) if (item->IsKindOf(RUNTIME_CLASS(APowerup)))
{ {
static_cast<APowerup *>(item)->CallInitEffect(); IFVIRTUALPTR(item, APowerup, InitEffect)
{
VMValue params[1] = { item };
VMFrameStack stack;
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
} }
item = item->Inventory; item = item->Inventory;
} }

View file

@ -87,6 +87,7 @@
#include "a_ammo.h" #include "a_ammo.h"
#include "r_data/colormaps.h" #include "r_data/colormaps.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "stats.h"
extern FILE *Logfile; extern FILE *Logfile;
@ -2974,8 +2975,12 @@ void DACSThinker::Serialize(FSerializer &arc)
} }
} }
cycle_t ACSTime;
void DACSThinker::Tick () void DACSThinker::Tick ()
{ {
ACSTime.Reset();
ACSTime.Clock();
DLevelScript *script = Scripts; DLevelScript *script = Scripts;
while (script) while (script)
@ -2993,6 +2998,7 @@ void DACSThinker::Tick ()
ACS_StringBuilderStack.Clear(); ACS_StringBuilderStack.Clear();
I_Error("Error: %d garbage entries on ACS string builder stack.", size); I_Error("Error: %d garbage entries on ACS string builder stack.", size);
} }
ACSTime.Unclock();
} }
void DACSThinker::StopScriptsFor (AActor *actor) void DACSThinker::StopScriptsFor (AActor *actor)
@ -10269,3 +10275,8 @@ CCMD(acsprofile)
ShowProfileData(ScriptProfiles, limit, sorter, false); ShowProfileData(ScriptProfiles, limit, sorter, false);
ShowProfileData(FuncProfiles, limit, sorter, true); ShowProfileData(FuncProfiles, limit, sorter, true);
} }
ADD_STAT(ACS)
{
return FStringf("ACS time: %f ms", ACSTime.TimeMS());
}

View file

@ -63,16 +63,6 @@ inline uint32 MakeSpecialColormap(int index)
return index | SPECIALCOLORMAP_MASK; 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); int AddSpecialColormap(float r1, float g1, float b1, float r2, float g2, float b2);

View file

@ -187,6 +187,7 @@ enum
DEPF_HEXENBOUNCE, DEPF_HEXENBOUNCE,
DEPF_DOOMBOUNCE, DEPF_DOOMBOUNCE,
DEPF_INTERHUBSTRIP, DEPF_INTERHUBSTRIP,
DEPF_NOTRAIL,
}; };
// Types of old style decorations // Types of old style decorations

View file

@ -462,7 +462,7 @@ static FFlagDef PlayerPawnFlagDefs[] =
static FFlagDef PowerSpeedFlagDefs[] = static FFlagDef PowerSpeedFlagDefs[] =
{ {
// PowerSpeed flags // 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[] = 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(AInventory), InventoryFlagDefs, countof(InventoryFlagDefs), 3 },
{ &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(AWeapon), WeaponFlagDefs, countof(WeaponFlagDefs), 3 },
{ &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 }, { &RUNTIME_CLASS_CASTLESS(APlayerPawn), PlayerPawnFlagDefs, countof(PlayerPawnFlagDefs), 3 },
{ &RUNTIME_CLASS_CASTLESS(APowerSpeed), PowerSpeedFlagDefs, countof(PowerSpeedFlagDefs), 1 },
}; };
#define NUM_FLAG_LISTS (countof(FlagLists)) #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; return NULL;
} }

View file

@ -354,6 +354,23 @@ void HandleDeprecatedFlags(AActor *defaults, PClassActor *info, bool set, int in
break; break;
case DEPF_INTERHUBSTRIP: // Old system was 0 or 1, so if the flag is cleared, assume 1. case DEPF_INTERHUBSTRIP: // Old system was 0 or 1, so if the flag is cleared, assume 1.
static_cast<AInventory*>(defaults)->InterHubAmount = set ? 0 : 1; static_cast<AInventory*>(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<PProperty>(info->Symbols.FindSymbol(name, true));
if (propp != nullptr)
{
*((char*)defaults + propp->Variables[0]->Offset) = set ? 1 : 0;
}
}
break;
}
default: default:
break; // silence GCC break; // silence GCC
} }

View file

@ -36,6 +36,7 @@
#include "dobject.h" #include "dobject.h"
#include "v_text.h" #include "v_text.h"
#include "stats.h" #include "stats.h"
#include "templates.h"
cycle_t VMCycles[10]; cycle_t VMCycles[10];
int VMCalls[10]; int VMCalls[10];
@ -605,11 +606,16 @@ ADD_STAT(VM)
{ {
double added = 0; double added = 0;
int addedc = 0; int addedc = 0;
for (auto d : VMCycles) added += d.TimeMS(); double peak = 0;
for (auto d : VMCycles)
{
added += d.TimeMS();
peak = MAX<double>(peak, d.TimeMS());
}
for (auto d : VMCalls) addedc += d; for (auto d : VMCalls) addedc += d;
memmove(&VMCycles[1], &VMCycles[0], 9 * sizeof(cycle_t)); memmove(&VMCycles[1], &VMCycles[0], 9 * sizeof(cycle_t));
memmove(&VMCalls[1], &VMCalls[0], 9 * sizeof(int)); memmove(&VMCalls[1], &VMCalls[0], 9 * sizeof(int));
VMCycles[0].Reset(); VMCycles[0].Reset();
VMCalls[0] = 0; 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);
} }

View file

@ -22,13 +22,232 @@ class Powerup : Inventory native
native color BlendColor; native color BlendColor;
native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility 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 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. // 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,12 +1100,11 @@ class PowerWeaponLevel2 : Powerup
// //
//=========================================================================== //===========================================================================
class PowerSpeed : Powerup native class PowerSpeed : Powerup
{ {
native int SpeedFlags; int NoTrail;
const PSF_NOTRAIL = 1;
Property NoTrail: NoTrail;
Default Default
{ {
@ -917,7 +1135,7 @@ class PowerSpeed : Powerup native
if (Owner.player.cheats & CF_PREDICTING) if (Owner.player.cheats & CF_PREDICTING)
return; return;
if (SpeedFlags & PSF_NOTRAIL) if (NoTrail)
return; return;
if (level.time & 1) if (level.time & 1)
@ -928,7 +1146,7 @@ class PowerSpeed : Powerup native
for (Inventory item = Inv; item != NULL; item = item.Inv) for (Inventory item = Inv; item != NULL; item = item.Inv)
{ {
let sitem = PowerSpeed(item); let sitem = PowerSpeed(item);
if (sitem != null && !(sitem.SpeedFlags & PSF_NOTRAIL)) if (sitem != null && !NoTrail)
{ {
return; return;
} }