diff --git a/docs/rh-log.txt b/docs/rh-log.txt index a87a9aa1d3..ba4085269a 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -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) - Converted a_doomhealth.cpp to DECORATE. - Added a PickupMessage property to the internal actor parser, replaced diff --git a/src/actor.h b/src/actor.h index ccebac8f17..ef12919733 100644 --- a/src/actor.h +++ b/src/actor.h @@ -545,6 +545,9 @@ public: // Tries to give the actor some ammo. bool GiveAmmo (const PClass *type, int amount); + // Destroys all the inventory the actor is holding. + void DestroyAllInventory (); + // Set the alphacolor field properly void SetShade (DWORD rgb); void SetShade (int r, int g, int b); diff --git a/src/d_player.h b/src/d_player.h index a588b1a3ac..7bcfff58b8 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -72,6 +72,8 @@ public: virtual void ActivateMorphWeapon (); virtual AWeapon *PickNewWeapon (const PClass *ammotype); virtual AWeapon *BestWeapon (const PClass *ammotype); + virtual void GiveDeathmatchInventory (); + virtual void FilterCoopRespawnInventory (APlayerPawn *oldplayer); enum EInvulState { diff --git a/src/doomdef.h b/src/doomdef.h index 46e0a1b51f..2d2e19f108 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -221,6 +221,13 @@ enum 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_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! diff --git a/src/g_game.cpp b/src/g_game.cpp index 11fb7289a3..ed25a30704 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1374,27 +1374,18 @@ void G_DoReborn (int playernum, bool freshbot) { // respawn at the start int i; - AInventory *oldInv; // first disassociate the corpse if (players[playernum].mo) { - oldInv = players[playernum].mo->Inventory; - players[playernum].mo->Inventory = NULL; G_QueueBody (players[playernum].mo); players[playernum].mo->player = NULL; } - else - { - oldInv = NULL; - } // spawn at random spot if in death match if (deathmatch) { G_DeathMatchSpawnPlayer (playernum); - if (players[playernum].mo == NULL) - i = 1; return; } @@ -1434,40 +1425,6 @@ void G_DoReborn (int playernum, bool freshbot) } 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; - } - } } } diff --git a/src/g_shared/a_artifacts.cpp b/src/g_shared/a_artifacts.cpp index aee90f235f..d4dc856fe3 100644 --- a/src/g_shared/a_artifacts.cpp +++ b/src/g_shared/a_artifacts.cpp @@ -273,6 +273,19 @@ AInventory *APowerup::CreateTossable () return NULL; } +//=========================================================================== +// +// APowerup :: OwnerDied +// +// Powerups don't last beyond death. +// +//=========================================================================== + +void APowerup::OwnerDied () +{ + Destroy (); +} + // Invulnerability Powerup --------------------------------------------------- IMPLEMENT_STATELESS_ACTOR (APowerInvulnerable, Any, -1, 0) diff --git a/src/g_shared/a_artifacts.h b/src/g_shared/a_artifacts.h index 52fe798ee5..617489afe1 100644 --- a/src/g_shared/a_artifacts.h +++ b/src/g_shared/a_artifacts.h @@ -30,6 +30,7 @@ public: virtual AInventory *CreateCopy (AActor *other); virtual AInventory *CreateTossable (); virtual void Serialize (FArchive &arc); + virtual void OwnerDied (); virtual PalEntry GetBlend (); virtual bool DrawPowerup (int x, int y); diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 6616daa04a..492c30b481 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -529,6 +529,18 @@ void AInventory::Travelled () { } +//=========================================================================== +// +// AInventory :: OwnerDied +// +// Items receive this message when their owners die. +// +//=========================================================================== + +void AInventory::OwnerDied () +{ +} + //=========================================================================== // // AInventory :: HandlePickup diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 4fabea402a..ead13b826b 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -146,6 +146,7 @@ public: virtual bool HandlePickup (AInventory *item); virtual bool Use (bool pickup); virtual void Travelled (); + virtual void OwnerDied (); virtual void AbsorbDamage (int damage, int damageType, int &newdamage); virtual void AlterWeaponSprite (vissprite_t *vis); diff --git a/src/infomacros.h b/src/infomacros.h index 522efbdf7e..d229d1c748 100644 --- a/src/infomacros.h +++ b/src/infomacros.h @@ -209,7 +209,7 @@ public: #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_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_YScale(x) ADD_BYTE_PROP(ADEF_YScale,x) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 04fabeeb56..1cc5ce34a5 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -294,7 +294,7 @@ void cht_DoCheat (player_t *player, int cheat) player->mo->height = player->mo->GetDefault()->height; player->mo->SetState (player->mo->SpawnState); player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); - player->mo->GiveDefaultInventory(); +// player->mo->GiveDefaultInventory(); P_SetPsprite(player, ps_weapon, player->ReadyWeapon->UpState); } } diff --git a/src/m_options.cpp b/src/m_options.cpp index f91d0c951c..3845650fd2 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -931,7 +931,7 @@ static menuitem_t DMFlagsItems[] = { { 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, "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, "No monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_NO_MONSTERS} }, { 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 FOV", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FOV} }, { 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 = diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 52190e58af..080789a5a4 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -334,6 +334,14 @@ void AActor::Die (AActor *source, AActor *inflictor) 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) { // [RH] When missiles die, they just explode P_ExplodeMissile (this, NULL); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 0673c5b210..4782c78447 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -677,6 +677,20 @@ void AActor::RemoveInventory (AInventory *item) } } +//============================================================================ +// +// AActor :: DestroyAllInventory +// +//============================================================================ + +void AActor::DestroyAllInventory () +{ + while (Inventory != NULL) + { + Inventory->Destroy (); + } +} + //============================================================================ // // AActor :: FirstInv @@ -3203,12 +3217,7 @@ void AActor::Deactivate (AActor *activator) void AActor::Destroy () { // [RH] Destroy any inventory this actor is carrying - while (Inventory != NULL) - { - AInventory *item = Inventory; - Inventory = item->Inventory; - item->Destroy (); - } + DestroyAllInventory (); // [RH] Unlink from tid chain RemoveFromHash (); @@ -3220,7 +3229,7 @@ void AActor::Destroy () // Delete all nodes on the current sector_list phares 3/16/98 P_DelSector_List(); - // stop any playing sound + // Transform any playing sound into positioned, non-actor sounds. S_RelinkSound (this, NULL); Super::Destroy (); @@ -3425,24 +3434,18 @@ void P_SpawnPlayer (mapthing2_t *mthing, bool startenterscripts) P_SetupPsprites (p); } - // give all cards in death match mode if (deathmatch) - { - 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(Spawn (PClass::m_Types[i], 0,0,0)); - if (!key->TryPickup (p->mo)) - { - key->Destroy (); - } - } - } - } + { // Give all cards in death match mode. + p->mo->GiveDeathmatchInventory (); + } + else if (multiplayer && state == PST_REBORN && oldactor != NULL) + { // Special inventory handling for respawning in coop + p->mo->FilterCoopRespawnInventory (oldactor); + } + if (oldactor != NULL) + { // Remove any inventory left from the old actor. Coop handles + // it above, but the other modes don't. + oldactor->DestroyAllInventory(); } if (StatusBar != NULL && (playernum == consoleplayer || StatusBar->GetPlayer() == playernum)) diff --git a/src/p_user.cpp b/src/p_user.cpp index 21f8f8fe54..38a941d500 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -38,6 +38,7 @@ #include "p_effect.h" #include "s_sound.h" #include "a_sharedglobal.h" +#include "a_keys.h" #include "statnums.h" #include "v_palette.h" #include "v_video.h" @@ -46,6 +47,7 @@ #include "sbar.h" #include "f_finale.h" #include "c_console.h" +#include "doomdef.h" static FRandom pr_healradius ("HealRadius"); @@ -456,6 +458,141 @@ AWeapon *APlayerPawn::PickNewWeapon (const PClass *ammotype) 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(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 () { @@ -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)) { F_StartSlideshow (); diff --git a/tools/dehsupp/scanner.c b/tools/dehsupp/scanner.c index ce434068fb..e3c6072cd6 100644 --- a/tools/dehsupp/scanner.c +++ b/tools/dehsupp/scanner.c @@ -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" #include #include