From 9c4a56536645482f8b6477ced1fcd4e6a6bcf71c Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 31 May 2012 09:46:07 +0000 Subject: [PATCH] - fixed: Inventory clearing after changing a level with the ACS ChangeLevel command did not properly clear the inventory. This will now use the same code as the ACS ClearInventory command. SVN r3673 (trunk) --- src/actor.h | 3 +++ src/g_game.cpp | 21 +-------------- src/p_acs.cpp | 72 ++------------------------------------------------ src/p_mobj.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 90 deletions(-) diff --git a/src/actor.h b/src/actor.h index 6c0ff2f80..12b775a10 100644 --- a/src/actor.h +++ b/src/actor.h @@ -658,6 +658,9 @@ public: // Tosses an item out of the inventory. virtual AInventory *DropInventory (AInventory *item); + // Removes all items from the inventory. + void ClearInventory(); + // Returns true if this view is considered "local" for the player. bool CheckLocalView (int playernum) const; diff --git a/src/g_game.cpp b/src/g_game.cpp index e0752d96a..224ade775 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1290,26 +1290,7 @@ void G_PlayerFinishLevel (int player, EFinishLevelType mode, int flags) // Clears the entire inventory and gives back the defaults for starting a game if (flags & CHANGELEVEL_RESETINVENTORY) { - AInventory *inv = p->mo->Inventory; - - while (inv != NULL) - { - AInventory *next = inv->Inventory; - if (!(inv->ItemFlags & IF_UNDROPPABLE)) - { - inv->Destroy (); - } - else if (inv->GetClass() == RUNTIME_CLASS(AHexenArmor)) - { - AHexenArmor *harmor = static_cast (inv); - harmor->Slots[3] = harmor->Slots[2] = harmor->Slots[1] = harmor->Slots[0] = 0; - } - inv = next; - } - p->ReadyWeapon = NULL; - p->PendingWeapon = WP_NOCHANGE; - p->psprites[ps_weapon].state = NULL; - p->psprites[ps_flash].state = NULL; + p->mo->ClearInventory(); p->mo->GiveDefaultInventory(); } } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 9bff85433..366519890 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -389,74 +389,6 @@ void P_WriteACSVars(FILE *stdfile) //---- Inventory functions --------------------------------------// // -//============================================================================ -// -// DoClearInv -// -// Clears the inventory of a single actor. -// -//============================================================================ - -static void DoClearInv (AActor *actor) -{ - // In case destroying an inventory item causes another to be destroyed - // (e.g. Weapons destroy their sisters), keep track of the pointer to - // the next inventory item rather than the next inventory item itself. - // For example, if a weapon is immediately followed by its sister, the - // next weapon we had tracked would be to the sister, so it is now - // invalid and we won't be able to find the complete inventory by - // following it. - // - // When we destroy an item, we leave invp alone, since the destruction - // process will leave it pointing to the next item we want to check. If - // we don't destroy an item, then we move invp to point to its Inventory - // pointer. - // - // It should be safe to assume that an item being destroyed will only - // destroy items further down in the chain, because if it was going to - // destroy something we already processed, we've already destroyed it, - // so it won't have anything to destroy. - - AInventory **invp = &actor->Inventory; - - while (*invp != NULL) - { - AInventory *inv = *invp; - if (!(inv->ItemFlags & IF_UNDROPPABLE)) - { - // For the sake of undroppable weapons, never remove ammo once - // it has been acquired; just set its amount to 0. - if (inv->IsKindOf(RUNTIME_CLASS(AAmmo))) - { - AAmmo *ammo = static_cast(inv); - ammo->Amount = 0; - invp = &inv->Inventory; - } - else - { - inv->Destroy (); - } - } - else if (inv->GetClass() == RUNTIME_CLASS(AHexenArmor)) - { - AHexenArmor *harmor = static_cast (inv); - harmor->Slots[3] = harmor->Slots[2] = harmor->Slots[1] = harmor->Slots[0] = 0; - invp = &inv->Inventory; - } - else - { - invp = &inv->Inventory; - } - } - if (actor->player != NULL) - { - actor->player->ReadyWeapon = NULL; - actor->player->PendingWeapon = WP_NOCHANGE; - actor->player->psprites[ps_weapon].state = NULL; - actor->player->psprites[ps_flash].state = NULL; - } -} - //============================================================================ // // ClearInventory @@ -472,12 +404,12 @@ static void ClearInventory (AActor *activator) for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i]) - DoClearInv (players[i].mo); + players[i].mo->ClearInventory(); } } else { - DoClearInv (activator); + activator->ClearInventory(); } } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f877f9646..5990650ea 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -786,6 +786,74 @@ bool AActor::GiveAmmo (const PClass *type, int amount) return false; } +//============================================================================ +// +// AActor :: ClearInventory +// +// Clears the inventory of a single actor. +// +//============================================================================ + +void AActor::ClearInventory() +{ + // In case destroying an inventory item causes another to be destroyed + // (e.g. Weapons destroy their sisters), keep track of the pointer to + // the next inventory item rather than the next inventory item itself. + // For example, if a weapon is immediately followed by its sister, the + // next weapon we had tracked would be to the sister, so it is now + // invalid and we won't be able to find the complete inventory by + // following it. + // + // When we destroy an item, we leave invp alone, since the destruction + // process will leave it pointing to the next item we want to check. If + // we don't destroy an item, then we move invp to point to its Inventory + // pointer. + // + // It should be safe to assume that an item being destroyed will only + // destroy items further down in the chain, because if it was going to + // destroy something we already processed, we've already destroyed it, + // so it won't have anything to destroy. + + AInventory **invp = &Inventory; + + while (*invp != NULL) + { + AInventory *inv = *invp; + if (!(inv->ItemFlags & IF_UNDROPPABLE)) + { + // For the sake of undroppable weapons, never remove ammo once + // it has been acquired; just set its amount to 0. + if (inv->IsKindOf(RUNTIME_CLASS(AAmmo))) + { + AAmmo *ammo = static_cast(inv); + ammo->Amount = 0; + invp = &inv->Inventory; + } + else + { + inv->Destroy (); + } + } + else if (inv->GetClass() == RUNTIME_CLASS(AHexenArmor)) + { + AHexenArmor *harmor = static_cast (inv); + harmor->Slots[3] = harmor->Slots[2] = harmor->Slots[1] = harmor->Slots[0] = 0; + invp = &inv->Inventory; + } + else + { + invp = &inv->Inventory; + } + } + if (player != NULL) + { + player->ReadyWeapon = NULL; + player->PendingWeapon = WP_NOCHANGE; + player->psprites[ps_weapon].state = NULL; + player->psprites[ps_flash].state = NULL; + } +} + //============================================================================ // // AActor :: CopyFriendliness