2006-02-24 04:48:15 +00:00
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "info.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "gi.h"
|
|
|
|
#include "p_lnspec.h"
|
|
|
|
#include "a_hereticglobal.h"
|
|
|
|
#include "sbar.h"
|
|
|
|
#include "statnums.h"
|
|
|
|
#include "c_dispatch.h"
|
|
|
|
#include "gstrings.h"
|
|
|
|
#include "templates.h"
|
2006-05-07 00:27:22 +00:00
|
|
|
#include "a_strifeglobal.h"
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
static FRandom pr_restore ("RestorePos");
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AAmmo, Any, -1, 0)
|
2007-03-07 02:24:24 +00:00
|
|
|
PROP_Inventory_FlagsSet (IF_KEEPDEPLETED)
|
2006-02-24 04:48:15 +00:00
|
|
|
PROP_Inventory_PickupSound ("misc/ammo_pkup")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AAmmo :: Serialize
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AAmmo::Serialize (FArchive &arc)
|
|
|
|
{
|
|
|
|
Super::Serialize (arc);
|
2006-04-11 16:27:41 +00:00
|
|
|
arc << BackpackAmount << BackpackMaxAmount;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AAmmo :: GetParentAmmo
|
|
|
|
//
|
|
|
|
// Returns the least-derived ammo type that this ammo is a descendant of.
|
|
|
|
// That is, if this ammo is an immediate subclass of Ammo, then this ammo's
|
|
|
|
// type is returned. If this ammo's superclass is not Ammo, then this
|
|
|
|
// function travels up the inheritance chain until it finds a type that is
|
|
|
|
// an immediate subclass of Ammo and returns that.
|
|
|
|
//
|
|
|
|
// The intent of this is that all unique ammo types will be immediate
|
|
|
|
// subclasses of Ammo. To make different pickups with different ammo amounts,
|
|
|
|
// you subclass the type of ammo you want a different amount for and edit
|
|
|
|
// that.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *AAmmo::GetParentAmmo () const
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *type = GetClass ();
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
while (type->ParentClass != RUNTIME_CLASS(AAmmo))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
type = type->ParentClass;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AAmmo :: HandlePickup
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AAmmo::HandlePickup (AInventory *item)
|
|
|
|
{
|
|
|
|
if (GetClass() == item->GetClass() ||
|
|
|
|
(item->IsKindOf (RUNTIME_CLASS(AAmmo)) && static_cast<AAmmo*>(item)->GetParentAmmo() == GetClass()))
|
|
|
|
{
|
|
|
|
if (Amount < MaxAmount)
|
|
|
|
{
|
2006-04-21 05:44:21 +00:00
|
|
|
int receiving = item->Amount;
|
|
|
|
|
2007-07-28 12:38:10 +00:00
|
|
|
if (!(item->ItemFlags&IF_IGNORESKILL))
|
2006-04-21 05:44:21 +00:00
|
|
|
{
|
2007-07-28 12:38:10 +00:00
|
|
|
// extra ammo in baby mode and nightmare mode
|
|
|
|
if (gameskill == sk_baby || (gameskill == sk_nightmare && gameinfo.gametype != GAME_Strife))
|
|
|
|
{
|
|
|
|
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
|
|
|
receiving += receiving;
|
|
|
|
else
|
|
|
|
receiving += receiving >> 1;
|
|
|
|
}
|
2006-04-21 05:44:21 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
int oldamount = Amount;
|
2006-04-21 05:44:21 +00:00
|
|
|
Amount += receiving;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (Amount > MaxAmount)
|
|
|
|
{
|
|
|
|
Amount = MaxAmount;
|
|
|
|
}
|
|
|
|
item->ItemFlags |= IF_PICKUPGOOD;
|
|
|
|
|
|
|
|
// If the player previously had this ammo but ran out, possibly switch
|
|
|
|
// to a weapon that uses it, but only if the player doesn't already
|
|
|
|
// have a weapon pending.
|
|
|
|
|
|
|
|
assert (Owner != NULL);
|
|
|
|
|
|
|
|
if (oldamount == 0 && Owner != NULL && Owner->player != NULL &&
|
|
|
|
!Owner->player->userinfo.neverswitch &&
|
|
|
|
Owner->player->PendingWeapon == WP_NOCHANGE &&
|
|
|
|
(Owner->player->ReadyWeapon == NULL ||
|
|
|
|
(Owner->player->ReadyWeapon->WeaponFlags & WIF_WIMPY_WEAPON)))
|
|
|
|
{
|
|
|
|
AWeapon *best = static_cast<APlayerPawn *>(Owner)->BestWeapon (GetClass());
|
|
|
|
if (best != NULL && (Owner->player->ReadyWeapon == NULL ||
|
|
|
|
best->SelectionOrder < Owner->player->ReadyWeapon->SelectionOrder))
|
|
|
|
{
|
|
|
|
Owner->player->PendingWeapon = best;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
return Inventory->HandlePickup (item);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AAmmo :: CreateCopy
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
AInventory *AAmmo::CreateCopy (AActor *other)
|
|
|
|
{
|
|
|
|
AInventory *copy;
|
2006-04-21 05:44:21 +00:00
|
|
|
int amount = Amount;
|
|
|
|
|
|
|
|
// extra ammo in baby mode and nightmare mode
|
2007-07-28 12:38:10 +00:00
|
|
|
if (!(ItemFlags&IF_IGNORESKILL))
|
2006-04-21 05:44:21 +00:00
|
|
|
{
|
2007-07-28 12:38:10 +00:00
|
|
|
if (gameskill == sk_baby || (gameskill == sk_nightmare && gameinfo.gametype != GAME_Strife))
|
|
|
|
{
|
|
|
|
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
|
|
|
amount <<= 1;
|
|
|
|
else
|
|
|
|
amount += amount >> 1;
|
|
|
|
}
|
2006-04-21 05:44:21 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
if (GetClass()->ParentClass != RUNTIME_CLASS(AAmmo))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *type = GetParentAmmo();
|
2006-07-08 02:17:35 +00:00
|
|
|
assert (type->ActorInfo != NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!GoAway ())
|
|
|
|
{
|
|
|
|
Destroy ();
|
|
|
|
}
|
2006-07-16 09:10:45 +00:00
|
|
|
|
|
|
|
copy = static_cast<AInventory *>(Spawn (type, 0, 0, 0, NO_REPLACE));
|
2006-04-21 05:44:21 +00:00
|
|
|
copy->Amount = amount;
|
2006-02-24 04:48:15 +00:00
|
|
|
copy->BecomeItem ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
copy = Super::CreateCopy (other);
|
2006-04-21 05:44:21 +00:00
|
|
|
copy->Amount = amount;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
if (copy->Amount > copy->MaxAmount)
|
|
|
|
{ // Don't pick up more ammo than you're supposed to be able to carry.
|
|
|
|
copy->Amount = copy->MaxAmount;
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// FUNC P_GiveBody
|
|
|
|
//
|
|
|
|
// Returns false if the body isn't needed at all.
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
bool P_GiveBody (AActor *actor, int num)
|
|
|
|
{
|
|
|
|
int max;
|
|
|
|
player_t *player = actor->player;
|
|
|
|
|
|
|
|
if (player != NULL)
|
|
|
|
{
|
2006-07-13 10:17:56 +00:00
|
|
|
max = static_cast<APlayerPawn*>(actor)->GetMaxHealth() + player->stamina;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (player->morphTics)
|
|
|
|
{
|
|
|
|
max = MAXMORPHHEALTH;
|
|
|
|
}
|
|
|
|
// [RH] For Strife: A negative body sets you up with a percentage
|
|
|
|
// of your full health.
|
|
|
|
if (num < 0)
|
|
|
|
{
|
|
|
|
num = max * -num / 100;
|
|
|
|
if (player->health < num)
|
|
|
|
{
|
|
|
|
player->health = num;
|
|
|
|
actor->health = num;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (player->health < max)
|
|
|
|
{
|
|
|
|
player->health += num;
|
|
|
|
if (player->health > max)
|
|
|
|
{
|
|
|
|
player->health = max;
|
|
|
|
}
|
|
|
|
actor->health = player->health;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
max = actor->GetDefault()->health;
|
|
|
|
if (num < 0)
|
|
|
|
{
|
|
|
|
num = max * -num / 100;
|
|
|
|
if (actor->health < num)
|
|
|
|
{
|
|
|
|
actor->health = num;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (actor->health < max)
|
|
|
|
{
|
|
|
|
actor->health += num;
|
|
|
|
if (actor->health > max)
|
|
|
|
{
|
|
|
|
actor->health = max;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_RestoreSpecialThing1
|
|
|
|
//
|
|
|
|
// Make a special thing visible again.
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_RestoreSpecialThing1 (AActor *thing)
|
|
|
|
{
|
|
|
|
thing->renderflags &= ~RF_INVISIBLE;
|
|
|
|
if (static_cast<AInventory *>(thing)->DoRespawn ())
|
|
|
|
{
|
|
|
|
S_Sound (thing, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_RestoreSpecialThing2
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_RestoreSpecialThing2 (AActor *thing)
|
|
|
|
{
|
|
|
|
thing->flags |= MF_SPECIAL;
|
|
|
|
if (!(thing->GetDefault()->flags & MF_NOGRAVITY))
|
|
|
|
{
|
|
|
|
thing->flags &= ~MF_NOGRAVITY;
|
|
|
|
}
|
|
|
|
thing->SetState (thing->SpawnState);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_RestoreSpecialDoomThing
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_RestoreSpecialDoomThing (AActor *self)
|
|
|
|
{
|
|
|
|
self->renderflags &= ~RF_INVISIBLE;
|
|
|
|
self->flags |= MF_SPECIAL;
|
|
|
|
if (!(self->GetDefault()->flags & MF_NOGRAVITY))
|
|
|
|
{
|
|
|
|
self->flags &= ~MF_NOGRAVITY;
|
|
|
|
}
|
|
|
|
if (static_cast<AInventory *>(self)->DoRespawn ())
|
|
|
|
{
|
|
|
|
self->SetState (self->SpawnState);
|
|
|
|
S_Sound (self, CHAN_VOICE, "misc/spawn", 1, ATTN_IDLE);
|
2006-11-04 22:26:04 +00:00
|
|
|
Spawn ("ItemFog", self->x, self->y, self->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROP A_RestoreSpecialPosition
|
|
|
|
//
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_RestoreSpecialPosition (AActor *self)
|
|
|
|
{
|
|
|
|
// Move item back to its original location
|
|
|
|
fixed_t _x, _y;
|
|
|
|
sector_t *sec;
|
|
|
|
|
|
|
|
_x = self->SpawnPoint[0] << FRACBITS;
|
|
|
|
_y = self->SpawnPoint[1] << FRACBITS;
|
|
|
|
sec = R_PointInSubsector (_x, _y)->sector;
|
|
|
|
|
|
|
|
self->SetOrigin (_x, _y, sec->floorplane.ZatPoint (_x, _y));
|
|
|
|
P_CheckPosition (self, _x, _y);
|
|
|
|
|
|
|
|
if (self->flags & MF_SPAWNCEILING)
|
|
|
|
{
|
|
|
|
self->z = self->ceilingz - self->height - (self->SpawnPoint[2] << FRACBITS);
|
|
|
|
}
|
|
|
|
else if (self->flags2 & MF2_SPAWNFLOAT)
|
|
|
|
{
|
|
|
|
fixed_t space = self->ceilingz - self->height - self->floorz;
|
|
|
|
if (space > 48*FRACUNIT)
|
|
|
|
{
|
|
|
|
space -= 40*FRACUNIT;
|
|
|
|
self->z = ((space * pr_restore())>>8) + self->floorz + 40*FRACUNIT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
self->z = self->floorz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
self->z = (self->SpawnPoint[2] << FRACBITS) + self->floorz;
|
|
|
|
if (self->flags2 & MF2_FLOATBOB)
|
|
|
|
{
|
|
|
|
self->z += FloatBobOffsets[(self->FloatBobPhase + level.maptime) & 63];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pickup flash -------------------------------------------------------------
|
|
|
|
|
|
|
|
class APickupFlash : public AActor
|
|
|
|
{
|
|
|
|
DECLARE_ACTOR (APickupFlash, AActor)
|
|
|
|
};
|
|
|
|
|
|
|
|
FState APickupFlash::States[] =
|
|
|
|
{
|
|
|
|
S_NORMAL (ACLO, 'D', 3, NULL , &States[1]),
|
|
|
|
S_NORMAL (ACLO, 'C', 3, NULL , &States[2]),
|
|
|
|
S_NORMAL (ACLO, 'D', 3, NULL , &States[3]),
|
|
|
|
S_NORMAL (ACLO, 'C', 3, NULL , &States[4]),
|
|
|
|
S_NORMAL (ACLO, 'B', 3, NULL , &States[5]),
|
|
|
|
S_NORMAL (ACLO, 'C', 3, NULL , &States[6]),
|
|
|
|
S_NORMAL (ACLO, 'B', 3, NULL , &States[7]),
|
|
|
|
S_NORMAL (ACLO, 'A', 3, NULL , &States[8]),
|
|
|
|
S_NORMAL (ACLO, 'B', 3, NULL , &States[9]),
|
|
|
|
S_NORMAL (ACLO, 'A', 3, NULL , NULL)
|
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_ACTOR (APickupFlash, Raven, -1, 0)
|
|
|
|
PROP_SpawnState (0)
|
|
|
|
PROP_Flags (MF_NOGRAVITY)
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/* AInventory implementation */
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
FState AInventory::States[] =
|
|
|
|
{
|
|
|
|
#define S_HIDEDOOMISH 0
|
|
|
|
S_NORMAL (TNT1, 'A', 1050, NULL , &States[S_HIDEDOOMISH+1]),
|
|
|
|
S_NORMAL (TNT1, 'A', 0, A_RestoreSpecialPosition , &States[S_HIDEDOOMISH+2]),
|
|
|
|
S_NORMAL (TNT1, 'A', 1, A_RestoreSpecialDoomThing , NULL),
|
|
|
|
|
|
|
|
#define S_HIDESPECIAL (S_HIDEDOOMISH+3)
|
|
|
|
S_NORMAL (ACLO, 'E', 1400, NULL , &States[S_HIDESPECIAL+1]),
|
|
|
|
S_NORMAL (ACLO, 'A', 0, A_RestoreSpecialPosition , &States[S_HIDESPECIAL+2]),
|
|
|
|
S_NORMAL (ACLO, 'A', 4, A_RestoreSpecialThing1 , &States[S_HIDESPECIAL+3]),
|
|
|
|
S_NORMAL (ACLO, 'B', 4, NULL , &States[S_HIDESPECIAL+4]),
|
|
|
|
S_NORMAL (ACLO, 'A', 4, NULL , &States[S_HIDESPECIAL+5]),
|
|
|
|
S_NORMAL (ACLO, 'B', 4, NULL , &States[S_HIDESPECIAL+6]),
|
|
|
|
S_NORMAL (ACLO, 'C', 4, NULL , &States[S_HIDESPECIAL+7]),
|
|
|
|
S_NORMAL (ACLO, 'B', 4, NULL , &States[S_HIDESPECIAL+8]),
|
|
|
|
S_NORMAL (ACLO, 'C', 4, NULL , &States[S_HIDESPECIAL+9]),
|
|
|
|
S_NORMAL (ACLO, 'D', 4, NULL , &States[S_HIDESPECIAL+10]),
|
|
|
|
S_NORMAL (ACLO, 'C', 4, NULL , &States[S_HIDESPECIAL+11]),
|
|
|
|
S_NORMAL (ACLO, 'D', 4, A_RestoreSpecialThing2 , NULL),
|
|
|
|
|
|
|
|
#define S_HELD (S_HIDESPECIAL+12)
|
|
|
|
S_NORMAL (TNT1, 'A', -1, NULL , NULL),
|
|
|
|
|
|
|
|
#define S_HOLDANDDESTROY (S_HELD+1)
|
|
|
|
S_NORMAL (TNT1, 'A', 1, NULL , NULL),
|
|
|
|
};
|
|
|
|
|
|
|
|
int AInventory::StaticLastMessageTic;
|
|
|
|
const char *AInventory::StaticLastMessage;
|
|
|
|
|
|
|
|
IMPLEMENT_POINTY_CLASS (AInventory)
|
|
|
|
DECLARE_POINTER (Owner)
|
|
|
|
END_POINTERS
|
|
|
|
|
|
|
|
BEGIN_DEFAULTS (AInventory, Any, -1, 0)
|
|
|
|
PROP_Inventory_Amount (1)
|
|
|
|
PROP_Inventory_MaxAmount (1)
|
|
|
|
PROP_UseSound ("misc/invuse")
|
|
|
|
PROP_Inventory_PickupSound ("misc/i_pkup")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: Tick
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::Tick ()
|
|
|
|
{
|
|
|
|
Super::Tick ();
|
|
|
|
if (DropTime)
|
|
|
|
{
|
|
|
|
if (--DropTime == 0)
|
|
|
|
{
|
|
|
|
flags |= GetDefault()->flags & (MF_SPECIAL|MF_SOLID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: Serialize
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::Serialize (FArchive &arc)
|
|
|
|
{
|
|
|
|
Super::Serialize (arc);
|
|
|
|
arc << Owner << Amount << MaxAmount << RespawnTics << ItemFlags;
|
|
|
|
if (arc.IsStoring ())
|
|
|
|
{
|
|
|
|
TexMan.WriteTexture (arc, Icon);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Icon = TexMan.ReadTexture (arc);
|
|
|
|
}
|
2006-04-11 16:27:41 +00:00
|
|
|
arc << AR_SOUNDW(PickupSound);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: SpecialDropAction
|
|
|
|
//
|
|
|
|
// Called by P_DropItem. Return true to prevent the standard drop tossing.
|
|
|
|
// A few Strife items that are meant to trigger actions rather than be
|
|
|
|
// picked up use this. Normal items shouldn't need it.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::SpecialDropAction (AActor *dropper)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: ShouldRespawn
|
|
|
|
//
|
|
|
|
// Returns true if the item should hide itself and reappear later when picked
|
|
|
|
// up.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::ShouldRespawn ()
|
|
|
|
{
|
2006-05-03 14:54:48 +00:00
|
|
|
if ((ItemFlags & IF_BIGPOWERUP) && !(dmflags & DF_RESPAWN_SUPER)) return false;
|
2006-02-24 04:48:15 +00:00
|
|
|
return !!(dmflags & DF_ITEMS_RESPAWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: BeginPlay
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::BeginPlay ()
|
|
|
|
{
|
|
|
|
Super::BeginPlay ();
|
|
|
|
ChangeStatNum (STAT_INVENTORY);
|
|
|
|
flags |= MF_DROPPED; // [RH] Items are dropped by default
|
|
|
|
}
|
|
|
|
|
2007-01-12 15:24:10 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: DoEffect
|
|
|
|
//
|
|
|
|
// Handles any effect an item might apply to its owner
|
|
|
|
// Normally only used by subclasses of APowerup
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::DoEffect ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: Travelled
|
|
|
|
//
|
|
|
|
// Called when an item in somebody's inventory is carried over to another
|
|
|
|
// map, in case it needs to do special reinitialization.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::Travelled ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-06-18 04:10:47 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: OwnerDied
|
|
|
|
//
|
|
|
|
// Items receive this message when their owners die.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::OwnerDied ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: HandlePickup
|
|
|
|
//
|
|
|
|
// Returns true if the pickup was handled (or should not happen at all),
|
|
|
|
// false if not.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::HandlePickup (AInventory *item)
|
|
|
|
{
|
|
|
|
if (item->GetClass() == GetClass())
|
|
|
|
{
|
|
|
|
if (Amount < MaxAmount)
|
|
|
|
{
|
|
|
|
Amount += item->Amount;
|
|
|
|
if (Amount > MaxAmount)
|
|
|
|
{
|
|
|
|
Amount = MaxAmount;
|
|
|
|
}
|
|
|
|
item->ItemFlags |= IF_PICKUPGOOD;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
return Inventory->HandlePickup (item);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: GoAway
|
|
|
|
//
|
|
|
|
// Returns true if you must create a copy of this item to give to the player
|
|
|
|
// or false if you can use this one instead.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::GoAway ()
|
|
|
|
{
|
|
|
|
// Dropped items never stick around
|
|
|
|
if (flags & MF_DROPPED)
|
|
|
|
{
|
|
|
|
if (ItemFlags & IF_PICKUPFLASH)
|
|
|
|
{
|
2006-07-16 09:10:45 +00:00
|
|
|
Spawn<APickupFlash> (x, y, z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ShouldStay ())
|
|
|
|
{
|
|
|
|
if (ItemFlags & IF_PICKUPFLASH)
|
|
|
|
{
|
2006-07-16 09:10:45 +00:00
|
|
|
Spawn<APickupFlash> (x, y, z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
Hide ();
|
|
|
|
if (ShouldRespawn ())
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: GoAwayAndDie
|
|
|
|
//
|
|
|
|
// Like GoAway but used by items that don't insert themselves into the
|
|
|
|
// inventory. If they won't be respawning, then they can destroy themselves.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::GoAwayAndDie ()
|
|
|
|
{
|
|
|
|
if (!GoAway ())
|
|
|
|
{
|
|
|
|
flags &= ~MF_SPECIAL;
|
|
|
|
SetState (&States[S_HOLDANDDESTROY]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: CreateCopy
|
|
|
|
//
|
|
|
|
// Returns an actor suitable for placing in an inventory, either itself or
|
|
|
|
// a copy based on whether it needs to respawn or not. Returning NULL
|
|
|
|
// indicates the item should not be picked up.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
AInventory *AInventory::CreateCopy (AActor *other)
|
|
|
|
{
|
|
|
|
AInventory *copy;
|
|
|
|
|
|
|
|
if (GoAway ())
|
|
|
|
{
|
2006-07-16 09:10:45 +00:00
|
|
|
copy = static_cast<AInventory *>(Spawn (GetClass(), 0, 0, 0, NO_REPLACE));
|
2006-02-24 04:48:15 +00:00
|
|
|
copy->Amount = Amount;
|
|
|
|
copy->MaxAmount = MaxAmount;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
copy = this;
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
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 == &AActor::States[AActor::S_NULL] ||
|
|
|
|
SpawnState == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if ((ItemFlags & IF_UNDROPPABLE) || Owner == NULL || Amount <= 0)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-03-07 02:24:24 +00:00
|
|
|
if (Amount == 1 && !(ItemFlags & IF_KEEPDEPLETED))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
BecomePickup ();
|
|
|
|
DropTime = 30;
|
|
|
|
flags &= ~(MF_SPECIAL|MF_SOLID);
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
copy = static_cast<AInventory *>(Spawn (GetClass(), Owner->x,
|
2006-07-16 09:10:45 +00:00
|
|
|
Owner->y, Owner->z, NO_REPLACE));
|
2006-02-24 04:48:15 +00:00
|
|
|
if (copy != NULL)
|
|
|
|
{
|
|
|
|
copy->MaxAmount = MaxAmount;
|
|
|
|
copy->Amount = 1;
|
|
|
|
Amount--;
|
|
|
|
}
|
|
|
|
copy->DropTime = 30;
|
|
|
|
copy->flags &= ~(MF_SPECIAL|MF_SOLID);
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: BecomeItem
|
|
|
|
//
|
|
|
|
// Lets this actor know that it's about to be placed in an inventory.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::BecomeItem ()
|
|
|
|
{
|
|
|
|
if (!(flags & (MF_NOBLOCKMAP|MF_NOSECTOR)))
|
|
|
|
{
|
|
|
|
UnlinkFromWorld ();
|
|
|
|
if (sector_list)
|
|
|
|
{
|
|
|
|
P_DelSeclist (sector_list);
|
|
|
|
sector_list = NULL;
|
|
|
|
}
|
|
|
|
flags |= MF_NOBLOCKMAP|MF_NOSECTOR;
|
|
|
|
LinkToWorld ();
|
|
|
|
}
|
|
|
|
RemoveFromHash ();
|
|
|
|
flags &= ~MF_SPECIAL;
|
|
|
|
SetState (&States[S_HELD]);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: BecomePickup
|
|
|
|
//
|
|
|
|
// Lets this actor know it should wait to be picked up.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::BecomePickup ()
|
|
|
|
{
|
|
|
|
if (Owner != NULL)
|
|
|
|
{
|
|
|
|
Owner->RemoveInventory (this);
|
|
|
|
}
|
|
|
|
if (flags & (MF_NOBLOCKMAP|MF_NOSECTOR))
|
|
|
|
{
|
|
|
|
UnlinkFromWorld ();
|
|
|
|
flags &= ~(MF_NOBLOCKMAP|MF_NOSECTOR);
|
|
|
|
LinkToWorld ();
|
|
|
|
P_FindFloorCeiling (this);
|
|
|
|
}
|
|
|
|
flags = GetDefault()->flags | MF_DROPPED;
|
|
|
|
renderflags &= ~RF_INVISIBLE;
|
|
|
|
SetState (SpawnState);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
void AInventory::AbsorbDamage (int damage, FName damageType, int &newdamage)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
Inventory->AbsorbDamage (damage, damageType, newdamage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-10 22:22:38 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: ModifyDamage
|
|
|
|
//
|
|
|
|
// Allows inventory items to manipulate the amount of damage
|
|
|
|
// inflicted. Damage is the amount of damage that would be done without manipulation,
|
|
|
|
// and newdamage is the amount that should be done after the item has changed
|
|
|
|
// it.
|
|
|
|
// 'active' means it is called by the inflictor, 'passive' by the target.
|
|
|
|
// It may seem that this is redundant and AbsorbDamage is the same. However,
|
|
|
|
// AbsorbDamage is called only for players and also depends on other settings
|
|
|
|
// which are undesirable for a protection artifact.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::ModifyDamage (int damage, FName damageType, int &newdamage, bool passive)
|
|
|
|
{
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
Inventory->ModifyDamage (damage, damageType, newdamage, passive);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-12 11:14:09 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: GetSpeedFactor
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
fixed_t AInventory::GetSpeedFactor ()
|
|
|
|
{
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
return Inventory->GetSpeedFactor();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FRACUNIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: AlterWeaponSprite
|
|
|
|
//
|
|
|
|
// Allows inventory items to alter a player's weapon sprite just before it
|
|
|
|
// is drawn.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-01-14 08:58:07 +00:00
|
|
|
int AInventory::AlterWeaponSprite (vissprite_t *vis)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
2007-01-14 08:58:07 +00:00
|
|
|
return Inventory->AlterWeaponSprite (vis);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2007-01-14 08:58:07 +00:00
|
|
|
return 0;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: Use
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::Use (bool pickup)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: Hide
|
|
|
|
//
|
|
|
|
// Hides this actor until it's time to respawn again.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::Hide ()
|
|
|
|
{
|
|
|
|
flags = (flags & ~MF_SPECIAL) | MF_NOGRAVITY;
|
|
|
|
renderflags |= RF_INVISIBLE;
|
|
|
|
if (gameinfo.gametype & GAME_Raven)
|
|
|
|
{
|
|
|
|
SetState (&States[S_HIDESPECIAL]);
|
|
|
|
tics = 1400;
|
2006-07-13 10:17:56 +00:00
|
|
|
if (ItemFlags & IF_PICKUPFLASH) tics += 30;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetState (&States[S_HIDEDOOMISH]);
|
|
|
|
tics = 1050;
|
|
|
|
}
|
|
|
|
if (RespawnTics != 0)
|
|
|
|
{
|
|
|
|
tics = RespawnTics;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-30 21:49:18 +00:00
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
static void PrintPickupMessage (const char *str)
|
|
|
|
{
|
|
|
|
if (str != NULL)
|
|
|
|
{
|
2006-05-11 17:56:35 +00:00
|
|
|
if (str[0]=='$')
|
2006-04-30 21:49:18 +00:00
|
|
|
{
|
2006-05-11 17:56:35 +00:00
|
|
|
str=GStrings(str+1);
|
2006-04-30 21:49:18 +00:00
|
|
|
}
|
|
|
|
Printf (PRINT_LOW, "%s\n", str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: Touch
|
|
|
|
//
|
|
|
|
// Handles collisions from another actor, possible adding itself to the
|
|
|
|
// collider's inventory.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::Touch (AActor *toucher)
|
|
|
|
{
|
|
|
|
// If a voodoo doll touches something, pretend the real player touched it instead.
|
|
|
|
if (toucher->player != NULL)
|
|
|
|
{
|
|
|
|
toucher = toucher->player->mo;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!TryPickup (toucher))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!(ItemFlags & IF_QUIET))
|
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
const char * message = PickupMessage ();
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
if (toucher->CheckLocalView (consoleplayer)
|
|
|
|
&& (StaticLastMessageTic != gametic || StaticLastMessage != message))
|
|
|
|
{
|
|
|
|
StaticLastMessageTic = gametic;
|
|
|
|
StaticLastMessage = message;
|
2006-04-30 21:49:18 +00:00
|
|
|
PrintPickupMessage (message);
|
2006-02-24 04:48:15 +00:00
|
|
|
StatusBar->FlashCrosshair ();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special check so voodoo dolls picking up items cause the
|
|
|
|
// real player to make noise.
|
|
|
|
if (toucher->player != NULL)
|
|
|
|
{
|
|
|
|
PlayPickupSound (toucher->player->mo);
|
|
|
|
toucher->player->bonuscount = BONUSADD;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PlayPickupSound (toucher);
|
|
|
|
}
|
2006-04-30 21:49:18 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// [RH] Execute an attached special (if any)
|
|
|
|
DoPickupSpecial (toucher);
|
|
|
|
|
|
|
|
if (flags & MF_COUNTITEM)
|
|
|
|
{
|
|
|
|
if (toucher->player != NULL)
|
|
|
|
{
|
|
|
|
toucher->player->itemcount++;
|
|
|
|
}
|
|
|
|
level.found_items++;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Added by MC: Check if item taken was the roam destination of any bot
|
|
|
|
for (int i = 0; i < MAXPLAYERS; i++)
|
|
|
|
{
|
|
|
|
if (playeringame[i] && this == players[i].dest)
|
|
|
|
players[i].dest = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: DoPickupSpecial
|
|
|
|
//
|
|
|
|
// Executes this actor's special when it is picked up.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::DoPickupSpecial (AActor *toucher)
|
|
|
|
{
|
|
|
|
if (special)
|
|
|
|
{
|
|
|
|
LineSpecials[special] (NULL, toucher, false,
|
|
|
|
args[0], args[1], args[2], args[3], args[4]);
|
|
|
|
special = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: PickupMessage
|
|
|
|
//
|
|
|
|
// Returns the message to print when this actor is picked up.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
const char *AInventory::PickupMessage ()
|
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
const char *message = GetClass()->Meta.GetMetaString (AIMETA_PickupMessage);
|
|
|
|
|
|
|
|
return message != NULL? message : "You got a pickup";
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: PlayPickupSound
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::PlayPickupSound (AActor *toucher)
|
|
|
|
{
|
|
|
|
S_SoundID (toucher, CHAN_PICKUP, PickupSound, 1,
|
|
|
|
(ItemFlags & IF_FANCYPICKUPSOUND) &&
|
|
|
|
(toucher == NULL || toucher->CheckLocalView (consoleplayer))
|
|
|
|
? ATTN_SURROUND : ATTN_NORM);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: ShouldStay
|
|
|
|
//
|
|
|
|
// Returns true if the item should not disappear, even temporarily.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::ShouldStay ()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: Destroy
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::Destroy ()
|
|
|
|
{
|
|
|
|
if (Owner != NULL)
|
|
|
|
{
|
|
|
|
Owner->RemoveInventory (this);
|
|
|
|
}
|
|
|
|
Inventory = NULL;
|
|
|
|
Super::Destroy ();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: GetBlend
|
|
|
|
//
|
|
|
|
// Returns a color to blend to the player's view as long as they possess this
|
|
|
|
// item.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
PalEntry AInventory::GetBlend ()
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: PrevItem
|
|
|
|
//
|
|
|
|
// Returns the previous item.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
AInventory *AInventory::PrevItem () const
|
|
|
|
{
|
|
|
|
AInventory *item = Owner->Inventory;
|
|
|
|
|
|
|
|
while (item != NULL && item->Inventory != this)
|
|
|
|
{
|
|
|
|
item = item->Inventory;
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: PrevInv
|
|
|
|
//
|
|
|
|
// Returns the previous item with IF_INVBAR set.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
AInventory *AInventory::PrevInv () const
|
|
|
|
{
|
|
|
|
AInventory *lastgood = NULL;
|
|
|
|
AInventory *item = Owner->Inventory;
|
|
|
|
|
|
|
|
while (item != NULL && item != this)
|
|
|
|
{
|
|
|
|
if (item->ItemFlags & IF_INVBAR)
|
|
|
|
{
|
|
|
|
lastgood = item;
|
|
|
|
}
|
|
|
|
item = item->Inventory;
|
|
|
|
}
|
|
|
|
return lastgood;
|
|
|
|
}
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: NextInv
|
|
|
|
//
|
|
|
|
// Returns the next item with IF_INVBAR set.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
AInventory *AInventory::NextInv () const
|
|
|
|
{
|
|
|
|
AInventory *item = Inventory;
|
|
|
|
|
|
|
|
while (item != NULL && !(item->ItemFlags & IF_INVBAR))
|
|
|
|
{
|
|
|
|
item = item->Inventory;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************/
|
|
|
|
/* AArtifact implementation */
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (APowerupGiver, Any, -1, 0)
|
|
|
|
PROP_Inventory_DefMaxAmount
|
|
|
|
PROP_Inventory_FlagsSet (IF_INVBAR|IF_FANCYPICKUPSOUND)
|
|
|
|
PROP_Inventory_PickupSound ("misc/p_pkup")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: DoRespawn
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::DoRespawn ()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-05-07 00:27:22 +00:00
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: GiveQuest
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::GiveQuest (AActor *toucher)
|
|
|
|
{
|
|
|
|
int quest = GetClass()->Meta.GetMetaInt(AIMETA_GiveQuest);
|
|
|
|
if (quest>0 && quest<31)
|
|
|
|
{
|
|
|
|
toucher->GiveInventoryType (QuestItemClasses[quest-1]);
|
|
|
|
}
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: TryPickup
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AInventory::TryPickup (AActor *toucher)
|
|
|
|
{
|
|
|
|
// 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->HandlePickup (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)
|
|
|
|
{
|
|
|
|
// Special case: If an item's MaxAmount is 0, you can still pick it
|
|
|
|
// up if it is autoactivate-able.
|
|
|
|
if (!(ItemFlags & IF_AUTOACTIVATE))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// The item is placed in the inventory just long enough to be used.
|
|
|
|
toucher->AddInventory (this);
|
|
|
|
bool usegood = Use (true);
|
|
|
|
toucher->RemoveInventory (this);
|
|
|
|
|
|
|
|
if (usegood || (ItemFlags & IF_ALWAYSPICKUP))
|
|
|
|
{
|
|
|
|
GoAwayAndDie ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Add the item to the inventory. It is not already there, or HandlePickup
|
|
|
|
// would have already taken care of it.
|
|
|
|
AInventory *copy = CreateCopy (toucher);
|
|
|
|
if (copy == NULL)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
copy->AttachToOwner (toucher);
|
|
|
|
if (ItemFlags & IF_AUTOACTIVATE)
|
|
|
|
{
|
|
|
|
if (copy->Use (true))
|
|
|
|
{
|
|
|
|
if (--copy->Amount <= 0)
|
|
|
|
{
|
2006-04-17 16:04:27 +00:00
|
|
|
copy->flags &= ~MF_SPECIAL;
|
|
|
|
copy->SetState (&States[S_HOLDANDDESTROY]);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-05-07 00:27:22 +00:00
|
|
|
|
|
|
|
GiveQuest(toucher);
|
2006-02-24 04:48:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// CCMD printinv
|
|
|
|
//
|
|
|
|
// Prints the console player's current inventory.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
CCMD (printinv)
|
|
|
|
{
|
|
|
|
AInventory *item;
|
2006-10-01 01:38:37 +00:00
|
|
|
int pnum = consoleplayer;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-01 01:38:37 +00:00
|
|
|
#ifdef _DEBUG
|
|
|
|
// Only allow peeking on other players' inventory in debug builds.
|
|
|
|
if (argv.argc() > 1)
|
|
|
|
{
|
|
|
|
pnum = atoi (argv[1]);
|
|
|
|
if (pnum < 0 || pnum >= MAXPLAYERS)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (players[pnum].mo == NULL)
|
2006-04-13 03:13:07 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2006-10-01 01:38:37 +00:00
|
|
|
for (item = players[pnum].mo->Inventory; item != NULL; item = item->Inventory)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-09-14 00:02:31 +00:00
|
|
|
Printf ("%s #%u (%d/%d)\n", item->GetClass()->TypeName.GetChars(),
|
2006-05-10 02:40:43 +00:00
|
|
|
item->InventoryID,
|
|
|
|
item->Amount, item->MaxAmount);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: AttachToOwner
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::AttachToOwner (AActor *other)
|
|
|
|
{
|
|
|
|
BecomeItem ();
|
|
|
|
other->AddInventory (this);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AInventory :: DetachFromOwner
|
|
|
|
//
|
|
|
|
// Performs any special work needed when the item leaves an inventory,
|
|
|
|
// either through destruction or becoming a pickup.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void AInventory::DetachFromOwner ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ACustomInventory, Any, -1, 0)
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// ACustomInventory :: SpecialDropAction
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool ACustomInventory::SpecialDropAction (AActor *dropper)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
return CallStateChain (dropper, FindState(NAME_Drop));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// ACustomInventory :: Use
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool ACustomInventory::Use (bool pickup)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
return CallStateChain (Owner, FindState(NAME_Use));
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// ACustomInventory :: TryPickup
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool ACustomInventory::TryPickup (AActor *toucher)
|
|
|
|
{
|
2006-10-31 14:53:21 +00:00
|
|
|
FState *pickupstate = FindState(NAME_Pickup);
|
|
|
|
bool useok = CallStateChain (toucher, pickupstate);
|
|
|
|
if ((useok || pickupstate == NULL) && FindState(NAME_Use) != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
useok = Super::TryPickup (toucher);
|
|
|
|
}
|
2006-04-09 20:03:55 +00:00
|
|
|
else if (useok || ItemFlags & IF_ALWAYSPICKUP)
|
|
|
|
{
|
2006-05-07 00:27:22 +00:00
|
|
|
GiveQuest (toucher);
|
2006-04-09 20:03:55 +00:00
|
|
|
GoAwayAndDie();
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
return useok;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AHealth, Any, -1, 0)
|
2006-11-04 13:06:42 +00:00
|
|
|
PROP_Inventory_Amount (1)
|
2006-02-24 04:48:15 +00:00
|
|
|
PROP_Inventory_MaxAmount (0)
|
|
|
|
PROP_Inventory_PickupSound ("misc/health_pkup")
|
|
|
|
END_DEFAULTS
|
|
|
|
|
2006-06-17 20:29:41 +00:00
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AHealth :: TryPickup
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
const char *AHealth::PickupMessage ()
|
|
|
|
{
|
|
|
|
int threshold = GetClass()->Meta.GetMetaInt(AIMETA_LowHealth, 0);
|
|
|
|
|
|
|
|
if (PrevHealth < threshold)
|
|
|
|
{
|
|
|
|
const char *message = GetClass()->Meta.GetMetaString (AIMETA_LowHealthMessage);
|
|
|
|
|
|
|
|
if (message != NULL)
|
|
|
|
{
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Super::PickupMessage();
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AHealth :: TryPickup
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AHealth::TryPickup (AActor *other)
|
|
|
|
{
|
|
|
|
player_t *player = other->player;
|
|
|
|
int max = MaxAmount;
|
|
|
|
|
2006-04-20 14:21:27 +00:00
|
|
|
if (player != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
PrevHealth = other->player->health;
|
2006-04-20 14:21:27 +00:00
|
|
|
if (max == 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-07-13 10:17:56 +00:00
|
|
|
max = static_cast<APlayerPawn*>(other)->GetMaxHealth() + player->stamina;
|
2006-04-20 14:21:27 +00:00
|
|
|
if (player->morphTics)
|
|
|
|
{
|
|
|
|
max = MAXMORPHHEALTH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (player->health >= max)
|
|
|
|
{
|
|
|
|
// You should be able to pick up the Doom health bonus even if
|
|
|
|
// you are already full on health.
|
|
|
|
if (ItemFlags & IF_ALWAYSPICKUP)
|
|
|
|
{
|
|
|
|
GoAwayAndDie ();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
player->health += Amount;
|
|
|
|
if (player->health > max)
|
|
|
|
{
|
|
|
|
player->health = max;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-04-20 14:21:27 +00:00
|
|
|
player->mo->health = player->health;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2006-04-20 14:21:27 +00:00
|
|
|
else
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-06-17 20:29:41 +00:00
|
|
|
PrevHealth = INT_MAX;
|
2006-04-20 14:21:27 +00:00
|
|
|
if (P_GiveBody(other, Amount) || ItemFlags & IF_ALWAYSPICKUP)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
GoAwayAndDie ();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
GoAwayAndDie ();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AHealthPickup, Any, -1, 0)
|
|
|
|
PROP_Inventory_DefMaxAmount
|
|
|
|
PROP_Inventory_FlagsSet (IF_INVBAR)
|
|
|
|
END_DEFAULTS
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AHealthPickup :: CreateCopy
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
AInventory *AHealthPickup::CreateCopy (AActor *other)
|
|
|
|
{
|
|
|
|
AInventory *copy = Super::CreateCopy (other);
|
|
|
|
copy->health = health;
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AHealthPickup :: CreateTossable
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
AInventory *AHealthPickup::CreateTossable ()
|
|
|
|
{
|
|
|
|
AInventory *copy = Super::CreateTossable ();
|
|
|
|
if (copy != NULL)
|
|
|
|
{
|
|
|
|
copy->health = health;
|
|
|
|
}
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AHealthPickup :: HandlePickup
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AHealthPickup::HandlePickup (AInventory *item)
|
|
|
|
{
|
|
|
|
// HealthPickups that are the same type but have different health amounts
|
|
|
|
// do not count as the same item.
|
|
|
|
if (item->health == health)
|
|
|
|
{
|
|
|
|
return Super::HandlePickup (item);
|
|
|
|
}
|
|
|
|
if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
return Inventory->HandlePickup (item);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AHealthPickup :: Use
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AHealthPickup::Use (bool pickup)
|
|
|
|
{
|
|
|
|
return P_GiveBody (Owner, health);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Backpack -----------------------------------------------------------------
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
2007-04-28 09:06:32 +00:00
|
|
|
// ABackpackItem :: Serialize
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-04-28 09:06:32 +00:00
|
|
|
void ABackpackItem::Serialize (FArchive &arc)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
Super::Serialize (arc);
|
2006-04-11 16:27:41 +00:00
|
|
|
arc << bDepleted;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
2007-04-28 09:06:32 +00:00
|
|
|
// ABackpackItem :: CreateCopy
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
// A backpack is being added to a player who doesn't yet have one. Give them
|
|
|
|
// every kind of ammo, and increase their max amounts.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-04-28 09:06:32 +00:00
|
|
|
AInventory *ABackpackItem::CreateCopy (AActor *other)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
// Find every unique type of ammo. Give it to the player if
|
|
|
|
// he doesn't have it already, and double it's maximum capacity.
|
2006-05-10 02:40:43 +00:00
|
|
|
for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
const PClass *type = PClass::m_Types[i];
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
if (type->ParentClass == RUNTIME_CLASS(AAmmo) &&
|
2006-02-24 04:48:15 +00:00
|
|
|
((AAmmo *)GetDefaultByType (type))->BackpackAmount > 0)
|
|
|
|
{
|
|
|
|
AAmmo *ammo = static_cast<AAmmo *>(other->FindInventory (type));
|
2006-11-25 04:47:42 +00:00
|
|
|
int amount = static_cast<AAmmo *>(GetDefaultByType(type))->BackpackAmount;
|
|
|
|
// extra ammo in baby mode and nightmare mode
|
2007-07-28 12:38:10 +00:00
|
|
|
if (!(ItemFlags&IF_IGNORESKILL))
|
2006-11-25 04:47:42 +00:00
|
|
|
{
|
2007-07-28 12:38:10 +00:00
|
|
|
if (gameskill == sk_baby || (gameskill == sk_nightmare && gameinfo.gametype != GAME_Strife))
|
|
|
|
{
|
|
|
|
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
|
|
|
amount <<= 1;
|
|
|
|
else
|
|
|
|
amount += amount >> 1;
|
|
|
|
}
|
2006-11-25 04:47:42 +00:00
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
if (ammo == NULL)
|
|
|
|
{ // The player did not have the ammo. Add it.
|
2006-07-16 09:10:45 +00:00
|
|
|
ammo = static_cast<AAmmo *>(Spawn (type, 0, 0, 0, NO_REPLACE));
|
2006-11-25 04:47:42 +00:00
|
|
|
ammo->Amount = bDepleted ? 0 : amount;
|
2006-02-24 04:48:15 +00:00
|
|
|
ammo->MaxAmount = ammo->BackpackMaxAmount;
|
|
|
|
ammo->AttachToOwner (other);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // The player had the ammo. Give some more.
|
|
|
|
if (ammo->MaxAmount < ammo->BackpackMaxAmount)
|
|
|
|
{
|
|
|
|
ammo->MaxAmount = ammo->BackpackMaxAmount;
|
|
|
|
}
|
|
|
|
if (!bDepleted && ammo->Amount < ammo->MaxAmount)
|
|
|
|
{
|
2006-11-25 04:47:42 +00:00
|
|
|
ammo->Amount += amount;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (ammo->Amount > ammo->MaxAmount)
|
|
|
|
{
|
|
|
|
ammo->Amount = ammo->MaxAmount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Super::CreateCopy (other);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
2007-04-28 09:06:32 +00:00
|
|
|
// ABackpackItem :: HandlePickup
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
// When the player picks up another backpack, just give them more ammo.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-04-28 09:06:32 +00:00
|
|
|
bool ABackpackItem::HandlePickup (AInventory *item)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
// Since you already have a backpack, that means you already have every
|
|
|
|
// kind of ammo in your inventory, so we don't need to look at the
|
2006-05-10 02:40:43 +00:00
|
|
|
// entire PClass list to discover what kinds of ammo exist, and we don't
|
2006-02-24 04:48:15 +00:00
|
|
|
// have to alter the MaxAmount either.
|
2007-04-28 09:06:32 +00:00
|
|
|
if (item->IsKindOf (RUNTIME_CLASS(ABackpackItem)))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
for (AInventory *probe = Owner->Inventory; probe != NULL; probe = probe->Inventory)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
if (probe->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (probe->Amount < probe->MaxAmount)
|
|
|
|
{
|
2006-11-25 04:47:42 +00:00
|
|
|
int amount = static_cast<AAmmo*>(probe->GetDefault())->BackpackAmount;
|
|
|
|
// extra ammo in baby mode and nightmare mode
|
2007-07-28 12:38:10 +00:00
|
|
|
if (!(item->ItemFlags&IF_IGNORESKILL))
|
2006-11-25 04:47:42 +00:00
|
|
|
{
|
2007-07-28 12:38:10 +00:00
|
|
|
if (gameskill == sk_baby || (gameskill == sk_nightmare && gameinfo.gametype != GAME_Strife))
|
|
|
|
{
|
|
|
|
if (gameinfo.gametype & (GAME_Doom|GAME_Strife))
|
|
|
|
amount <<= 1;
|
|
|
|
else
|
|
|
|
amount += amount >> 1;
|
|
|
|
}
|
2006-11-25 04:47:42 +00:00
|
|
|
}
|
|
|
|
probe->Amount += amount;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (probe->Amount > probe->MaxAmount)
|
|
|
|
{
|
|
|
|
probe->Amount = probe->MaxAmount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// The pickup always succeeds, even if you didn't get anything
|
|
|
|
item->ItemFlags |= IF_PICKUPGOOD;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (Inventory != NULL)
|
|
|
|
{
|
|
|
|
return Inventory->HandlePickup (item);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
2007-04-28 09:06:32 +00:00
|
|
|
// ABackpackItem :: CreateTossable
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
// The tossed backpack must not give out any more ammo, otherwise a player
|
|
|
|
// could cheat by dropping their backpack and picking it up for more ammo.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-04-28 09:06:32 +00:00
|
|
|
AInventory *ABackpackItem::CreateTossable ()
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2007-04-28 09:06:32 +00:00
|
|
|
ABackpackItem *pack = static_cast<ABackpackItem *>(Super::CreateTossable());
|
2006-02-24 04:48:15 +00:00
|
|
|
pack->bDepleted = true;
|
|
|
|
return pack;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
2007-04-28 09:06:32 +00:00
|
|
|
// ABackpackItem :: DetachFromOwner
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-04-28 09:06:32 +00:00
|
|
|
void ABackpackItem::DetachFromOwner ()
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
// When removing a backpack, drop the player's ammo maximums to normal
|
|
|
|
AInventory *item;
|
|
|
|
|
|
|
|
for (item = Owner->Inventory; item != NULL; item = item->Inventory)
|
|
|
|
{
|
2006-05-10 02:40:43 +00:00
|
|
|
if (item->GetClass()->ParentClass == RUNTIME_CLASS(AAmmo) &&
|
2006-02-24 04:48:15 +00:00
|
|
|
item->MaxAmount == static_cast<AAmmo*>(item)->BackpackMaxAmount)
|
|
|
|
{
|
|
|
|
item->MaxAmount = static_cast<AInventory*>(item->GetDefault())->MaxAmount;
|
|
|
|
if (item->Amount > item->MaxAmount)
|
|
|
|
{
|
|
|
|
item->Amount = item->MaxAmount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
2006-06-17 20:29:41 +00:00
|
|
|
// ABackpack
|
2006-02-24 04:48:15 +00:00
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
2007-04-28 09:06:32 +00:00
|
|
|
IMPLEMENT_ABSTRACT_ACTOR(ABackpackItem)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
IMPLEMENT_ABSTRACT_ACTOR (AMapRevealer)
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
//
|
|
|
|
// AMapRevealer :: TryPickup
|
|
|
|
//
|
|
|
|
// The MapRevealer doesn't actually go in your inventory. Instead, it sets
|
|
|
|
// a flag on the level.
|
|
|
|
//
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
bool AMapRevealer::TryPickup (AActor *toucher)
|
|
|
|
{
|
|
|
|
level.flags |= LEVEL_ALLMAP;
|
2006-05-07 00:27:22 +00:00
|
|
|
GiveQuest (toucher);
|
2006-02-24 04:48:15 +00:00
|
|
|
GoAwayAndDie ();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|