aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Handlers/LootHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/Handlers/LootHandler.cpp')
-rw-r--r--src/server/game/Handlers/LootHandler.cpp181
1 files changed, 124 insertions, 57 deletions
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)