Update aoe_loot.cpp

This commit is contained in:
TerraByte
2025-04-17 19:46:01 -05:00
committed by GitHub
parent e14628b717
commit 26d929574e

View File

@@ -17,7 +17,6 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "Corpse.h" #include "Corpse.h"
using namespace Acore::ChatCommands; using namespace Acore::ChatCommands;
using namespace WorldPackets; using namespace WorldPackets;
@@ -28,18 +27,7 @@ bool AoeLootServer::CanPacketReceive(WorldSession* session, WorldPacket& packet)
Player* player = session->GetPlayer(); Player* player = session->GetPlayer();
if (player) if (player)
{ {
/* // Trigger AOE loot when a player attempts to loot a corpse
// Check if SHIFT key is pressed - if so, bypass AOE loot
if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_MODIFIER_ACTIVE))
{
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: Bypassing AOE loot because SHIFT key is held");
ChatHandler(player->GetSession()).PSendSysMessage("AOE Loot: SHIFT key detected - bypassing AOE loot");
}
return true; // Let the normal loot handling proceed
}
*/
ChatHandler handler(player->GetSession()); ChatHandler handler(player->GetSession());
handler.ParseCommands(".startaoeloot"); handler.ParseCommands(".startaoeloot");
} }
@@ -56,7 +44,7 @@ ChatCommandTable AoeLootCommandScript::GetCommands() const
return playerAoeLootCommandTable; return playerAoeLootCommandTable;
} }
// Custom function to handle gold looting without distance checks // Handle gold looting without distance checks
bool AoeLootCommandScript::ProcessLootMoney(Player* player, Creature* creature) bool AoeLootCommandScript::ProcessLootMoney(Player* player, Creature* creature)
{ {
if (!player || !creature) if (!player || !creature)
@@ -66,38 +54,32 @@ bool AoeLootCommandScript::ProcessLootMoney(Player* player, Creature* creature)
if (!loot || loot->gold == 0) if (!loot || loot->gold == 0)
return false; return false;
// Store gold amount before we modify it
uint32 goldAmount = loot->gold; uint32 goldAmount = loot->gold;
// Handle group money distribution if needed
bool shareMoney = true; // Share by default for creature corpses bool shareMoney = true; // Share by default for creature corpses
if (shareMoney && player->GetGroup()) if (shareMoney && player->GetGroup())
{ {
Group* group = player->GetGroup(); Group* group = player->GetGroup();
std::vector<Player*> playersNear; std::vector<Player*> playersNear;
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member) if (member)
continue; playersNear.push_back(member);
// For AOE looting, we don't do a distance check - just include all group members
playersNear.push_back(member);
} }
uint32 goldPerPlayer = uint32((loot->gold) / (playersNear.size())); uint32 goldPerPlayer = uint32((loot->gold) / (playersNear.size()));
for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i) for (Player* groupMember : playersNear)
{ {
(*i)->ModifyMoney(goldPerPlayer); groupMember->ModifyMoney(goldPerPlayer);
(*i)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer); groupMember->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer);
WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1); WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1);
data << uint32(goldPerPlayer); data << uint32(goldPerPlayer);
data << uint8(playersNear.size() > 1 ? 0 : 1); // 0 is "Your share is..." and 1 is "You loot..." data << uint8(playersNear.size() > 1 ? 0 : 1); // 0 is "Your share is..." and 1 is "You loot..."
(*i)->GetSession()->SendPacket(&data); groupMember->GetSession()->SendPacket(&data);
} }
} }
else else
@@ -116,12 +98,6 @@ bool AoeLootCommandScript::ProcessLootMoney(Player* player, Creature* creature)
loot->gold = 0; loot->gold = 0;
loot->NotifyMoneyRemoved(); loot->NotifyMoneyRemoved();
// Delete container if empty
if (loot->isLooted())
{
// The loot release will be handled in the main function
}
return true; return true;
} }
@@ -131,21 +107,17 @@ bool AoeLootCommandScript::ProcessLootSlot(Player* player, ObjectGuid lguid, uin
return false; return false;
Loot* loot = nullptr; Loot* loot = nullptr;
float aoeDistance = sConfigMgr->GetOption<float>("AOELoot.Range", 55.0f);
// Get the loot object based on the GUID type. // Get the loot object based on the GUID type
if (lguid.IsGameObject()) if (lguid.IsGameObject())
{ {
GameObject* go = player->GetMap()->GetGameObject(lguid); GameObject* go = player->GetMap()->GetGameObject(lguid);
// Use increased distance for AOE looting
float aoeDistance = sConfigMgr->GetOption<float>("AOELoot.Range", 55.0f);
// Modified distance check
if (!go || ((go->GetOwnerGUID() != player->GetGUID() && if (!go || ((go->GetOwnerGUID() != player->GetGUID() &&
go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) &&
!go->IsWithinDistInMap(player, aoeDistance))) !go->IsWithinDistInMap(player, aoeDistance)))
{ {
// We're outside of range - silently fail when batch processing
return false; return false;
} }
@@ -173,16 +145,16 @@ bool AoeLootCommandScript::ProcessLootSlot(Player* player, ObjectGuid lguid, uin
if (creature && creature->IsAlive()) if (creature && creature->IsAlive())
{ {
bool isPickpocketing = creature && creature->IsAlive() && (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING); bool isPickpocketing = creature->IsAlive() &&
// Use regular interaction distance for pickpocketing (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) &&
bool lootAllowed = creature && creature->IsAlive() == isPickpocketing; creature->loot.loot_type == LOOT_PICKPOCKETING);
// Modified distance check with appropriate range
bool lootAllowed = creature->IsAlive() == isPickpocketing;
if (!lootAllowed || !creature->IsWithinDistInMap(player, INTERACTION_DISTANCE)) if (!lootAllowed || !creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
{
// We're outside of range - silently fail when batch processing
return false; return false;
}
} }
loot = &creature->loot; loot = &creature->loot;
} }
@@ -194,32 +166,29 @@ bool AoeLootCommandScript::ProcessLootSlot(Player* player, ObjectGuid lguid, uin
QuestItem* ffaitem = nullptr; QuestItem* ffaitem = nullptr;
QuestItem* conditem = nullptr; QuestItem* conditem = nullptr;
LootItem* item = loot->LootItemInSlot(lootSlot, player, &qitem, &ffaitem, &conditem); LootItem* item = loot->LootItemInSlot(lootSlot, player, &qitem, &ffaitem, &conditem);
if (!item) if (!item)
{ {
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true)) if (sConfigMgr->GetOption<bool>("AOELoot.Debug", false))
{
LOG_DEBUG("module.aoe_loot", "No valid loot item found in slot {}", lootSlot); LOG_DEBUG("module.aoe_loot", "No valid loot item found in slot {}", lootSlot);
}
return false; return false;
} }
// Now call StoreLootItem with the validated slot // Store the loot item in the player's inventory
InventoryResult msg; InventoryResult msg;
// Use StoreLootItem directly
player->StoreLootItem(lootSlot, loot, msg); player->StoreLootItem(lootSlot, loot, msg);
if (msg == EQUIP_ERR_OK )
if (msg == EQUIP_ERR_OK)
{ {
// Successfully looted the item // Successfully looted the item
loot->items[lootSlot].is_looted = true; loot->items[lootSlot].is_looted = true;
loot->unlootedCount--; loot->unlootedCount--;
// Notify the player about the looted item if (sConfigMgr->GetOption<bool>("AOELoot.Debug", false))
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
{
LOG_DEBUG("module.aoe_loot", "Successfully looted item (ID: {}) x{} from {}", item->itemid, static_cast<uint32_t>(item->count), lguid.ToString()); LOG_DEBUG("module.aoe_loot", "Successfully looted item (ID: {}) x{} from {}", item->itemid, static_cast<uint32_t>(item->count), lguid.ToString());
}
} }
// Handle mail fallback for items // Handle mail fallback for items
if (msg != EQUIP_ERR_OK && lguid.IsItem() && loot->loot_type != LOOT_CORPSE) if (msg != EQUIP_ERR_OK && lguid.IsItem() && loot->loot_type != LOOT_CORPSE)
{ {
@@ -230,7 +199,6 @@ bool AoeLootCommandScript::ProcessLootSlot(Player* player, ObjectGuid lguid, uin
player->SendItemRetrievalMail(item->itemid, item->count); player->SendItemRetrievalMail(item->itemid, item->count);
} }
// Success
return true; return true;
} }
@@ -240,93 +208,74 @@ bool AoeLootCommandScript::HandleStartAoeLootCommand(ChatHandler* handler, Optio
return true; return true;
Player* player = handler->GetSession()->GetPlayer(); Player* player = handler->GetSession()->GetPlayer();
if (!player) if (!player)
return true; return true;
float range = sConfigMgr->GetOption<float>("AOELoot.Range", 55.0); float range = sConfigMgr->GetOption<float>("AOELoot.Range", 55.0);
bool debugMode = sConfigMgr->GetOption<bool>("AOELoot.Debug", false);
std::list<Creature*> nearbyCorpses; std::list<Creature*> nearbyCorpses;
player->GetDeadCreatureListInGrid(nearbyCorpses, range); player->GetDeadCreatureListInGrid(nearbyCorpses, range);
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true)) if (debugMode)
{ {
LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} nearby corpses within range {}.", nearbyCorpses.size(), range); LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} nearby corpses within range {}.", nearbyCorpses.size(), range);
handler->PSendSysMessage(fmt::format("AOE Loot: Found {} nearby corpses within range {}.", nearbyCorpses.size(), range));
} }
// Filter valid corpses first // Filter valid corpses
std::list<Creature*> validCorpses; std::list<Creature*> validCorpses;
// Process each corpse one by one
for (auto* creature : nearbyCorpses) for (auto* creature : nearbyCorpses)
{ {
if (!player || !creature) if (!player || !creature)
{
continue; continue;
}
// Check if creature is valid for looting by this player
if (!creature->hasLootRecipient() || !creature->isTappedBy(player)) if (!creature->hasLootRecipient() || !creature->isTappedBy(player))
{
// Not a valid loot target for this player
continue; continue;
}
// Skip if corpse is not valid for looting // Skip if corpse is not lootable
if (!creature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE)) if (!creature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE))
{ {
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true)) if (debugMode)
{ LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not lootable", creature->GetGUID().ToString());
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - ***NOT LOOTABLE***", creature->GetGUID().ToString());
handler->PSendSysMessage(fmt::format("AOE Loot: Skipping creature {} - ***NOT LOOTABLE***", creature->GetGUID().ToString()));
}
continue; continue;
} }
// Additional permission check // Additional permission check for instances
if (player->GetMap()->Instanceable() && !player->isAllowedToLoot(creature)) if (player->GetMap()->Instanceable() && !player->isAllowedToLoot(creature))
{ {
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true)) if (debugMode)
{ LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not your loot", creature->GetGUID().ToString());
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - ***NOT YOUR LOOT***", creature->GetGUID().ToString());
handler->PSendSysMessage(fmt::format("AOE Loot: Skipping creature {} - ***NOT YOUR LOOT***", creature->GetGUID().ToString()));
}
continue; continue;
} }
// Add to valid list of creatures to loot
validCorpses.push_back(creature);
validCorpses.push_back(creature);
} }
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
if (debugMode)
{ {
LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} VALID nearby corpses within range {}.", validCorpses.size(), range); LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} valid nearby corpses within range {}.", validCorpses.size(), range);
handler->PSendSysMessage(fmt::format("AOE Loot: Found {} VALID nearby corpses within range {}.", validCorpses.size(), range));
} }
// Process all corpses silently and quickly
// Process all valid corpses
for (auto* creature : validCorpses) for (auto* creature : validCorpses)
{ {
Loot* loot = &creature->loot; Loot* loot = &creature->loot;
if (!loot) if (!loot)
{
continue; continue;
}
player->SetLootGUID(creature->GetGUID());
// Process quest items // Process quest items
if (!loot->quest_items.empty()) if (!loot->quest_items.empty())
{ {
// Try to loot each potential quest slot
for (uint8 i = 0; i < loot->quest_items.size(); ++i) for (uint8 i = 0; i < loot->quest_items.size(); ++i)
{ {
uint8 lootSlot = loot->items.size() + i; uint8 lootSlot = loot->items.size() + i;
ProcessLootSlot(player, creature->GetGUID(), lootSlot);
// Store the loot item in the player's inventory if (debugMode)
AoeLootCommandScript::ProcessLootSlot(player, creature->GetGUID(), lootSlot); LOG_DEBUG("module.aoe_loot", "AOE Loot: looted quest item in slot {}", lootSlot);
// Debug logging
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: looted QUEST ITEM in slot {}", lootSlot);
handler->PSendSysMessage(fmt::format("AOE Loot: looted QUEST ITEM in slot {}", lootSlot));
}
} }
} }
@@ -334,60 +283,49 @@ bool AoeLootCommandScript::HandleStartAoeLootCommand(ChatHandler* handler, Optio
for (uint8 lootSlot = 0; lootSlot < loot->items.size(); ++lootSlot) for (uint8 lootSlot = 0; lootSlot < loot->items.size(); ++lootSlot)
{ {
player->SetLootGUID(creature->GetGUID()); player->SetLootGUID(creature->GetGUID());
// Store the loot item in the player's inventory ProcessLootSlot(player, creature->GetGUID(), lootSlot);
AoeLootCommandScript::ProcessLootSlot(player, creature->GetGUID(), lootSlot);
// Debug if (debugMode && lootSlot < loot->items.size())
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
{ {
LOG_DEBUG("module.aoe_loot", "AOE Loot: looted item from slot {} (ID: {}) from {}", lootSlot, loot->items[lootSlot].itemid, creature->GetGUID().ToString()); LOG_DEBUG("module.aoe_loot", "AOE Loot: looted item from slot {} (ID: {}) from {}", lootSlot, loot->items[lootSlot].itemid, creature->GetGUID().ToString());
handler->PSendSysMessage(fmt::format("AOE Loot: looted item from slot {} (ID: {})", lootSlot, loot->items[lootSlot].itemid));
} }
} }
// Handle money with direct packet // Handle money
if (loot->gold > 0) if (loot->gold > 0)
{ {
// Store the gold amount before it gets cleared by HandleLootMoneyOpcode
uint32 goldAmount = loot->gold; uint32 goldAmount = loot->gold;
AoeLootCommandScript::ProcessLootMoney(player, creature); ProcessLootMoney(player, creature);
if (debugMode)
// Debug {
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true)) LOG_DEBUG("module.aoe_loot", "AOE Loot: Looted {} copper from {}", goldAmount, creature->GetGUID().ToString());
{ }
LOG_DEBUG("module.aoe_loot", "AOE Loot: Looted {} copper from {}", goldAmount, creature->GetGUID().ToString());
handler->PSendSysMessage(fmt::format("AOE Loot: Looted {} copper from {}", goldAmount, creature->GetGUID().ToString()));
}
} }
// Check if the corpse is now fully looted // Release loot if corpse is fully looted
if (loot->isLooted()) if (loot->isLooted())
{ {
WorldPacket releaseData(CMSG_LOOT_RELEASE, 8); WorldPacket releaseData(CMSG_LOOT_RELEASE, 8);
releaseData << creature->GetGUID(); releaseData << creature->GetGUID();
player->GetSession()->HandleLootReleaseOpcode(releaseData); player->GetSession()->HandleLootReleaseOpcode(releaseData);
// Cleanup the loot object from the corpse
//creature->AllLootRemovedFromCorpse();
//creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
// Force update the world state to reflect the loot being gone
} }
player->SetLootGUID(ObjectGuid::Empty);
} }
return true; return true;
} }
// Copied from sudlud's "mod-aoe-loot" module. // Display login message to player
void AoeLootPlayer::OnPlayerLogin(Player* player) void AoeLootPlayer::OnPlayerLogin(Player* player)
{ {
if (sConfigMgr->GetOption<bool>("AOELoot.Enable", true)) if (sConfigMgr->GetOption<bool>("AOELoot.Enable", true) &&
sConfigMgr->GetOption<bool>("AOELoot.Message", true))
{ {
if (sConfigMgr->GetOption<bool>("AOELoot.Message", true)) ChatHandler(player->GetSession()).PSendSysMessage(AOE_ACORE_STRING_MESSAGE);
ChatHandler(player->GetSession()).PSendSysMessage(AOE_ACORE_STRING_MESSAGE);
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Add script registrations
void AddSC_AoeLoot() void AddSC_AoeLoot()
{ {
new AoeLootPlayer(); new AoeLootPlayer();