- partial scriptification of AInventory.

- scriptification of CustomInventory.
This commit is contained in:
Christoph Oelckers 2017-01-19 19:14:22 +01:00
parent 19b1c10ba8
commit 7c6542e595
10 changed files with 294 additions and 391 deletions

View file

@ -2620,9 +2620,9 @@ void FParser::SF_MaxPlayerAmmo()
if(amount < 0) amount = 0; if(amount < 0) amount = 0;
if (!iammo) if (!iammo)
{ {
iammo = static_cast<AInventory *>(Spawn (ammotype)); players[playernum].mo->GiveAmmo(ammotype, 1);
iammo = players[playernum].mo->FindInventory(ammotype);
iammo->Amount = 0; iammo->Amount = 0;
iammo->AttachToOwner (players[playernum].mo);
} }
iammo->MaxAmount = amount; iammo->MaxAmount = amount;

View file

@ -332,28 +332,6 @@ DEFINE_ACTION_FUNCTION(AInventory, HandlePickup)
ACTION_RETURN_BOOL(self->HandlePickup(item)); ACTION_RETURN_BOOL(self->HandlePickup(item));
} }
bool AInventory::CallHandlePickup(AInventory *item)
{
auto self = this;
while (self != nullptr)
{
IFVIRTUALPTR(self, AInventory, HandlePickup)
{
// Without the type cast this picks the 'void *' assignment...
VMValue params[2] = { (DObject*)self, (DObject*)item };
VMReturn ret;
int retval;
ret.IntAt(&retval);
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
if (retval) return true;
}
else if (self->HandlePickup(item)) return true;
self = self->Inventory;
}
return false;
}
//=========================================================================== //===========================================================================
// //
// AInventory :: GoAway // AInventory :: GoAway
@ -450,20 +428,6 @@ DEFINE_ACTION_FUNCTION(AInventory, CreateCopy)
ACTION_RETURN_OBJECT(self->CreateCopy(other)); ACTION_RETURN_OBJECT(self->CreateCopy(other));
} }
AInventory *AInventory::CallCreateCopy(AActor *other)
{
IFVIRTUAL(AInventory, CreateCopy)
{
VMValue params[2] = { (DObject*)this, (DObject*)other };
VMReturn ret;
AInventory *retval;
ret.PointerAt((void**)&retval);
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
return retval;
}
else return CreateCopy(other);
}
//=========================================================================== //===========================================================================
// //
@ -475,47 +439,7 @@ AInventory *AInventory::CallCreateCopy(AActor *other)
// //
//=========================================================================== //===========================================================================
AInventory *AInventory::CreateTossable () AInventory *AInventory::CreateTossable()
{
AInventory *copy;
// If this actor lacks a SpawnState, don't drop it. (e.g. A base weapon
// like the fist can't be dropped because you'll never see it.)
if (SpawnState == ::GetDefault<AActor>()->SpawnState ||
SpawnState == NULL)
{
return NULL;
}
if ((ItemFlags & (IF_UNDROPPABLE|IF_UNTOSSABLE)) || Owner == NULL || Amount <= 0)
{
return NULL;
}
if (Amount == 1 && !(ItemFlags & IF_KEEPDEPLETED))
{
BecomePickup ();
DropTime = 30;
flags &= ~(MF_SPECIAL|MF_SOLID);
return this;
}
copy = static_cast<AInventory *>(Spawn (GetClass(), Owner->Pos(), NO_REPLACE));
if (copy != NULL)
{
copy->MaxAmount = MaxAmount;
copy->Amount = 1;
copy->DropTime = 30;
copy->flags &= ~(MF_SPECIAL|MF_SOLID);
Amount--;
}
return copy;
}
DEFINE_ACTION_FUNCTION(AInventory, CreateTossable)
{
PARAM_SELF_PROLOGUE(AInventory);
ACTION_RETURN_OBJECT(self->CreateTossable());
}
AInventory *AInventory::CallCreateTossable()
{ {
IFVIRTUAL(AInventory, CreateTossable) IFVIRTUAL(AInventory, CreateTossable)
{ {
@ -594,30 +518,6 @@ DEFINE_ACTION_FUNCTION(AInventory, BecomePickup)
return 0; return 0;
} }
//===========================================================================
//
// AInventory :: AbsorbDamage
//
// Allows inventory items (primarily armor) to reduce the amount of damage
// taken. Damage is the amount of damage that would be done without armor,
// and newdamage is the amount that should be done after the armor absorbs
// it.
//
//===========================================================================
void AInventory::AbsorbDamage (int damage, FName damageType, int &newdamage)
{
}
DEFINE_ACTION_FUNCTION(AInventory, AbsorbDamage)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_INT(damage);
PARAM_NAME(type);
PARAM_POINTER(newdmg, int);
self->AbsorbDamage(damage, type, *newdmg);
return 0;
}
//=========================================================================== //===========================================================================
// //
// AInventory :: ModifyDamage // AInventory :: ModifyDamage
@ -699,18 +599,6 @@ bool AInventory::GetNoTeleportFreeze ()
// //
//=========================================================================== //===========================================================================
bool AInventory::Use (bool pickup)
{
return false;
}
DEFINE_ACTION_FUNCTION(AInventory, Use)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_BOOL(pickup);
ACTION_RETURN_BOOL(self->Use(pickup));
}
bool AInventory::CallUse(bool pickup) bool AInventory::CallUse(bool pickup)
{ {
IFVIRTUAL(AInventory, Use) IFVIRTUAL(AInventory, Use)
@ -721,9 +609,7 @@ bool AInventory::CallUse(bool pickup)
ret.IntAt(&retval); ret.IntAt(&retval);
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
return !!retval; return !!retval;
} }
else return Use(pickup);
} }
@ -1153,28 +1039,6 @@ AInventory *AInventory::NextInv ()
return item; return item;
} }
//===========================================================================
//
// AInventory :: DrawPowerup
//
// Gives this item a chance to draw a special status indicator on the screen.
// Returns false if it didn't draw anything.
//
//===========================================================================
bool AInventory::DrawPowerup (int x, int y)
{
return false;
}
DEFINE_ACTION_FUNCTION(AInventory, DrawPowerup)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_INT(x);
PARAM_INT(y);
ACTION_RETURN_BOOL(self->DrawPowerup(x, y));
}
//=========================================================================== //===========================================================================
// //
// AInventory :: DoRespawn // AInventory :: DoRespawn
@ -1219,117 +1083,6 @@ void AInventory::GiveQuest (AActor *toucher)
} }
} }
//===========================================================================
//
// AInventory :: TryPickup
//
//===========================================================================
bool AInventory::TryPickup (AActor *&toucher)
{
AActor *newtoucher = toucher; // in case changed by the powerup
// If HandlePickup() returns true, it will set the IF_PICKUPGOOD flag
// to indicate that this item has been picked up. If the item cannot be
// picked up, then it leaves the flag cleared.
ItemFlags &= ~IF_PICKUPGOOD;
if (toucher->Inventory != NULL && toucher->Inventory->CallHandlePickup (this))
{
// Let something else the player is holding intercept the pickup.
if (!(ItemFlags & IF_PICKUPGOOD))
{
return false;
}
ItemFlags &= ~IF_PICKUPGOOD;
GoAwayAndDie ();
}
else if (MaxAmount > 0)
{
// Add the item to the inventory. It is not already there, or HandlePickup
// would have already taken care of it.
AInventory *copy = CallCreateCopy (toucher);
if (copy == NULL)
{
return false;
}
// Some powerups cannot activate absolutely, for
// example, PowerMorph; fail the pickup if so.
if (copy->ItemFlags & IF_INITEFFECTFAILED)
{
if (copy != this) copy->Destroy();
else ItemFlags &= ~IF_INITEFFECTFAILED;
return false;
}
// Handle owner-changing powerups
if (copy->ItemFlags & IF_CREATECOPYMOVED)
{
newtoucher = copy->Owner;
copy->Owner = NULL;
copy->ItemFlags &= ~IF_CREATECOPYMOVED;
}
// Continue onwards with the rest
copy->CallAttachToOwner (newtoucher);
if (ItemFlags & IF_AUTOACTIVATE)
{
if (copy->CallUse (true))
{
if (--copy->Amount <= 0)
{
copy->flags &= ~MF_SPECIAL;
copy->SetState (copy->FindState("HoldAndDestroy"));
}
}
}
}
else if (ItemFlags & IF_AUTOACTIVATE)
{
// Special case: If an item's MaxAmount is 0, you can still pick it
// up if it is autoactivate-able.
// The item is placed in the inventory just long enough to be used.
toucher->AddInventory(this);
bool usegood = CallUse(true);
toucher->RemoveInventory(this);
if (usegood)
{
GoAwayAndDie();
}
else
{
return false;
}
}
return true;
}
DEFINE_ACTION_FUNCTION(AInventory, TryPickup)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_POINTER_NOT_NULL(toucher, AActor*);
ACTION_RETURN_BOOL(self->TryPickup(*toucher));
}
//===========================================================================
//
// AInventory :: TryPickupRestricted
//
//===========================================================================
bool AInventory::TryPickupRestricted (AActor *&toucher)
{
return false;
}
DEFINE_ACTION_FUNCTION(AInventory, TryPickupRestricted)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_POINTER_NOT_NULL(toucher, AActor*);
ACTION_RETURN_BOOL(self->TryPickupRestricted(*toucher));
}
//=========================================================================== //===========================================================================
// //
// AInventory :: CallTryPickup // AInventory :: CallTryPickup
@ -1355,7 +1108,6 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return)
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
res = !!retval; res = !!retval;
} }
else res = TryPickup(toucher);
} }
else if (!(ItemFlags & IF_RESTRICTABSOLUTELY)) else if (!(ItemFlags & IF_RESTRICTABSOLUTELY))
{ {
@ -1369,7 +1121,6 @@ bool AInventory::CallTryPickup (AActor *toucher, AActor **toucher_return)
GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr); GlobalVMStack.Call(func, params, 2, &ret, 1, nullptr);
res = !!retval; res = !!retval;
} }
else res = TryPickupRestricted(toucher);
} }
else else
return false; return false;
@ -1502,20 +1253,6 @@ CCMD (targetinv)
// //
//=========================================================================== //===========================================================================
void AInventory::AttachToOwner (AActor *other)
{
BecomeItem ();
other->AddInventory (this);
}
DEFINE_ACTION_FUNCTION(AInventory, AttachToOwner)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_OBJECT_NOT_NULL(other, AActor);
self->AttachToOwner(other);
return 0;
}
void AInventory::CallAttachToOwner(AActor *other) void AInventory::CallAttachToOwner(AActor *other)
{ {
IFVIRTUAL(AInventory, AttachToOwner) IFVIRTUAL(AInventory, AttachToOwner)
@ -1523,87 +1260,13 @@ void AInventory::CallAttachToOwner(AActor *other)
VMValue params[2] = { (DObject*)this, (DObject*)other }; VMValue params[2] = { (DObject*)this, (DObject*)other };
GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr);
} }
else AttachToOwner(other);
} }
//===========================================================================
//
// AInventory :: DetachFromOwner
//
// Performs any special work needed when the item leaves an inventory,
// either through destruction or becoming a pickup.
//
//===========================================================================
void AInventory::DetachFromOwner ()
{
}
DEFINE_ACTION_FUNCTION(AInventory, DetachFromOwner)
{
PARAM_SELF_PROLOGUE(AInventory);
self->DetachFromOwner();
return 0;
}
void AInventory::CallDetachFromOwner()
{
IFVIRTUAL(AInventory, DetachFromOwner)
{
VMValue params[1] = { (DObject*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
else DetachFromOwner();
}
//=========================================================================== //===========================================================================
//=========================================================================== //===========================================================================
IMPLEMENT_CLASS(AStateProvider, false, false) IMPLEMENT_CLASS(AStateProvider, false, false)
IMPLEMENT_CLASS(ACustomInventory, false, false)
//===========================================================================
//
// ACustomInventory :: SpecialDropAction
//
//===========================================================================
bool ACustomInventory::SpecialDropAction (AActor *dropper)
{
return CallStateChain (dropper, FindState(NAME_Drop));
}
//===========================================================================
//
// ACustomInventory :: Use
//
//===========================================================================
bool ACustomInventory::Use (bool pickup)
{
return CallStateChain (Owner, FindState(NAME_Use));
}
//===========================================================================
//
// ACustomInventory :: TryPickup
//
//===========================================================================
bool ACustomInventory::TryPickup (AActor *&toucher)
{
FState *pickupstate = FindState(NAME_Pickup);
bool useok = CallStateChain (toucher, pickupstate);
if ((useok || pickupstate == NULL) && FindState(NAME_Use) != NULL)
{
useok = Super::TryPickup (toucher);
}
else if (useok)
{
GoAwayAndDie();
}
return useok;
}

View file

@ -90,23 +90,17 @@ public:
virtual bool SpecialDropAction (AActor *dropper); virtual bool SpecialDropAction (AActor *dropper);
bool CallSpecialDropAction(AActor *dropper); bool CallSpecialDropAction(AActor *dropper);
virtual bool TryPickup(AActor *&toucher);
virtual bool TryPickupRestricted(AActor *&toucher);
bool CallTryPickup(AActor *toucher, AActor **toucher_return = NULL); // This wraps both virtual methods plus a few more checks. bool CallTryPickup(AActor *toucher, AActor **toucher_return = NULL); // This wraps both virtual methods plus a few more checks.
virtual AInventory *CreateCopy(AActor *other); virtual AInventory *CreateCopy(AActor *other);
AInventory *CallCreateCopy(AActor *other);
virtual AInventory *CreateTossable(); AInventory *CreateTossable();
AInventory *CallCreateTossable();
virtual FString PickupMessage(); virtual FString PickupMessage();
FString GetPickupMessage(); FString GetPickupMessage();
virtual bool HandlePickup(AInventory *item); virtual bool HandlePickup(AInventory *item);
bool CallHandlePickup(AInventory *item);
virtual bool Use(bool pickup);
bool CallUse(bool pickup); bool CallUse(bool pickup);
virtual PalEntry GetBlend(); virtual PalEntry GetBlend();
@ -120,20 +114,11 @@ public:
virtual void PlayPickupSound(AActor *toucher); virtual void PlayPickupSound(AActor *toucher);
void CallPlayPickupSound(AActor *toucher); void CallPlayPickupSound(AActor *toucher);
virtual void AttachToOwner(AActor *other);
void CallAttachToOwner(AActor *other); void CallAttachToOwner(AActor *other);
virtual void DetachFromOwner();
void CallDetachFromOwner();
// still need to be done. // still need to be done.
virtual void AbsorbDamage(int damage, FName damageType, int &newdamage);
void ModifyDamage(int damage, FName damageType, int &newdamage, bool passive); void ModifyDamage(int damage, FName damageType, int &newdamage, bool passive);
// visual stuff is for later. Right now the VM has not yet access to the needed functionality.
virtual bool DrawPowerup(int x, int y);
// virtual on the script side only. // virtual on the script side only.
double GetSpeedFactor(); double GetSpeedFactor();
bool GetNoTeleportFreeze(); bool GetNoTeleportFreeze();
@ -151,6 +136,8 @@ public:
AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set. AInventory *PrevInv(); // Returns the previous item with IF_INVBAR set.
AInventory *NextInv(); // Returns the next item with IF_INVBAR set. AInventory *NextInv(); // Returns the next item with IF_INVBAR set.
bool CallStateChain(AActor *actor, FState *state);
TObjPtr<AActor> Owner; // Who owns this item? NULL if it's still a pickup. TObjPtr<AActor> Owner; // Who owns this item? NULL if it's still a pickup.
int Amount; // Amount of item this instance has int Amount; // Amount of item this instance has
int MaxAmount; // Max amount of item this instance can have int MaxAmount; // Max amount of item this instance can have
@ -180,20 +167,6 @@ class AStateProvider : public AInventory
DECLARE_CLASS (AStateProvider, AInventory) DECLARE_CLASS (AStateProvider, AInventory)
}; };
// CustomInventory: Supports the Use, Pickup, and Drop states from 96x
class ACustomInventory : public AStateProvider
{
DECLARE_CLASS (ACustomInventory, AStateProvider)
public:
// This is used when an inventory item's use state sequence is executed.
bool CallStateChain (AActor *actor, FState *state);
virtual bool TryPickup (AActor *&toucher) override;
virtual bool Use (bool pickup) override;
virtual bool SpecialDropAction (AActor *dropper) override;
};
extern PClassActor *QuestItemClasses[31]; extern PClassActor *QuestItemClasses[31];

View file

@ -196,6 +196,7 @@ xx(PowerWeaponLevel2)
xx(PowerFlight) xx(PowerFlight)
xx(PowerSpeed) xx(PowerSpeed)
xx(PowerTorch) xx(PowerTorch)
xx(CustomInventory)
xx(AcolyteBlue) xx(AcolyteBlue)
xx(SpectralLightningV1) xx(SpectralLightningV1)

View file

@ -108,7 +108,7 @@ static FRandom pr_bfgselfdamage("BFGSelfDamage");
// //
//========================================================================== //==========================================================================
bool ACustomInventory::CallStateChain (AActor *actor, FState *state) bool AInventory::CallStateChain (AActor *actor, FState *state)
{ {
INTBOOL result = false; INTBOOL result = false;
int counter = 0; int counter = 0;
@ -223,6 +223,13 @@ bool ACustomInventory::CallStateChain (AActor *actor, FState *state)
return !!result; return !!result;
} }
DEFINE_ACTION_FUNCTION(AInventory, CallStateChain)
{
PARAM_SELF_PROLOGUE(AInventory);
PARAM_OBJECT(affectee, AActor);
PARAM_STATE(state);
ACTION_RETURN_BOOL(self->CallStateChain(affectee, state));
}
//========================================================================== //==========================================================================
// //

View file

@ -844,7 +844,13 @@ void AActor::RemoveInventory(AInventory *item)
if (inv == item) if (inv == item)
{ {
*invp = item->Inventory; *invp = item->Inventory;
item->DetachFromOwner();
IFVIRTUALPTR(item, AInventory, DetachFromOwner)
{
VMValue params[1] = { item };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
item->Owner = NULL; item->Owner = NULL;
item->Inventory = NULL; item->Inventory = NULL;
break; break;
@ -1032,7 +1038,7 @@ DEFINE_ACTION_FUNCTION(AActor, UseInventory)
AInventory *AActor::DropInventory (AInventory *item) AInventory *AActor::DropInventory (AInventory *item)
{ {
AInventory *drop = item->CallCreateTossable (); AInventory *drop = item->CreateTossable ();
if (drop == NULL) if (drop == NULL)
{ {
@ -3622,7 +3628,6 @@ int AActor::AbsorbDamage(int damage, FName dmgtype)
VMValue params[4] = { item, damage, dmgtype.GetIndex(), &damage }; VMValue params[4] = { item, damage, dmgtype.GetIndex(), &damage };
GlobalVMStack.Call(func, params, 4, nullptr, 0, nullptr); GlobalVMStack.Call(func, params, 4, nullptr, 0, nullptr);
} }
else item->AbsorbDamage(damage, dmgtype, damage);
} }
return damage; return damage;
} }

View file

@ -253,12 +253,16 @@ static void CheckForUnsafeStates(PClassActor *obj)
if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables. if (obj->Size == RUNTIME_CLASS(AWeapon)->Size) return; // This class cannot have user variables.
test = weaponstates; test = weaponstates;
} }
else if (obj->IsDescendantOf(RUNTIME_CLASS(ACustomInventory))) else
{ {
if (obj->Size == RUNTIME_CLASS(ACustomInventory)->Size) return; // This class cannot have user variables. auto citype = PClass::FindActor(NAME_CustomInventory);
test = pickupstates; if (obj->IsDescendantOf(citype))
{
if (obj->Size == citype->Size) return; // This class cannot have user variables.
test = pickupstates;
}
else return; // something else derived from AStateProvider. We do not know what this may be.
} }
else return; // something else derived from AStateProvider. We do not know what this may be.
for (; *test != NAME_None; test++) for (; *test != NAME_None; test++)
{ {
@ -338,7 +342,7 @@ static void CheckStates(PClassActor *obj)
{ {
CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites"); CheckStateLabels(obj, weaponstates, SUF_WEAPON, "weapon sprites");
} }
else if (obj->IsDescendantOf(RUNTIME_CLASS(ACustomInventory))) else if (obj->IsDescendantOf(PClass::FindActor(NAME_CustomInventory)))
{ {
CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain"); CheckStateLabels(obj, pickupstates, SUF_ITEM, "CustomInventory state chain");
} }

View file

@ -2464,7 +2464,12 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
PFunction *virtsym = nullptr; PFunction *virtsym = nullptr;
if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast<PFunction>(cls->ParentClass->Symbols.FindSymbol(FName(f->Name), true)); if (cls != nullptr && cls->ParentClass != nullptr) virtsym = dyn_cast<PFunction>(cls->ParentClass->Symbols.FindSymbol(FName(f->Name), true));
unsigned vindex = ~0u; unsigned vindex = ~0u;
if (virtsym != nullptr) vindex = virtsym->Variants[0].Implementation->VirtualIndex; if (virtsym != nullptr)
{
auto imp = virtsym->Variants[0].Implementation;
if (imp != nullptr) vindex = imp->VirtualIndex;
else Error(f, "Virtual base function %s not found in %s", FName(f->Name).GetChars(), cls->ParentClass->TypeName.GetChars());
}
if (!(f->Flags & ZCC_Native)) if (!(f->Flags & ZCC_Native))
{ {

View file

@ -9,9 +9,9 @@ class Inventory : Actor native
{ {
const BLINKTHRESHOLD = (4*32); const BLINKTHRESHOLD = (4*32);
native Actor Owner; // Who owns this item? NULL if it's still a pickup. native Actor Owner; // Who owns self item? NULL if it's still a pickup.
native int Amount; // Amount of item this instance has native int Amount; // Amount of item self instance has
native int MaxAmount; // Max amount of item this instance can have native int MaxAmount; // Max amount of item self instance can have
native int InterHubAmount; // Amount of item that can be kept between hubs or levels native int InterHubAmount; // Amount of item that can be kept between hubs or levels
native int RespawnTics; // Tics from pickup time to respawn time native int RespawnTics; // Tics from pickup time to respawn time
native TextureID Icon; // Icon to show on status bar or HUD native TextureID Icon; // Icon to show on status bar or HUD
@ -33,19 +33,13 @@ class Inventory : Actor native
Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG"; Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG";
} }
virtual native bool Use (bool pickup);
virtual native color GetBlend (); virtual native color GetBlend ();
virtual native bool HandlePickup(Inventory item); virtual native bool HandlePickup(Inventory item);
virtual native Inventory CreateCopy(Actor other); virtual native Inventory CreateCopy(Actor other);
virtual native Inventory CreateTossable();
virtual native bool SpecialDropAction (Actor dropper); virtual native bool SpecialDropAction (Actor dropper);
virtual native String PickupMessage(); virtual native String PickupMessage();
virtual native bool ShouldStay(); virtual native bool ShouldStay();
virtual native void PlayPickupSound(Actor user); virtual native void PlayPickupSound(Actor user);
virtual native void AttachToOwner(Actor user);
virtual native void DetachFromOwner();
virtual native bool DrawPowerup(int x, int y);
virtual native void AbsorbDamage (int damage, Name damageType, out int newdamage);
native bool DoRespawn(); native bool DoRespawn();
native bool GoAway(); native bool GoAway();
@ -55,9 +49,8 @@ class Inventory : Actor native
// In this case the caller function is more than a simple wrapper around the virtual method and // In this case the caller function is more than a simple wrapper around the virtual method and
// is what must be actually called to pick up an item. // is what must be actually called to pick up an item.
virtual protected native bool TryPickup(in out Actor toucher);
virtual protected native bool TryPickupRestricted(in out Actor toucher);
native bool, Actor CallTryPickup(Actor toucher); native bool, Actor CallTryPickup(Actor toucher);
native bool CallStateChain (Actor actor, State state);
States(Actor, Overlay, Weapon, Item) States(Actor, Overlay, Weapon, Item)
{ {
@ -138,6 +131,188 @@ class Inventory : Actor native
} }
} }
//===========================================================================
//
// AInventory :: CallHandlePickup
//
// Runs all HandlePickup methods in the chain
//
//===========================================================================
private bool CallHandlePickup(Inventory item)
{
let me = self;
while (me != null)
{
if (me.HandlePickup(item)) return true;
me = me.Inv;
}
return false;
}
//===========================================================================
//
// AInventory :: TryPickup
//
//===========================================================================
virtual protected bool TryPickup (in out Actor toucher)
{
Actor newtoucher = toucher; // in case changed by the powerup
// If HandlePickup() returns true, it will set the IF_PICKUPGOOD flag
// to indicate that self item has been picked up. If the item cannot be
// picked up, then it leaves the flag cleared.
bPickupGood = false;
if (toucher.Inv != NULL && toucher.Inv.CallHandlePickup (self))
{
// Let something else the player is holding intercept the pickup.
if (!bPickupGood)
{
return false;
}
bPickupGood = false;
GoAwayAndDie ();
}
else if (MaxAmount > 0)
{
// Add the item to the inventory. It is not already there, or HandlePickup
// would have already taken care of it.
let copy = CreateCopy (toucher);
if (copy == NULL)
{
return false;
}
// Some powerups cannot activate absolutely, for
// example, PowerMorph; fail the pickup if so.
if (copy.bInitEffectFailed)
{
if (copy != self) copy.Destroy();
else bInitEffectFailed;
return false;
}
// Handle owner-changing powerups
if (copy.bCreateCopyMoved)
{
newtoucher = copy.Owner;
copy.Owner = NULL;
bCreateCopyMoved = false;
}
// Continue onwards with the rest
copy.AttachToOwner (newtoucher);
if (bAutoActivate)
{
if (copy.Use (true))
{
if (--copy.Amount <= 0)
{
copy.bSpecial = false;
copy.SetStateLabel ("HoldAndDestroy");
}
}
}
}
else if (bAutoActivate)
{
// Special case: If an item's MaxAmount is 0, you can still pick it
// up if it is autoactivate-able.
// The item is placed in the inventory just long enough to be used.
toucher.AddInventory(self);
bool usegood = Use(true);
toucher.RemoveInventory(self);
if (usegood)
{
GoAwayAndDie();
}
else
{
return false;
}
}
return true;
}
//===========================================================================
//
// AInventory :: TryPickupRestricted
//
//===========================================================================
virtual bool TryPickupRestricted (in out Actor toucher)
{
return false;
}
//===========================================================================
//
// AInventory :: AttachToOwner
//
//===========================================================================
virtual void AttachToOwner (Actor other)
{
BecomeItem ();
other.AddInventory (self);
}
//===========================================================================
//
// AInventory :: DetachFromOwner
//
// Performs any special work needed when the item leaves an inventory,
// either through destruction or becoming a pickup.
//
//===========================================================================
virtual void DetachFromOwner ()
{
}
//===========================================================================
//
// AInventory::CreateTossable
//
// Creates a copy of the item suitable for dropping. If this actor embodies
// only one item, then it is tossed out itself. Otherwise, the count drops
// by one and a new item with an amount of 1 is spawned.
//
//===========================================================================
virtual Inventory CreateTossable ()
{
// If self actor lacks a SpawnState, don't drop it. (e.g. A base weapon
// like the fist can't be dropped because you'll never see it.)
if (SpawnState == GetDefaultByType("Actor").SpawnState || SpawnState == NULL)
{
return NULL;
}
if (bUndroppable || bUntossable || Owner == NULL || Amount <= 0)
{
return NULL;
}
if (Amount == 1 && !bKeepDepleted)
{
BecomePickup ();
DropTime = 30;
bSpecial = bSolid = false;
return self;
}
let copy = Inventory(Spawn (GetClass(), Owner.Pos, NO_REPLACE));
if (copy != NULL)
{
copy.MaxAmount = MaxAmount;
copy.Amount = 1;
copy.DropTime = 30;
copy.bSpecial = copy.bSolid = false;
Amount--;
}
return copy;
}
//=========================================================================== //===========================================================================
// //
// AInventory :: DepleteOrDestroy // AInventory :: DepleteOrDestroy
@ -186,12 +361,38 @@ class Inventory : Actor native
virtual void DoEffect() {} virtual void DoEffect() {}
virtual bool Use (bool pickup) { return false; }
virtual double GetSpeedFactor() { return 1; } virtual double GetSpeedFactor() { return 1; }
virtual bool GetNoTeleportFreeze() { return false; } virtual bool GetNoTeleportFreeze() { return false; }
virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {} virtual void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) {}
virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {} virtual void AlterWeaponSprite(VisStyle vis, in out int changed) {}
virtual void OwnerDied() {} virtual void OwnerDied() {}
//===========================================================================
//
// AInventory :: DrawPowerup
//
// Gives self item a chance to draw a special status indicator on the screen.
// Returns false if it didn't draw anything.
//
//===========================================================================
virtual bool DrawPowerup(int x, int y) { return false; }
//===========================================================================
//
// AInventory :: AbsorbDamage
//
// Allows inventory items (primarily armor) to reduce the amount of damage
// taken. Damage is the amount of damage that would be done without armor,
// and newdamage is the amount that should be done after the armor absorbs
// it.
//
//===========================================================================
virtual void AbsorbDamage (int damage, Name damageType, out int newdamage) {}
} }
class DehackedPickup : Inventory native class DehackedPickup : Inventory native

View file

@ -36,4 +36,48 @@ class CustomInventory : StateProvider native
deprecated action void A_Lower() {} deprecated action void A_Lower() {}
deprecated action void A_Raise() {} deprecated action void A_Raise() {}
deprecated action void A_CheckReload() {} deprecated action void A_CheckReload() {}
//===========================================================================
//
// ACustomInventory :: SpecialDropAction
//
//===========================================================================
override bool SpecialDropAction (Actor dropper)
{
return CallStateChain (dropper, FindState('Drop'));
}
//===========================================================================
//
// ACustomInventory :: Use
//
//===========================================================================
override bool Use (bool pickup)
{
return CallStateChain (Owner, FindState('Use'));
}
//===========================================================================
//
// ACustomInventory :: TryPickup
//
//===========================================================================
override bool TryPickup (in out Actor toucher)
{
let pickupstate = FindState('Pickup');
bool useok = CallStateChain (toucher, pickupstate);
if ((useok || pickupstate == NULL) && FindState('Use') != NULL)
{
useok = Super.TryPickup (toucher);
}
else if (useok)
{
GoAwayAndDie();
}
return useok;
}
} }