diff options
author | Intel <chemicstry@gmail.com> | 2014-12-30 02:23:37 +0200 |
---|---|---|
committer | Intel <chemicstry@gmail.com> | 2015-01-15 22:37:10 +0200 |
commit | dc9ce43c4506431bf13a303b4508cf9504b4fb58 (patch) | |
tree | 90b2bf6e2e19223a49c07edcb86cc884765bc925 /src/server | |
parent | 8e95ca9c578d6f8eb1076c88abd5ae4d05c0e9ce (diff) |
Core/Loot: Implemented SMSG_LOOT_RESPONSE, SMSG_LOOT_REMOVED, CMSG_AUTOSTORE_LOOT_ITEM
AoE looting is work in progress.
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Object/ObjectGuid.cpp | 1 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 49 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 2 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 1 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 1 | ||||
-rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 95 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.cpp | 183 | ||||
-rw-r--r-- | src/server/game/Loot/LootMgr.h | 66 | ||||
-rw-r--r-- | src/server/game/Server/Packets/LootPackets.cpp | 64 | ||||
-rw-r--r-- | src/server/game/Server/Packets/LootPackets.h | 70 | ||||
-rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 11 |
13 files changed, 353 insertions, 198 deletions
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 070263cd85e..d6fa2129a8e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1290,6 +1290,8 @@ bool Creature::LoadCreatureFromDB(ObjectGuid::LowType guid, Map* map, bool addTo m_creatureData = data; + loot.SetGUID(ObjectGuid::Create<HighGuid::LootObject>(data->mapid, data->id, sObjectMgr->GetGenerator<HighGuid::LootObject>()->Generate())); + if (addToMap && !GetMap()->AddToMap(this)) return false; return true; diff --git a/src/server/game/Entities/Object/ObjectGuid.cpp b/src/server/game/Entities/Object/ObjectGuid.cpp index cf63f858b58..65884541f55 100644 --- a/src/server/game/Entities/Object/ObjectGuid.cpp +++ b/src/server/game/Entities/Object/ObjectGuid.cpp @@ -250,5 +250,6 @@ template ObjectGuid::LowType ObjectGuidGenerator<HighGuid::Item>::Generate(); template ObjectGuid::LowType ObjectGuidGenerator<HighGuid::GameObject>::Generate(); template ObjectGuid::LowType ObjectGuidGenerator<HighGuid::DynamicObject>::Generate(); template ObjectGuid::LowType ObjectGuidGenerator<HighGuid::Corpse>::Generate(); +template ObjectGuid::LowType ObjectGuidGenerator<HighGuid::LootObject>::Generate(); template ObjectGuid::LowType ObjectGuidGenerator<HighGuid::AreaTrigger>::Generate(); template ObjectGuid::LowType ObjectGuidGenerator<HighGuid::Transport>::Generate(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 4f71347045d..e0e5f0f72be 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -91,6 +91,7 @@ #include "MovementPackets.h" #include "ItemPackets.h" #include "QuestPackets.h" +#include "LootPackets.h" #include <boost/dynamic_bitset.hpp> #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -4794,8 +4795,8 @@ void Player::DeleteOldCharacters(uint32 keepDays) */ void Player::BuildPlayerRepop() { - WorldPackets::Misc::PreRessurect packet;
- packet.PlayerGUID = GetGUID();
+ WorldPackets::Misc::PreRessurect packet; + packet.PlayerGUID = GetGUID(); GetSession()->SendPacket(packet.Write()); if (getRace() == RACE_NIGHTELF) @@ -4849,8 +4850,8 @@ void Player::BuildPlayerRepop() void Player::ResurrectPlayer(float restore_percent, bool applySickness) { - WorldPackets::Misc::DeathReleaseLoc packet;
- packet.MapID = -1;
+ WorldPackets::Misc::DeathReleaseLoc packet; + packet.MapID = -1; GetSession()->SendPacket(packet.Write()); // speed change, land walk @@ -5271,9 +5272,9 @@ void Player::RepopAtGraveyard() TeleportTo(ClosestGrave->MapID, ClosestGrave->Loc.X, ClosestGrave->Loc.Y, ClosestGrave->Loc.Z, (ClosestGrave->Facing * M_PI) / 180); // Orientation is initially in degrees if (isDead()) // not send if alive, because it used in TeleportTo() { - WorldPackets::Misc::DeathReleaseLoc packet;
- packet.MapID = ClosestGrave->MapID;
- packet.Loc = G3D::Vector3(ClosestGrave->Loc.X, ClosestGrave->Loc.Y, ClosestGrave->Loc.Z);
+ WorldPackets::Misc::DeathReleaseLoc packet; + packet.MapID = ClosestGrave->MapID; + packet.Loc = G3D::Vector3(ClosestGrave->Loc.X, ClosestGrave->Loc.Y, ClosestGrave->Loc.Z); GetSession()->SendPacket(packet.Write()); } } @@ -8913,11 +8914,16 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type) { SetLootGUID(guid); - WorldPacket data(SMSG_LOOT_RESPONSE, (9 + 50)); // we guess size - data << guid; - data << uint8(loot_type); - data << LootView(*loot, this, permission); - SendDirectMessage(&data); + WorldPackets::Loot::LootResponse packet; + packet.LootObj = guid; + packet.Owner = loot->GetGUID(); + packet.LootMethod = loot_type; + if (!GetGroup()) + packet.PersonalLooting = true; + else + packet.PersonalLooting = false; + loot->BuildLootResponse(packet, this, permission); + SendDirectMessage(packet.Write()); // add 'this' player as one of the players that are looting 'loot' loot->AddLooter(GetGUID()); @@ -8944,11 +8950,14 @@ void Player::SendNotifyLootMoneyRemoved() GetSession()->SendPacket(&data); } -void Player::SendNotifyLootItemRemoved(uint8 lootSlot) +void Player::SendNotifyLootItemRemoved(ObjectGuid owner, ObjectGuid lootObj, uint8 lootSlot) { - WorldPacket data(SMSG_LOOT_REMOVED, 1); - data << uint8(lootSlot); - GetSession()->SendPacket(&data); + WorldPackets::Loot::LootRemoved packet; + packet.Owner = owner; + packet.LootObj = lootObj; + // Since 6.x client expects loot to be starting from 1 hence the +1 + packet.LootListID = lootSlot+1; + GetSession()->SendPacket(packet.Write()); } void Player::SendUpdateWorldState(uint32 variable, uint32 value, bool hidden /*= false*/) @@ -24325,8 +24334,8 @@ int32 Player::CalculateCorpseReclaimDelay(bool load) void Player::SendCorpseReclaimDelay(uint32 delay) { - WorldPackets::Misc::CorpseReclaimDelay packet;
- packet.Remaining = delay;
+ WorldPackets::Misc::CorpseReclaimDelay packet; + packet.Remaining = delay; GetSession()->SendPacket(packet.Write()); } @@ -25033,7 +25042,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(lootSlot); + SendNotifyLootItemRemoved(GetLootGUID(), loot->GetGUID(), lootSlot); else loot->NotifyQuestItemRemoved(qitem->index); } @@ -25043,7 +25052,7 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot) { //freeforall case, notify only one player of the removal ffaitem->is_looted = true; - SendNotifyLootItemRemoved(lootSlot); + SendNotifyLootItemRemoved(GetLootGUID(), loot->GetGUID(), lootSlot); } else { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e939c3cba2c..e3f0725b41f 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2285,7 +2285,7 @@ class Player : public Unit, public GridObject<Player> void SendLoot(ObjectGuid guid, LootType loot_type); void SendLootError(ObjectGuid guid, LootError error); void SendLootRelease(ObjectGuid guid); - void SendNotifyLootItemRemoved(uint8 lootSlot); + void SendNotifyLootItemRemoved(ObjectGuid owner, ObjectGuid lootObj, uint8 lootSlot); void SendNotifyLootMoneyRemoved(); /*********************************************************/ diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 24740a1043a..e44d1eeb016 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -247,6 +247,7 @@ template<> ObjectGuidGenerator<HighGuid::Item>* ObjectMgr::GetGenerator() { retu template<> ObjectGuidGenerator<HighGuid::GameObject>* ObjectMgr::GetGenerator() { return &_gameObjectGuidGenerator; } template<> ObjectGuidGenerator<HighGuid::DynamicObject>* ObjectMgr::GetGenerator() { return &_dynamicObjectGuidGenerator; } template<> ObjectGuidGenerator<HighGuid::Corpse>* ObjectMgr::GetGenerator() { return &_corpseGuidGenerator; } +template<> ObjectGuidGenerator<HighGuid::LootObject>* ObjectMgr::GetGenerator() { return &_lootObjectGuidGenerator; } template<> ObjectGuidGenerator<HighGuid::AreaTrigger>* ObjectMgr::GetGenerator() { return &_areaTriggerGuidGenerator; } template<> ObjectGuidGenerator<HighGuid::Transport>* ObjectMgr::GetGenerator() { return &_moTransportGuidGenerator; } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 95bbe693335..579cc7a5d4e 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1320,6 +1320,7 @@ class ObjectMgr ObjectGuidGenerator<HighGuid::GameObject> _gameObjectGuidGenerator; ObjectGuidGenerator<HighGuid::DynamicObject> _dynamicObjectGuidGenerator; ObjectGuidGenerator<HighGuid::Corpse> _corpseGuidGenerator; + ObjectGuidGenerator<HighGuid::LootObject> _lootObjectGuidGenerator; ObjectGuidGenerator<HighGuid::AreaTrigger> _areaTriggerGuidGenerator; ObjectGuidGenerator<HighGuid::Transport> _moTransportGuidGenerator; diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 91353104be4..35096da66b1 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -33,71 +33,74 @@ #include "LootPackets.h" #include "WorldSession.h" -void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) +void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::AutoStoreLootItem& packet) { TC_LOG_DEBUG("network", "WORLD: CMSG_AUTOSTORE_LOOT_ITEM"); Player* player = GetPlayer(); ObjectGuid lguid = player->GetLootGUID(); - Loot* loot = NULL; - uint8 lootSlot = 0; - - recvData >> lootSlot; - if (lguid.IsGameObject()) + /// @todo Implement looting by LootObject guid + for (WorldPackets::Loot::LootRequest const& req : packet.Loot) { - GameObject* go = player->GetMap()->GetGameObject(lguid); + Loot* loot = NULL; - // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO - if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) + if (lguid.IsGameObject()) { - player->SendLootRelease(lguid); - return; - } + GameObject* go = player->GetMap()->GetGameObject(lguid); - loot = &go->loot; - } - else if (lguid.IsItem()) - { - Item* pItem = player->GetItemByGuid(lguid); + // not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO + if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE))) + { + player->SendLootRelease(lguid); + continue; + } - if (!pItem) - { - player->SendLootRelease(lguid); - return; + loot = &go->loot; } - - loot = &pItem->loot; - } - else if (lguid.IsCorpse()) - { - Corpse* bones = ObjectAccessor::GetCorpse(*player, lguid); - if (!bones) + else if (lguid.IsItem()) { - player->SendLootRelease(lguid); - return; - } + Item* pItem = player->GetItemByGuid(lguid); - loot = &bones->loot; - } - else - { - Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); + if (!pItem) + { + player->SendLootRelease(lguid); + continue; + } - bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); - if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) + loot = &pItem->loot; + } + else if (lguid.IsCorpse()) { - player->SendLootError(lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL); - return; + Corpse* bones = ObjectAccessor::GetCorpse(*player, lguid); + if (!bones) + { + player->SendLootRelease(lguid); + continue; + } + + loot = &bones->loot; } + else + { + Creature* creature = GetPlayer()->GetMap()->GetCreature(lguid); - loot = &creature->loot; - } + bool lootAllowed = creature && creature->IsAlive() == (player->getClass() == CLASS_ROGUE && creature->loot.loot_type == LOOT_PICKPOCKETING); + if (!lootAllowed || !creature->IsWithinDistInMap(_player, INTERACTION_DISTANCE)) + { + player->SendLootError(lguid, lootAllowed ? LOOT_ERROR_TOO_FAR : LOOT_ERROR_DIDNT_KILL); + continue; + } - player->StoreLootItem(lootSlot, loot); + loot = &creature->loot; + } - // If player is removing the last LootItem, delete the empty container. - if (loot->isLooted() && lguid.IsItem()) - player->GetSession()->DoLootRelease(lguid); + // Since 6.x client sends loot starting from 1 hence the -1 + player->StoreLootItem(req.LootListID-1, loot); + + // If player is removing the last LootItem, delete the empty container. + if (loot->isLooted() && lguid.IsItem()) + player->GetSession()->DoLootRelease(lguid); + } } void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 78068d16436..930b1fc775a 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -27,6 +27,7 @@ #include "Group.h" #include "Player.h" #include "Containers.h" +#include "LootPackets.h" static Rates const qualityToRate[MAX_ITEM_QUALITY] = { @@ -413,6 +414,13 @@ void LootItem::AddAllowedLooter(const Player* player) allowedGUIDs.insert(player->GetGUID()); } +void LootItem::BuildItemInstance(WorldPackets::Item::ItemInstance& instance) const +{ + instance.ItemID = itemid; + instance.RandomPropertiesSeed = randomSuffix; + instance.RandomPropertiesID = randomPropertyId; +} + // // --------- Loot --------- // @@ -633,7 +641,7 @@ void Loot::NotifyItemRemoved(uint8 lootIndex) i_next = i; ++i_next; if (Player* player = ObjectAccessor::FindPlayer(*i)) - player->SendNotifyLootItemRemoved(lootIndex); + player->SendNotifyLootItemRemoved(player->GetLootGUID(), GetGUID(), lootIndex); else PlayersLooting.erase(i); } @@ -680,7 +688,7 @@ void Loot::NotifyQuestItemRemoved(uint8 questIndex) break; if (j < pql.size()) - player->SendNotifyLootItemRemoved(items.size()+j); + player->SendNotifyLootItemRemoved(player->GetLootGUID(), GetGUID(), items.size()+j); } } else @@ -854,40 +862,14 @@ bool Loot::hasOverThresholdItem() const return false; } -ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li) -{ - b << uint32(li.itemid); - b << uint32(li.count); // nr of items of this type - b << uint32(/*sObjectMgr->GetItemTemplate(li.itemid)->DisplayInfoID*/); - b << uint32(li.randomSuffix); - b << uint32(li.randomPropertyId); - //b << uint8(0); // slot type - will send after this function call - return b; -} - -ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) +void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* viewer, PermissionTypes permission) const { - if (lv.permission == NONE_PERMISSION) - { - b << uint32(0); // gold - b << uint8(0); // item count - b << uint8(0); // currency count - return b; - } - - Loot &l = lv.loot; - - uint8 itemsShown = 0; - uint8 currenciesShown = 0; - - b << uint32(l.gold); //gold + if (permission == NONE_PERMISSION) + return; - size_t count_pos = b.wpos(); // pos of item count byte - b << uint8(0); // item count placeholder - size_t currency_count_pos = b.wpos(); // pos of currency count byte - b << uint8(0); // currency count placeholder + packet.Coins = gold; - switch (lv.permission) + switch (permission) { case GROUP_PERMISSION: case MASTER_PERMISSION: @@ -895,22 +877,22 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) { // if you are not the round-robin group looter, you can only see // blocked rolled items and quest items, and !ffa items - for (uint8 i = 0; i < l.items.size(); ++i) + for (uint8 i = 0; i < items.size(); ++i) { - if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer)) + if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer)) { uint8 slot_type; - if (l.items[i].is_blocked) // for ML & restricted is_blocked = !is_underthreshold + if (items[i].is_blocked) // for ML & restricted is_blocked = !is_underthreshold { - switch (lv.permission) + switch (permission) { case GROUP_PERMISSION: slot_type = LOOT_SLOT_TYPE_ROLL_ONGOING; break; case MASTER_PERMISSION: { - if (lv.viewer->GetGroup() && lv.viewer->GetGroup()->GetMasterLooterGuid() == lv.viewer->GetGUID()) + if (viewer->GetGroup() && viewer->GetGroup()->GetMasterLooterGuid() == viewer->GetGUID()) slot_type = LOOT_SLOT_TYPE_MASTER; else slot_type = LOOT_SLOT_TYPE_LOCKED; @@ -923,7 +905,7 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) continue; } } - else if (l.roundRobinPlayer.IsEmpty() || lv.viewer->GetGUID() == l.roundRobinPlayer || !l.items[i].is_underthreshold) + else if (roundRobinPlayer.IsEmpty() || viewer->GetGUID() == roundRobinPlayer || !items[i].is_underthreshold) { // no round robin owner or he has released the loot // or it IS the round robin group owner @@ -934,26 +916,32 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) // item shall not be displayed. continue; - b << uint8(i) << l.items[i]; - b << uint8(slot_type); - ++itemsShown; + WorldPackets::Loot::LootItem lootItem; + lootItem.LootListID = packet.Items.size()+1; + lootItem.LootItemType = slot_type; + lootItem.Quantity = items[i].count; + items[i].BuildItemInstance(lootItem.Loot); + packet.Items.push_back(lootItem); } } break; } case ROUND_ROBIN_PERMISSION: { - for (uint8 i = 0; i < l.items.size(); ++i) + for (uint8 i = 0; i < items.size(); ++i) { - if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer)) + if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer)) { - if (!l.roundRobinPlayer.IsEmpty() && lv.viewer->GetGUID() != l.roundRobinPlayer) + if (!roundRobinPlayer.IsEmpty() && viewer->GetGUID() != roundRobinPlayer) // item shall not be displayed. continue; - b << uint8(i) << l.items[i]; - b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); - ++itemsShown; + WorldPackets::Loot::LootItem lootItem; + lootItem.LootListID = packet.Items.size()+1; + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; + lootItem.Quantity = items[i].count; + items[i].BuildItemInstance(lootItem.Loot); + packet.Items.push_back(lootItem); } } break; @@ -961,128 +949,133 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) case ALL_PERMISSION: case OWNER_PERMISSION: { - uint8 slot_type = lv.permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT; - for (uint8 i = 0; i < l.items.size(); ++i) + for (uint8 i = 0; i < items.size(); ++i) { - if (!l.items[i].is_looted && !l.items[i].freeforall && l.items[i].conditions.empty() && l.items[i].AllowedForPlayer(lv.viewer)) + if (!items[i].is_looted && !items[i].freeforall && items[i].conditions.empty() && items[i].AllowedForPlayer(viewer)) { - b << uint8(i) << l.items[i]; - b << uint8(slot_type); - ++itemsShown; + WorldPackets::Loot::LootItem lootItem; + lootItem.LootListID = packet.Items.size()+1; + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; + lootItem.Quantity = items[i].count; + items[i].BuildItemInstance(lootItem.Loot); + packet.Items.push_back(lootItem); } } break; } default: - return b; + return; } - LootSlotType slotType = lv.permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT; - QuestItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems(); - QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUID().GetCounter()); + QuestItemMap const& lootPlayerQuestItems = GetPlayerQuestItems(); + QuestItemMap::const_iterator q_itr = lootPlayerQuestItems.find(viewer->GetGUID().GetCounter()); if (q_itr != lootPlayerQuestItems.end()) { QuestItemList* q_list = q_itr->second; for (QuestItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi) { - LootItem &item = l.quest_items[qi->index]; + LootItem const& item = quest_items[qi->index]; if (!qi->is_looted && !item.is_looted) { - b << uint8(l.items.size() + (qi - q_list->begin())); - b << item; + WorldPackets::Loot::LootItem lootItem; + lootItem.LootListID = packet.Items.size()+1; + lootItem.Quantity = item.count; + item.BuildItemInstance(lootItem.Loot); + if (item.follow_loot_rules) { - switch (lv.permission) + switch (permission) { case MASTER_PERMISSION: - b << uint8(LOOT_SLOT_TYPE_MASTER); + lootItem.LootItemType = LOOT_SLOT_TYPE_MASTER; break; case RESTRICTED_PERMISSION: - b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType)); + lootItem.LootItemType = item.is_blocked ? LOOT_SLOT_TYPE_LOCKED : LOOT_SLOT_TYPE_ALLOW_LOOT; break; case GROUP_PERMISSION: case ROUND_ROBIN_PERMISSION: if (!item.is_blocked) - b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; else - b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); + lootItem.LootItemType = LOOT_SLOT_TYPE_ROLL_ONGOING; break; default: - b << uint8(slotType); + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; break; } } else - b << uint8(slotType); - ++itemsShown; + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; + + packet.Items.push_back(lootItem); } } } - QuestItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems(); - QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUID().GetCounter()); + QuestItemMap const& lootPlayerFFAItems = GetPlayerFFAItems(); + QuestItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(viewer->GetGUID().GetCounter()); if (ffa_itr != lootPlayerFFAItems.end()) { QuestItemList* ffa_list = ffa_itr->second; for (QuestItemList::const_iterator fi = ffa_list->begin(); fi != ffa_list->end(); ++fi) { - LootItem &item = l.items[fi->index]; + LootItem const& item = items[fi->index]; if (!fi->is_looted && !item.is_looted) { - b << uint8(fi->index); - b << item; - b << uint8(slotType); - ++itemsShown; + WorldPackets::Loot::LootItem lootItem; + lootItem.LootListID = packet.Items.size()+1; + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; + lootItem.Quantity = item.count; + item.BuildItemInstance(lootItem.Loot); + packet.Items.push_back(lootItem); } } } - QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems(); - QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUID().GetCounter()); + QuestItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems(); + QuestItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(viewer->GetGUID().GetCounter()); if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end()) { QuestItemList* conditional_list = nn_itr->second; for (QuestItemList::const_iterator ci = conditional_list->begin(); ci != conditional_list->end(); ++ci) { - LootItem &item = l.items[ci->index]; + LootItem const& item = items[ci->index]; if (!ci->is_looted && !item.is_looted) { - b << uint8(ci->index); - b << item; + WorldPackets::Loot::LootItem lootItem; + lootItem.LootListID = packet.Items.size()+1; + lootItem.Quantity = item.count; + item.BuildItemInstance(lootItem.Loot); + if (item.follow_loot_rules) { - switch (lv.permission) + switch (permission) { case MASTER_PERMISSION: - b << uint8(LOOT_SLOT_TYPE_MASTER); + lootItem.LootItemType = LOOT_SLOT_TYPE_MASTER; break; case RESTRICTED_PERMISSION: - b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType)); + lootItem.LootItemType = item.is_blocked ? LOOT_SLOT_TYPE_LOCKED : LOOT_SLOT_TYPE_ALLOW_LOOT; break; case GROUP_PERMISSION: case ROUND_ROBIN_PERMISSION: if (!item.is_blocked) - b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT); + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; else - b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING); + lootItem.LootItemType = LOOT_SLOT_TYPE_ROLL_ONGOING; break; default: - b << uint8(slotType); + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; break; } } else - b << uint8(slotType); - ++itemsShown; + lootItem.LootItemType = LOOT_SLOT_TYPE_ALLOW_LOOT; + + packet.Items.push_back(lootItem); } } } - - //update number of items and currencies shown - b.put<uint8>(count_pos, itemsShown); - b.put<uint8>(currency_count_pos, currenciesShown); - - return b; } // diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index 3bd5fadc49d..e6f48b45c28 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -29,6 +29,19 @@ #include <vector> #include <list> +namespace WorldPackets +{ + namespace Loot + { + class LootResponse; + } + + namespace Item + { + struct ItemInstance; + } +} + enum RollType { ROLL_PASS = 0, @@ -116,7 +129,7 @@ enum LootSlotType LOOT_SLOT_TYPE_ROLL_ONGOING = 1, // roll is ongoing. player cannot loot. LOOT_SLOT_TYPE_MASTER = 2, // item can only be distributed by group loot master. LOOT_SLOT_TYPE_LOCKED = 3, // item is shown in red. player cannot loot. - LOOT_SLOT_TYPE_OWNER = 4 // ignore binding confirmation and etc, for single player looting + LOOT_SLOT_TYPE_OWNER = 4 // ignore binding confirmation and etc, for single player looting (6.x no longer used) }; class Player; @@ -176,6 +189,8 @@ struct LootItem bool AllowedForPlayer(Player const* player) const; void AddAllowedLooter(Player const* player); GuidSet const& GetAllowedLooters() const { return allowedGUIDs; } + + void BuildItemInstance(WorldPackets::Item::ItemInstance& instance) const; }; struct QuestItem @@ -301,15 +316,9 @@ class LootValidatorRefManager : public RefManager<Loot, LootValidatorRef> }; //===================================================== -struct LootView; - -ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li); -ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv); struct Loot { - friend ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv); - QuestItemMap const& GetPlayerQuestItems() const { return PlayerQuestItems; } QuestItemMap const& GetPlayerFFAItems() const { return PlayerFFAItems; } QuestItemMap const& GetPlayerNonQuestNonFFAConditionalItems() const { return PlayerNonQuestNonFFAConditionalItems; } @@ -329,6 +338,9 @@ struct Loot Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_CORPSE), maxDuplicates(1) { } ~Loot() { clear(); } + ObjectGuid const& GetGUID() const { return _GUID; } + void SetGUID(ObjectGuid const& guid) { _GUID = guid; } + // For deleting items at loot removal since there is no backward interface to the Item() void DeleteLootItemFromContainerItemDB(uint32 itemID); void DeleteLootMoneyFromContainerItemDB(); @@ -384,28 +396,26 @@ struct Loot bool hasItemFor(Player* player) const; bool hasOverThresholdItem() const; - private: - void FillNotNormalLootFor(Player* player, bool presentAtLooting); - QuestItemList* FillFFALoot(Player* player); - QuestItemList* FillQuestLoot(Player* player); - QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting); - - GuidSet PlayersLooting; - QuestItemMap PlayerQuestItems; - QuestItemMap PlayerFFAItems; - QuestItemMap PlayerNonQuestNonFFAConditionalItems; - - // All rolls are registered here. They need to know, when the loot is not valid anymore - LootValidatorRefManager i_LootValidatorRefManager; -}; + // Builds data for SMSG_LOOT_RESPONSE + void BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* viewer, PermissionTypes permission = ALL_PERMISSION) const; -struct LootView -{ - Loot &loot; - Player* viewer; - PermissionTypes permission; - LootView(Loot &_loot, Player* _viewer, PermissionTypes _permission = ALL_PERMISSION) - : loot(_loot), viewer(_viewer), permission(_permission) { } +private: + + void FillNotNormalLootFor(Player* player, bool presentAtLooting); + QuestItemList* FillFFALoot(Player* player); + QuestItemList* FillQuestLoot(Player* player); + QuestItemList* FillNonQuestNonFFAConditionalLoot(Player* player, bool presentAtLooting); + + GuidSet PlayersLooting; + QuestItemMap PlayerQuestItems; + QuestItemMap PlayerFFAItems; + QuestItemMap PlayerNonQuestNonFFAConditionalItems; + + // All rolls are registered here. They need to know, when the loot is not valid anymore + LootValidatorRefManager i_LootValidatorRefManager; + + // Loot GUID + ObjectGuid _GUID; }; extern LootStore LootTemplates_Creature; diff --git a/src/server/game/Server/Packets/LootPackets.cpp b/src/server/game/Server/Packets/LootPackets.cpp index 5a8027858e3..776c6fe105d 100644 --- a/src/server/game/Server/Packets/LootPackets.cpp +++ b/src/server/game/Server/Packets/LootPackets.cpp @@ -21,3 +21,67 @@ void WorldPackets::Loot::LootUnit::Read() { _worldPacket >> Unit; } + +WorldPacket const* WorldPackets::Loot::LootResponse::Write() +{ + _worldPacket << LootObj; + _worldPacket << Owner; + _worldPacket << Threshold; + _worldPacket << LootMethod; + _worldPacket << AcquireReason; + _worldPacket << FailureReason; + _worldPacket << Coins; + _worldPacket << uint32(Items.size()); + _worldPacket << uint32(Currencies.size()); + + for (LootItem const& item : Items) + { + _worldPacket.WriteBits(item.Type, 2); + _worldPacket.WriteBits(item.UIType, 3); + _worldPacket.WriteBit(item.CanTradeToTapList); + _worldPacket.FlushBits(); + + _worldPacket << item.Quantity; + _worldPacket << item.LootItemType; + _worldPacket << item.LootListID; + _worldPacket << item.Loot; // WorldPackets::Item::ItemInstance + } + + for (LootCurrency const& currency : Currencies) + { + _worldPacket << currency.CurrencyID; + _worldPacket << currency.Quantity; + _worldPacket << currency.LootListID; + _worldPacket.WriteBits(currency.UIType, 3); + _worldPacket.FlushBits(); + } + + _worldPacket.WriteBit(PersonalLooting); + _worldPacket.WriteBit(Acquired); + _worldPacket.WriteBit(AELooting); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::Loot::AutoStoreLootItem::Read() +{ + uint32 Count; + _worldPacket >> Count; + + Loot.resize(Count); + for (uint32 i = 0; i < Count; ++i) + { + _worldPacket >> Loot[i].Object; + _worldPacket >> Loot[i].LootListID; + } +} + +WorldPacket const* WorldPackets::Loot::LootRemoved::Write() +{ + _worldPacket << Owner; + _worldPacket << LootObj; + _worldPacket << LootListID; + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/LootPackets.h b/src/server/game/Server/Packets/LootPackets.h index c12cc7224c7..ffe079e3583 100644 --- a/src/server/game/Server/Packets/LootPackets.h +++ b/src/server/game/Server/Packets/LootPackets.h @@ -20,6 +20,7 @@ #include "Packet.h" #include "ObjectGuid.h" +#include "ItemPackets.h" namespace WorldPackets { @@ -34,6 +35,75 @@ namespace WorldPackets ObjectGuid Unit; }; + + struct LootItem + { + uint8 Type = 0; + uint8 UIType = 0; + uint32 Quantity = 0; + uint8 LootItemType = 0; + uint8 LootListID = 0; + bool CanTradeToTapList = false; + WorldPackets::Item::ItemInstance Loot; + }; + + struct LootCurrency + { + uint32 CurrencyID = 0; + uint32 Quantity = 0; + uint8 LootListID = 0; + uint8 UIType = 0; + }; + + class LootResponse final : public ServerPacket + { + public: + LootResponse() : ServerPacket(SMSG_LOOT_RESPONSE, 100) { } + + WorldPacket const* Write() override; + + ObjectGuid LootObj; + ObjectGuid Owner; + uint8 Threshold = 17; // Most common value + uint8 LootMethod = 0; + uint8 AcquireReason = 0; + uint8 FailureReason = 2; // Most common value + uint32 Coins = 0; + std::vector<LootItem> Items; + std::vector<LootCurrency> Currencies; + bool PersonalLooting = false; + bool Acquired = false; + bool AELooting = false; + }; + + struct LootRequest + { + ObjectGuid Object; + uint8 LootListID = 0; + }; + + // PlayerCliLootItem + class AutoStoreLootItem final : public ClientPacket + { + public: + AutoStoreLootItem(WorldPacket&& packet) : ClientPacket(CMSG_AUTOSTORE_LOOT_ITEM, std::move(packet)) { } + + void Read() override; + + std::vector<LootRequest> Loot; + }; + + class LootRemoved final : public ServerPacket + { + public: + LootRemoved() : ServerPacket(SMSG_LOOT_REMOVED, 30) { } + + WorldPacket const* Write() override; + + ObjectGuid LootObj; + ObjectGuid Owner; + uint8 LootListID = 0; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 7f21315a982..8ca4d4d37f4 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -174,7 +174,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOEQUIP_ITEM_SLOT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemSlotOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOSTORE_BAG_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBagItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOSTORE_BANK_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoStoreBankItemOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutostoreLootItemOpcode ); + DEFINE_HANDLER(CMSG_AUTOSTORE_LOOT_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Loot::AutoStoreLootItem, &WorldSession::HandleAutostoreLootItemOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTO_DECLINE_GUILD_INVITES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoDeclineGuildInvites ); DEFINE_HANDLER(CMSG_BANKER_ACTIVATE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::NPC::Hello, &WorldSession::HandleBankerActivateOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLEFIELD_LEAVE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleBattlefieldLeaveOpcode ); @@ -1090,8 +1090,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MASTER_LIST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_MONEY_NOTIFY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RELEASE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_REMOVED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + 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_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_ROLL_WON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_LOOT_SLOT_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 9639d90572c..82c0c49db72 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -167,6 +167,7 @@ namespace WorldPackets namespace Loot { class LootUnit; + class AutoStoreLootItem; } namespace Misc @@ -178,10 +179,10 @@ namespace WorldPackets class TutorialSetFlag; class SetDungeonDifficulty; class SetRaidDifficulty; - class PortGraveyard;
- class ReclaimCorpse;
- class RepopRequest;
- class RequestCemeteryList;
+ class PortGraveyard; + class ReclaimCorpse; + class RepopRequest; + class RequestCemeteryList; class ResurrectResponse; } @@ -687,7 +688,7 @@ class WorldSession void HandlePingOpcode(WorldPacket& recvPacket); void HandleRepopRequest(WorldPackets::Misc::RepopRequest& packet); - void HandleAutostoreLootItemOpcode(WorldPacket& recvPacket); + void HandleAutostoreLootItemOpcode(WorldPackets::Loot::AutoStoreLootItem& packet); void HandleLootMoneyOpcode(WorldPacket& recvPacket); void HandleLootOpcode(WorldPackets::Loot::LootUnit& packet); void HandleLootReleaseOpcode(WorldPacket& recvPacket); |