Core/Loot: converted SMSG_LOOT_RESPONSE to packet class and properly incorporate currency loot into loot generation

This commit is contained in:
Ovahlord committed 2021-04-30 12:50:14 +02:00
1 parent 9aeaf346c2
commit 0ae695908c
8 files changed
+293 -147

No files matched your search

+10 -10
View File
@@ -8554,11 +8554,11 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
{
SetLootGUID(guid);
WorldPacket data(SMSG_LOOT_RESPONSE, 8 + 1 + 50 + 1 + 1); // we guess size
data << uint64(guid);
data << uint8(loot_type);
data << LootView(*loot, this, permission);
SendDirectMessage(&data);
WorldPackets::Loot::LootResponse packet;
packet.Owner = guid;
packet.AcquireReason = loot_type;
loot->BuildLootResponse(packet, this, permission);
SendDirectMessage(packet.Write());
// add 'this' player as one of the players that are looting 'loot'
loot->AddLooter(GetGUID());
@@ -8572,11 +8572,11 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
void Player::SendLootError(ObjectGuid guid, LootError error) const
{
WorldPacket data(SMSG_LOOT_RESPONSE, 10);
data << uint64(guid);
data << uint8(LOOT_NONE);
data << uint8(error);
SendDirectMessage(&data);
WorldPackets::Loot::LootResponse lootResponse;
lootResponse.Owner = guid;
lootResponse.AcquireReason = LOOT_NONE;
lootResponse.FailureReason = error;
SendDirectMessage(lootResponse.Write());
}
void Player::SendNotifyLootMoneyRemoved() const
+1 -1
View File
@@ -1561,7 +1561,7 @@ void Group::CountTheRoll(Rolls::iterator rollI, Map* allowedMap)
WorldPackets::Loot::DisenchantCredit disenchantCredit;
disenchantCredit.Disenchanter = m_disenchantInfo.DisenchanterGUID;
disenchantCredit.Item.ItemID = item->itemid;
disenchantCredit.Item.RandomPropertiesID = item->randomPropertyId.Type == ItemRandomEnchantmentType::Property ? item->randomPropertyId.Id : -item->randomPropertyId.Id;
disenchantCredit.Item.RandomPropertiesID = item->randomPropertyId.Type == ItemRandomEnchantmentType::Property ? item->randomPropertyId.Id : -int32(item->randomPropertyId.Id);
disenchantCredit.Item.RandomPropertiesSeed = item->randomSuffix;
BroadcastPacket(disenchantCredit.Write(), false);
+180 -136
View File
@@ -22,6 +22,7 @@
#include "ItemTemplate.h"
#include "Log.h"
#include "LootMgr.h"
#include "LootPackets.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Player.h"
@@ -70,6 +71,9 @@ bool LootItem::AllowedForPlayer(Player const* player) const
if (!sConditionMgr->IsObjectMeetToConditions(const_cast<Player*>(player), conditions))
return false;
if (is_currency)
return true;
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(itemid);
if (!pProto)
return false;
@@ -610,40 +614,14 @@ bool Loot::hasOverThresholdItem() const
return false;
}
ByteBuffer& operator<<(ByteBuffer& b, LootItem const& li)
void Loot::BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* viewer, PermissionTypes permission) const
{
b << uint32(li.itemid);
b << uint32(li.count); // nr of items of this type
b << uint32(ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(li.itemid))->GetDisplayID());
b << int32(li.randomSuffix);
b << int32(li.randomPropertyId.Type == ItemRandomEnchantmentType::Property ? li.randomPropertyId.Id : -int32(li.randomPropertyId.Id));
//b << uint8(0); // slot type - will send after this function call
return b;
}
if (permission == NONE_PERMISSION)
return;
ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
{
if (lv.permission == NONE_PERMISSION)
{
b << uint32(0); // gold
b << uint8(0); // item count
b << uint8(0); // currency count
return b;
}
packet.Coins = gold;
Loot &l = lv.loot;
uint8 itemsShown = 0;
uint8 currenciesShown = 0;
b << uint32(l.gold); //gold
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
switch (lv.permission)
switch (permission)
{
case GROUP_PERMISSION:
case MASTER_PERMISSION:
@@ -651,22 +629,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) && !l.items[i].is_currency)
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;
@@ -679,44 +657,72 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
continue;
}
}
else if (!l.items[i].rollWinnerGUID.IsEmpty())
{
if (l.items[i].rollWinnerGUID == lv.viewer->GetGUID())
slot_type = LOOT_SLOT_TYPE_OWNER;
else
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
// => item is lootable
slot_type = LOOT_SLOT_TYPE_ALLOW_LOOT;
}
else if (!items[i].rollWinnerGUID.IsEmpty())
{
if (items[i].rollWinnerGUID == viewer->GetGUID())
slot_type = LOOT_SLOT_TYPE_OWNER;
else
continue;
}
else
// item shall not be displayed.
continue;
b << uint8(i) << l.items[i];
b << uint8(slot_type);
++itemsShown;
if (!items[i].is_currency)
{
WorldPackets::Loot::LootItemData lootItem;
lootItem.LootListID = i;
lootItem.UIType = slot_type;
lootItem.Quantity = items[i].count;
lootItem.Loot.Initialize(items[i]);
packet.Items.push_back(lootItem);
}
else
{
WorldPackets::Loot::LootCurrency lootCurrency;
lootCurrency.LootListID = i;
lootCurrency.CurrencyID = items[i].itemid;
lootCurrency.Quantity = items[i].count;
packet.Currencies.push_back(lootCurrency);
}
}
}
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) && !!l.items[i].is_currency)
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;
if (!items[i].is_currency)
{
WorldPackets::Loot::LootItemData lootItem;
lootItem.LootListID = i;
lootItem.UIType = LOOT_SLOT_TYPE_ALLOW_LOOT;
lootItem.Quantity = items[i].count;
lootItem.Loot.Initialize(items[i]);
packet.Items.push_back(lootItem);
}
else
{
WorldPackets::Loot::LootCurrency lootCurrency;
lootCurrency.LootListID = i;
lootCurrency.CurrencyID = items[i].itemid;
lootCurrency.Quantity = items[i].count;
packet.Currencies.push_back(lootCurrency);
}
}
}
break;
@@ -724,132 +730,170 @@ 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) && !l.items[i].is_currency)
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;
if (!items[i].is_currency)
{
WorldPackets::Loot::LootItemData lootItem;
lootItem.LootListID = i;
lootItem.UIType = permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT;
lootItem.Quantity = items[i].count;
lootItem.Loot.Initialize(items[i]);
packet.Items.push_back(lootItem);
}
else
{
WorldPackets::Loot::LootCurrency lootCurrency;
lootCurrency.LootListID = i;
lootCurrency.CurrencyID = items[i].itemid;
lootCurrency.Quantity = items[i].count;
packet.Currencies.push_back(lootCurrency);
}
}
}
break;
}
default:
return b;
return;
}
LootSlotType slotType = lv.permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT;
NotNormalLootItemMap const& lootPlayerQuestItems = l.GetPlayerQuestItems();
NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(lv.viewer->GetGUID());
LootSlotType slotType = permission == OWNER_PERMISSION ? LOOT_SLOT_TYPE_OWNER : LOOT_SLOT_TYPE_ALLOW_LOOT;
NotNormalLootItemMap const& lootPlayerQuestItems = GetPlayerQuestItems();
NotNormalLootItemMap::const_iterator q_itr = lootPlayerQuestItems.find(viewer->GetGUID());
if (q_itr != lootPlayerQuestItems.end())
{
NotNormalLootItemList* q_list = q_itr->second;
for (NotNormalLootItemList::const_iterator qi = q_list->begin(); qi != q_list->end(); ++qi)
NotNormalLootItemList const& q_list = *q_itr->second;
for (std::size_t i = 0; i < q_list.size(); ++i)
{
LootItem &item = l.quest_items[qi->index];
if (!qi->is_looted && !item.is_looted)
NotNormalLootItem const& qi = q_list[i];
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;
if (item.follow_loot_rules)
if (!item.is_currency)
{
switch (lv.permission)
WorldPackets::Loot::LootItemData lootItem;
lootItem.LootListID = items.size() + i;
lootItem.Quantity = item.count;
lootItem.Loot.Initialize(item);
if (item.follow_loot_rules)
{
case MASTER_PERMISSION:
b << uint8(LOOT_SLOT_TYPE_MASTER);
break;
case RESTRICTED_PERMISSION:
b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType));
break;
case GROUP_PERMISSION:
case ROUND_ROBIN_PERMISSION:
if (!item.is_blocked)
b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
else
b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING);
break;
default:
b << uint8(slotType);
break;
switch (permission)
{
case MASTER_PERMISSION:
lootItem.UIType = LOOT_SLOT_TYPE_MASTER;
break;
case RESTRICTED_PERMISSION:
lootItem.UIType = item.is_blocked ? LOOT_SLOT_TYPE_LOCKED : LOOT_SLOT_TYPE_ALLOW_LOOT;
break;
case GROUP_PERMISSION:
if (!item.is_blocked)
lootItem.UIType = LOOT_SLOT_TYPE_ALLOW_LOOT;
else
lootItem.UIType = LOOT_SLOT_TYPE_ROLL_ONGOING;
break;
default:
lootItem.UIType = slotType;
break;
}
}
else
lootItem.UIType = slotType;
packet.Items.push_back(lootItem);
}
else
b << uint8(slotType);
++itemsShown;
{
WorldPackets::Loot::LootCurrency lootCurrency;
lootCurrency.LootListID = items.size() + i;
lootCurrency.CurrencyID = item.itemid;
lootCurrency.Quantity = item.count;
packet.Currencies.push_back(lootCurrency);
}
}
}
}
NotNormalLootItemMap const& lootPlayerFFAItems = l.GetPlayerFFAItems();
NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(lv.viewer->GetGUID());
NotNormalLootItemMap const& lootPlayerFFAItems = GetPlayerFFAItems();
NotNormalLootItemMap::const_iterator ffa_itr = lootPlayerFFAItems.find(viewer->GetGUID());
if (ffa_itr != lootPlayerFFAItems.end())
{
NotNormalLootItemList* ffa_list = ffa_itr->second;
for (NotNormalLootItemList::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;
if (!item.is_currency)
{
WorldPackets::Loot::LootItemData lootItem;
lootItem.LootListID = fi->index;
lootItem.UIType = slotType;
lootItem.Quantity = item.count;
lootItem.Loot.Initialize(item);
packet.Items.push_back(lootItem);
}
else
{
WorldPackets::Loot::LootCurrency lootCurrency;
lootCurrency.LootListID = fi->index;
lootCurrency.CurrencyID = item.itemid;
lootCurrency.Quantity = item.count;
packet.Currencies.push_back(lootCurrency);
}
}
}
}
NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = l.GetPlayerNonQuestNonFFAConditionalItems();
NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(lv.viewer->GetGUID());
NotNormalLootItemMap const& lootPlayerNonQuestNonFFAConditionalItems = GetPlayerNonQuestNonFFAConditionalItems();
NotNormalLootItemMap::const_iterator nn_itr = lootPlayerNonQuestNonFFAConditionalItems.find(viewer->GetGUID());
if (nn_itr != lootPlayerNonQuestNonFFAConditionalItems.end())
{
NotNormalLootItemList* conditional_list = nn_itr->second;
for (NotNormalLootItemList::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;
switch (lv.permission)
if (!item.is_currency)
{
case MASTER_PERMISSION:
b << uint8(LOOT_SLOT_TYPE_MASTER);
break;
case RESTRICTED_PERMISSION:
b << (item.is_blocked ? uint8(LOOT_SLOT_TYPE_LOCKED) : uint8(slotType));
break;
case GROUP_PERMISSION:
case ROUND_ROBIN_PERMISSION:
if (!item.is_blocked)
b << uint8(LOOT_SLOT_TYPE_ALLOW_LOOT);
else
b << uint8(LOOT_SLOT_TYPE_ROLL_ONGOING);
break;
default:
b << uint8(slotType);
break;
WorldPackets::Loot::LootItemData lootItem;
lootItem.LootListID = ci->index;
lootItem.Quantity = item.count;
lootItem.Loot.Initialize(item);
switch (permission)
{
case MASTER_PERMISSION:
lootItem.UIType = LOOT_SLOT_TYPE_MASTER;
break;
case RESTRICTED_PERMISSION:
lootItem.UIType = item.is_blocked ? LOOT_SLOT_TYPE_LOCKED : LOOT_SLOT_TYPE_ALLOW_LOOT;
break;
case GROUP_PERMISSION:
if (!item.is_blocked)
lootItem.UIType = LOOT_SLOT_TYPE_ALLOW_LOOT;
else
lootItem.UIType = LOOT_SLOT_TYPE_ROLL_ONGOING;
break;
default:
lootItem.UIType = slotType;
break;
}
packet.Items.push_back(lootItem);
}
else
{
WorldPackets::Loot::LootCurrency lootCurrency;
lootCurrency.LootListID = ci->index;
lootCurrency.CurrencyID = item.itemid;
lootCurrency.Quantity = item.count;
packet.Currencies.push_back(lootCurrency);
}
++itemsShown;
}
}
}
for (uint8 i = 0; i < l.items.size(); ++i)
{
if (!l.items[i].is_currency || l.items[i].count == 0 || l.items[i].is_looted)
continue;
b << uint8(i);
b << uint32(l.items[i].itemid);
b << uint32(l.items[i].count);
++currenciesShown;
}
//update number of items and currencies shown
b.put<uint8>(count_pos, itemsShown);
b.put<uint8>(currency_count_pos, currenciesShown);
return b;
}
+11
View File
@@ -33,6 +33,14 @@ class Player;
struct Loot;
struct LootStoreItem;
namespace WorldPackets
{
namespace Loot
{
class LootResponse;
}
}
enum RollType
{
ROLL_PASS = 0,
@@ -286,6 +294,9 @@ struct TC_GAME_API Loot
bool hasItemFor(Player* player) const;
bool hasOverThresholdItem() const;
// Builds data for SMSG_LOOT_RESPONSE
void BuildLootResponse(WorldPackets::Loot::LootResponse& packet, Player* viewer, PermissionTypes permission = ALL_PERMISSION) const;
private:
void FillNotNormalLootFor(Player* player, bool presentAtLooting);
NotNormalLootItemList* FillFFALoot(Player* player);
@@ -17,16 +17,26 @@
#include "ItemPacketsCommon.h"
#include "Item.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "Loot.h"
void WorldPackets::Item::ItemInstance::Initialize(::Item const* item)
{
ItemID = item->GetEntry();
ItemDisplayID = item->GetDisplayId();
RandomPropertiesID = item->GetItemRandomPropertyId();
RandomPropertiesSeed = item->GetItemSuffixFactor();
}
void WorldPackets::Item::ItemInstance::Initialize(::LootItem const& lootItem)
{
ItemID = lootItem.itemid;
ItemDisplayID = ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(lootItem.itemid))->GetDisplayID();
RandomPropertiesID = lootItem.randomPropertyId.Type == ItemRandomEnchantmentType::Property ? lootItem.randomPropertyId.Id : -int32(lootItem.randomPropertyId.Id);
RandomPropertiesSeed = lootItem.randomSuffix;
}
bool WorldPackets::Item::ItemInstance::operator==(ItemInstance const& r) const
{
if (ItemID != r.ItemID || RandomPropertiesID != r.RandomPropertiesID || RandomPropertiesSeed != r.RandomPropertiesSeed)
@@ -33,8 +33,10 @@ namespace WorldPackets
struct ItemInstance
{
void Initialize(::Item const* item);
void Initialize(::LootItem const& lootItem);
uint32 ItemID = 0;
int32 ItemDisplayID = 0;
int32 RandomPropertiesSeed = 0;
int32 RandomPropertiesID = 0;
@@ -16,6 +16,7 @@
*/
#include "LootPackets.h"
#include "ItemPacketsCommon.h"
WorldPacket const* WorldPackets::Loot::LootMoneyNotify::Write()
{
@@ -77,3 +78,48 @@ WorldPacket const* WorldPackets::Loot::DisenchantCredit::Write()
return &_worldPacket;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Loot::LootItemData const& lootItemData)
{
data << uint8(lootItemData.LootListID);
data << uint32(lootItemData.Loot.ItemID);
data << uint32(lootItemData.Quantity);
data << int32(lootItemData.Loot.ItemDisplayID);
data << int32(lootItemData.Loot.RandomPropertiesSeed);
data << int32(lootItemData.Loot.RandomPropertiesID);
data << uint8(lootItemData.UIType);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Loot::LootCurrency const& lootCurrency)
{
data << uint8(lootCurrency.LootListID);
data << uint32(lootCurrency.CurrencyID);
data << uint32(lootCurrency.Quantity);
return data;
}
WorldPacket const* WorldPackets::Loot::LootResponse::Write()
{
_worldPacket << Owner;
_worldPacket << uint8(AcquireReason);
if (!AcquireReason)
{
_worldPacket << uint8(FailureReason);
return &_worldPacket;
}
_worldPacket << uint32(Coins);
_worldPacket << uint8(Items.size());
_worldPacket << uint8(Currencies.size());
for (LootItemData const& lootItemData : Items)
_worldPacket << lootItemData;
for (LootCurrency const& lootCurrency : Currencies)
_worldPacket << lootCurrency;
return &_worldPacket;
}
@@ -88,6 +88,39 @@ namespace WorldPackets
ObjectGuid Disenchanter;
WorldPackets::Item::ItemInstance Item;
};
struct LootItemData
{
uint8 Type = 0;
uint8 UIType = 0;
uint32 Quantity = 0;
uint8 LootItemType = 0;
uint8 LootListID = 0;
WorldPackets::Item::ItemInstance Loot;
};
struct LootCurrency
{
uint32 CurrencyID = 0;
uint32 Quantity = 0;
uint8 LootListID = 0;
};
class LootResponse final : public ServerPacket
{
public:
LootResponse() : ServerPacket(SMSG_LOOT_RESPONSE, 100) { }
WorldPacket const* Write() override;
ObjectGuid Owner;
uint8 Threshold = 2; // Most common value, 2 = Uncommon
uint8 AcquireReason = 0;
uint8 FailureReason = 17; // Most common value
uint32 Coins = 0;
std::vector<LootItemData> Items;
std::vector<LootCurrency> Currencies;
};
}
}