mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 21:11:39 +00:00
Merge remote-tracking branch 'gzdoom/master' into qzdoom
# Conflicts: # src/r_things.cpp
This commit is contained in:
commit
53a79ca215
49 changed files with 1336 additions and 1275 deletions
|
@ -1330,6 +1330,12 @@ void C_HideConsole ()
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_Console, HideConsole)
|
||||
{
|
||||
C_HideConsole();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool C_HandleKey (event_t *ev, FCommandBuffer &buffer)
|
||||
{
|
||||
int data1 = ev->data1;
|
||||
|
|
|
@ -219,6 +219,7 @@ DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionStyle)
|
|||
DEFINE_FIELD_X(DehInfo, DehInfo, ExplosionAlpha)
|
||||
DEFINE_FIELD_X(DehInfo, DehInfo, NoAutofreeze)
|
||||
DEFINE_FIELD_X(DehInfo, DehInfo, BFGCells)
|
||||
DEFINE_FIELD_X(DehInfo, DehInfo, BlueAC)
|
||||
|
||||
// Doom identified pickup items by their sprites. ZDoom prefers to use their
|
||||
// class type to identify them instead. To support the traditional Doom
|
||||
|
|
|
@ -456,9 +456,7 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld, bool s
|
|||
auto def = GetDefaultByType(p);
|
||||
if (def != nullptr)
|
||||
{
|
||||
def->Class = p;
|
||||
def->DObject::PointerSubstitution(old, notOld);
|
||||
def->Class = nullptr; // reset pointer. Defaults should not have a valid class pointer.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,7 +208,6 @@ enum EObjectFlags
|
|||
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
|
||||
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
|
||||
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
|
||||
OF_SuperCall = 1 << 12, // A super call from the VM is about to be performed
|
||||
};
|
||||
|
||||
template<class T> class TObjPtr;
|
||||
|
@ -453,6 +452,8 @@ public:
|
|||
|
||||
void *ScriptVar(FName field, PType *type);
|
||||
|
||||
protected:
|
||||
|
||||
public:
|
||||
DObject ();
|
||||
DObject (PClass *inClass);
|
||||
|
|
|
@ -1782,6 +1782,18 @@ PClassPointer::PClassPointer(PClass *restrict)
|
|||
else mDescriptiveName = "ClassPointer";
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer - isCompatible
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PClassPointer::isCompatible(PType *type)
|
||||
{
|
||||
auto other = dyn_cast<PClassPointer>(type);
|
||||
return (other != nullptr && other->ClassRestriction->IsDescendantOf(ClassRestriction));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClassPointer :: IsMatch
|
||||
|
@ -3333,6 +3345,20 @@ void PClass::InitializeDefaults()
|
|||
{
|
||||
assert(Defaults == NULL);
|
||||
Defaults = (BYTE *)M_Malloc(Size);
|
||||
|
||||
// run the constructor on the defaults to set the vtbl pointer which is needed to run class-aware functions on them.
|
||||
// bSerialOverride prevents linking into the thinker chains.
|
||||
auto s = DThinker::bSerialOverride;
|
||||
DThinker::bSerialOverride = true;
|
||||
ConstructNative(Defaults);
|
||||
DThinker::bSerialOverride = s;
|
||||
// We must unlink the defaults from the class list because it's just a static block of data to the engine.
|
||||
DObject *optr = (DObject*)Defaults;
|
||||
GC::Root = optr->ObjNext;
|
||||
optr->ObjNext = nullptr;
|
||||
optr->SetClass(this);
|
||||
|
||||
|
||||
if (ParentClass->Defaults != NULL)
|
||||
{
|
||||
memcpy(Defaults, ParentClass->Defaults, ParentClass->Size);
|
||||
|
|
|
@ -599,6 +599,7 @@ public:
|
|||
|
||||
// this is only here to block PPointer's implementation
|
||||
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) const override {}
|
||||
bool isCompatible(PType *type);
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
@ -639,6 +640,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
|
||||
|
|
|
@ -1263,10 +1263,11 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags)
|
|||
|
||||
// Strip all current powers, unless moving in a hub and the power is okay to keep.
|
||||
item = p->mo->Inventory;
|
||||
auto ptype = PClass::FindActor(NAME_Powerup);
|
||||
while (item != NULL)
|
||||
{
|
||||
next = item->Inventory;
|
||||
if (item->IsKindOf (RUNTIME_CLASS(APowerup)))
|
||||
if (item->IsKindOf (ptype))
|
||||
{
|
||||
if (deathmatch || ((mode != FINISH_SameHub || !(item->ItemFlags & IF_HUBPOWER))
|
||||
&& !(item->ItemFlags & IF_PERSISTENTPOWER))) // Keep persistent powers in non-deathmatch games
|
||||
|
|
|
@ -48,100 +48,13 @@ IMPLEMENT_CLASS(APowerup, false, false)
|
|||
// Powerup-Giver -------------------------------------------------------------
|
||||
|
||||
|
||||
IMPLEMENT_CLASS(APowerupGiver, false, true)
|
||||
|
||||
IMPLEMENT_POINTERS_START(APowerupGiver)
|
||||
IMPLEMENT_POINTER(PowerupType)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
DEFINE_FIELD(APowerupGiver, PowerupType)
|
||||
DEFINE_FIELD(APowerupGiver, EffectTics)
|
||||
DEFINE_FIELD(APowerupGiver, BlendColor)
|
||||
DEFINE_FIELD(APowerupGiver, Mode)
|
||||
DEFINE_FIELD(APowerupGiver, Strength)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerupGiver :: Use
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool APowerupGiver::Use (bool pickup)
|
||||
{
|
||||
if (PowerupType == NULL) return true; // item is useless
|
||||
if (Owner == nullptr) return true;
|
||||
|
||||
APowerup *power = static_cast<APowerup *> (Spawn (PowerupType));
|
||||
|
||||
if (EffectTics != 0)
|
||||
{
|
||||
power->EffectTics = EffectTics;
|
||||
}
|
||||
if (BlendColor != 0)
|
||||
{
|
||||
if (BlendColor != MakeSpecialColormap(65535)) power->BlendColor = BlendColor;
|
||||
else power->BlendColor = 0;
|
||||
}
|
||||
if (Mode != NAME_None)
|
||||
{
|
||||
power->Mode = Mode;
|
||||
}
|
||||
if (Strength != 0)
|
||||
{
|
||||
power->Strength = Strength;
|
||||
}
|
||||
|
||||
power->ItemFlags |= ItemFlags & (IF_ALWAYSPICKUP|IF_ADDITIVETIME|IF_NOTELEPORTFREEZE);
|
||||
if (power->CallTryPickup (Owner))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
power->GoAwayAndDie ();
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerupGiver :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerupGiver::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
auto def = (APowerupGiver*)GetDefault();
|
||||
arc("poweruptype", PowerupType, def->PowerupType)
|
||||
("effecttics", EffectTics, def->EffectTics)
|
||||
("blendcolor", BlendColor, def->BlendColor)
|
||||
("mode", Mode, def->Mode)
|
||||
("strength", Strength, def->Strength);
|
||||
}
|
||||
|
||||
// Powerup -------------------------------------------------------------------
|
||||
|
||||
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,438 +69,6 @@ void APowerup::Serialize(FSerializer &arc)
|
|||
arc("effecttics", EffectTics, def->EffectTics)
|
||||
("blendcolor", BlendColor, def->BlendColor)
|
||||
("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;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerup :: OwnerDied
|
||||
//
|
||||
// Powerups don't last beyond death.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerup::OwnerDied ()
|
||||
{
|
||||
Destroy ();
|
||||
}
|
||||
|
||||
// Invulnerability Powerup ---------------------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS(APowerInvulnerable, false, false)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerInvulnerable :: InitEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerInvulnerable::InitEffect ()
|
||||
{
|
||||
Super::InitEffect();
|
||||
Owner->effects &= ~FX_RESPAWNINVUL;
|
||||
Owner->flags2 |= MF2_INVULNERABLE;
|
||||
if (Mode == NAME_None && Owner->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
|
||||
{
|
||||
Mode = static_cast<PClassPlayerPawn *>(Owner->GetClass())->InvulMode;
|
||||
}
|
||||
if (Mode == NAME_Reflective)
|
||||
{
|
||||
Owner->flags2 |= MF2_REFLECTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerInvulnerable :: DoEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerInvulnerable::DoEffect ()
|
||||
{
|
||||
Super::DoEffect ();
|
||||
|
||||
if (Owner == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Mode == NAME_Ghost)
|
||||
{
|
||||
if (!(Owner->flags & MF_SHADOW))
|
||||
{
|
||||
// Don't mess with the translucency settings if an
|
||||
// invisibility powerup is active.
|
||||
Owner->RenderStyle = STYLE_Translucent;
|
||||
if (!(level.time & 7) && Owner->Alpha > 0 && Owner->Alpha < 1)
|
||||
{
|
||||
if (Owner->Alpha == HX_SHADOW)
|
||||
{
|
||||
Owner->Alpha = HX_ALTSHADOW;
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner->Alpha = 0;
|
||||
Owner->flags2 |= MF2_NONSHOOTABLE;
|
||||
}
|
||||
}
|
||||
if (!(level.time & 31))
|
||||
{
|
||||
if (Owner->Alpha == 0)
|
||||
{
|
||||
Owner->flags2 &= ~MF2_NONSHOOTABLE;
|
||||
Owner->Alpha = HX_ALTSHADOW;
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner->Alpha = HX_SHADOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner->flags2 &= ~MF2_NONSHOOTABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerInvulnerable :: EndEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerInvulnerable::EndEffect ()
|
||||
{
|
||||
Super::EndEffect();
|
||||
|
||||
if (Owner == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Owner->flags2 &= ~MF2_INVULNERABLE;
|
||||
Owner->effects &= ~FX_RESPAWNINVUL;
|
||||
if (Mode == NAME_Ghost)
|
||||
{
|
||||
Owner->flags2 &= ~MF2_NONSHOOTABLE;
|
||||
if (!(Owner->flags & MF_SHADOW))
|
||||
{
|
||||
// Don't mess with the translucency settings if an
|
||||
// invisibility powerup is active.
|
||||
Owner->RenderStyle = STYLE_Normal;
|
||||
Owner->Alpha = 1.;
|
||||
}
|
||||
}
|
||||
else if (Mode == NAME_Reflective)
|
||||
{
|
||||
Owner->flags2 &= ~MF2_REFLECTIVE;
|
||||
}
|
||||
|
||||
if (Owner->player != NULL)
|
||||
{
|
||||
Owner->player->fixedcolormap = NOFIXEDCOLORMAP;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
IMPLEMENT_POINTERS_START(APowerMorph)
|
||||
IMPLEMENT_POINTER(PlayerClass)
|
||||
IMPLEMENT_POINTER(MorphFlash)
|
||||
IMPLEMENT_POINTER(UnMorphFlash)
|
||||
IMPLEMENT_POINTERS_END
|
||||
|
||||
|
||||
DEFINE_FIELD(APowerMorph, PlayerClass)
|
||||
DEFINE_FIELD(APowerMorph, MorphFlash)
|
||||
DEFINE_FIELD(APowerMorph, UnMorphFlash)
|
||||
DEFINE_FIELD(APowerMorph, MorphStyle)
|
||||
DEFINE_FIELD(APowerMorph, MorphedPlayer)
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerMorph :: Serialize
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void APowerMorph::Serialize(FSerializer &arc)
|
||||
{
|
||||
Super::Serialize (arc);
|
||||
arc("playerclass", PlayerClass)
|
||||
("morphstyle", MorphStyle)
|
||||
("morphflash", MorphFlash)
|
||||
("unmorphflash", UnMorphFlash)
|
||||
("morphedplayer", MorphedPlayer);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,85 +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);
|
||||
};
|
||||
|
||||
// An artifact is an item that gives the player a powerup when activated.
|
||||
class APowerupGiver : public AInventory
|
||||
{
|
||||
DECLARE_CLASS (APowerupGiver, AInventory)
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
virtual bool Use (bool pickup) override;
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
|
||||
|
||||
PClassActor *PowerupType;
|
||||
int EffectTics; // Non-0 to override the powerup's default tics
|
||||
PalEntry BlendColor; // Non-0 to override the powerup's default blend
|
||||
FNameNoInit Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility
|
||||
double Strength; // Meaning depends on powerup - currently used only by Invisibility
|
||||
};
|
||||
|
||||
class APowerInvulnerable : public APowerup
|
||||
{
|
||||
DECLARE_CLASS (APowerInvulnerable, APowerup)
|
||||
protected:
|
||||
virtual void InitEffect () override;
|
||||
virtual void DoEffect () override;
|
||||
virtual void EndEffect () override;
|
||||
};
|
||||
|
||||
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 )
|
||||
HAS_OBJECT_POINTERS
|
||||
public:
|
||||
|
||||
virtual void Serialize(FSerializer &arc) override;
|
||||
|
||||
// Variables
|
||||
PClassPlayerPawn *PlayerClass;
|
||||
PClassActor *MorphFlash, *UnMorphFlash;
|
||||
int MorphStyle;
|
||||
player_t *MorphedPlayer;
|
||||
};
|
||||
|
||||
#endif //__A_ARTIFACTS_H__
|
||||
|
|
|
@ -368,18 +368,6 @@ void AInventory::CallDoEffect()
|
|||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AInventory :: OwnerDied
|
||||
//
|
||||
// Items receive this message when their owners die.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void AInventory::OwnerDied ()
|
||||
{
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// AInventory :: HandlePickup
|
||||
|
@ -1348,7 +1336,7 @@ bool AInventory::TryPickup (AActor *&toucher)
|
|||
}
|
||||
// The item is placed in the inventory just long enough to be used.
|
||||
toucher->AddInventory (this);
|
||||
bool usegood = Use (true);
|
||||
bool usegood = CallUse (true);
|
||||
toucher->RemoveInventory (this);
|
||||
|
||||
if (usegood)
|
||||
|
|
|
@ -138,8 +138,6 @@ public:
|
|||
// virtual on the script side only.
|
||||
double GetSpeedFactor();
|
||||
bool GetNoTeleportFreeze();
|
||||
// Stuff for later when more features are exported.
|
||||
virtual void OwnerDied();
|
||||
|
||||
|
||||
bool GoAway();
|
||||
|
|
|
@ -1288,6 +1288,19 @@ bool FWeaponSlots::LocateWeapon (PClassWeapon *type, int *const slot, int *const
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FWeaponSlots, LocateWeapon)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FWeaponSlots);
|
||||
PARAM_CLASS(weap, AWeapon);
|
||||
int slot = 0, index = 0;
|
||||
bool retv = self->LocateWeapon(weap, &slot, &index);
|
||||
if (numret >= 1) ret[0].SetInt(retv);
|
||||
if (numret >= 2) ret[1].SetInt(slot);
|
||||
if (numret >= 3) ret[2].SetInt(index);
|
||||
return MIN(numret, 3);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindMostRecentWeapon
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
@ -593,11 +594,17 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor
|
|||
|
||||
void EndAllPowerupEffects(AInventory *item)
|
||||
{
|
||||
auto ptype = PClass::FindActor(NAME_Powerup);
|
||||
while (item != NULL)
|
||||
{
|
||||
if (item->IsKindOf(RUNTIME_CLASS(APowerup)))
|
||||
if (item->IsKindOf(ptype))
|
||||
{
|
||||
static_cast<APowerup *>(item)->CallEndEffect();
|
||||
IFVIRTUALPTRNAME(item, NAME_Powerup, EndEffect)
|
||||
{
|
||||
VMValue params[1] = { item };
|
||||
VMFrameStack stack;
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
item = item->Inventory;
|
||||
}
|
||||
|
@ -613,11 +620,17 @@ void EndAllPowerupEffects(AInventory *item)
|
|||
|
||||
void InitAllPowerupEffects(AInventory *item)
|
||||
{
|
||||
auto ptype = PClass::FindActor(NAME_Powerup);
|
||||
while (item != NULL)
|
||||
{
|
||||
if (item->IsKindOf(RUNTIME_CLASS(APowerup)))
|
||||
if (item->IsKindOf(ptype))
|
||||
{
|
||||
static_cast<APowerup *>(item)->CallInitEffect();
|
||||
IFVIRTUALPTRNAME(item, NAME_Powerup, EndEffect)
|
||||
{
|
||||
VMValue params[1] = { item };
|
||||
VMFrameStack stack;
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
|
||||
}
|
||||
}
|
||||
item = item->Inventory;
|
||||
}
|
||||
|
|
|
@ -1158,10 +1158,10 @@ class CommandDrawNumber : public CommandDrawString
|
|||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
inventoryItem = PClass::FindActor(sc.String);
|
||||
if(inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(inventoryItem))
|
||||
if(inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(inventoryItem))
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
inventoryItem = RUNTIME_CLASS(APowerupGiver);
|
||||
inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
||||
}
|
||||
|
||||
if(parenthesized) sc.MustGetToken(')');
|
||||
|
@ -1433,11 +1433,14 @@ class CommandDrawNumber : public CommandDrawString
|
|||
break;
|
||||
case POWERUPTIME:
|
||||
{
|
||||
//Get the PowerupType and check to see if the player has any in inventory.
|
||||
PClassActor* powerupType = ((APowerupGiver*) GetDefaultByType(inventoryItem))->PowerupType;
|
||||
APowerup* powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType);
|
||||
if(powerup != NULL)
|
||||
num = powerup->EffectTics / TICRATE + 1;
|
||||
// num = statusBar.CPlayer.mo.GetEffectTicsForItem(inventoryItem) / TICRATE + 1;
|
||||
static VMFunction *func = nullptr;
|
||||
if (func == nullptr) func = static_cast<PFunction*>(RUNTIME_CLASS(APlayerPawn)->Symbols.FindSymbol("GetEffectTicsForItem", false))->Variants[0].Implementation;
|
||||
VMValue params[] = { statusBar->CPlayer->mo, inventoryItem };
|
||||
int retv;
|
||||
VMReturn ret(&retv);
|
||||
GlobalVMStack.Call(func, params, 2, &ret, 1);
|
||||
num = retv / TICRATE + 1;
|
||||
break;
|
||||
}
|
||||
case INVENTORY:
|
||||
|
@ -2655,10 +2658,10 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
if(!parenthesized || !sc.CheckToken(TK_StringConst))
|
||||
sc.MustGetToken(TK_Identifier);
|
||||
data.inventoryItem = PClass::FindActor(sc.String);
|
||||
if(data.inventoryItem == NULL || !RUNTIME_CLASS(APowerupGiver)->IsAncestorOf(data.inventoryItem))
|
||||
if(data.inventoryItem == NULL || !PClass::FindActor(NAME_PowerupGiver)->IsAncestorOf(data.inventoryItem))
|
||||
{
|
||||
sc.ScriptMessage("'%s' is not a type of PowerupGiver.", sc.String);
|
||||
data.inventoryItem = RUNTIME_CLASS(APowerupGiver);
|
||||
data.inventoryItem = PClass::FindActor(NAME_PowerupGiver);
|
||||
}
|
||||
|
||||
if(parenthesized) sc.MustGetToken(')');
|
||||
|
@ -2822,18 +2825,16 @@ class CommandDrawBar : public SBarInfoCommand
|
|||
break;
|
||||
case POWERUPTIME:
|
||||
{
|
||||
//Get the PowerupType and check to see if the player has any in inventory.
|
||||
APowerupGiver *powerupGiver = (APowerupGiver*) GetDefaultByType(data.inventoryItem);
|
||||
PClassActor *powerupType = powerupGiver->PowerupType;
|
||||
APowerup *powerup = (APowerup*) statusBar->CPlayer->mo->FindInventory(powerupType);
|
||||
if(powerup != NULL && powerupType != NULL && powerupGiver != NULL)
|
||||
{
|
||||
value = powerup->EffectTics + 1;
|
||||
if(powerupGiver->EffectTics == 0) //if 0 we need to get the default from the powerup
|
||||
max = ((APowerup*) GetDefaultByType(powerupType))->EffectTics + 1;
|
||||
else
|
||||
max = powerupGiver->EffectTics + 1;
|
||||
}
|
||||
static VMFunction *func = nullptr;
|
||||
if (func == nullptr) func = static_cast<PFunction*>(RUNTIME_CLASS(APlayerPawn)->Symbols.FindSymbol("GetEffectTicsForItem", false))->Variants[0].Implementation;
|
||||
VMValue params[] = { statusBar->CPlayer->mo, data.inventoryItem };
|
||||
VMReturn ret[2];
|
||||
int ival;
|
||||
ret[0].IntAt(&ival);
|
||||
ret[1].IntAt(&max);
|
||||
GlobalVMStack.Call(func, params, 2, ret, 2);
|
||||
value = ival + 1;
|
||||
max++;
|
||||
break;
|
||||
}
|
||||
case SAVEPERCENT:
|
||||
|
|
|
@ -45,6 +45,10 @@
|
|||
|
||||
gameinfo_t gameinfo;
|
||||
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, backpacktype)
|
||||
DEFINE_FIELD_X(GameInfoStruct, gameinfo_t, Armor2Percent)
|
||||
|
||||
|
||||
const char *GameNames[17] =
|
||||
{
|
||||
NULL, "Doom", "Heretic", NULL, "Hexen", NULL, NULL, NULL, "Strife", NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Chex"
|
||||
|
|
2
src/gi.h
2
src/gi.h
|
@ -148,7 +148,7 @@ struct gameinfo_t
|
|||
FString translator;
|
||||
DWORD defaultbloodcolor;
|
||||
DWORD defaultbloodparticlecolor;
|
||||
FString backpacktype;
|
||||
FName backpacktype;
|
||||
FString statusbar;
|
||||
FString intermissionMusic;
|
||||
int intermissionOrder;
|
||||
|
|
442
src/m_cheat.cpp
442
src/m_cheat.cpp
|
@ -50,6 +50,7 @@
|
|||
#include "a_armor.h"
|
||||
#include "a_ammo.h"
|
||||
#include "g_levellocals.h"
|
||||
#include "virtual.h"
|
||||
|
||||
// [RH] Actually handle the cheat. The cheat code in st_stuff.c now just
|
||||
// writes some bytes to the network data stream, and the network code
|
||||
|
@ -324,16 +325,10 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
}
|
||||
else
|
||||
{
|
||||
player->mo->Revive();
|
||||
player->playerstate = PST_LIVE;
|
||||
player->health = player->mo->health = player->mo->GetDefault()->health;
|
||||
player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight;
|
||||
player->mo->flags = player->mo->GetDefault()->flags;
|
||||
player->mo->flags2 = player->mo->GetDefault()->flags2;
|
||||
player->mo->flags3 = player->mo->GetDefault()->flags3;
|
||||
player->mo->flags4 = player->mo->GetDefault()->flags4;
|
||||
player->mo->flags5 = player->mo->GetDefault()->flags5;
|
||||
player->mo->flags6 = player->mo->GetDefault()->flags6;
|
||||
player->mo->flags7 = player->mo->GetDefault()->flags7;
|
||||
player->mo->renderflags &= ~RF_INVISIBLE;
|
||||
player->mo->Height = player->mo->GetDefault()->Height;
|
||||
player->mo->radius = player->mo->GetDefault()->radius;
|
||||
|
@ -344,7 +339,6 @@ void cht_DoCheat (player_t *player, int cheat)
|
|||
{
|
||||
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
|
||||
}
|
||||
player->mo->DamageType = NAME_None;
|
||||
if (player->ReadyWeapon != nullptr)
|
||||
{
|
||||
P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetUpState());
|
||||
|
@ -588,434 +582,24 @@ const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quic
|
|||
|
||||
void cht_Give (player_t *player, const char *name, int amount)
|
||||
{
|
||||
enum { ALL_NO, ALL_YES, ALL_YESYES } giveall;
|
||||
int i;
|
||||
PClassActor *type;
|
||||
if (player->mo == nullptr) return;
|
||||
|
||||
if (player != &players[consoleplayer])
|
||||
Printf ("%s is a cheater: give %s\n", player->userinfo.GetName(), name);
|
||||
|
||||
if (player->mo == NULL || player->health <= 0)
|
||||
IFVIRTUALPTR(player->mo, APlayerPawn, CheatGive)
|
||||
{
|
||||
return;
|
||||
VMValue params[3] = { player->mo, FString(name), amount };
|
||||
GlobalVMStack.Call(func, params, 3, nullptr, 0);
|
||||
}
|
||||
|
||||
giveall = ALL_NO;
|
||||
if (stricmp (name, "all") == 0)
|
||||
{
|
||||
giveall = ALL_YES;
|
||||
}
|
||||
else if (stricmp (name, "everything") == 0)
|
||||
{
|
||||
giveall = ALL_YESYES;
|
||||
}
|
||||
|
||||
if (stricmp (name, "health") == 0)
|
||||
{
|
||||
if (amount > 0)
|
||||
{
|
||||
player->mo->health += amount;
|
||||
player->health = player->mo->health;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->health = player->mo->health = player->mo->GetMaxHealth();
|
||||
}
|
||||
}
|
||||
|
||||
if (giveall || stricmp (name, "backpack") == 0)
|
||||
{
|
||||
// Select the correct type of backpack based on the game
|
||||
type = PClass::FindActor(gameinfo.backpacktype);
|
||||
if (type != NULL)
|
||||
{
|
||||
player->mo->GiveInventory(static_cast<PClassInventory *>(type), 1, true);
|
||||
}
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || stricmp (name, "ammo") == 0)
|
||||
{
|
||||
// Find every unique type of ammo. Give it to the player if
|
||||
// he doesn't have it already, and set each to its maximum.
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
PClassActor *type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->ParentClass == RUNTIME_CLASS(AAmmo))
|
||||
{
|
||||
PClassInventory *atype = static_cast<PClassInventory *>(type);
|
||||
AInventory *ammo = player->mo->FindInventory(atype);
|
||||
if (ammo == NULL)
|
||||
{
|
||||
ammo = static_cast<AInventory *>(Spawn (atype));
|
||||
ammo->AttachToOwner (player->mo);
|
||||
ammo->Amount = ammo->MaxAmount;
|
||||
}
|
||||
else if (ammo->Amount < ammo->MaxAmount)
|
||||
{
|
||||
ammo->Amount = ammo->MaxAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || stricmp (name, "armor") == 0)
|
||||
{
|
||||
if (gameinfo.gametype != GAME_Hexen)
|
||||
{
|
||||
ABasicArmorPickup *armor = Spawn<ABasicArmorPickup> ();
|
||||
armor->SaveAmount = 100*deh.BlueAC;
|
||||
armor->SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : 0.5;
|
||||
if (!armor->CallTryPickup (player->mo))
|
||||
{
|
||||
armor->Destroy ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
AHexenArmor *armor = Spawn<AHexenArmor> ();
|
||||
armor->health = i;
|
||||
armor->Amount = 0;
|
||||
if (!armor->CallTryPickup (player->mo))
|
||||
{
|
||||
armor->Destroy ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || stricmp (name, "keys") == 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey)))
|
||||
{
|
||||
AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]);
|
||||
if (key->KeyNumber != 0)
|
||||
{
|
||||
key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClassActor::AllActorClasses[i])));
|
||||
if (!key->CallTryPickup (player->mo))
|
||||
{
|
||||
key->Destroy ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || stricmp (name, "weapons") == 0)
|
||||
{
|
||||
AWeapon *savedpending = player->PendingWeapon;
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
// Don't give replaced weapons unless the replacement was done by Dehacked.
|
||||
if (type != RUNTIME_CLASS(AWeapon) &&
|
||||
type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) &&
|
||||
(static_cast<PClassActor *>(type)->GetReplacement() == type ||
|
||||
static_cast<PClassActor *>(type)->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup))))
|
||||
{
|
||||
// Give the weapon only if it belongs to the current game or
|
||||
if (player->weapons.LocateWeapon(static_cast<PClassWeapon*>(type), NULL, NULL))
|
||||
{
|
||||
AWeapon *def = (AWeapon*)GetDefaultByType (type);
|
||||
if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON))
|
||||
{
|
||||
player->mo->GiveInventory(static_cast<PClassInventory *>(type), 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
player->PendingWeapon = savedpending;
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || stricmp (name, "artifacts") == 0)
|
||||
{
|
||||
auto pitype = PClass::FindActor(NAME_PuzzleItem);
|
||||
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
if (type->IsDescendantOf (RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
AInventory *def = (AInventory*)GetDefaultByType (type);
|
||||
if (def->Icon.isValid() && def->MaxAmount > 1 &&
|
||||
!type->IsDescendantOf (pitype) &&
|
||||
!type->IsDescendantOf (RUNTIME_CLASS(APowerup)) &&
|
||||
!type->IsDescendantOf (RUNTIME_CLASS(AArmor)))
|
||||
{
|
||||
// Do not give replaced items unless using "give everything"
|
||||
if (giveall == ALL_YESYES || type->GetReplacement() == type)
|
||||
{
|
||||
player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount <= 0 ? def->MaxAmount : amount, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || stricmp (name, "puzzlepieces") == 0)
|
||||
{
|
||||
auto pitype = PClass::FindActor(NAME_PuzzleItem);
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
if (type->IsDescendantOf (pitype))
|
||||
{
|
||||
AInventory *def = (AInventory*)GetDefaultByType (type);
|
||||
if (def->Icon.isValid())
|
||||
{
|
||||
// Do not give replaced items unless using "give everything"
|
||||
if (giveall == ALL_YESYES || type->GetReplacement() == type)
|
||||
{
|
||||
player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount <= 0 ? def->MaxAmount : amount, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall)
|
||||
return;
|
||||
|
||||
type = PClass::FindActor(name);
|
||||
if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AInventory)))
|
||||
{
|
||||
if (player == &players[consoleplayer])
|
||||
Printf ("Unknown item \"%s\"\n", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void cht_Take (player_t *player, const char *name, int amount)
|
||||
{
|
||||
bool takeall;
|
||||
PClassActor *type;
|
||||
if (player->mo == nullptr) return;
|
||||
|
||||
if (player->mo == NULL || player->health <= 0)
|
||||
IFVIRTUALPTR(player->mo, APlayerPawn, CheatTake)
|
||||
{
|
||||
return;
|
||||
VMValue params[3] = { player->mo, FString(name), amount };
|
||||
GlobalVMStack.Call(func, params, 3, nullptr, 0);
|
||||
}
|
||||
|
||||
takeall = (stricmp (name, "all") == 0);
|
||||
|
||||
if (!takeall && stricmp (name, "health") == 0)
|
||||
{
|
||||
if (player->mo->health - amount <= 0
|
||||
|| player->health - amount <= 0
|
||||
|| amount == 0)
|
||||
{
|
||||
|
||||
cht_Suicide (player);
|
||||
|
||||
if (player == &players[consoleplayer])
|
||||
C_HideConsole ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
if (player->mo)
|
||||
{
|
||||
player->mo->health -= amount;
|
||||
player->health = player->mo->health;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->health -= amount;
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || stricmp (name, "backpack") == 0)
|
||||
{
|
||||
// Take away all types of backpacks the player might own.
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
PClass *type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->IsDescendantOf(PClass::FindClass(NAME_BackpackItem)))
|
||||
{
|
||||
AInventory *pack = player->mo->FindInventory(static_cast<PClassActor *>(type));
|
||||
|
||||
if (pack)
|
||||
pack->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || stricmp (name, "ammo") == 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
PClass *type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->ParentClass == RUNTIME_CLASS (AAmmo))
|
||||
{
|
||||
AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type));
|
||||
|
||||
if (ammo)
|
||||
ammo->DepleteOrDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || stricmp (name, "armor") == 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->IsDescendantOf (RUNTIME_CLASS (AArmor)))
|
||||
{
|
||||
AInventory *armor = player->mo->FindInventory(static_cast<PClassActor *>(type));
|
||||
|
||||
if (armor)
|
||||
armor->DepleteOrDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || stricmp (name, "keys") == 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->IsDescendantOf (RUNTIME_CLASS (AKey)))
|
||||
{
|
||||
AActor *key = player->mo->FindInventory(static_cast<PClassActor *>(type));
|
||||
|
||||
if (key)
|
||||
key->Destroy ();
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || stricmp (name, "weapons") == 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type != RUNTIME_CLASS(AWeapon) &&
|
||||
type->IsDescendantOf (RUNTIME_CLASS (AWeapon)))
|
||||
{
|
||||
AActor *weapon = player->mo->FindInventory(static_cast<PClassActor *>(type));
|
||||
|
||||
if (weapon)
|
||||
weapon->Destroy ();
|
||||
|
||||
player->ReadyWeapon = nullptr;
|
||||
player->PendingWeapon = WP_NOCHANGE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || stricmp (name, "artifacts") == 0)
|
||||
{
|
||||
auto pitype = PClass::FindActor(NAME_PuzzleItem);
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->IsDescendantOf (RUNTIME_CLASS (AInventory)))
|
||||
{
|
||||
if (!type->IsDescendantOf (pitype) &&
|
||||
!type->IsDescendantOf (RUNTIME_CLASS (APowerup)) &&
|
||||
!type->IsDescendantOf (RUNTIME_CLASS (AArmor)) &&
|
||||
!type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) &&
|
||||
!type->IsDescendantOf (RUNTIME_CLASS (AKey)))
|
||||
{
|
||||
AActor *artifact = player->mo->FindInventory(static_cast<PClassActor *>(type));
|
||||
|
||||
if (artifact)
|
||||
artifact->Destroy ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || stricmp (name, "puzzlepieces") == 0)
|
||||
{
|
||||
auto pitype = PClass::FindActor(NAME_PuzzleItem);
|
||||
for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = PClassActor::AllActorClasses[i];
|
||||
|
||||
if (type->IsDescendantOf (pitype))
|
||||
{
|
||||
AActor *puzzlepiece = player->mo->FindInventory(static_cast<PClassActor *>(type));
|
||||
|
||||
if (puzzlepiece)
|
||||
puzzlepiece->Destroy ();
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall)
|
||||
return;
|
||||
|
||||
type = PClass::FindActor (name);
|
||||
if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS (AInventory)))
|
||||
{
|
||||
if (player == &players[consoleplayer])
|
||||
Printf ("Unknown item \"%s\"\n", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->mo->TakeInventory(type, amount ? amount : 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
class DSuicider : public DThinker
|
||||
|
@ -1070,6 +654,12 @@ void cht_Suicide (player_t *plyr)
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(APlayerPawn, CheatSuicide)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(APlayerPawn);
|
||||
cht_Suicide(self->player);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CCMD (mdk)
|
||||
{
|
||||
|
|
|
@ -706,6 +706,17 @@ xx(WBobSpeed)
|
|||
xx(PlayerClass)
|
||||
xx(Wi_NoAutostartMap)
|
||||
|
||||
xx(MorphStyle)
|
||||
xx(MorphFlash)
|
||||
xx(UnMorphFlash)
|
||||
xx(Powerup)
|
||||
xx(EffectTics)
|
||||
xx(PowerupGiver)
|
||||
xx(BlendColor)
|
||||
xx(Strength)
|
||||
xx(Mode)
|
||||
xx(PowerupType)
|
||||
|
||||
// Decorate compatibility functions
|
||||
xx(BuiltinTypeCheck)
|
||||
xx(BuiltinRandom)
|
||||
|
|
|
@ -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)
|
||||
|
@ -5713,7 +5719,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
|
|||
if (argCount >= 2)
|
||||
{
|
||||
PClassActor *powerupclass = PClass::FindActor(FBehavior::StaticLookupString(args[1]));
|
||||
if (powerupclass == NULL || !RUNTIME_CLASS(APowerup)->IsAncestorOf(powerupclass))
|
||||
if (powerupclass == NULL || !powerupclass->IsDescendantOf(PClass::FindActor(NAME_Powerup)))
|
||||
{
|
||||
Printf("'%s' is not a type of Powerup.\n", FBehavior::StaticLookupString(args[1]));
|
||||
return 0;
|
||||
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -1224,22 +1224,6 @@ DEFINE_ACTION_FUNCTION(AActor, CheckInventory)
|
|||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// State jump function
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_ACTION_FUNCTION(AActor, CheckArmorType)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_NAME (type);
|
||||
PARAM_INT_DEF(amount);
|
||||
|
||||
ABasicArmor *armor = (ABasicArmor *)self->FindInventory(NAME_BasicArmor);
|
||||
|
||||
ACTION_RETURN_BOOL(armor && armor->ArmorType == type && armor->Amount >= amount);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Parameterized version of A_Explode
|
||||
|
|
|
@ -357,15 +357,19 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
|
|||
static int dieticks[MAXPLAYERS]; // [ZzZombo] not used? Except if for peeking in debugger...
|
||||
int pnum = int(this->player-players);
|
||||
dieticks[pnum] = gametic;
|
||||
fprintf (debugfile, "died (%d) on tic %d (%s)\n", pnum, gametic,
|
||||
this->player->cheats&CF_PREDICTING?"predicting":"real");
|
||||
fprintf(debugfile, "died (%d) on tic %d (%s)\n", pnum, gametic,
|
||||
this->player->cheats&CF_PREDICTING ? "predicting" : "real");
|
||||
}
|
||||
|
||||
// [RH] Notify this actor's items.
|
||||
for (AInventory *item = Inventory; item != NULL; )
|
||||
{
|
||||
AInventory *next = item->Inventory;
|
||||
item->OwnerDied();
|
||||
IFVIRTUALPTR(item, AInventory, OwnerDied)
|
||||
{
|
||||
VMValue params[1] = { item };
|
||||
GlobalVMStack.Call(func, params, 1, nullptr, 0);
|
||||
}
|
||||
item = next;
|
||||
}
|
||||
|
||||
|
|
|
@ -822,11 +822,13 @@ bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat)
|
|||
return result;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, Inventory)
|
||||
DEFINE_ACTION_FUNCTION(AActor, GiveInventory)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT_NOT_NULL(item, AInventory);
|
||||
ACTION_RETURN_BOOL(self->UseInventory(item));
|
||||
PARAM_CLASS(type, AInventory);
|
||||
PARAM_INT(amount);
|
||||
PARAM_BOOL_DEF(givecheat);
|
||||
ACTION_RETURN_BOOL(self->GiveInventory(type, amount, givecheat));
|
||||
}
|
||||
|
||||
|
||||
|
@ -918,6 +920,16 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate
|
|||
return result;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, TakeInventory)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT_NOT_NULL(item, AInventory);
|
||||
PARAM_INT(amount);
|
||||
PARAM_BOOL_DEF(fromdecorate);
|
||||
PARAM_BOOL_DEF(notakeinfinite);
|
||||
self->RemoveInventory(item);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
|
@ -5369,15 +5381,13 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
|
|||
oldactor->DestroyAllInventory();
|
||||
}
|
||||
// [BC] Handle temporary invulnerability when respawned
|
||||
if ((state == PST_REBORN || state == PST_ENTER) &&
|
||||
(dmflags2 & DF2_YES_RESPAWN_INVUL) &&
|
||||
(multiplayer || alwaysapplydmflags))
|
||||
if (state == PST_REBORN || state == PST_ENTER)
|
||||
{
|
||||
APowerup *invul = static_cast<APowerup*>(p->mo->GiveInventoryType (RUNTIME_CLASS(APowerInvulnerable)));
|
||||
invul->EffectTics = 3*TICRATE;
|
||||
invul->BlendColor = 0; // don't mess with the view
|
||||
invul->ItemFlags |= IF_UNDROPPABLE; // Don't drop this
|
||||
p->mo->effects |= FX_RESPAWNINVUL; // [RH] special effect
|
||||
IFVIRTUALPTR(p->mo, APlayerPawn, OnRespawn)
|
||||
{
|
||||
VMValue param = p->mo;
|
||||
GlobalVMStack.Call(func, ¶m, 1, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (StatusBar != NULL && (playernum == consoleplayer || StatusBar->GetPlayer() == playernum))
|
||||
|
|
|
@ -638,6 +638,14 @@ void player_t::SendPitchLimits() const
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
DEFINE_ACTION_FUNCTION(_PlayerInfo, GetUserName)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(player_t);
|
||||
ACTION_RETURN_STRING(self->userinfo.GetName());
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APlayerPawn
|
||||
|
@ -1158,7 +1166,7 @@ void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
|
|||
}
|
||||
else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
|
||||
defitem == NULL &&
|
||||
item->IsKindOf(RUNTIME_CLASS(APowerupGiver)))
|
||||
item->IsKindOf(PClass::FindActor(NAME_PowerupGiver)))
|
||||
{
|
||||
item->Destroy();
|
||||
}
|
||||
|
|
|
@ -72,16 +72,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);
|
||||
|
||||
|
||||
|
|
|
@ -4362,9 +4362,8 @@ ExpEmit FxDotCross::Emit(VMFunctionBuilder *build)
|
|||
FxTypeCheck::FxTypeCheck(FxExpression *l, FxExpression *r)
|
||||
: FxExpression(EFX_TypeCheck, l->ScriptPosition)
|
||||
{
|
||||
left = new FxTypeCast(l, NewPointer(RUNTIME_CLASS(DObject)), false);
|
||||
right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), r);
|
||||
EmitTail = false;
|
||||
left = l;
|
||||
right = r;
|
||||
ValueType = TypeBool;
|
||||
}
|
||||
|
||||
|
@ -4389,9 +4388,27 @@ FxTypeCheck::~FxTypeCheck()
|
|||
FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx)
|
||||
{
|
||||
CHECKRESOLVED();
|
||||
// This must resolve the cast separately so that it can set the proper type for class descriptors.
|
||||
RESOLVE(left, ctx);
|
||||
RESOLVE(right, ctx);
|
||||
ABORT(right && left);
|
||||
|
||||
if (left->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
|
||||
{
|
||||
left = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), left);
|
||||
ClassCheck = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
left = new FxTypeCast(left, NewPointer(RUNTIME_CLASS(DObject)), false);
|
||||
ClassCheck = false;
|
||||
}
|
||||
right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), right);
|
||||
|
||||
RESOLVE(left, ctx);
|
||||
RESOLVE(right, ctx);
|
||||
ABORT(right && left);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -4408,7 +4425,8 @@ ExpEmit FxTypeCheck::EmitCommon(VMFunctionBuilder *build)
|
|||
castee.Free(build);
|
||||
casttype.Free(build);
|
||||
ExpEmit ares(build, REGT_POINTER);
|
||||
build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
|
||||
if (!ClassCheck) build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
|
||||
else build->Emit(casttype.Konst ? OP_DYNCASTC_K : OP_DYNCASTC_R, ares.RegNum, castee.RegNum, casttype.RegNum);
|
||||
return ares;
|
||||
}
|
||||
|
||||
|
@ -9938,37 +9956,76 @@ ExpEmit FxJumpStatement::Emit(VMFunctionBuilder *build)
|
|||
//==========================================================================
|
||||
|
||||
FxReturnStatement::FxReturnStatement(FxExpression *value, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_ReturnStatement, pos), Value(value)
|
||||
: FxExpression(EFX_ReturnStatement, pos)
|
||||
{
|
||||
if (value != nullptr) Args.Push(value);
|
||||
ValueType = TypeVoid;
|
||||
}
|
||||
|
||||
FxReturnStatement::FxReturnStatement(FArgumentList &values, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_ReturnStatement, pos)
|
||||
{
|
||||
Args = std::move(values);
|
||||
ValueType = TypeVoid;
|
||||
}
|
||||
|
||||
FxReturnStatement::~FxReturnStatement()
|
||||
{
|
||||
SAFE_DELETE(Value);
|
||||
}
|
||||
|
||||
FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
|
||||
{
|
||||
bool fail = false;
|
||||
CHECKRESOLVED();
|
||||
SAFE_RESOLVE_OPT(Value, ctx);
|
||||
for (auto &Value : Args)
|
||||
{
|
||||
SAFE_RESOLVE_OPT(Value, ctx);
|
||||
fail |= (Value == nullptr);
|
||||
}
|
||||
if (fail)
|
||||
{
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PPrototype *retproto;
|
||||
if (Value == nullptr)
|
||||
if (Args.Size() == 0)
|
||||
{
|
||||
TArray<PType *> none(0);
|
||||
retproto = NewPrototype(none, none);
|
||||
}
|
||||
else
|
||||
else if (Args.Size() == 1)
|
||||
{
|
||||
// If we already know the real return type we need at least try to cast the value to its proper type (unless in an anonymous function.)
|
||||
if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() > 0 && ctx.Function->SymbolName != NAME_None)
|
||||
{
|
||||
Value = new FxTypeCast(Value, ctx.ReturnProto->ReturnTypes[0], false, false);
|
||||
Value = Value->Resolve(ctx);
|
||||
ABORT(Value);
|
||||
Args[0] = new FxTypeCast(Args[0], ctx.ReturnProto->ReturnTypes[0], false, false);
|
||||
Args[0] = Args[0]->Resolve(ctx);
|
||||
ABORT(Args[0]);
|
||||
}
|
||||
retproto = Value->ReturnProto();
|
||||
retproto = Args[0]->ReturnProto();
|
||||
}
|
||||
else if (ctx.ReturnProto != nullptr && ctx.ReturnProto->ReturnTypes.Size() == Args.Size())
|
||||
{
|
||||
for (unsigned i = 0; i < Args.Size(); i++)
|
||||
{
|
||||
auto &Value = Args[0];
|
||||
Value = new FxTypeCast(Value, ctx.ReturnProto->ReturnTypes[i], false, false);
|
||||
Value = Value->Resolve(ctx);
|
||||
if (Value == nullptr) fail = true;
|
||||
}
|
||||
if (fail)
|
||||
{
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
return this; // no point calling CheckReturn here.
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Incorrect number of return values. Got %u, but expected %u", Args.Size(), ctx.ReturnProto->ReturnTypes.Size());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ctx.CheckReturn(retproto, ScriptPosition);
|
||||
|
@ -9978,8 +10035,20 @@ FxExpression *FxReturnStatement::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
TArray<ExpEmit> outs;
|
||||
|
||||
ExpEmit out(0, REGT_NIL);
|
||||
|
||||
// If there's structs to destroy here we need to emit all returns before destroying them.
|
||||
if (build->ConstructedStructs.Size())
|
||||
{
|
||||
for (auto ret : Args)
|
||||
{
|
||||
ExpEmit r = ret->Emit(build);
|
||||
outs.Push(r);
|
||||
}
|
||||
}
|
||||
|
||||
// call the destructors for all structs requiring one.
|
||||
// go in reverse order of construction
|
||||
for (int i = build->ConstructedStructs.Size() - 1; i >= 0; i--)
|
||||
|
@ -9995,19 +10064,19 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
|
|||
|
||||
// If we return nothing, use a regular RET opcode.
|
||||
// Otherwise just return the value we're given.
|
||||
if (Value == nullptr)
|
||||
if (Args.Size() == 0)
|
||||
{
|
||||
build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
|
||||
}
|
||||
else
|
||||
else if (Args.Size() == 1)
|
||||
{
|
||||
out = Value->Emit(build);
|
||||
out = outs.Size() > 0? outs[0] : Args[0]->Emit(build);
|
||||
|
||||
// Check if it is a function call that simplified itself
|
||||
// into a tail call in which case we don't emit anything.
|
||||
if (!out.Final)
|
||||
{
|
||||
if (Value->ValueType == TypeVoid)
|
||||
if (Args[0]->ValueType == TypeVoid)
|
||||
{ // Nothing is returned.
|
||||
build->Emit(OP_RET, RET_FINAL, REGT_NIL, 0);
|
||||
}
|
||||
|
@ -10017,6 +10086,14 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned i = 0; i < Args.Size(); i++)
|
||||
{
|
||||
out = outs.Size() > 0 ? outs[i] : Args[i]->Emit(build);
|
||||
build->Emit(OP_RET, i < Args.Size() - 1 ? i : i+RET_FINAL, EncodeRegType(out), out.RegNum);
|
||||
}
|
||||
}
|
||||
|
||||
out.Final = true;
|
||||
return out;
|
||||
|
@ -10024,9 +10101,9 @@ ExpEmit FxReturnStatement::Emit(VMFunctionBuilder *build)
|
|||
|
||||
VMFunction *FxReturnStatement::GetDirectFunction()
|
||||
{
|
||||
if (Value != nullptr)
|
||||
if (Args.Size() == 1)
|
||||
{
|
||||
return Value->GetDirectFunction();
|
||||
return Args[0]->GetDirectFunction();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -1086,7 +1086,7 @@ class FxTypeCheck : public FxExpression
|
|||
public:
|
||||
FxExpression *left;
|
||||
FxExpression *right;
|
||||
bool EmitTail;
|
||||
bool ClassCheck;
|
||||
|
||||
FxTypeCheck(FxExpression*, FxExpression*);
|
||||
~FxTypeCheck();
|
||||
|
@ -1911,10 +1911,11 @@ public:
|
|||
|
||||
class FxReturnStatement : public FxExpression
|
||||
{
|
||||
FxExpression *Value;
|
||||
FArgumentList Args;
|
||||
|
||||
public:
|
||||
FxReturnStatement(FxExpression *value, const FScriptPosition &pos);
|
||||
FxReturnStatement(FArgumentList &args, const FScriptPosition &pos);
|
||||
~FxReturnStatement();
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
|
|
|
@ -913,13 +913,14 @@ static void ParseActorProperty(FScanner &sc, Baggage &bag)
|
|||
|
||||
if (prop != NULL)
|
||||
{
|
||||
if (bag.Info->IsDescendantOf(*prop->cls))
|
||||
auto pcls = PClass::FindActor(prop->clsname);
|
||||
if (bag.Info->IsDescendantOf(pcls))
|
||||
{
|
||||
ParsePropertyParams(sc, prop, (AActor *)bag.Info->Defaults, bag);
|
||||
}
|
||||
else
|
||||
{
|
||||
sc.ScriptMessage("'%s' requires an actor of type '%s'\n", propname.GetChars(), (*prop->cls)->TypeName.GetChars());
|
||||
sc.ScriptMessage("'%s' requires an actor of type '%s'\n", propname.GetChars(), pcls->TypeName.GetChars());
|
||||
FScriptPosition::ErrorCounter++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,6 +187,7 @@ enum
|
|||
DEPF_HEXENBOUNCE,
|
||||
DEPF_DOOMBOUNCE,
|
||||
DEPF_INTERHUBSTRIP,
|
||||
DEPF_NOTRAIL,
|
||||
};
|
||||
|
||||
// Types of old style decorations
|
||||
|
@ -229,7 +230,7 @@ struct FPropertyInfo
|
|||
{
|
||||
const char *name;
|
||||
const char *params;
|
||||
const PClass * const *cls;
|
||||
const char *clsname;
|
||||
PropHandler Handler;
|
||||
int category;
|
||||
};
|
||||
|
@ -241,17 +242,24 @@ int MatchString (const char *in, const char **strings);
|
|||
#define DEFINE_PROPERTY_BASE(name, paramlist, clas, cat) \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \
|
||||
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
|
||||
{ #name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
|
||||
{ #name, #paramlist, #clas, (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
|
||||
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params)
|
||||
|
||||
#define DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \
|
||||
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
|
||||
{ #prefix"."#name, #paramlist, &RUNTIME_CLASS_CASTLESS(A##clas), (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
|
||||
{ #prefix"."#name, #paramlist, #clas, (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
|
||||
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
|
||||
static void Handler_##name##_##paramlist##_##clas(A##clas *defaults, PClassActor *info, Baggage &bag, FPropParam *params)
|
||||
|
||||
#define DEFINE_PREFIXED_SCRIPTED_PROPERTY_BASE(prefix, name, paramlist, clas, cat) \
|
||||
static void Handler_##name##_##paramlist##_##clas(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params); \
|
||||
static FPropertyInfo Prop_##name##_##paramlist##_##clas = \
|
||||
{ #prefix"."#name, #paramlist, #clas, (PropHandler)Handler_##name##_##paramlist##_##clas, cat }; \
|
||||
MSVC_PSEG FPropertyInfo *infoptr_##name##_##paramlist##_##clas GCC_PSEG = &Prop_##name##_##paramlist##_##clas; \
|
||||
static void Handler_##name##_##paramlist##_##clas(AActor *defaults, PClassActor *info, Baggage &bag, FPropParam *params)
|
||||
|
||||
|
||||
#define DEFINE_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_PROPERTY)
|
||||
#define DEFINE_INFO_PROPERTY(name, paramlist, clas) DEFINE_PROPERTY_BASE(name, paramlist, clas, CAT_INFO)
|
||||
|
@ -259,6 +267,9 @@ int MatchString (const char *in, const char **strings);
|
|||
#define DEFINE_CLASS_PROPERTY(name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(clas, name, paramlist, clas, CAT_PROPERTY)
|
||||
#define DEFINE_CLASS_PROPERTY_PREFIX(prefix, name, paramlist, clas) DEFINE_PREFIXED_PROPERTY_BASE(prefix, name, paramlist, clas, CAT_PROPERTY)
|
||||
|
||||
#define DEFINE_SCRIPTED_PROPERTY(name, paramlist, clas) DEFINE_PREFIXED_SCRIPTED_PROPERTY_BASE(clas, name, paramlist, clas, CAT_PROPERTY)
|
||||
#define DEFINE_SCRIPTED_PROPERTY_PREFIX(prefix, name, paramlist, clas) DEFINE_PREFIXED_SCRIPTED_PROPERTY_BASE(prefix, name, paramlist, clas, CAT_PROPERTY)
|
||||
|
||||
#define PROP_PARM_COUNT (params[0].i)
|
||||
|
||||
#define PROP_STRING_PARM(var, no) \
|
||||
|
|
|
@ -100,6 +100,7 @@ static FFlagDef InternalActorFlagDefs[]=
|
|||
DEFINE_FLAG(MF6, INTRYMOVE, AActor, flags6),
|
||||
DEFINE_FLAG(MF7, HANDLENODELAY, AActor, flags7),
|
||||
DEFINE_FLAG(MF7, FLYCHEAT, AActor, flags7),
|
||||
DEFINE_FLAG(FX, RESPAWNINVUL, AActor, effects),
|
||||
};
|
||||
|
||||
|
||||
|
@ -461,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[] =
|
||||
|
@ -472,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))
|
||||
|
||||
|
@ -547,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;
|
||||
}
|
||||
|
||||
|
@ -782,6 +788,11 @@ void InitThingdef()
|
|||
PField *dehf = new PField("deh", dstruct, VARF_Native | VARF_Static, (intptr_t)&deh);
|
||||
GlobalSymbols.AddSymbol(dehf);
|
||||
|
||||
// set up a variable for the global gameinfo data
|
||||
PStruct *gistruct = NewNativeStruct("GameInfoStruct", nullptr);
|
||||
PField *gi = new PField("gameinfo", gistruct, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&gameinfo);
|
||||
GlobalSymbols.AddSymbol(gi);
|
||||
|
||||
// set up a variable for the global players array.
|
||||
PStruct *pstruct = NewNativeStruct("PlayerInfo", nullptr);
|
||||
pstruct->Size = sizeof(player_t);
|
||||
|
@ -790,6 +801,9 @@ void InitThingdef()
|
|||
PField *playerf = new PField("players", parray, VARF_Native | VARF_Static, (intptr_t)&players);
|
||||
GlobalSymbols.AddSymbol(playerf);
|
||||
|
||||
pstruct->AddNativeField("weapons", NewNativeStruct("WeaponSlots", nullptr), myoffsetof(player_t, weapons), VARF_Native);
|
||||
|
||||
|
||||
parray = NewArray(TypeBool, MAXPLAYERS);
|
||||
playerf = new PField("playeringame", parray, VARF_Native | VARF_Static | VARF_ReadOnly, (intptr_t)&playeringame);
|
||||
GlobalSymbols.AddSymbol(playerf);
|
||||
|
@ -925,7 +939,7 @@ DEFINE_ACTION_FUNCTION(FString, Replace)
|
|||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_STRING(s1);
|
||||
PARAM_STRING(s2);
|
||||
self->Substitute(*s1, *s2);
|
||||
self->Substitute(s1, s2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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:
|
||||
break; // silence GCC
|
||||
}
|
||||
|
@ -439,12 +456,45 @@ int MatchString (const char *in, const char **strings)
|
|||
return -1;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Get access to scripted fields.
|
||||
// Fortunately there's only a handful that cannot be done with a
|
||||
// scripted property definition, most notably the powerup and morph stuff.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool PointerCheck(PType *symtype, PType *checktype)
|
||||
{
|
||||
auto symptype = dyn_cast<PClassPointer>(symtype);
|
||||
auto checkptype = dyn_cast<PClassPointer>(checktype);
|
||||
return symptype != nullptr && checkptype != nullptr && symptype->ClassRestriction->IsDescendantOf(checkptype->ClassRestriction);
|
||||
}
|
||||
|
||||
static void *ScriptVar(DObject *obj, PClass *cls, FName field, PType *type)
|
||||
{
|
||||
auto sym = dyn_cast<PField>(cls->Symbols.FindSymbol(field, true));
|
||||
if (sym && (sym->Type == type || PointerCheck(sym->Type, type)))
|
||||
{
|
||||
return (((char*)obj) + sym->Offset);
|
||||
}
|
||||
I_Error("Variable %s of type %s not found in %s\n", field.GetChars(), type->DescriptiveName(), cls->TypeName.GetChars());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T &TypedScriptVar(DObject *obj, PClass *cls, FName field, PType *type)
|
||||
{
|
||||
return *(T*)ScriptVar(obj, cls, field, type);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Info Property handlers
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
|
@ -2235,14 +2285,11 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
|
|||
|
||||
int alpha;
|
||||
PalEntry *pBlendColor;
|
||||
bool isgiver = info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver));
|
||||
|
||||
if (info->IsDescendantOf(RUNTIME_CLASS(APowerup)))
|
||||
if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || isgiver)
|
||||
{
|
||||
pBlendColor = &((APowerup*)defaults)->BlendColor;
|
||||
}
|
||||
else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
|
||||
{
|
||||
pBlendColor = &((APowerupGiver*)defaults)->BlendColor;
|
||||
pBlendColor = &TypedScriptVar<PalEntry>(defaults, info, NAME_BlendColor, TypeColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2264,7 +2311,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, color, C_f, Inventory)
|
|||
*pBlendColor = MakeSpecialColormap(v);
|
||||
return;
|
||||
}
|
||||
else if (!stricmp(name, "none") && info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
|
||||
else if (!stricmp(name, "none") && isgiver)
|
||||
{
|
||||
*pBlendColor = MakeSpecialColormap(65535);
|
||||
return;
|
||||
|
@ -2290,13 +2337,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, colormap, FFFfff, Inventory)
|
|||
{
|
||||
PalEntry * pBlendColor;
|
||||
|
||||
if (info->IsDescendantOf(RUNTIME_CLASS(APowerup)))
|
||||
if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
||||
{
|
||||
pBlendColor = &((APowerup*)defaults)->BlendColor;
|
||||
}
|
||||
else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
|
||||
{
|
||||
pBlendColor = &((APowerupGiver*)defaults)->BlendColor;
|
||||
pBlendColor = &TypedScriptVar<PalEntry>(defaults, info, NAME_BlendColor, TypeColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2334,13 +2377,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, duration, I, Inventory)
|
|||
{
|
||||
int *pEffectTics;
|
||||
|
||||
if (info->IsDescendantOf(RUNTIME_CLASS(APowerup)))
|
||||
if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
||||
{
|
||||
pEffectTics = &((APowerup*)defaults)->EffectTics;
|
||||
}
|
||||
else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
|
||||
{
|
||||
pEffectTics = &((APowerupGiver*)defaults)->EffectTics;
|
||||
pEffectTics = &TypedScriptVar<int>(defaults, info, NAME_EffectTics, TypeSInt32);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2359,13 +2398,9 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, strength, F, Inventory)
|
|||
{
|
||||
double *pStrength;
|
||||
|
||||
if (info->IsDescendantOf(RUNTIME_CLASS(APowerup)))
|
||||
if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
||||
{
|
||||
pStrength = &((APowerup*)defaults)->Strength;
|
||||
}
|
||||
else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
|
||||
{
|
||||
pStrength = &((APowerupGiver*)defaults)->Strength;
|
||||
pStrength = &TypedScriptVar<double>(defaults, info, NAME_Strength, TypeFloat64);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2383,13 +2418,10 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory)
|
|||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
FName *pMode;
|
||||
if (info->IsDescendantOf(RUNTIME_CLASS(APowerup)))
|
||||
|
||||
if (info->IsDescendantOf(PClass::FindActor(NAME_Powerup)) || info->IsDescendantOf(PClass::FindActor(NAME_PowerupGiver)))
|
||||
{
|
||||
pMode = &((APowerup*)defaults)->Mode;
|
||||
}
|
||||
else if (info->IsDescendantOf(RUNTIME_CLASS(APowerupGiver)))
|
||||
{
|
||||
pMode = &((APowerupGiver*)defaults)->Mode;
|
||||
pMode = &TypedScriptVar<FName>(defaults, info, NAME_Mode, TypeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2402,7 +2434,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, mode, S, Inventory)
|
|||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
|
||||
DEFINE_SCRIPTED_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
|
||||
|
@ -2422,8 +2454,7 @@ DEFINE_CLASS_PROPERTY_PREFIX(powerup, type, S, PowerupGiver)
|
|||
I_Error("Unknown powerup type %s", str);
|
||||
}
|
||||
}
|
||||
|
||||
defaults->PowerupType = cls;
|
||||
TypedScriptVar<PClassActor*>(defaults, info, NAME_PowerupType, NewClassPointer(RUNTIME_CLASS(AActor))) = cls;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -3009,37 +3040,37 @@ DEFINE_CLASS_PROPERTY(unmorphflash, S, MorphProjectile)
|
|||
//==========================================================================
|
||||
// (non-fatal with non-existent types only in DECORATE)
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(playerclass, S, PowerMorph)
|
||||
DEFINE_SCRIPTED_PROPERTY(playerclass, S, PowerMorph)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
defaults->PlayerClass = FindClassTentativePlayerPawn(str, bag.fromDecorate);
|
||||
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_PlayerClass, NewClassPointer(RUNTIME_CLASS(APlayerPawn))) = FindClassTentativePlayerPawn(str, bag.fromDecorate);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(morphstyle, M, PowerMorph)
|
||||
DEFINE_SCRIPTED_PROPERTY(morphstyle, M, PowerMorph)
|
||||
{
|
||||
PROP_INT_PARM(i, 0);
|
||||
defaults->MorphStyle = i;
|
||||
TypedScriptVar<int>(defaults, bag.Info, NAME_MorphStyle, TypeSInt32) = i;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
// (non-fatal with non-existent types only in DECORATE)
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(morphflash, S, PowerMorph)
|
||||
DEFINE_SCRIPTED_PROPERTY(morphflash, S, PowerMorph)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
defaults->MorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_MorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
// (non-fatal with non-existent types only in DECORATE)
|
||||
//==========================================================================
|
||||
DEFINE_CLASS_PROPERTY(unmorphflash, S, PowerMorph)
|
||||
DEFINE_SCRIPTED_PROPERTY(unmorphflash, S, PowerMorph)
|
||||
{
|
||||
PROP_STRING_PARM(str, 0);
|
||||
defaults->UnMorphFlash = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
TypedScriptVar<PClassActor*>(defaults, bag.Info, NAME_UnMorphFlash, NewClassPointer(RUNTIME_CLASS(AActor))) = FindClassTentative(str, RUNTIME_CLASS(AActor), bag.fromDecorate);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -393,6 +393,11 @@ struct VMReturn
|
|||
TagOfs = 0;
|
||||
RegType = REGT_POINTER;
|
||||
}
|
||||
VMReturn() { }
|
||||
VMReturn(int *loc) { IntAt(loc); }
|
||||
VMReturn(double *loc) { FloatAt(loc); }
|
||||
VMReturn(FString *loc) { StringAt(loc); }
|
||||
VMReturn(void **loc) { PointerAt(loc); }
|
||||
};
|
||||
|
||||
struct VMRegisters;
|
||||
|
|
|
@ -401,7 +401,7 @@ begin:
|
|||
OP(MOVEA):
|
||||
{
|
||||
ASSERTA(a); ASSERTA(B);
|
||||
int b = B;
|
||||
b = B;
|
||||
reg.a[a] = reg.a[b];
|
||||
reg.atag[a] = reg.atag[b];
|
||||
NEXTOP;
|
||||
|
@ -409,7 +409,7 @@ begin:
|
|||
OP(MOVEV2):
|
||||
{
|
||||
ASSERTF(a); ASSERTF(B);
|
||||
int b = B;
|
||||
b = B;
|
||||
reg.f[a] = reg.f[b];
|
||||
reg.f[a + 1] = reg.f[b + 1];
|
||||
NEXTOP;
|
||||
|
@ -417,7 +417,7 @@ begin:
|
|||
OP(MOVEV3):
|
||||
{
|
||||
ASSERTF(a); ASSERTF(B);
|
||||
int b = B;
|
||||
b = B;
|
||||
reg.f[a] = reg.f[b];
|
||||
reg.f[a + 1] = reg.f[b + 1];
|
||||
reg.f[a + 2] = reg.f[b + 2];
|
||||
|
@ -435,6 +435,18 @@ begin:
|
|||
reg.a[a] = (reg.a[b] && ((DObject*)(reg.a[b]))->IsKindOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr;
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
OP(DYNCASTC_R) :
|
||||
ASSERTA(a); ASSERTA(B); ASSERTA(C);
|
||||
b = B;
|
||||
reg.a[a] = (reg.a[b] && ((PClass*)(reg.a[b]))->IsDescendantOf((PClass*)(reg.a[C]))) ? reg.a[b] : nullptr;
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
OP(DYNCASTC_K) :
|
||||
ASSERTA(a); ASSERTA(B); ASSERTKA(C);
|
||||
b = B;
|
||||
reg.a[a] = (reg.a[b] && ((PClass*)(reg.a[b]))->IsDescendantOf((PClass*)(konsta[C].o))) ? reg.a[b] : nullptr;
|
||||
reg.atag[a] = ATAG_OBJECT;
|
||||
NEXTOP;
|
||||
OP(CAST):
|
||||
if (C == CAST_I2F)
|
||||
{
|
||||
|
@ -1746,9 +1758,21 @@ static void DoCast(const VMRegisters ®, const VMFrame *f, int a, int b, int c
|
|||
break;
|
||||
|
||||
case CAST_P2S:
|
||||
{
|
||||
ASSERTS(a); ASSERTA(b);
|
||||
reg.s[a].Format("%s<%p>", reg.atag[b] == ATAG_OBJECT ? (reg.a[b] == nullptr? "Object" : ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars() ) : "Pointer", reg.a[b]);
|
||||
break;
|
||||
if (reg.a[b] == nullptr) reg.s[a] = "null";
|
||||
else if (reg.atag[b] == ATAG_OBJECT)
|
||||
{
|
||||
auto op = static_cast<DObject*>(reg.a[b]);
|
||||
if (op->IsKindOf(RUNTIME_CLASS(PClass))) reg.s[a].Format("Class<%s>", static_cast<PClass*>(op)->TypeName.GetChars());
|
||||
else reg.s[a].Format("Object<%p>", ((DObject*)reg.a[b])->GetClass()->TypeName.GetChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
reg.s[a].Format("%s<%p>", "Pointer", reg.a[b]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CAST_S2I:
|
||||
ASSERTD(a); ASSERTS(b);
|
||||
|
|
|
@ -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<double>(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);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,8 @@ xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C
|
|||
xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C
|
||||
xx(DYNCAST_R, dyncast, RPRPRP, NOP, 0, 0), // aA = dyn_cast<aC>(aB);
|
||||
xx(DYNCAST_K, dyncast, RPRPKP, NOP, 0, 0), // aA = dyn_cast<aKC>(aB);
|
||||
xx(DYNCASTC_R, dyncastc, RPRPRP, NOP, 0, 0), // aA = dyn_cast<aC>(aB); for class types
|
||||
xx(DYNCASTC_K, dyncastc, RPRPKP, NOP, 0, 0), // aA = dyn_cast<aKC>(aB);
|
||||
|
||||
// Control flow.
|
||||
xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++
|
||||
|
|
|
@ -2022,13 +2022,14 @@ void ZCCCompiler::ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *pro
|
|||
|
||||
if (property != nullptr && property->category != CAT_INFO)
|
||||
{
|
||||
if (cls->IsDescendantOf(*property->cls))
|
||||
auto pcls = PClass::FindActor(property->clsname);
|
||||
if (cls->IsDescendantOf(pcls))
|
||||
{
|
||||
DispatchProperty(property, prop, (AActor *)bag.Info->Defaults, bag);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), (*property->cls)->TypeName.GetChars());
|
||||
Error(prop, "'%s' requires an actor of type '%s'\n", propname.GetChars(), pcls->TypeName.GetChars());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -3313,16 +3314,9 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
|
|||
{
|
||||
return new FxReturnStatement(nullptr, *ast);
|
||||
}
|
||||
else if (args.Size() == 1)
|
||||
{
|
||||
auto arg = args[0];
|
||||
args[0] = nullptr;
|
||||
return new FxReturnStatement(arg, *ast);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(ast, "Return with multiple values not implemented yet.");
|
||||
return new FxReturnStatement(nullptr, *ast);
|
||||
return new FxReturnStatement(args, *ast);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -615,8 +615,8 @@ SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader)
|
|||
SoundDecoder *decoder = NULL;
|
||||
int pos = reader->Tell();
|
||||
|
||||
#ifdef HAVE_MPG123
|
||||
decoder = new MPG123Decoder;
|
||||
#ifdef HAVE_SNDFILE
|
||||
decoder = new SndFileDecoder;
|
||||
if (decoder->open(reader))
|
||||
return decoder;
|
||||
reader->Seek(pos, SEEK_SET);
|
||||
|
@ -624,8 +624,8 @@ SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader)
|
|||
delete decoder;
|
||||
decoder = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_SNDFILE
|
||||
decoder = new SndFileDecoder;
|
||||
#ifdef HAVE_MPG123
|
||||
decoder = new MPG123Decoder;
|
||||
if (decoder->open(reader))
|
||||
return decoder;
|
||||
reader->Seek(pos, SEEK_SET);
|
||||
|
|
|
@ -14,25 +14,22 @@ static bool inited = false;
|
|||
|
||||
off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence)
|
||||
{
|
||||
MPG123Decoder *self = reinterpret_cast<MPG123Decoder*>(handle);
|
||||
FileReader *reader = self->Reader;
|
||||
FileReader *reader = reinterpret_cast<MPG123Decoder*>(handle)->Reader;
|
||||
|
||||
if(whence == SEEK_SET)
|
||||
offset += self->StartOffset;
|
||||
else if(whence == SEEK_CUR)
|
||||
if(whence == SEEK_CUR)
|
||||
{
|
||||
if(offset < 0 && reader->Tell()+offset < self->StartOffset)
|
||||
if(offset < 0 && reader->Tell()+offset < 0)
|
||||
return -1;
|
||||
}
|
||||
else if(whence == SEEK_END)
|
||||
{
|
||||
if(offset < 0 && reader->GetLength()+offset < self->StartOffset)
|
||||
if(offset < 0 && reader->GetLength()+offset < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(reader->Seek(offset, whence) != 0)
|
||||
return -1;
|
||||
return reader->Tell() - self->StartOffset;
|
||||
return reader->Tell();
|
||||
}
|
||||
|
||||
ssize_t MPG123Decoder::file_read(void *handle, void *buffer, size_t bytes)
|
||||
|
@ -71,45 +68,7 @@ bool MPG123Decoder::open(FileReader *reader)
|
|||
}
|
||||
|
||||
Reader = reader;
|
||||
StartOffset = 0;
|
||||
|
||||
char data[10];
|
||||
if(file_read(this, data, 10) != 10)
|
||||
return false;
|
||||
|
||||
int start_offset = 0;
|
||||
// Check for ID3 tags and skip them
|
||||
if(memcmp(data, "ID3", 3) == 0 &&
|
||||
(BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff &&
|
||||
(data[5]&0x0f) == 0 && (data[6]&0x80) == 0 &&
|
||||
(data[7]&0x80) == 0 && (data[8]&0x80) == 0 &&
|
||||
(data[9]&0x80) == 0)
|
||||
{
|
||||
// ID3v2
|
||||
start_offset = (data[6]<<21) | (data[7]<<14) |
|
||||
(data[8]<< 7) | (data[9] );
|
||||
start_offset += ((data[5]&0x10) ? 20 : 10);
|
||||
}
|
||||
|
||||
StartOffset = start_offset;
|
||||
if(file_lseek(this, 0, SEEK_SET) != 0)
|
||||
return false;
|
||||
|
||||
// Check for a frame header
|
||||
bool frame_ok = false;
|
||||
if(file_read(this, data, 3) == 3)
|
||||
{
|
||||
if((BYTE)data[0] == 0xff &&
|
||||
((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/))
|
||||
{
|
||||
int brate_idx = (data[2]>>4) & 0x0f;
|
||||
int srate_idx = (data[2]>>2) & 0x03;
|
||||
if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3)
|
||||
frame_ok = (file_lseek(this, 0, SEEK_SET) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if(frame_ok)
|
||||
{
|
||||
MPG123 = mpg123_new(NULL, NULL);
|
||||
if(mpg123_replace_reader_handle(MPG123, file_read, file_lseek, NULL) == MPG123_OK &&
|
||||
|
|
|
@ -30,7 +30,6 @@ private:
|
|||
bool Done;
|
||||
|
||||
FileReader *Reader;
|
||||
int StartOffset;
|
||||
static off_t file_lseek(void *handle, off_t offset, int whence);
|
||||
static ssize_t file_read(void *handle, void *buffer, size_t bytes);
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ bool SndFileDecoder::open(FileReader *reader)
|
|||
SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell };
|
||||
|
||||
Reader = reader;
|
||||
SndInfo.format = 0;
|
||||
SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this);
|
||||
if (SndFile)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "zscript/inventory/powerups.txt"
|
||||
|
||||
#include "zscript/shared/player.txt"
|
||||
#include "zscript/shared/player_cheat.txt"
|
||||
#include "zscript/shared/morph.txt"
|
||||
#include "zscript/shared/botstuff.txt"
|
||||
#include "zscript/shared/sharedmisc.txt"
|
||||
|
|
|
@ -487,6 +487,8 @@ class Actor : Thinker native
|
|||
native void AddInventory(Inventory inv);
|
||||
native void RemoveInventory(Inventory inv);
|
||||
native void ClearInventory();
|
||||
native bool GiveInventory(class<Inventory> type, int amount, bool givecheat = false);
|
||||
native bool TakeInventory(class<Inventory> itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false);
|
||||
native Inventory FindInventory(class<Inventory> itemtype, bool subclass = false);
|
||||
native Inventory GiveInventoryType(class<Inventory> itemtype);
|
||||
native Inventory DropInventory (Inventory item);
|
||||
|
|
|
@ -106,11 +106,15 @@ extend class Actor
|
|||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
// rather pointless these days to do it this way.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
native bool CheckArmorType(name Type, int amount = 1);
|
||||
bool CheckArmorType(name Type, int amount = 1)
|
||||
{
|
||||
let myarmor = BasicArmor(FindInventory("BasicArmor"));
|
||||
return myarmor != null && myarmor.ArmorType == type && myarmor.Amount >= amount;
|
||||
}
|
||||
|
||||
action state A_JumpIfArmorType(name Type, statelabel label, int amount = 1)
|
||||
{
|
||||
|
|
|
@ -32,11 +32,23 @@ struct TexMan
|
|||
native static TextureID CheckForTexture(String name, int usetype, int flags = TryAny);
|
||||
}
|
||||
|
||||
struct Screen
|
||||
struct Screen native
|
||||
{
|
||||
native static void DrawHUDTexture(TextureID tex, double x, double y);
|
||||
}
|
||||
|
||||
struct Console native
|
||||
{
|
||||
native static void HideConsole();
|
||||
}
|
||||
|
||||
struct GameInfoStruct native
|
||||
{
|
||||
// will be extended as needed.
|
||||
native Name backpacktype;
|
||||
native double Armor2Percent;
|
||||
}
|
||||
|
||||
class Object native
|
||||
{
|
||||
native bool bDestroyed;
|
||||
|
@ -200,6 +212,7 @@ struct DehInfo native
|
|||
native double ExplosionAlpha;
|
||||
native int NoAutofreeze;
|
||||
native int BFGCells;
|
||||
native int BlueAC;
|
||||
}
|
||||
|
||||
struct State native
|
||||
|
|
|
@ -64,6 +64,7 @@ class Inventory : Actor native
|
|||
virtual bool GetNoTeleportFreeze() { return false; }
|
||||
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {}
|
||||
virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {}
|
||||
virtual void OwnerDied() {}
|
||||
|
||||
native bool GoAway();
|
||||
native void GoAwayAndDie();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
class PowerupGiver : Inventory native
|
||||
class PowerupGiver : Inventory
|
||||
{
|
||||
|
||||
native Class<Actor> PowerupType;
|
||||
native int EffectTics; // Non-0 to override the powerup's default tics
|
||||
native color BlendColor; // Non-0 to override the powerup's default blend
|
||||
native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility
|
||||
native double Strength; // Meaning depends on powerup - currently used only by Invisibility
|
||||
Class<Actor> PowerupType;
|
||||
int EffectTics; // Non-0 to override the powerup's default tics
|
||||
color BlendColor; // Non-0 to override the powerup's default blend
|
||||
Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility
|
||||
double Strength; // Meaning depends on powerup - currently used only by Invisibility
|
||||
|
||||
Default
|
||||
{
|
||||
|
@ -14,6 +14,48 @@ class PowerupGiver : Inventory native
|
|||
+INVENTORY.FANCYPICKUPSOUND
|
||||
Inventory.PickupSound "misc/p_pkup";
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerupGiver :: Use
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override bool Use (bool pickup)
|
||||
{
|
||||
if (PowerupType == NULL) return true; // item is useless
|
||||
if (Owner == null) return true;
|
||||
|
||||
let power = Powerup(Spawn (PowerupType));
|
||||
|
||||
if (EffectTics != 0)
|
||||
{
|
||||
power.EffectTics = EffectTics;
|
||||
}
|
||||
if (BlendColor != 0)
|
||||
{
|
||||
if (BlendColor != Powerup.SPECIALCOLORMAP_MASK | 65535) power.BlendColor = BlendColor;
|
||||
else power.BlendColor = 0;
|
||||
}
|
||||
if (Mode != 'None')
|
||||
{
|
||||
power.Mode = Mode;
|
||||
}
|
||||
if (Strength != 0)
|
||||
{
|
||||
power.Strength = Strength;
|
||||
}
|
||||
|
||||
power.bAlwaysPickup |= bAlwaysPickup;
|
||||
power.bAdditiveTime |= bAdditiveTime;
|
||||
power.bNoTeleportFreeze |= bNoTeleportFreeze;
|
||||
if (power.CallTryPickup (Owner))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
power.GoAwayAndDie ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class Powerup : Inventory native
|
||||
|
@ -22,13 +64,245 @@ 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);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerup :: OwnerDied
|
||||
//
|
||||
// Powerups don't last beyond death.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void OwnerDied ()
|
||||
{
|
||||
Destroy ();
|
||||
}
|
||||
|
||||
native virtual void InitEffect();
|
||||
native virtual void EndEffect();
|
||||
native bool isBlinking();
|
||||
|
||||
}
|
||||
|
||||
|
@ -38,14 +312,134 @@ class Powerup : Inventory native
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
class PowerInvulnerable : Powerup native
|
||||
class PowerInvulnerable : Powerup
|
||||
{
|
||||
Default
|
||||
{
|
||||
Powerup.Duration -30;
|
||||
inventory.icon "SPSHLD0";
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerInvulnerable :: InitEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void InitEffect ()
|
||||
{
|
||||
Super.InitEffect();
|
||||
Owner.bRespawnInvul = false;
|
||||
Owner.bInvulnerable = true;
|
||||
if (Mode == 'None' && Owner is "PlayerPawn")
|
||||
{
|
||||
Mode = PlayerPawn(Owner).InvulMode;
|
||||
}
|
||||
if (Mode == 'Reflective')
|
||||
{
|
||||
Owner.bReflective = true;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerInvulnerable :: DoEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void DoEffect ()
|
||||
{
|
||||
Super.DoEffect ();
|
||||
|
||||
if (Owner == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Mode == 'Ghost')
|
||||
{
|
||||
if (!Owner.bShadow)
|
||||
{
|
||||
// Don't mess with the translucency settings if an
|
||||
// invisibility powerup is active.
|
||||
let alpha = Owner.Alpha;
|
||||
if (!(level.time & 7) && alpha > 0 && alpha < 1)
|
||||
{
|
||||
if (alpha == HX_SHADOW)
|
||||
{
|
||||
alpha = HX_ALTSHADOW;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = 0;
|
||||
Owner.bNonShootable = true;
|
||||
}
|
||||
}
|
||||
if (!(level.time & 31))
|
||||
{
|
||||
if (alpha == 0)
|
||||
{
|
||||
Owner.bNonShootable = false;
|
||||
alpha = HX_ALTSHADOW;
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = HX_SHADOW;
|
||||
}
|
||||
}
|
||||
Owner.A_SetRenderStyle(alpha, STYLE_Translucent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner.bNonShootable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerInvulnerable :: EndEffect
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void EndEffect ()
|
||||
{
|
||||
Super.EndEffect();
|
||||
|
||||
if (Owner == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Owner.bRespawnInvul = false;
|
||||
Owner.bInvulnerable = false;
|
||||
if (Mode == 'Ghost')
|
||||
{
|
||||
Owner.bNonShootable = false;
|
||||
if (!bShadow)
|
||||
{
|
||||
// Don't mess with the translucency settings if an
|
||||
// invisibility powerup is active.
|
||||
Owner.A_SetRenderStyle(1, STYLE_Normal);
|
||||
}
|
||||
}
|
||||
else if (Mode == 'Reflective')
|
||||
{
|
||||
Owner.bReflective = false;
|
||||
}
|
||||
|
||||
if (Owner.player != NULL)
|
||||
{
|
||||
Owner.player.fixedcolormap = PlayerInfo.NOFIXEDCOLORMAP;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// APowerInvulnerable :: AlterWeaponSprite
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
override void AlterWeaponSprite (VisStyle vis, in out int changed)
|
||||
{
|
||||
if (Owner != NULL)
|
||||
|
@ -761,13 +1155,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;
|
||||
|
@ -797,7 +1190,7 @@ class PowerSpeed : Powerup native
|
|||
if (Owner.player.cheats & CF_PREDICTING)
|
||||
return;
|
||||
|
||||
if (SpeedFlags & PSF_NOTRAIL)
|
||||
if (NoTrail)
|
||||
return;
|
||||
|
||||
if (level.time & 1)
|
||||
|
@ -808,7 +1201,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;
|
||||
}
|
||||
|
@ -1552,13 +1945,13 @@ class PowerInfiniteAmmo : Powerup
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
class PowerMorph : Powerup native
|
||||
class PowerMorph : Powerup
|
||||
{
|
||||
native Class<PlayerPawn> PlayerClass;
|
||||
native Class<Actor> MorphFlash, UnMorphFlash;
|
||||
native int MorphStyle;
|
||||
native PlayerInfo MorphedPlayer;
|
||||
|
||||
Class<PlayerPawn> PlayerClass;
|
||||
Class<Actor> MorphFlash, UnMorphFlash;
|
||||
int MorphStyle;
|
||||
PlayerInfo MorphedPlayer;
|
||||
|
||||
Default
|
||||
{
|
||||
Powerup.Duration -40;
|
||||
|
|
|
@ -125,3 +125,7 @@ class WeaponPiece : Inventory native
|
|||
}
|
||||
}
|
||||
|
||||
struct WeaponSlots native
|
||||
{
|
||||
native bool, int, int LocateWeapon(class<Weapon> weap);
|
||||
}
|
|
@ -102,6 +102,36 @@ class PlayerPawn : Actor native
|
|||
virtual void MorphPlayerThink()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnRespawn()
|
||||
{
|
||||
if (sv_respawnprotect && (multiplayer || alwaysapplydmflags))
|
||||
{
|
||||
let invul = Powerup(Spawn("PowerInvulnerable"));
|
||||
invul.EffectTics = 3 * TICRATE;
|
||||
invul.BlendColor = 0; // don't mess with the view
|
||||
invul.bUndroppable = true; // Don't drop this
|
||||
bRespawnInvul = true; // [RH] special effect
|
||||
}
|
||||
}
|
||||
|
||||
// This is for SBARINFO.
|
||||
int, int GetEffectTicsForItem(class<Inventory> item)
|
||||
{
|
||||
let pg = (class<PowerupGiver>)(item);
|
||||
if (pg != null)
|
||||
{
|
||||
let powerupType = (class<Powerup>)(GetDefaultByType(pg).PowerupType);
|
||||
let powerup = Powerup(FindInventory(powerupType));
|
||||
if(powerup != null)
|
||||
{
|
||||
let maxtics = GetDefaultByType(powerupType).EffectTics;
|
||||
if (maxtics == 0) maxtics = powerup.default.EffectTics;
|
||||
return powerup.EffectTics, maxtics;
|
||||
}
|
||||
}
|
||||
return 0, 0;
|
||||
}
|
||||
|
||||
native int GetMaxHealth();
|
||||
native bool ResetAirSupply (bool playgasp = false);
|
||||
|
@ -260,11 +290,12 @@ struct PlayerInfo native // this is what internally is known as player_t
|
|||
native Actor ConversationPC;
|
||||
native double ConversationNPCAngle;
|
||||
native bool ConversationFaceTalker;
|
||||
//native WeaponSlots weapons; <- defined internally
|
||||
|
||||
/* these are not doable yet
|
||||
ticcmd_t cmd;
|
||||
usercmd_t original_cmd;
|
||||
userinfo_t userinfo; // [RH] who is this?
|
||||
FWeaponSlots weapons;
|
||||
userinfo_t userinfo;
|
||||
*/
|
||||
|
||||
|
||||
|
@ -278,5 +309,6 @@ FWeaponSlots weapons;
|
|||
native PSprite FindPSprite(int id);
|
||||
native void SetLogNumber (int text);
|
||||
native void SetLogText (String text);
|
||||
native String GetUserName();
|
||||
|
||||
}
|
||||
|
|
402
wadsrc/static/zscript/shared/player_cheat.txt
Normal file
402
wadsrc/static/zscript/shared/player_cheat.txt
Normal file
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
** player_cheat.txt
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1999-2016 Randy Heit
|
||||
** Copyright 2006-2017 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
extend class PlayerPawn
|
||||
{
|
||||
enum EAll
|
||||
{
|
||||
ALL_NO,
|
||||
ALL_YES,
|
||||
ALL_YESYES
|
||||
}
|
||||
|
||||
native void CheatSuicide();
|
||||
|
||||
virtual void CheatGive (String name, int amount)
|
||||
{
|
||||
int i;
|
||||
Class<Inventory> type;
|
||||
let player = self.player;
|
||||
|
||||
if (PlayerNumber() != consoleplayer)
|
||||
A_Log(format ("%s is a cheater: give %s\n", player.GetUserName(), name));
|
||||
|
||||
if (player.mo == NULL || player.health <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int giveall = ALL_NO;
|
||||
if (name ~== "all")
|
||||
{
|
||||
giveall = ALL_YES;
|
||||
}
|
||||
else if (name ~== "everything")
|
||||
{
|
||||
giveall = ALL_YESYES;
|
||||
}
|
||||
|
||||
if (name ~== "health")
|
||||
{
|
||||
if (amount > 0)
|
||||
{
|
||||
health += amount;
|
||||
player.health = health;
|
||||
}
|
||||
else
|
||||
{
|
||||
player.health = health = GetMaxHealth();
|
||||
}
|
||||
}
|
||||
|
||||
if (giveall || name ~== "backpack")
|
||||
{
|
||||
// Select the correct type of backpack based on the game
|
||||
type = (class<Inventory>)(gameinfo.backpacktype);
|
||||
if (type != NULL)
|
||||
{
|
||||
GiveInventory(type, 1, true);
|
||||
}
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || name ~== "ammo")
|
||||
{
|
||||
// Find every unique type of ammo. Give it to the player if
|
||||
// he doesn't have it already, and set each to its maximum.
|
||||
for (i = 0; i < AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = (class<Inventory>)(AllActorClasses[i]);
|
||||
|
||||
if (type != null && type.GetParentClass() == "Ammo")
|
||||
{
|
||||
let ammoitem = FindInventory(type);
|
||||
if (ammoitem == NULL)
|
||||
{
|
||||
ammoitem = Inventory(Spawn (type));
|
||||
ammoitem.AttachToOwner (self);
|
||||
ammoitem.Amount = ammoitem.MaxAmount;
|
||||
}
|
||||
else if (ammoitem.Amount < ammoitem.MaxAmount)
|
||||
{
|
||||
ammoitem.Amount = ammoitem.MaxAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || name ~== "armor")
|
||||
{
|
||||
if (GameType() != GAME_Hexen)
|
||||
{
|
||||
let armoritem = BasicArmorPickup(Spawn("BasicArmorPickup"));
|
||||
armoritem.SaveAmount = 100*deh.BlueAC;
|
||||
armoritem.SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : 0.5;
|
||||
if (!armoritem.CallTryPickup (self))
|
||||
{
|
||||
armoritem.Destroy ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
let armoritem = Inventory(Spawn("HexenArmor"));
|
||||
armoritem.health = i;
|
||||
armoritem.Amount = 0;
|
||||
if (!armoritem.CallTryPickup (self))
|
||||
{
|
||||
armoritem.Destroy ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || name ~== "keys")
|
||||
{
|
||||
for (int i = 0; i < AllActorClasses.Size(); ++i)
|
||||
{
|
||||
if (AllActorClasses[i] is "Key")
|
||||
{
|
||||
readonly<Key> keyitem = GetDefaultByType ((class<Key>)(AllActorClasses[i]));
|
||||
if (keyitem.KeyNumber != 0)
|
||||
{
|
||||
let item = Inventory(Spawn(AllActorClasses[i]));
|
||||
if (!item.CallTryPickup (self))
|
||||
{
|
||||
item.Destroy ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || name ~== "weapons")
|
||||
{
|
||||
let savedpending = player.PendingWeapon;
|
||||
for (i = 0; i < AllActorClasses.Size(); ++i)
|
||||
{
|
||||
let type = (class<Weapon>)(AllActorClasses[i]);
|
||||
if (type != null && type != "Weapon")
|
||||
{
|
||||
// Don't give replaced weapons unless the replacement was done by Dehacked.
|
||||
let rep = GetReplacement(type);
|
||||
if (rep == type || rep is "DehackedPickup")
|
||||
{
|
||||
// Give the weapon only if it is set in a weapon slot.
|
||||
if (player.weapons.LocateWeapon(type))
|
||||
{
|
||||
readonly<Weapon> def = GetDefaultByType (type);
|
||||
if (giveall == ALL_YESYES || !def.bCheatNotWeapon)
|
||||
{
|
||||
GiveInventory(type, 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
player.PendingWeapon = savedpending;
|
||||
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || name ~== "artifacts")
|
||||
{
|
||||
for (i = 0; i < AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = (class<Inventory>)(AllActorClasses[i]);
|
||||
if (type!= null)
|
||||
{
|
||||
let def = GetDefaultByType (type);
|
||||
if (def.Icon.isValid() && def.MaxAmount > 1 &&
|
||||
!(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor"))
|
||||
{
|
||||
// Do not give replaced items unless using "give everything"
|
||||
if (giveall == ALL_YESYES || GetReplacement(type) == type)
|
||||
{
|
||||
GiveInventory(type, amount <= 0 ? def.MaxAmount : amount, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall || name ~== "puzzlepieces")
|
||||
{
|
||||
for (i = 0; i < AllActorClasses.Size(); ++i)
|
||||
{
|
||||
let type = (class<PuzzleItem>)(AllActorClasses[i]);
|
||||
if (type != null)
|
||||
{
|
||||
let def = GetDefaultByType (type);
|
||||
if (def.Icon.isValid())
|
||||
{
|
||||
// Do not give replaced items unless using "give everything"
|
||||
if (giveall == ALL_YESYES || GetReplacement(type) == type)
|
||||
{
|
||||
GiveInventory(type, amount <= 0 ? def.MaxAmount : amount, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!giveall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (giveall)
|
||||
return;
|
||||
|
||||
type = name;
|
||||
if (type == NULL)
|
||||
{
|
||||
if (PlayerNumber() == consoleplayer)
|
||||
A_Log(format("Unknown item \"%s\"\n", name));
|
||||
}
|
||||
else
|
||||
{
|
||||
GiveInventory(type, amount, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void CheatTakeType(class<Inventory> deletetype)
|
||||
{
|
||||
for (int i = 0; i < AllActorClasses.Size(); ++i)
|
||||
{
|
||||
let type = (class<Inventory>)(AllActorClasses[i]);
|
||||
|
||||
if (type != null && type is deletetype)
|
||||
{
|
||||
let pack = FindInventory(type);
|
||||
if (pack) pack.Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void CheatTake (String name, int amount)
|
||||
{
|
||||
bool takeall;
|
||||
Class<Inventory> type;
|
||||
let player = self.player;
|
||||
|
||||
|
||||
if (player.mo == NULL || player.health <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
takeall = name ~== "all";
|
||||
|
||||
if (!takeall && name ~== "health")
|
||||
{
|
||||
if (player.mo.health - amount <= 0
|
||||
|| player.health - amount <= 0
|
||||
|| amount == 0)
|
||||
{
|
||||
|
||||
CheatSuicide ();
|
||||
|
||||
if (PlayerNumber() == consoleplayer)
|
||||
Console.HideConsole ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
if (player.mo)
|
||||
{
|
||||
player.mo.health -= amount;
|
||||
player.health = player.mo.health;
|
||||
}
|
||||
else
|
||||
{
|
||||
player.health -= amount;
|
||||
}
|
||||
}
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || name ~== "backpack")
|
||||
{
|
||||
CheatTakeType("BackpackItem");
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || name ~== "ammo")
|
||||
{
|
||||
CheatTakeType("Ammo");
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || name ~== "armor")
|
||||
{
|
||||
CheatTakeType("Armor");
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || name ~== "keys")
|
||||
{
|
||||
CheatTakeType("Key");
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || name ~== "weapons")
|
||||
{
|
||||
CheatTakeType("Weapon");
|
||||
CheatTakeType("WeaponHolder");
|
||||
player.ReadyWeapon = null;
|
||||
player.PendingWeapon = WP_NOCHANGE;
|
||||
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || name ~== "artifacts")
|
||||
{
|
||||
for (int i = 0; i < AllActorClasses.Size(); ++i)
|
||||
{
|
||||
type = (class<Inventory>)(AllActorClasses[i]);
|
||||
if (type!= null && !(type is "PuzzleItem") && !(type is "Powerup") && !(type is "Ammo") && !(type is "Armor"))
|
||||
{
|
||||
let pack = FindInventory(type);
|
||||
if (pack) pack.Destroy();
|
||||
}
|
||||
}
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall || name ~== "puzzlepieces")
|
||||
{
|
||||
CheatTakeType("PuzzleItem");
|
||||
if (!takeall)
|
||||
return;
|
||||
}
|
||||
|
||||
if (takeall)
|
||||
return;
|
||||
|
||||
type = name;
|
||||
if (type == NULL)
|
||||
{
|
||||
if (PlayerNumber() == consoleplayer)
|
||||
A_Log(format("Unknown item \"%s\"\n", name));
|
||||
}
|
||||
else
|
||||
{
|
||||
TakeInventory(type, max(amount, 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -166,7 +166,7 @@ class AlienSpectre1 : SpectralMonster
|
|||
player.GiveInventoryType ("UpgradeAccuracy");
|
||||
}
|
||||
Sigil sigl = Sigil(player.FindInventory("Sigil"));
|
||||
if (sigl != null /*&& sigl.NumPieces == 5*/)
|
||||
if (sigl != null && sigl.health == 5)
|
||||
{ // You wield the power of the complete Sigil.
|
||||
log = 85;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue