mirror of
https://github.com/brighton-chi/mod-aoe-loot.git
synced 2026-01-13 00:58:34 +00:00
Update aoe_loot.cpp
This commit is contained in:
@@ -19,8 +19,9 @@
|
||||
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
using namespace WorldPackets;
|
||||
|
||||
bool AOELootServer::CanPacketReceive(WorldSession* session, WorldPacket& packet)
|
||||
bool AoeLootServer::CanPacketReceive(WorldSession* session, WorldPacket& packet)
|
||||
{
|
||||
if (packet.GetOpcode() == CMSG_LOOT)
|
||||
{
|
||||
@@ -55,34 +56,211 @@ ChatCommandTable AoeLootCommandScript::GetCommands() const
|
||||
return playerAoeLootCommandTable;
|
||||
}
|
||||
|
||||
// Custom function to handle gold looting without distance checks
|
||||
bool AoeLootCommandScript::ProcessLootMoney(Player* player, Creature* creature)
|
||||
{
|
||||
if (!player || !creature)
|
||||
return false;
|
||||
|
||||
Loot* loot = &creature->loot;
|
||||
if (!loot || loot->gold == 0)
|
||||
return false;
|
||||
|
||||
// Store gold amount before we modify it
|
||||
uint32 goldAmount = loot->gold;
|
||||
|
||||
// Handle group money distribution if needed
|
||||
bool shareMoney = true; // Share by default for creature corpses
|
||||
|
||||
if (shareMoney && player->GetGroup())
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
|
||||
std::vector<Player*> playersNear;
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member)
|
||||
continue;
|
||||
|
||||
// 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()));
|
||||
|
||||
for (std::vector<Player*>::const_iterator i = playersNear.begin(); i != playersNear.end(); ++i)
|
||||
{
|
||||
(*i)->ModifyMoney(goldPerPlayer);
|
||||
(*i)->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, goldPerPlayer);
|
||||
|
||||
WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1);
|
||||
data << uint32(goldPerPlayer);
|
||||
data << uint8(playersNear.size() > 1 ? 0 : 1); // 0 is "Your share is..." and 1 is "You loot..."
|
||||
(*i)->GetSession()->SendPacket(&data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No group - give all gold to the player
|
||||
player->ModifyMoney(loot->gold);
|
||||
player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold);
|
||||
|
||||
WorldPacket data(SMSG_LOOT_MONEY_NOTIFY, 4 + 1);
|
||||
data << uint32(loot->gold);
|
||||
data << uint8(1); // "You loot..."
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
// Mark the money as looted
|
||||
loot->gold = 0;
|
||||
loot->NotifyMoneyRemoved();
|
||||
|
||||
// Delete container if empty
|
||||
if (loot->isLooted())
|
||||
{
|
||||
// The loot release will be handled in the main function
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AoeLootCommandScript::ProcessLootSlot(Player* player, ObjectGuid lguid, uint8 lootSlot)
|
||||
{
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
Loot* loot = nullptr;
|
||||
|
||||
// Get the loot object based on the GUID type.
|
||||
if (lguid.IsGameObject())
|
||||
{
|
||||
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() &&
|
||||
go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) &&
|
||||
!go->IsWithinDistInMap(player, aoeDistance)))
|
||||
{
|
||||
// We're outside of range - silently fail when batch processing
|
||||
return false;
|
||||
}
|
||||
|
||||
loot = &go->loot;
|
||||
}
|
||||
else if (lguid.IsItem())
|
||||
{
|
||||
Item* pItem = player->GetItemByGuid(lguid);
|
||||
if (!pItem)
|
||||
return false;
|
||||
|
||||
loot = &pItem->loot;
|
||||
}
|
||||
else if (lguid.IsCorpse())
|
||||
{
|
||||
Corpse* bones = ObjectAccessor::GetCorpse(*player, lguid);
|
||||
if (!bones)
|
||||
return false;
|
||||
|
||||
loot = &bones->loot;
|
||||
}
|
||||
else
|
||||
{
|
||||
Creature* creature = player->GetMap()->GetCreature(lguid);
|
||||
|
||||
if (creature && creature->IsAlive())
|
||||
{
|
||||
bool isPickpocketing = creature && creature->IsAlive() && (player->IsClass(CLASS_ROGUE, CLASS_CONTEXT_ABILITY) && creature->loot.loot_type == LOOT_PICKPOCKETING);
|
||||
// Use regular interaction distance for pickpocketing
|
||||
bool lootAllowed = creature && creature->IsAlive() == isPickpocketing;
|
||||
// Modified distance check with appropriate range
|
||||
if (!lootAllowed || !creature->IsWithinDistInMap(player, INTERACTION_DISTANCE))
|
||||
{
|
||||
// We're outside of range - silently fail when batch processing
|
||||
return false;
|
||||
}
|
||||
}
|
||||
loot = &creature->loot;
|
||||
}
|
||||
|
||||
if (!loot)
|
||||
return false;
|
||||
|
||||
// Check if the item is already looted
|
||||
QuestItem* qitem = nullptr;
|
||||
QuestItem* ffaitem = nullptr;
|
||||
QuestItem* conditem = nullptr;
|
||||
LootItem* item = loot->LootItemInSlot(lootSlot, player, &qitem, &ffaitem, &conditem);
|
||||
if (!item)
|
||||
{
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
LOG_DEBUG("module.aoe_loot", "No valid loot item found in slot {}", lootSlot);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now call StoreLootItem with the validated slot
|
||||
InventoryResult msg;
|
||||
|
||||
// Use StoreLootItem directly
|
||||
player->StoreLootItem(lootSlot, loot, msg);
|
||||
if (msg == EQUIP_ERR_OK )
|
||||
{
|
||||
// Successfully looted the item
|
||||
loot->items[lootSlot].is_looted = true;
|
||||
loot->unlootedCount--;
|
||||
|
||||
// Notify the player about the looted item
|
||||
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());
|
||||
}
|
||||
}
|
||||
// Handle mail fallback for items
|
||||
if (msg != EQUIP_ERR_OK && lguid.IsItem() && loot->loot_type != LOOT_CORPSE)
|
||||
{
|
||||
item->is_looted = true;
|
||||
loot->NotifyItemRemoved(item->itemIndex);
|
||||
loot->unlootedCount--;
|
||||
|
||||
player->SendItemRetrievalMail(item->itemid, item->count);
|
||||
}
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AoeLootCommandScript::HandleStartAoeLootCommand(ChatHandler* handler, Optional<std::string> /*args*/)
|
||||
{
|
||||
if (!sConfigMgr->GetOption<bool>("AOELoot.Enable", true))
|
||||
return true;
|
||||
return true;
|
||||
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
|
||||
if (!player)
|
||||
return true;
|
||||
return true;
|
||||
|
||||
float range = sConfigMgr->GetOption<float>("AOELoot.Range", 55.0);
|
||||
|
||||
std::list<Creature*> nearbyCorpses;
|
||||
player->GetDeadCreatureListInGrid(nearbyCorpses, range);
|
||||
|
||||
uint32 totalItemsLooted = 0;
|
||||
uint32 totalCopperLooted = 0;
|
||||
uint32 totalCorpsesLooted = 0;
|
||||
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
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
|
||||
std::list<Creature*> validCorpses;
|
||||
// Process each corpse one by one
|
||||
for (auto* creature : nearbyCorpses)
|
||||
{
|
||||
if (!player || !creature || !player->IsInWorld())
|
||||
if (!player || !creature)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -98,40 +276,34 @@ bool AoeLootCommandScript::HandleStartAoeLootCommand(ChatHandler* handler, Optio
|
||||
{
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
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()));
|
||||
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;
|
||||
}
|
||||
|
||||
// Additional permission check
|
||||
if (player->GetMap()->Instanceable())
|
||||
{
|
||||
if(!player->isAllowedToLoot(creature))
|
||||
{
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - player not allowed to loot", creature->GetGUID().ToString());
|
||||
handler->PSendSysMessage(fmt::format("AOE Loot: Skipping creature {} - player not allowed to loot", creature->GetGUID().ToString()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Double-check distance to prevent exploits
|
||||
if (player->GetDistance(creature) > range)
|
||||
if (player->GetMap()->Instanceable() && !player->isAllowedToLoot(creature))
|
||||
{
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - out of range", creature->GetGUID().ToString());
|
||||
handler->PSendSysMessage(fmt::format("AOE Loot: Skipping creature {} - out of range", 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;
|
||||
}
|
||||
// Add to valid list of creatures to loot
|
||||
validCorpses.push_back(creature);
|
||||
|
||||
// Set this corpse as the current loot target
|
||||
player->SetLootGUID(creature->GetGUID());
|
||||
|
||||
}
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
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
|
||||
for (auto* creature : validCorpses)
|
||||
{
|
||||
Loot* loot = &creature->loot;
|
||||
|
||||
if (!loot)
|
||||
@@ -139,87 +311,73 @@ bool AoeLootCommandScript::HandleStartAoeLootCommand(ChatHandler* handler, Optio
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process quest items
|
||||
if (!loot->quest_items.empty())
|
||||
{
|
||||
// Try to loot each potential quest slot
|
||||
for (uint8 i = 0; i < loot->quest_items.size(); ++i)
|
||||
{
|
||||
uint8 lootSlot = loot->items.size() + i;
|
||||
|
||||
// Store the loot item in the player's inventory
|
||||
AoeLootCommandScript::ProcessLootSlot(player, creature->GetGUID(), 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process regular items
|
||||
for (uint8 lootSlot = 0; lootSlot < loot->items.size(); ++lootSlot)
|
||||
{
|
||||
|
||||
player->SetLootGUID(creature->GetGUID());
|
||||
// Store the loot item in the player's inventory
|
||||
InventoryResult msg;
|
||||
player->StoreLootItem(lootSlot, loot, msg);
|
||||
AoeLootCommandScript::ProcessLootSlot(player, creature->GetGUID(), lootSlot);
|
||||
|
||||
// Debug
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
totalItemsLooted++;
|
||||
|
||||
LOG_DEBUG("module.aoe_loot", "AOE Loot: Successfully looted item from slot {} (ID: {}) from {}", lootSlot, loot->items[lootSlot].itemid, creature->GetGUID().ToString());
|
||||
handler->PSendSysMessage(fmt::format("AOE Loot: Successfully looted item from slot {} (ID: {})", lootSlot, loot->items[lootSlot].itemid));
|
||||
}
|
||||
}
|
||||
|
||||
// Process quest items
|
||||
if (!loot->quest_items.empty())
|
||||
{
|
||||
// Calculate starting slot for quest items
|
||||
uint8 firstQuestSlot = loot->items.size();
|
||||
|
||||
// Try to loot each potential quest slot
|
||||
for (uint8 i = 0; i < loot->quest_items.size(); ++i)
|
||||
{
|
||||
uint8 lootSlot = firstQuestSlot + i;
|
||||
|
||||
// Store the loot item in the player's inventory
|
||||
InventoryResult msg;
|
||||
player->StoreLootItem(lootSlot, loot, msg);
|
||||
|
||||
// Debug logging
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
totalItemsLooted++;
|
||||
|
||||
LOG_DEBUG("module.aoe_loot", "AOE Loot: Successfully looted quest item from slot {}", lootSlot);
|
||||
handler->PSendSysMessage(fmt::format("AOE Loot: Successfully looted quest item from slot {}", lootSlot));
|
||||
|
||||
}
|
||||
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
|
||||
if (loot->gold > 0)
|
||||
{
|
||||
WorldPacket moneyPacket(CMSG_LOOT_MONEY, 0);
|
||||
player->GetSession()->HandleLootMoneyOpcode(moneyPacket);
|
||||
// Store the gold amount before it gets cleared by HandleLootMoneyOpcode
|
||||
uint32 goldAmount = loot->gold;
|
||||
AoeLootCommandScript::ProcessLootMoney(player, creature);
|
||||
|
||||
// Debug
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
totalCopperLooted += loot->gold;
|
||||
LOG_DEBUG("module.aoe_loot", "AOE Loot: Looted {} copper from {}", loot->gold, creature->GetGUID().ToString());
|
||||
handler->PSendSysMessage(fmt::format("AOE Loot: Looted {} copper from {}", loot->gold, creature->GetGUID().ToString()));
|
||||
}
|
||||
|
||||
// Debug
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
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
|
||||
if (loot->isLooted())
|
||||
{
|
||||
WorldPacket releaseData(CMSG_LOOT_RELEASE, 8);
|
||||
releaseData << creature->GetGUID();
|
||||
player->GetSession()->HandleLootReleaseOpcode(releaseData);
|
||||
// Cleanup the loot object from the corpse
|
||||
creature->AllLootRemovedFromCorpse();
|
||||
creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||
}
|
||||
|
||||
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Debug", true))
|
||||
{
|
||||
LOG_DEBUG("module.aoe_loot", "AOE Loot: Summary - Looted {} items, {} gold from {} corpses", totalItemsLooted, totalCopperLooted, totalCorpsesLooted);
|
||||
handler->PSendSysMessage(fmt::format("AOE Loot: Looted {} items and {} gold from {} corpses", totalItemsLooted, totalCopperLooted, totalCorpsesLooted));
|
||||
//creature->AllLootRemovedFromCorpse();
|
||||
//creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||
// Force update the world state to reflect the loot being gone
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Copied from sudlud's "mod-aoe-loot" module.
|
||||
void AOELootPlayer::OnPlayerLogin(Player* player)
|
||||
void AoeLootPlayer::OnPlayerLogin(Player* player)
|
||||
{
|
||||
if (sConfigMgr->GetOption<bool>("AOELoot.Enable", true))
|
||||
{
|
||||
@@ -232,7 +390,7 @@ void AOELootPlayer::OnPlayerLogin(Player* player)
|
||||
|
||||
void AddSC_AoeLoot()
|
||||
{
|
||||
new AOELootPlayer();
|
||||
new AOELootServer();
|
||||
new AoeLootPlayer();
|
||||
new AoeLootServer();
|
||||
new AoeLootCommandScript();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user