diff options
author | Trazom62 <none@none> | 2010-05-31 19:10:26 +0200 |
---|---|---|
committer | Trazom62 <none@none> | 2010-05-31 19:10:26 +0200 |
commit | 15847b2f2f8be359f7d152a9f088c4a4052e9622 (patch) | |
tree | 7ebe081787b9a60cabd2f66c58578d58b93ec104 | |
parent | 1a636d3af87ff1390925c407f93e49bb687027b6 (diff) |
Fix exploit with swaping already looted items.
Patch by Vladimir from idea of Zhenya.
Fixes issue #702.
--HG--
branch : trunk
-rw-r--r-- | src/game/Item.cpp | 20 | ||||
-rw-r--r-- | src/game/Item.h | 1 | ||||
-rw-r--r-- | src/game/ItemHandler.cpp | 7 | ||||
-rw-r--r-- | src/game/Player.cpp | 167 |
4 files changed, 104 insertions, 91 deletions
diff --git a/src/game/Item.cpp b/src/game/Item.cpp index cbb27666033..4cfd9484f9f 100644 --- a/src/game/Item.cpp +++ b/src/game/Item.cpp @@ -705,6 +705,9 @@ bool Item::IsEquipped() const bool Item::CanBeTraded(bool mail) const { + if (m_lootGenerated) + return false; + if ((!mail || !IsBoundAccountWide()) && IsSoulBound()) return false; @@ -766,6 +769,23 @@ bool Item::IsBoundByEnchant() const return false; } +uint8 Item::CanBeMergedPartlyWith(ItemPrototype const* proto) const +{ + // not allow merge looting currently items + if (m_lootGenerated) + return EQUIP_ERR_ALREADY_LOOTED; + + // check item type + if (GetEntry() != proto->ItemId) + return EQUIP_ERR_ITEM_CANT_STACK; + + // check free space (full stacks can't be target of merge + if (GetCount() >= proto->GetMaxStackSize()) + return EQUIP_ERR_ITEM_CANT_STACK; + + return EQUIP_ERR_OK; +} + bool Item::IsFitToSpellRequirements(SpellEntry const* spellInfo) const { ItemPrototype const* proto = GetProto(); diff --git a/src/game/Item.h b/src/game/Item.h index b4112b3d132..1bddd344ed4 100644 --- a/src/game/Item.h +++ b/src/game/Item.h @@ -265,6 +265,7 @@ class Item : public Object uint32 GetMaxStackCount() const { return GetProto()->GetMaxStackSize(); } uint8 GetGemCountWithID(uint32 GemID) const; uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const; + uint8 CanBeMergedPartlyWith(ItemPrototype const* proto) const; uint8 GetSlot() const {return m_slot;} Bag *GetContainer() { return m_container; } diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp index 5e70910f774..53aede43492 100644 --- a/src/game/ItemHandler.cpp +++ b/src/game/ItemHandler.cpp @@ -153,13 +153,6 @@ void WorldSession::HandleAutoEquipItemOpcode(WorldPacket & recv_data) if (!pSrcItem) return; // only at cheat - if (pSrcItem->m_lootGenerated) // prevent swap looting item - { - //best error message found for attempting to swap while looting - _player->SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL); - return; - } - uint16 dest; uint8 msg = _player->CanEquipItem(NULL_SLOT, dest, pSrcItem, !pSrcItem->IsBag()); if (msg != EQUIP_ERR_OK) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 0864266fb81..5e74fc99e3e 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -9892,13 +9892,10 @@ uint8 Player::_CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVe // non empty slot, check item type else { - // check item type - if (pItem2->GetEntry() != pProto->ItemId) - return EQUIP_ERR_ITEM_CANT_STACK; - - // check free space - if (pItem2->GetCount() >= pProto->GetMaxStackSize()) - return EQUIP_ERR_ITEM_CANT_STACK; + // can be merged at least partly + uint8 res = pItem2->CanBeMergedPartlyWith(pProto); + if (res != EQUIP_ERR_OK) + return res; // free stack space or infinity need_space = pProto->GetMaxStackSize() - pItem2->GetCount(); @@ -9953,40 +9950,30 @@ uint8 Player::_CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemPrototyp if ((pItem2 != NULL) != merge) continue; + uint32 need_space = pProto->GetMaxStackSize(); + if (pItem2) { - if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize()) - { - uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount(); - if (need_space > count) - need_space = count; - - ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); - if (!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; + // can be merged at least partly + uint8 res = pItem2->CanBeMergedPartlyWith(pProto); + if (res != EQUIP_ERR_OK) + continue; - if (count == 0) - return EQUIP_ERR_OK; - } - } + // descrease at current stacksize + need_space -= pItem2->GetCount(); } - else - { - uint32 need_space = pProto->GetMaxStackSize(); - if (need_space > count) - need_space = count; - ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); - if (!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; + if (need_space > count) + need_space = count; - if (count == 0) - return EQUIP_ERR_OK; - } + ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space); + if (!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if (count==0) + return EQUIP_ERR_OK; } } return EQUIP_ERR_OK; @@ -10010,39 +9997,30 @@ uint8 Player::_CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, I if ((pItem2 != NULL) != merge) continue; + uint32 need_space = pProto->GetMaxStackSize(); + if (pItem2) { - if (pItem2->GetEntry() == pProto->ItemId && pItem2->GetCount() < pProto->GetMaxStackSize()) - { - uint32 need_space = pProto->GetMaxStackSize() - pItem2->GetCount(); - if (need_space > count) - need_space = count; - ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); - if (!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; + // can be merged at least partly + uint8 res = pItem2->CanBeMergedPartlyWith(pProto); + if (res != EQUIP_ERR_OK) + continue; - if (count == 0) - return EQUIP_ERR_OK; - } - } + // descrease at current stacksize + need_space -= pItem2->GetCount(); } - else - { - uint32 need_space = pProto->GetMaxStackSize(); - if (need_space > count) - need_space = count; - ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); - if (!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; + if (need_space > count) + need_space = count; - if (count == 0) - return EQUIP_ERR_OK; - } + ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space); + if (!newPosition.isContainedIn(dest)) + { + dest.push_back(newPosition); + count -= need_space; + + if (count==0) + return EQUIP_ERR_OK; } } return EQUIP_ERR_OK; @@ -10060,11 +10038,22 @@ uint8 Player::_CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED :EQUIP_ERR_ITEM_NOT_FOUND; } - if (pItem && pItem->IsBindedNotWith(this)) + if (pItem) { - if (no_space_count) - *no_space_count = count; - return EQUIP_ERR_DONT_OWN_THAT_ITEM; + // item used + if (pItem->m_lootGenerated) + { + if (no_space_count) + *no_space_count = count; + return EQUIP_ERR_ALREADY_LOOTED; + } + + if (pItem->IsBindedNotWith(this)) + { + if (no_space_count) + *no_space_count = count; + return EQUIP_ERR_DONT_OWN_THAT_ITEM; + } } // check count of items (skip for auto move for same player from bank) @@ -10542,6 +10531,10 @@ uint8 Player::CanStoreItems(Item **pItems,int count) const if (!pProto) return EQUIP_ERR_ITEM_NOT_FOUND; + // item used + if (pItem->m_lootGenerated) + return EQUIP_ERR_ALREADY_LOOTED; + // item it 'bind' if (pItem->IsBindedNotWith(this)) return EQUIP_ERR_DONT_OWN_THAT_ITEM; @@ -10561,8 +10554,8 @@ uint8 Player::CanStoreItems(Item **pItems,int count) const for (int t = KEYRING_SLOT_START; t < KEYRING_SLOT_END; ++t) { - pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t); - if (pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) + pItem2 = GetItemByPos( INVENTORY_SLOT_BAG_0, t ); + if( pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_keys[t-KEYRING_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) { inv_keys[t-KEYRING_SLOT_START] += pItem->GetCount(); b_found = true; @@ -10574,7 +10567,7 @@ uint8 Player::CanStoreItems(Item **pItems,int count) const for (int t = CURRENCYTOKEN_SLOT_START; t < CURRENCYTOKEN_SLOT_END; ++t) { pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t); - if (pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_tokens[t-CURRENCYTOKEN_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) + if( pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_tokens[t-CURRENCYTOKEN_SLOT_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) { inv_tokens[t-CURRENCYTOKEN_SLOT_START] += pItem->GetCount(); b_found = true; @@ -10586,7 +10579,7 @@ uint8 Player::CanStoreItems(Item **pItems,int count) const for (int t = INVENTORY_SLOT_ITEM_START; t < INVENTORY_SLOT_ITEM_END; ++t) { pItem2 = GetItemByPos(INVENTORY_SLOT_BAG_0, t); - if (pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_slot_items[t-INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) + if( pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_slot_items[t-INVENTORY_SLOT_ITEM_START] + pItem->GetCount() <= pProto->GetMaxStackSize()) { inv_slot_items[t-INVENTORY_SLOT_ITEM_START] += pItem->GetCount(); b_found = true; @@ -10603,7 +10596,7 @@ uint8 Player::CanStoreItems(Item **pItems,int count) const for (uint32 j = 0; j < pBag->GetBagSize(); j++) { pItem2 = GetItemByPos(t, j); - if (pItem2 && pItem2->GetEntry() == pItem->GetEntry() && inv_bags[t-INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->GetMaxStackSize()) + if( pItem2 && pItem2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inv_bags[t-INVENTORY_SLOT_BAG_START][j] + pItem->GetCount() <= pProto->GetMaxStackSize()) { inv_bags[t-INVENTORY_SLOT_BAG_START][j] += pItem->GetCount(); b_found = true; @@ -10745,6 +10738,10 @@ uint8 Player::CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, boo ItemPrototype const *pProto = pItem->GetProto(); if (pProto) { + // item used + if (pItem->m_lootGenerated) + return EQUIP_ERR_ALREADY_LOOTED; + if (pItem->IsBindedNotWith(this)) return EQUIP_ERR_DONT_OWN_THAT_ITEM; @@ -10888,6 +10885,10 @@ uint8 Player::CanUnequipItem(uint16 pos, bool swap) const if (!pProto) return EQUIP_ERR_ITEM_NOT_FOUND; + // item used + if (pItem->m_lootGenerated) + return EQUIP_ERR_ALREADY_LOOTED; + // do not allow unequipping gear except weapons, offhands, projectiles, relics in // - combat // - in-progress arenas @@ -10912,12 +10913,6 @@ uint8 Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pI if (!pItem) return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; - if (pItem->m_lootGenerated) - { - GetSession()->DoLootRelease(GetLootGUID()); - return EQUIP_ERR_OK; - } - uint32 count = pItem->GetCount(); sLog.outDebug("STORAGE: CanBankItem bag = %u, slot = %u, item = %u, count = %u", bag, slot, pItem->GetEntry(), pItem->GetCount()); @@ -10925,6 +10920,10 @@ uint8 Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pI if (!pProto) return swap ? EQUIP_ERR_ITEMS_CANT_BE_SWAPPED : EQUIP_ERR_ITEM_NOT_FOUND; + // item used + if (pItem->m_lootGenerated) + return EQUIP_ERR_ALREADY_LOOTED; + if (pItem->IsBindedNotWith(this)) return EQUIP_ERR_DONT_OWN_THAT_ITEM; @@ -12061,6 +12060,13 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) return; } + if (pSrcItem->m_lootGenerated) // prevent split looting item (item + { + //best error message found for attempting to split while looting + SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL); + return; + } + // not let split all items (can be only at cheating) if (pSrcItem->GetCount() == count) { @@ -12075,13 +12081,6 @@ void Player::SplitItem(uint16 src, uint16 dst, uint32 count) return; } - if (pSrcItem->m_lootGenerated) // prevent split looting item (item - { - //best error message found for attempting to split while looting - SendEquipError(EQUIP_ERR_COULDNT_SPLIT_ITEMS, pSrcItem, NULL); - return; - } - sLog.outDebug("STORAGE: SplitItem bag = %u, slot = %u, item = %u, count = %u", dstbag, dstslot, pSrcItem->GetEntry(), count); Item *pNewItem = pSrcItem->CloneItem(count, this); if (!pNewItem) |