- Finally implemented code to keep some or all of your inventory intact when

respawning in coop. Now the new inventory code should finally be complete. :-)
- Fixed: PROP_Inventory_PickupMessage was improperly defined for non-VC++
  compilation.


SVN r197 (trunk)
This commit is contained in:
Randy Heit 2006-06-18 04:10:47 +00:00
parent 1bd6ac028b
commit c87e2252ed
16 changed files with 231 additions and 77 deletions

View file

@ -1,3 +1,9 @@
June 17, 2006
- Finally implemented code to keep some or all of your inventory intact when
respawning in coop. Now the new inventory code should finally be complete. :-)
- Fixed: PROP_Inventory_PickupMessage was improperly defined for non-VC++
compilation.
June 17, 2006 (Changes by Graf Zahl) June 17, 2006 (Changes by Graf Zahl)
- Converted a_doomhealth.cpp to DECORATE. - Converted a_doomhealth.cpp to DECORATE.
- Added a PickupMessage property to the internal actor parser, replaced - Added a PickupMessage property to the internal actor parser, replaced

View file

@ -545,6 +545,9 @@ public:
// Tries to give the actor some ammo. // Tries to give the actor some ammo.
bool GiveAmmo (const PClass *type, int amount); bool GiveAmmo (const PClass *type, int amount);
// Destroys all the inventory the actor is holding.
void DestroyAllInventory ();
// Set the alphacolor field properly // Set the alphacolor field properly
void SetShade (DWORD rgb); void SetShade (DWORD rgb);
void SetShade (int r, int g, int b); void SetShade (int r, int g, int b);

View file

@ -72,6 +72,8 @@ public:
virtual void ActivateMorphWeapon (); virtual void ActivateMorphWeapon ();
virtual AWeapon *PickNewWeapon (const PClass *ammotype); virtual AWeapon *PickNewWeapon (const PClass *ammotype);
virtual AWeapon *BestWeapon (const PClass *ammotype); virtual AWeapon *BestWeapon (const PClass *ammotype);
virtual void GiveDeathmatchInventory ();
virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer);
enum EInvulState enum EInvulState
{ {

View file

@ -221,6 +221,13 @@ enum
DF_NO_FOV = 1 << 19, // Only let the arbitrator set FOV (for all players) DF_NO_FOV = 1 << 19, // Only let the arbitrator set FOV (for all players)
DF_NO_COOP_WEAPON_SPAWN = 1 << 20, // Don't spawn multiplayer weapons in coop games DF_NO_COOP_WEAPON_SPAWN = 1 << 20, // Don't spawn multiplayer weapons in coop games
DF_NO_CROUCH = 1 << 21, // Don't allow crouching DF_NO_CROUCH = 1 << 21, // Don't allow crouching
DF_COOP_LOSE_INVENTORY = 1 << 22, // Lose all your old inventory when respawning in coop
DF_COOP_LOSE_KEYS = 1 << 23, // Lose keys when respawning in coop
DF_COOP_LOSE_WEAPONS = 1 << 24, // Lose weapons when respawning in coop
DF_COOP_LOSE_ARMOR = 1 << 25, // Lose armor when respawning in coop
DF_COOP_LOSE_POWERUPS = 1 << 26, // Lose powerups when respawning in coop
DF_COOP_LOSE_AMMO = 1 << 27, // Lose ammo when respawning in coop
DF_COOP_HALVE_AMMO = 1 << 28, // Lose half your ammo when respawning in coop (but not less than the normal starting amount)
}; };
// [BC] More dmflags. w00p! // [BC] More dmflags. w00p!

View file

@ -1374,27 +1374,18 @@ void G_DoReborn (int playernum, bool freshbot)
{ {
// respawn at the start // respawn at the start
int i; int i;
AInventory *oldInv;
// first disassociate the corpse // first disassociate the corpse
if (players[playernum].mo) if (players[playernum].mo)
{ {
oldInv = players[playernum].mo->Inventory;
players[playernum].mo->Inventory = NULL;
G_QueueBody (players[playernum].mo); G_QueueBody (players[playernum].mo);
players[playernum].mo->player = NULL; players[playernum].mo->player = NULL;
} }
else
{
oldInv = NULL;
}
// spawn at random spot if in death match // spawn at random spot if in death match
if (deathmatch) if (deathmatch)
{ {
G_DeathMatchSpawnPlayer (playernum); G_DeathMatchSpawnPlayer (playernum);
if (players[playernum].mo == NULL)
i = 1;
return; return;
} }
@ -1434,40 +1425,6 @@ void G_DoReborn (int playernum, bool freshbot)
} }
P_SpawnPlayer (&playerstarts[playernum]); P_SpawnPlayer (&playerstarts[playernum]);
} }
// Cooperative net-play, retain keys, weapons, and some ammo,
// but throw the other inventory items away.
if (!freshbot)
{
AInventory *probe = oldInv;
while (probe != NULL)
{
AInventory *next = probe->Inventory;
if (probe->IsKindOf (RUNTIME_CLASS(AWeapon)))
{
// Keep weapons
}
else if (probe->IsKindOf (RUNTIME_CLASS(AKey)))
{
// Keep keys
}
else if (probe->IsKindOf (RUNTIME_CLASS(AAmmo)))
{
// Take away some ammo
if (probe->Amount > 0)
{
probe->Amount = MAX(1, probe->Amount / 2);
}
}
else
{
// Eliminate it
probe->Destroy ();
}
probe = next;
}
}
} }
} }

View file

@ -273,6 +273,19 @@ AInventory *APowerup::CreateTossable ()
return NULL; return NULL;
} }
//===========================================================================
//
// APowerup :: OwnerDied
//
// Powerups don't last beyond death.
//
//===========================================================================
void APowerup::OwnerDied ()
{
Destroy ();
}
// Invulnerability Powerup --------------------------------------------------- // Invulnerability Powerup ---------------------------------------------------
IMPLEMENT_STATELESS_ACTOR (APowerInvulnerable, Any, -1, 0) IMPLEMENT_STATELESS_ACTOR (APowerInvulnerable, Any, -1, 0)

View file

@ -30,6 +30,7 @@ public:
virtual AInventory *CreateCopy (AActor *other); virtual AInventory *CreateCopy (AActor *other);
virtual AInventory *CreateTossable (); virtual AInventory *CreateTossable ();
virtual void Serialize (FArchive &arc); virtual void Serialize (FArchive &arc);
virtual void OwnerDied ();
virtual PalEntry GetBlend (); virtual PalEntry GetBlend ();
virtual bool DrawPowerup (int x, int y); virtual bool DrawPowerup (int x, int y);

View file

@ -529,6 +529,18 @@ void AInventory::Travelled ()
{ {
} }
//===========================================================================
//
// AInventory :: OwnerDied
//
// Items receive this message when their owners die.
//
//===========================================================================
void AInventory::OwnerDied ()
{
}
//=========================================================================== //===========================================================================
// //
// AInventory :: HandlePickup // AInventory :: HandlePickup

View file

@ -146,6 +146,7 @@ public:
virtual bool HandlePickup (AInventory *item); virtual bool HandlePickup (AInventory *item);
virtual bool Use (bool pickup); virtual bool Use (bool pickup);
virtual void Travelled (); virtual void Travelled ();
virtual void OwnerDied ();
virtual void AbsorbDamage (int damage, int damageType, int &newdamage); virtual void AbsorbDamage (int damage, int damageType, int &newdamage);
virtual void AlterWeaponSprite (vissprite_t *vis); virtual void AlterWeaponSprite (vissprite_t *vis);

View file

@ -209,7 +209,7 @@ public:
#define PROP_Inventory_Icon(x) ADD_STRING_PROP(ADEF_Inventory_Icon,"\20",x) #define PROP_Inventory_Icon(x) ADD_STRING_PROP(ADEF_Inventory_Icon,"\20",x)
#define PROP_Obituary(x) ADD_STRING_PROP(ADEF_Obituary,"\21",x) #define PROP_Obituary(x) ADD_STRING_PROP(ADEF_Obituary,"\21",x)
#define PROP_HitObituary(x) ADD_STRING_PROP(ADEF_HitObituary,"\22",x) #define PROP_HitObituary(x) ADD_STRING_PROP(ADEF_HitObituary,"\22",x)
#define PROP_Inventory_PickupMessage(x) ADD_STRING_PROP(ADEF_Obituary,"\23",x) #define PROP_Inventory_PickupMessage(x) ADD_STRING_PROP(ADEF_Inventory_PickupMsg,"\23",x)
#define PROP_XScale(x) ADD_BYTE_PROP(ADEF_XScale,x) #define PROP_XScale(x) ADD_BYTE_PROP(ADEF_XScale,x)
#define PROP_YScale(x) ADD_BYTE_PROP(ADEF_YScale,x) #define PROP_YScale(x) ADD_BYTE_PROP(ADEF_YScale,x)

View file

@ -294,7 +294,7 @@ void cht_DoCheat (player_t *player, int cheat)
player->mo->height = player->mo->GetDefault()->height; player->mo->height = player->mo->GetDefault()->height;
player->mo->SetState (player->mo->SpawnState); player->mo->SetState (player->mo->SpawnState);
player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players));
player->mo->GiveDefaultInventory(); // player->mo->GiveDefaultInventory();
P_SetPsprite(player, ps_weapon, player->ReadyWeapon->UpState); P_SetPsprite(player, ps_weapon, player->ReadyWeapon->UpState);
} }
} }

View file

@ -931,7 +931,7 @@ static menuitem_t DMFlagsItems[] = {
{ bitflag, "Allow exit (DM)", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_EXIT} }, { bitflag, "Allow exit (DM)", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_EXIT} },
{ bitflag, "Barrels respawn (DM)", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_BARRELS_RESPAWN} }, { bitflag, "Barrels respawn (DM)", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_BARRELS_RESPAWN} },
{ bitflag, "Respawn protection (DM)",{&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_INVUL} }, { bitflag, "Respawn protection (DM)",{&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_INVUL} },
{ bitflag, "Drop weapons", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_WEAPONDROP} }, { bitflag, "Drop weapon", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_WEAPONDROP} },
{ bitflag, "Infinite ammo", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_INFINITE_AMMO} }, { bitflag, "Infinite ammo", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_INFINITE_AMMO} },
{ bitflag, "No monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_NO_MONSTERS} }, { bitflag, "No monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_NO_MONSTERS} },
{ bitflag, "Monsters respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_MONSTERS_RESPAWN} }, { bitflag, "Monsters respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_MONSTERS_RESPAWN} },
@ -943,7 +943,16 @@ static menuitem_t DMFlagsItems[] = {
{ bitflag, "Allow freelook", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FREELOOK} }, { bitflag, "Allow freelook", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FREELOOK} },
{ bitflag, "Allow FOV", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FOV} }, { bitflag, "Allow FOV", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FOV} },
{ bitflag, "Allow BFG aiming", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NO_FREEAIMBFG} }, { bitflag, "Allow BFG aiming", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NO_FREEAIMBFG} },
{ bitflag, "Multi. weapons in coop", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_COOP_WEAPON_SPAWN} }, { redtext, " ", {NULL}, {0}, {0}, {0}, {NULL} },
{ whitetext,"Cooperative Settings", {NULL}, {0}, {0}, {0}, {NULL} },
{ bitflag, "Spawn multi. weapons", {&dmflags},{1}, {0}, {0}, {(value_t *)DF_NO_COOP_WEAPON_SPAWN} },
{ bitflag, "Lose entire inventory",{&dmflags}, {0}, {0}, {0}, {(value_t *)DF_COOP_LOSE_INVENTORY} },
{ bitflag, "Keep keys", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_COOP_LOSE_KEYS} },
{ bitflag, "Keep weapons", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_COOP_LOSE_WEAPONS} },
{ bitflag, "Keep armor", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_COOP_LOSE_ARMOR} },
{ bitflag, "Keep powerups", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_COOP_LOSE_POWERUPS} },
{ bitflag, "Keep ammo", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_COOP_LOSE_AMMO} },
{ bitflag, "Lose half ammo", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_COOP_HALVE_AMMO} },
}; };
static menu_t DMFlagsMenu = static menu_t DMFlagsMenu =

View file

@ -334,6 +334,14 @@ void AActor::Die (AActor *source, AActor *inflictor)
this->player->cheats&CF_PREDICTING?"predicting":"real"); 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();
item = next;
}
if (flags & MF_MISSILE) if (flags & MF_MISSILE)
{ // [RH] When missiles die, they just explode { // [RH] When missiles die, they just explode
P_ExplodeMissile (this, NULL); P_ExplodeMissile (this, NULL);

View file

@ -677,6 +677,20 @@ void AActor::RemoveInventory (AInventory *item)
} }
} }
//============================================================================
//
// AActor :: DestroyAllInventory
//
//============================================================================
void AActor::DestroyAllInventory ()
{
while (Inventory != NULL)
{
Inventory->Destroy ();
}
}
//============================================================================ //============================================================================
// //
// AActor :: FirstInv // AActor :: FirstInv
@ -3203,12 +3217,7 @@ void AActor::Deactivate (AActor *activator)
void AActor::Destroy () void AActor::Destroy ()
{ {
// [RH] Destroy any inventory this actor is carrying // [RH] Destroy any inventory this actor is carrying
while (Inventory != NULL) DestroyAllInventory ();
{
AInventory *item = Inventory;
Inventory = item->Inventory;
item->Destroy ();
}
// [RH] Unlink from tid chain // [RH] Unlink from tid chain
RemoveFromHash (); RemoveFromHash ();
@ -3220,7 +3229,7 @@ void AActor::Destroy ()
// Delete all nodes on the current sector_list phares 3/16/98 // Delete all nodes on the current sector_list phares 3/16/98
P_DelSector_List(); P_DelSector_List();
// stop any playing sound // Transform any playing sound into positioned, non-actor sounds.
S_RelinkSound (this, NULL); S_RelinkSound (this, NULL);
Super::Destroy (); Super::Destroy ();
@ -3425,24 +3434,18 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool startenterscripts)
P_SetupPsprites (p); P_SetupPsprites (p);
} }
// give all cards in death match mode
if (deathmatch) if (deathmatch)
{ { // Give all cards in death match mode.
for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) p->mo->GiveDeathmatchInventory ();
{ }
if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) else if (multiplayer && state == PST_REBORN && oldactor != NULL)
{ { // Special inventory handling for respawning in coop
AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); p->mo->FilterCoopRespawnInventory (oldactor);
if (key->KeyNumber != 0) }
{ if (oldactor != NULL)
key = static_cast<AKey *>(Spawn (PClass::m_Types[i], 0,0,0)); { // Remove any inventory left from the old actor. Coop handles
if (!key->TryPickup (p->mo)) // it above, but the other modes don't.
{ oldactor->DestroyAllInventory();
key->Destroy ();
}
}
}
}
} }
if (StatusBar != NULL && (playernum == consoleplayer || StatusBar->GetPlayer() == playernum)) if (StatusBar != NULL && (playernum == consoleplayer || StatusBar->GetPlayer() == playernum))

View file

@ -38,6 +38,7 @@
#include "p_effect.h" #include "p_effect.h"
#include "s_sound.h" #include "s_sound.h"
#include "a_sharedglobal.h" #include "a_sharedglobal.h"
#include "a_keys.h"
#include "statnums.h" #include "statnums.h"
#include "v_palette.h" #include "v_palette.h"
#include "v_video.h" #include "v_video.h"
@ -46,6 +47,7 @@
#include "sbar.h" #include "sbar.h"
#include "f_finale.h" #include "f_finale.h"
#include "c_console.h" #include "c_console.h"
#include "doomdef.h"
static FRandom pr_healradius ("HealRadius"); static FRandom pr_healradius ("HealRadius");
@ -456,6 +458,141 @@ AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype)
return best; return best;
} }
//===========================================================================
//
// APlayerPawn :: GiveDeathmatchInventory
//
// Gives players items they should have in addition to their default
// inventory when playing deathmatch. (i.e. all keys)
//
//===========================================================================
void APlayerPawn::GiveDeathmatchInventory()
{
for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i)
{
if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey)))
{
AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]);
if (key->KeyNumber != 0)
{
key = static_cast<AKey *>(Spawn (PClass::m_Types[i], 0,0,0));
if (!key->TryPickup (this))
{
key->Destroy ();
}
}
}
}
}
//===========================================================================
//
// APlayerPawn :: FilterCoopRespawnInventory
//
// When respawning in coop, this function is called to walk through the dead
// player's inventory and modify it according to the current game flags so
// that it can be transferred to the new live player. This player currently
// has the default inventory, and the oldplayer has the inventory at the time
// of death.
//
//===========================================================================
void APlayerPawn::FilterCoopRespawnInventory (APlayerPawn *oldplayer)
{
AInventory *item, *next, *defitem;
// If we're losing everything, this is really simple.
if (dmflags & DF_COOP_LOSE_INVENTORY)
{
oldplayer->DestroyAllInventory();
return;
}
// If we don't want to lose anything, then we don't need to bother checking
// the old inventory.
if (dmflags & (DF_COOP_LOSE_KEYS |
DF_COOP_LOSE_WEAPONS |
DF_COOP_LOSE_AMMO |
DF_COOP_HALVE_AMMO |
DF_COOP_LOSE_ARMOR |
DF_COOP_LOSE_POWERUPS))
{
// Walk through the old player's inventory and destroy or modify
// according to dmflags.
for (item = oldplayer->Inventory; item != NULL; item = next)
{
next = item->Inventory;
// If this item is part of the default inventory, we never want
// to destroy it, although we might want to copy the default
// inventory amount.
defitem = FindInventory (item->GetClass());
if ((dmflags & DF_COOP_LOSE_KEYS) &&
defitem == NULL &&
item->IsKindOf(RUNTIME_CLASS(AKey)))
{
item->Destroy();
}
else if ((dmflags & DF_COOP_LOSE_WEAPONS) &&
defitem == NULL &&
item->IsKindOf(RUNTIME_CLASS(AWeapon)))
{
item->Destroy();
}
else if ((dmflags & DF_COOP_LOSE_ARMOR) &&
defitem == NULL &&
item->IsKindOf(RUNTIME_CLASS(AArmor)))
{
item->Destroy();
}
else if ((dmflags & DF_COOP_LOSE_POWERUPS) &&
defitem == NULL &&
item->IsKindOf(RUNTIME_CLASS(APowerupGiver)))
{
item->Destroy();
}
else if ((dmflags & (DF_COOP_LOSE_AMMO | DF_COOP_HALVE_AMMO)) &&
item->IsKindOf(RUNTIME_CLASS(AAmmo)))
{
if (defitem == NULL)
{
if (dmflags & DF_COOP_LOSE_AMMO)
{
// Do NOT destroy the ammo, because a weapon might reference it.
item->Amount = 0;
}
else if (item->Amount > 1)
{
item->Amount /= 2;
}
}
else
{
// When set to lose ammo, you get to keep all your starting ammo.
// When set to halve ammo, you won't be left with less than your starting amount.
if (dmflags & DF_COOP_LOSE_AMMO)
{
item->Amount = defitem->Amount;
}
else if (item->Amount > 1)
{
item->Amount = MAX(item->Amount / 2, defitem->Amount);
}
}
}
}
}
// Now destroy the default inventory this player is holding and move
// over the old player's remaining inventory.
DestroyAllInventory();
ObtainInventory (oldplayer);
player->ReadyWeapon = NULL;
PickNewWeapon (NULL);
}
const char *APlayerPawn::GetSoundClass () const char *APlayerPawn::GetSoundClass ()
{ {
@ -559,11 +696,6 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor)
} }
} }
} }
// Kill the player's inventory
while (Inventory != NULL)
{
Inventory->Destroy ();
}
if (!multiplayer && (level.flags & LEVEL_DEATHSLIDESHOW)) if (!multiplayer && (level.flags & LEVEL_DEATHSLIDESHOW))
{ {
F_StartSlideshow (); F_StartSlideshow ();

View file

@ -1,4 +1,4 @@
/* Generated by re2c 0.10.3 on Sat May 27 10:44:26 2006 */ /* Generated by re2c 0.10.3 on Wed Jun 14 22:02:31 2006 */
#line 1 "scanner.re" #line 1 "scanner.re"
#include <string.h> #include <string.h>
#include <malloc.h> #include <malloc.h>