diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 70 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 13 | ||||
| -rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 181 | ||||
| -rw-r--r-- | src/server/game/Handlers/MiscHandler.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 30 | ||||
| -rw-r--r-- | src/server/game/Loot/LootMgr.h | 23 | ||||
| -rw-r--r-- | src/server/game/Server/Packets/LootPackets.cpp | 9 | ||||
| -rw-r--r-- | src/server/game/Server/Packets/LootPackets.h | 26 | ||||
| -rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 6 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.h | 1 |
11 files changed, 280 insertions, 89 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 52e4369123a..8ea901380a2 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -8019,6 +8019,28 @@ void Player::_ApplyAllLevelScaleItemMods(bool apply) } } +ObjectGuid Player::GetLootWorldObjectGUID(ObjectGuid const& lootObjectGuid) const +{ + auto itr = m_AELootView.find(lootObjectGuid); + if (itr != m_AELootView.end()) + return itr->second; + + return ObjectGuid::Empty; +} + +void Player::RemoveAELootedObject(ObjectGuid const& lootObjectGuid) +{ + m_AELootView.erase(lootObjectGuid); +} + +bool Player::HasLootWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const +{ + return m_AELootView.end() != std::find_if(m_AELootView.begin(), m_AELootView.end(), [&lootWorldObjectGuid](std::pair<ObjectGuid, ObjectGuid> const& lootView) + { + return lootView.second == lootWorldObjectGuid; + }); +} + /* If in a battleground a player dies, and an enemy removes the insignia, the player's bones is lootable Called by remove insignia spell effect */ void Player::RemovedInsignia(Player* looterPlr) @@ -8060,10 +8082,15 @@ void Player::SendLootRelease(ObjectGuid guid) const SendDirectMessage(packet.Write()); } -void Player::SendLoot(ObjectGuid guid, LootType loot_type) +void Player::SendLootReleaseAll() const +{ + SendDirectMessage(WorldPackets::Loot::LootReleaseAll().Write()); +} + +void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = false*/) { ObjectGuid currentLootGuid = GetLootGUID(); - if (!currentLootGuid.IsEmpty()) + if (!currentLootGuid.IsEmpty() && !aeLooting) m_session->DoLootRelease(currentLootGuid); Loot* loot; @@ -8244,7 +8271,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) Creature* creature = GetMap()->GetCreature(guid); // must be in range and creature must be alive for pickpocket and must be dead for another loot - if (!creature || creature->IsAlive() != (loot_type == LOOT_PICKPOCKETING) || !creature->IsWithinDistInMap(this, INTERACTION_DISTANCE)) + if (!creature || creature->IsAlive() != (loot_type == LOOT_PICKPOCKETING) || (!aeLooting && !creature->IsWithinDistInMap(this, INTERACTION_DISTANCE))) { SendLootRelease(guid); return; @@ -8381,19 +8408,22 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) } } - SetLootGUID(guid); + if (!aeLooting) + SetLootGUID(guid); WorldPackets::Loot::LootResponse packet; - packet.LootObj = guid; - packet.Owner = loot->GetGUID(); + packet.Owner = guid; + packet.LootObj = loot->GetGUID(); packet._LootMethod = _lootMethod; packet.AcquireReason = loot_type; packet.Acquired = true; // false == No Loot (this too^^) + packet.AELooting = aeLooting; loot->BuildLootResponse(packet, this, permission); SendDirectMessage(packet.Write()); // add 'this' player as one of the players that are looting 'loot' loot->AddLooter(GetGUID()); + m_AELootView[loot->GetGUID()] = guid; } else SendLootError(GetLootGUID(), LOOT_ERROR_DIDNT_KILL); @@ -8418,10 +8448,10 @@ void Player::SendNotifyLootMoneyRemoved(ObjectGuid lootObj) const SendDirectMessage(packet.Write()); } -void Player::SendNotifyLootItemRemoved(ObjectGuid owner, ObjectGuid lootObj, uint8 lootSlot) const +void Player::SendNotifyLootItemRemoved(ObjectGuid lootObj, uint8 lootSlot) const { WorldPackets::Loot::LootRemoved packet; - packet.Owner = owner; + packet.Owner = GetLootWorldObjectGUID(lootObj); packet.LootObj = lootObj; packet.LootListID = lootSlot + 1; GetSession()->SendPacket(packet.Write()); @@ -25106,7 +25136,7 @@ void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore cons } } -void Player::StoreLootItem(uint8 lootSlot, Loot* loot) +void Player::StoreLootItem(uint8 lootSlot, Loot* loot, AELootResult* aeResult/* = nullptr*/) { QuestItem* qitem = nullptr; QuestItem* ffaitem = nullptr; @@ -25122,14 +25152,14 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) if (!item->AllowedForPlayer(this)) { - SendLootRelease(GetLootGUID()); + SendLootReleaseAll(); return; } // questitems use the blocked field for other purposes if (!qitem && item->is_blocked) { - SendLootRelease(GetLootGUID()); + SendLootReleaseAll(); return; } @@ -25144,7 +25174,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) qitem->is_looted = true; //freeforall is 1 if everyone's supposed to get the quest item. if (item->freeforall || loot->GetPlayerQuestItems().size() == 1) - SendNotifyLootItemRemoved(GetLootGUID(), loot->GetGUID(), lootSlot); + SendNotifyLootItemRemoved(loot->GetGUID(), lootSlot); else loot->NotifyQuestItemRemoved(qitem->index); } @@ -25154,7 +25184,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) { //freeforall case, notify only one player of the removal ffaitem->is_looted = true; - SendNotifyLootItemRemoved(GetLootGUID(), loot->GetGUID(), lootSlot); + SendNotifyLootItemRemoved(loot->GetGUID(), lootSlot); } else { @@ -25176,10 +25206,16 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) if (Guild* guild = GetGuild()) guild->AddGuildNews(GUILD_NEWS_ITEM_LOOTED, GetGUID(), 0, item->itemid); - SendNewItem(newitem, uint32(item->count), false, false, true); - UpdateCriteria(CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); - UpdateCriteria(CRITERIA_TYPE_LOOT_TYPE, item->itemid, item->count, loot->loot_type); - UpdateCriteria(CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); + // if aeLooting then we must delay sending out item so that it appears properly stacked in chat + if (!aeResult) + { + SendNewItem(newitem, uint32(item->count), false, false, true); + UpdateCriteria(CRITERIA_TYPE_LOOT_ITEM, item->itemid, item->count); + UpdateCriteria(CRITERIA_TYPE_LOOT_TYPE, item->itemid, item->count, loot->loot_type); + UpdateCriteria(CRITERIA_TYPE_LOOT_EPIC_ITEM, item->itemid, item->count); + } + else + aeResult->Add(newitem, item->count, loot->loot_type); // LootItem is being removed (looted) from the container, delete it from the DB. if (!loot->containerID.IsEmpty()) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index ee23fb76cdc..c4f229de191 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1394,7 +1394,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool StoreNewItemInBestSlots(uint32 item_id, uint32 item_count); void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast = false); void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false) { AutoStoreLoot(NULL_BAG, NULL_SLOT, loot_id, store, broadcast); } - void StoreLootItem(uint8 lootSlot, Loot* loot); + void StoreLootItem(uint8 lootSlot, Loot* loot, AELootResult* aeResult = nullptr); InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = nullptr, uint32* offendingItemId = nullptr) const; InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item* pItem = nullptr, bool swap = false, uint32* no_space_count = nullptr) const; @@ -1987,6 +1987,10 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> ObjectGuid const& GetLootGUID() const { return GetGuidValue(PLAYER_LOOT_TARGET_GUID); } void SetLootGUID(ObjectGuid const& guid) { SetGuidValue(PLAYER_LOOT_TARGET_GUID, guid); } + ObjectGuid GetLootWorldObjectGUID(ObjectGuid const& lootObjectGuid) const; + void RemoveAELootedObject(ObjectGuid const& lootObjectGuid); + bool HasLootWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const; + std::unordered_map<ObjectGuid, ObjectGuid> const& GetAELootView() const { return m_AELootView; } void RemovedInsignia(Player* looterPlr); @@ -2193,10 +2197,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> PlayerMenu* PlayerTalkClass; std::vector<ItemSetEffect*> ItemSetEff; - void SendLoot(ObjectGuid guid, LootType loot_type); + void SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting = false); void SendLootError(ObjectGuid guid, LootError error) const; void SendLootRelease(ObjectGuid guid) const; - void SendNotifyLootItemRemoved(ObjectGuid owner, ObjectGuid lootObj, uint8 lootSlot) const; + void SendLootReleaseAll() const; + void SendNotifyLootItemRemoved(ObjectGuid lootObj, uint8 lootSlot) const; void SendNotifyLootMoneyRemoved(ObjectGuid lootObj) const; /*********************************************************/ @@ -2837,6 +2842,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> WorldLocation _corpseLocation; SceneMgr m_sceneMgr; + + std::unordered_map<ObjectGuid /*LootObject*/, ObjectGuid /*world object*/> m_AELootView; }; TC_GAME_API void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 9b6a8923615..ac5c0a92474 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -21,6 +21,8 @@ #include "Corpse.h" #include "Creature.h" #include "GameObject.h" +#include "CellImpl.h" +#include "GridNotifiersImpl.h" #include "Group.h" #include "GuildMgr.h" #include "LootMgr.h" @@ -34,12 +36,14 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& packet) { Player* player = GetPlayer(); - ObjectGuid lguid = player->GetLootGUID(); + AELootResult aeResult; + AELootResult* aeResultPtr = player->GetAELootView().size() > 1 ? &aeResult : nullptr; /// @todo Implement looting by LootObject guid for (WorldPackets::Loot::LootRequest const& req : packet.Loot) { - Loot* loot = NULL; + Loot* loot = nullptr; + ObjectGuid lguid = player->GetLootWorldObjectGUID(req.Object); if (lguid.IsGameObject()) { @@ -91,78 +95,89 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p loot = &creature->loot; } - player->StoreLootItem(req.LootListID - 1, loot); + player->StoreLootItem(req.LootListID - 1, loot, aeResultPtr); // If player is removing the last LootItem, delete the empty container. if (loot->isLooted() && lguid.IsItem()) player->GetSession()->DoLootRelease(lguid); } + + if (aeResultPtr) + { + for (AELootResult::ResultValue const& resultValue : aeResult) + { + player->SendNewItem(resultValue.item, resultValue.count, false, false, true); + player->UpdateCriteria(CRITERIA_TYPE_LOOT_ITEM, resultValue.item->GetEntry(), resultValue.count); + player->UpdateCriteria(CRITERIA_TYPE_LOOT_TYPE, resultValue.item->GetEntry(), resultValue.count, resultValue.lootType); + player->UpdateCriteria(CRITERIA_TYPE_LOOT_EPIC_ITEM, resultValue.item->GetEntry(), resultValue.count); + } + } } void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet*/) { Player* player = GetPlayer(); - ObjectGuid guid = player->GetLootGUID(); - if (!guid) - return; - - Loot* loot = NULL; - bool shareMoney = true; - - switch (guid.GetHigh()) + for (std::pair<ObjectGuid, ObjectGuid> const& lootView : player->GetAELootView()) { - case HighGuid::GameObject: - { - GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); + ObjectGuid guid = lootView.second; + Loot* loot = nullptr; + bool shareMoney = true; - // do not check distance for GO if player is the owner of it (ex. fishing bobber) - if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE)))) - loot = &go->loot; - - break; - } - case HighGuid::Corpse: // remove insignia ONLY in BG + switch (guid.GetHigh()) { - Corpse* bones = ObjectAccessor::GetCorpse(*player, guid); - - if (bones && bones->IsWithinDistInMap(player, INTERACTION_DISTANCE)) + case HighGuid::GameObject: { - loot = &bones->loot; - shareMoney = false; - } + GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid); - break; - } - case HighGuid::Item: - { - if (Item* item = player->GetItemByGuid(guid)) + // do not check distance for GO if player is the owner of it (ex. fishing bobber) + if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE)))) + loot = &go->loot; + + break; + } + case HighGuid::Corpse: // remove insignia ONLY in BG { - loot = &item->loot; - shareMoney = false; + Corpse* bones = ObjectAccessor::GetCorpse(*player, guid); + + if (bones && bones->IsWithinDistInMap(player, INTERACTION_DISTANCE)) + { + loot = &bones->loot; + shareMoney = false; + } + + break; } - break; - } - case HighGuid::Creature: - case HighGuid::Vehicle: - { - Creature* creature = player->GetMap()->GetCreature(guid); - bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); - if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE)) + case HighGuid::Item: { - loot = &creature->loot; - if (creature->IsAlive()) + if (Item* item = player->GetItemByGuid(guid)) + { + loot = &item->loot; shareMoney = false; + } + break; } - else - player->SendLootError(guid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL); - break; + case HighGuid::Creature: + case HighGuid::Vehicle: + { + Creature* creature = player->GetMap()->GetCreature(guid); + bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); + if (lootAllowed && creature->IsWithinDistInMap(player, INTERACTION_DISTANCE)) + { + loot = &creature->loot; + if (creature->IsAlive()) + shareMoney = false; + } + else + player->SendLootError(guid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL); + break; + } + default: + continue; // unlootable type } - default: - return; // unlootable type - } - if (loot) - { + if (!loot) + continue; + loot->NotifyMoneyRemoved(); if (shareMoney && player->GetGroup()) //item, pickpocket and players can be looted only single player { @@ -223,14 +238,59 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet } } +class AELootCreatureCheck +{ +public: + static float constexpr LootDistance = 30.0f; + + AELootCreatureCheck(Player* looter, ObjectGuid mainLootTarget) : _looter(looter), _mainLootTarget(mainLootTarget) { } + + bool operator()(Creature* creature) const + { + if (creature->IsAlive()) + return false; + + if (creature->GetGUID() == _mainLootTarget) + return false; + + if (!_looter->IsWithinDist(creature, LootDistance)) + return false; + + return _looter->isAllowedToLoot(creature); + } + + Player* _looter; + ObjectGuid _mainLootTarget; +}; + void WorldSession::HandleLootOpcode(WorldPackets::Loot::LootUnit& packet) { // Check possible cheat if (!GetPlayer()->IsAlive() || !packet.Unit.IsCreatureOrVehicle()) return; + std::list<Creature*> corpses; + AELootCreatureCheck check(_player, packet.Unit); + Trinity::CreatureListSearcher<AELootCreatureCheck> searcher(_player, corpses, check); + _player->VisitNearbyGridObject(AELootCreatureCheck::LootDistance, searcher); + + if (!corpses.empty()) + SendPacket(WorldPackets::Loot::AELootTargets(uint32(corpses.size() + 1)).Write()); + GetPlayer()->SendLoot(packet.Unit, LOOT_CORPSE); + if (!corpses.empty()) + { + // main target + SendPacket(WorldPackets::Loot::AELootTargetsAck().Write()); + + for (Creature* creature : corpses) + { + GetPlayer()->SendLoot(creature->GetGUID(), LOOT_CORPSE, true); + SendPacket(WorldPackets::Loot::AELootTargetsAck().Write()); + } + } + // interrupt cast if (GetPlayer()->IsNonMeleeSpellCast(false)) GetPlayer()->InterruptNonMeleeSpells(false); @@ -240,10 +300,8 @@ void WorldSession::HandleLootReleaseOpcode(WorldPackets::Loot::LootRelease& pack { // cheaters can modify lguid to prevent correct apply loot release code and re-loot // use internal stored guid - ObjectGuid lguid = GetPlayer()->GetLootGUID(); - if (!lguid.IsEmpty()) - if (lguid == packet.Unit) - DoLootRelease(lguid); + if (GetPlayer()->HasLootWorldObjectGUID(packet.Unit)) + DoLootRelease(packet.Unit); } void WorldSession::DoLootRelease(ObjectGuid lguid) @@ -251,7 +309,8 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) Player *player = GetPlayer(); Loot *loot; - player->SetLootGUID(ObjectGuid::Empty); + if (player->GetLootGUID() == lguid) + player->SetLootGUID(ObjectGuid::Empty); player->SendLootRelease(lguid); player->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_LOOTING); @@ -382,6 +441,14 @@ void WorldSession::DoLootRelease(ObjectGuid lguid) //Player is not looking at loot list, he doesn't need to see updates on the loot list loot->RemoveLooter(player->GetGUID()); + player->RemoveAELootedObject(loot->GetGUID()); +} + +void WorldSession::DoLootReleaseAll() +{ + std::unordered_map<ObjectGuid, ObjectGuid> lootView = _player->GetAELootView(); + for (std::pair<ObjectGuid, ObjectGuid> lootPair : lootView) + DoLootRelease(lootPair.second); } void WorldSession::HandleLootMasterGiveOpcode(WorldPacket& recvData) diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 499f11e0d75..1ec1564d9ed 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -247,9 +247,8 @@ void WorldSession::HandleWhoOpcode(WorldPackets::Who::WhoRequestPkt& whoRequest) void WorldSession::HandleLogoutRequestOpcode(WorldPackets::Character::LogoutRequest& /*logoutRequest*/) { - ObjectGuid lguid = GetPlayer()->GetLootGUID(); - if (!lguid.IsEmpty()) - DoLootRelease(lguid); + if (!GetPlayer()->GetLootGUID().IsEmpty()) + GetPlayer()->SendLootReleaseAll(); bool instantLogout = (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) && !GetPlayer()->IsInCombat()) || GetPlayer()->IsInFlight() || HasPermission(rbac::RBAC_PERM_INSTANT_LOGOUT); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index e4a9ef76a1e..0bde9c54458 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -649,7 +649,7 @@ void Loot::NotifyItemRemoved(uint8 lootIndex) i_next = i; ++i_next; if (Player* player = ObjectAccessor::FindPlayer(*i)) - player->SendNotifyLootItemRemoved(player->GetLootGUID(), GetGUID(), lootIndex); + player->SendNotifyLootItemRemoved(GetGUID(), lootIndex); else PlayersLooting.erase(i); } @@ -696,7 +696,7 @@ void Loot::NotifyQuestItemRemoved(uint8 questIndex) break; if (j < pql.size()) - player->SendNotifyLootItemRemoved(player->GetLootGUID(), GetGUID(), items.size()+j); + player->SendNotifyLootItemRemoved(GetGUID(), items.size()+j); } } else @@ -1884,3 +1884,29 @@ void LoadLootTables() LoadLootTemplates_Reference(); } + +void AELootResult::Add(Item* item, uint8 count, LootType lootType) +{ + auto itr = _byItem.find(item); + if (itr != _byItem.end()) + _byOrder[itr->second].count += count; + else + { + _byItem[item] = _byOrder.size(); + ResultValue value; + value.item = item; + value.count = count; + value.lootType = lootType; + _byOrder.push_back(value); + } +} + +AELootResult::OrderedStorage::const_iterator AELootResult::begin() const +{ + return _byOrder.begin(); +} + +AELootResult::OrderedStorage::const_iterator AELootResult::end() const +{ + return _byOrder.end(); +} diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index e64661aa337..c1c9a65854b 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -29,6 +29,8 @@ #include <vector> #include <list> +class Item; + namespace WorldPackets { namespace Loot @@ -413,6 +415,27 @@ private: uint32 _difficultyBonusTreeMod; }; +class TC_GAME_API AELootResult +{ +public: + struct ResultValue + { + Item* item; + uint8 count; + LootType lootType; + }; + + typedef std::vector<ResultValue> OrderedStorage; + + void Add(Item* item, uint8 count, LootType lootType); + + OrderedStorage::const_iterator begin() const; + OrderedStorage::const_iterator end() const; + + OrderedStorage _byOrder; + std::unordered_map<Item*, OrderedStorage::size_type> _byItem; +}; + TC_GAME_API extern LootStore LootTemplates_Creature; TC_GAME_API extern LootStore LootTemplates_Fishing; TC_GAME_API extern LootStore LootTemplates_Gameobject; diff --git a/src/server/game/Server/Packets/LootPackets.cpp b/src/server/game/Server/Packets/LootPackets.cpp index ff61790e2fe..685a2d7dbc3 100644 --- a/src/server/game/Server/Packets/LootPackets.cpp +++ b/src/server/game/Server/Packets/LootPackets.cpp @@ -37,8 +37,8 @@ void WorldPackets::Loot::LootUnit::Read() WorldPacket const* WorldPackets::Loot::LootResponse::Write() { - _worldPacket << LootObj; _worldPacket << Owner; + _worldPacket << LootObj; _worldPacket << uint8(FailureReason); _worldPacket << uint8(AcquireReason); _worldPacket << uint8(_LootMethod); @@ -200,3 +200,10 @@ WorldPacket const* WorldPackets::Loot::LootRollsComplete::Write() return &_worldPacket; } + +WorldPacket const* WorldPackets::Loot::AELootTargets::Write() +{ + _worldPacket << uint32(Count); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/LootPackets.h b/src/server/game/Server/Packets/LootPackets.h index 9074b58bab1..0507b62e48b 100644 --- a/src/server/game/Server/Packets/LootPackets.h +++ b/src/server/game/Server/Packets/LootPackets.h @@ -167,6 +167,14 @@ namespace WorldPackets ObjectGuid Owner; }; + class LootReleaseAll final : public ServerPacket + { + public: + LootReleaseAll() : ServerPacket(SMSG_LOOT_RELEASE_ALL, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; + class LootList final : public ServerPacket { public: @@ -255,6 +263,24 @@ namespace WorldPackets ObjectGuid LootObj; uint8 LootListID = 0; }; + + class AELootTargets : public ServerPacket + { + public: + AELootTargets(uint32 count) : ServerPacket(SMSG_AE_LOOT_TARGETS, 4), Count(count) { } + + WorldPacket const* Write() override; + + uint32 Count; + }; + + class AELootTargetsAck : public ServerPacket + { + public: + AELootTargetsAck() : ServerPacket(SMSG_AE_LOOT_TARGET_ACK, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 74d59b96e78..3bf5d8ed66a 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -848,8 +848,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_LOSS_OF_CONTROL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADD_RUNE_POWER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ADJUST_SPLINE_DURATION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AE_LOOT_TARGETS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AE_LOOT_TARGET_ACK, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AE_LOOT_TARGETS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AE_LOOT_TARGET_ACK, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AI_REACTION, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACCOUNT_CRITERIA, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ALL_ACHIEVEMENT_DATA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); @@ -1326,7 +1326,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_LIST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MONEY_NOTIFY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE_ALL, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE_ALL, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_REMOVED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 72750f97ade..b61971c1f45 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -510,9 +510,8 @@ void WorldSession::LogoutPlayer(bool save) if (_player) { - ObjectGuid lguid = _player->GetLootGUID(); - if (!lguid.IsEmpty()) - DoLootRelease(lguid); + if (!_player->GetLootGUID().IsEmpty()) + DoLootReleaseAll(); ///- If the player just died before logging out, make him appear as a ghost if (_player->GetDeathTimer()) diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 44c133db4c1..4526d756d8b 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -1077,6 +1077,7 @@ class TC_GAME_API WorldSession void SendPetitionShowList(ObjectGuid guid); void DoLootRelease(ObjectGuid lguid); + void DoLootReleaseAll(); // Account mute time time_t m_muteTime; |
