diff --git a/src/actor.h b/src/actor.h index 6c07c99dc..03266f9bb 100644 --- a/src/actor.h +++ b/src/actor.h @@ -643,6 +643,11 @@ public: // Removes the item from the inventory list. virtual void RemoveInventory (AInventory *item); + // Take the amount value of an item from the inventory list. + // If nothing is left, the item may be destroyed. + // Returns true if the initial item count is positive. + virtual bool TakeInventory (PClassActor *itemclass, int amount, bool fromdecorate = false, bool notakeinfinite = false); + // Uses an item and removes it from the inventory. virtual bool UseInventory (AInventory *item); diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 14ead016e..14bc49007 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -137,14 +137,9 @@ bool P_MorphPlayer (player_t *activator, player_t *p, PClassPlayerPawn *spawntyp hxarmor->Slots[3] = 0; hxarmor->Slots[4] = spawntype->HexenArmor[0]; } - else if (item->ItemFlags & IF_KEEPDEPLETED) - { - // Set depletable armor to 0 (this includes BasicArmor). - item->Amount = 0; - } else { - item->Destroy (); + item->DepleteOrDestroy(); } } item = next; diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp index 892ea01e0..0019c8aca 100644 --- a/src/g_shared/a_pickups.cpp +++ b/src/g_shared/a_pickups.cpp @@ -1177,6 +1177,32 @@ void AInventory::Destroy () if (SendItemDrop == this) SendItemDrop = NULL; } +//=========================================================================== +// +// AInventory :: DepleteOrDestroy +// +// If the item is depleted, just change its amount to 0, otherwise it's destroyed. +// +//=========================================================================== + +void AInventory::DepleteOrDestroy () +{ + // If it's not ammo or an internal armor, destroy it. + // Ammo needs to stick around, even when it's zero for the benefit + // of the weapons that use it and to maintain the maximum ammo + // amounts a backpack might have given. + // Armor shouldn't be removed because they only work properly when + // they are the last items in the inventory. + if (ItemFlags & IF_KEEPDEPLETED) + { + Amount = 0; + } + else + { + Destroy(); + } +} + //=========================================================================== // // AInventory :: GetBlend diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h index 1331151ff..7bd94f9fb 100644 --- a/src/g_shared/a_pickups.h +++ b/src/g_shared/a_pickups.h @@ -155,6 +155,7 @@ public: virtual void MarkPrecacheSounds() const; virtual void BeginPlay (); virtual void Destroy (); + virtual void DepleteOrDestroy (); virtual void Tick (); virtual bool ShouldRespawn (); virtual bool ShouldStay (); diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index 60436719c..163757581 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -769,10 +769,7 @@ void cht_Give (player_t *player, const char *name, int amount) static_cast(type)->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) { // Give the weapon only if it belongs to the current game or - // is in a weapon slot. - if (static_cast(type)->GameFilter == GAME_Any || - (static_cast(type)->GameFilter & gameinfo.gametype) || - player->weapons.LocateWeapon(static_cast(type), NULL, NULL)) + if (player->weapons.LocateWeapon(static_cast(type), NULL, NULL)) { AWeapon *def = (AWeapon*)GetDefaultByType (type); if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON)) @@ -854,7 +851,7 @@ void cht_Give (player_t *player, const char *name, int amount) void cht_Take (player_t *player, const char *name, int amount) { bool takeall; - PClass *type; + PClassActor *type; if (player->mo == NULL || player->health <= 0) { @@ -1045,7 +1042,7 @@ void cht_Take (player_t *player, const char *name, int amount) if (takeall) return; - type = PClass::FindClass (name); + type = PClass::FindActor (name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (player == &players[consoleplayer]) @@ -1053,24 +1050,7 @@ void cht_Take (player_t *player, const char *name, int amount) } else { - AInventory *inventory = player->mo->FindInventory(static_cast(type)); - - if (inventory != NULL) - { - inventory->Amount -= amount ? amount : 1; - - if (inventory->Amount <= 0) - { - if (inventory->ItemFlags & IF_KEEPDEPLETED) - { - inventory->Amount = 0; - } - else - { - inventory->Destroy (); - } - } - } + player->mo->TakeInventory(type, amount ? amount : 1); } return; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 52bcda4d6..2b3923d34 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1131,40 +1131,6 @@ static void GiveInventory (AActor *activator, const char *type, int amount) } } -//============================================================================ -// -// DoTakeInv -// -// Takes an item from a single actor. -// -//============================================================================ - -static void DoTakeInv (AActor *actor, PClassActor *info, int amount) -{ - AInventory *item = actor->FindInventory (info); - if (item != NULL) - { - item->Amount -= amount; - if (item->Amount <= 0) - { - // If it's not ammo or an internal armor, destroy it. - // Ammo needs to stick around, even when it's zero for the benefit - // of the weapons that use it and to maintain the maximum ammo - // amounts a backpack might have given. - // Armor shouldn't be removed because they only work properly when - // they are the last items in the inventory. - if (item->ItemFlags & IF_KEEPDEPLETED) - { - item->Amount = 0; - } - else - { - item->Destroy (); - } - } - } -} - //============================================================================ // // TakeInventory @@ -1199,12 +1165,12 @@ static void TakeInventory (AActor *activator, const char *type, int amount) for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i]) - DoTakeInv (players[i].mo, info, amount); + players[i].mo->TakeInventory(info, amount); } } else { - DoTakeInv (activator, info, amount); + activator->TakeInventory(info, amount); } } @@ -2302,8 +2268,8 @@ void FBehavior::LoadScriptsDirectory () } // [EP] Clang 3.5.0 optimizer miscompiles this function and causes random -// crashes in the program. I hope that Clang 3.5.x will fix this. -#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ >= 5 +// crashes in the program. This is fixed in 3.5.1 onwards. +#if defined(__clang__) && __clang_major__ == 3 && __clang_minor__ == 5 && __clang_patchlevel__ == 0 asm("" : "+g" (NumScripts)); #endif for (i = 0; i < NumScripts; ++i) @@ -4781,8 +4747,8 @@ static void SetActorTeleFog(AActor *activator, int tid, FString telefogsrc, FStr FActorIterator iterator(tid); AActor *actor; - PClassActor * src = telefogsrc.IsNotEmpty() ? PClass::FindActor(telefogsrc) : NULL; - PClassActor * dest = telefogdest.IsNotEmpty() ? PClass::FindActor(telefogdest) : NULL; + PClassActor * src = PClass::FindActor(telefogsrc); + PClassActor * dest = PClass::FindActor(telefogdest); while ((actor = iterator.Next())) { if (telefogsrc.IsNotEmpty()) diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index b8fa0c29f..a768c72b9 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -649,22 +649,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount) if (itemtype == RUNTIME_CLASS(ASigil)) return; - AInventory *item = player->mo->FindInventory (itemtype); - if (item != NULL) - { - item->Amount -= amount; - if (item->Amount <= 0) - { - if (item->ItemFlags & IF_KEEPDEPLETED) - { - item->Amount = 0; - } - else - { - item->Destroy (); - } - } - } + player->mo->TakeInventory(itemtype, amount); } CUSTOM_CVAR(Float, dlg_musicvolume, 1.0f, CVAR_ARCHIVE) diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 547cecace..a85dc94d9 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -944,13 +944,13 @@ bool P_LoadGLNodes(MapData * map) result=true; for(unsigned i=0; i<4;i++) { - if (strnicmp(f_gwa->GetLump(i+1)->Name, check[i], 8)) + if (strnicmp(f_gwa->GetLump(li+i+1)->Name, check[i], 8)) { result=false; break; } else - gwalumps[i] = f_gwa->GetLump(i+1)->NewReader(); + gwalumps[i] = f_gwa->GetLump(li+i+1)->NewReader(); } if (result) result = DoLoadGLNodes(gwalumps); } diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index a4b849cbc..b68c4601d 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -799,10 +799,7 @@ static int UseHealthItems(TArray &Items, int &saveHealth) saveHealth -= maxhealth; if (--Items[index]->Amount == 0) { - if (!(Items[index]->ItemFlags & IF_KEEPDEPLETED)) - { - Items[index]->Destroy (); - } + Items[index]->DepleteOrDestroy (); Items.Delete(index); break; } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 2aff70798..a16b9a47d 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -685,6 +685,57 @@ void AActor::RemoveInventory(AInventory *item) } } +//============================================================================ +// +// AActor :: TakeInventory +// +//============================================================================ + +bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate, bool notakeinfinite) +{ + AInventory *item = FindInventory(itemclass); + + if (item == NULL) + return false; + + if (!fromdecorate) + { + item->Amount -= amount; + if (item->Amount <= 0) + { + item->DepleteOrDestroy(); + } + // It won't be used in non-decorate context, so return false here + return false; + } + + bool result = false; + if (item->Amount > 0) + { + result = true; + } + + if (item->IsKindOf(RUNTIME_CLASS(AHexenArmor))) + return false; + + // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set + // and infinite ammo is on + if (notakeinfinite && + ((dmflags & DF_INFINITE_AMMO) || (player && player->cheats & CF_INFINITEAMMO)) && + item->IsKindOf(RUNTIME_CLASS(AAmmo))) + { + // Nothing to do here, except maybe res = false;? Would it make sense? + } + else if (!amount || amount>=item->Amount) + { + item->DepleteOrDestroy(); + } + else item->Amount-=amount; + + return result; +} + + //============================================================================ // // AActor :: DestroyAllInventory @@ -752,9 +803,9 @@ bool AActor::UseInventory (AInventory *item) if (dmflags2 & DF2_INFINITE_INVENTORY) return true; - if (--item->Amount <= 0 && !(item->ItemFlags & IF_KEEPDEPLETED)) + if (--item->Amount <= 0) { - item->Destroy (); + item->DepleteOrDestroy (); } return true; } diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index dc2cbc418..aaaf2d4f4 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1996,34 +1996,8 @@ int DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) return numret; } - bool res = false; - - AInventory *inv = receiver->FindInventory(itemtype); - - if (inv && !inv->IsKindOf(RUNTIME_CLASS(AHexenArmor))) - { - if (inv->Amount > 0) - { - res = true; - } - // Do not take ammo if the "no take infinite/take as ammo depletion" flag is set - // and infinite ammo is on - if (flags & TIF_NOTAKEINFINITE && - ((dmflags & DF_INFINITE_AMMO) || (receiver->player->cheats & CF_INFINITEAMMO)) && - inv->IsKindOf(RUNTIME_CLASS(AAmmo))) - { - // Nothing to do here, except maybe res = false;? Would it make sense? - } - else if (!amount || amount>=inv->Amount) - { - if (inv->ItemFlags&IF_KEEPDEPLETED) inv->Amount=0; - else inv->Destroy(); - } - else - { - inv->Amount -= amount; - } - } + bool res = receiver->TakeInventory(itemtype, amount, true, (flags & TIF_NOTAKEINFINITE) != 0); + if (!orresult) { ACTION_SET_RESULT(res); diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index 17d080090..c60977b27 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1448,8 +1448,8 @@ DEFINE_PROPERTY(stamina, I, Actor) DEFINE_PROPERTY(telefogsourcetype, S, Actor) { PROP_STRING_PARM(str, 0); - if (!stricmp(str, "") || !stricmp(str, "none")) defaults->TeleFogSourceType = NULL; - else defaults->TeleFogSourceType = FindClassTentative(str, RUNTIME_CLASS(AActor)); + + defaults->TeleFogSourceType = FindClassTentative(str, RUNTIME_CLASS(AActor)); } //========================================================================== @@ -1458,8 +1458,8 @@ DEFINE_PROPERTY(telefogsourcetype, S, Actor) DEFINE_PROPERTY(telefogdesttype, S, Actor) { PROP_STRING_PARM(str, 0); - if (!stricmp(str, "") || !stricmp(str, "none")) defaults->TeleFogDestType = NULL; - else defaults->TeleFogDestType = FindClassTentative(str, RUNTIME_CLASS(AActor)); + + defaults->TeleFogDestType = FindClassTentative(str, RUNTIME_CLASS(AActor)); } //==========================================================================