aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp2
-rw-r--r--src/server/game/Entities/Object/ObjectGuid.cpp1
-rw-r--r--src/server/game/Entities/Player/Player.cpp49
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp1
-rw-r--r--src/server/game/Globals/ObjectMgr.h1
-rw-r--r--src/server/game/Handlers/LootHandler.cpp95
-rw-r--r--src/server/game/Loot/LootMgr.cpp183
-rw-r--r--src/server/game/Loot/LootMgr.h66
-rw-r--r--src/server/game/Server/Packets/LootPackets.cpp64
-rw-r--r--src/server/game/Server/Packets/LootPackets.h70
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp6
-rw-r--r--src/server/game/Server/WorldSession.h11
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);