mirror of
https://github.com/azerothcore/mod-aoe-loot
synced 2025-11-29 21:38:16 +08:00
Merge pull request #49 from ide1234000/master
This commit is contained in:
209
src/aoe_loot.cpp
209
src/aoe_loot.cpp
@@ -16,87 +16,176 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "aoe_loot.h"
|
#include "aoe_loot.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
void AOELootPlayer::OnPlayerLogin(Player* player)
|
void AOELootPlayer::OnPlayerLogin(Player* player)
|
||||||
{
|
{
|
||||||
|
if (!player)
|
||||||
|
return;
|
||||||
|
|
||||||
if (sConfigMgr->GetOption<bool>("AOELoot.Enable", true))
|
if (sConfigMgr->GetOption<bool>("AOELoot.Enable", true))
|
||||||
{
|
{
|
||||||
if (sConfigMgr->GetOption<bool>("AOELoot.Message", true))
|
if (sConfigMgr->GetOption<bool>("AOELoot.Message", true))
|
||||||
ChatHandler(player->GetSession()).PSendSysMessage(AOE_ACORE_STRING_MESSAGE);
|
{
|
||||||
|
if (WorldSession* session = player->GetSession())
|
||||||
|
ChatHandler(session).PSendSysMessage(AOE_ACORE_STRING_MESSAGE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AOELootServer::CanPacketReceive(WorldSession* session, WorldPacket& packet)
|
bool AOELootServer::CanPacketReceive(WorldSession* session, WorldPacket& packet)
|
||||||
{
|
{
|
||||||
if (packet.GetOpcode() == CMSG_LOOT)
|
// Only handle loot packets
|
||||||
{
|
if (packet.GetOpcode() != CMSG_LOOT)
|
||||||
Player* player = session->GetPlayer();
|
return true;
|
||||||
|
|
||||||
if (!sConfigMgr->GetOption<bool>("AOELoot.Enable", true))
|
// Basic validation checks
|
||||||
return true;
|
if (!session)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (player->GetGroup() && !sConfigMgr->GetOption<bool>("AOELoot.Group", true))
|
Player* player = session->GetPlayer();
|
||||||
return true;
|
if (!player)
|
||||||
|
return true;
|
||||||
|
|
||||||
float range = sConfigMgr->GetOption<float>("AOELoot.Range", 55.0);
|
// Check if module is enabled
|
||||||
|
if (!sConfigMgr->GetOption<bool>("AOELoot.Enable", true))
|
||||||
|
return true;
|
||||||
|
|
||||||
std::list<Creature*> lootcreature; player->GetDeadCreatureListInGrid(lootcreature, range);
|
// Check group settings
|
||||||
|
if (player->GetGroup() && !sConfigMgr->GetOption<bool>("AOELoot.Group", true))
|
||||||
|
return true;
|
||||||
|
|
||||||
ObjectGuid guid; packet >> guid;
|
// Get configured loot range
|
||||||
|
float range = sConfigMgr->GetOption<float>("AOELoot.Range", 30.0f);
|
||||||
|
|
||||||
Loot* mainloot = &(player->GetMap()->GetCreature(guid))->loot;
|
// Limit range to reasonable values
|
||||||
|
if (range < 5.0f)
|
||||||
|
range = 5.0f;
|
||||||
|
|
||||||
for (auto itr = lootcreature.begin(); itr != lootcreature.end(); ++itr)
|
if (range > 100.0f)
|
||||||
|
range = 100.0f;
|
||||||
|
|
||||||
|
// Read target GUID from packet
|
||||||
|
ObjectGuid targetGuid;
|
||||||
|
packet >> targetGuid;
|
||||||
|
|
||||||
|
if (!targetGuid)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Get target creature
|
||||||
|
Creature* mainCreature = player->GetMap()->GetCreature(targetGuid);
|
||||||
|
if (!mainCreature)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Check if main creature has loot
|
||||||
|
if (!mainCreature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Get nearby corpses
|
||||||
|
std::list<Creature*> nearbyCorpses;
|
||||||
|
player->GetDeadCreatureListInGrid(nearbyCorpses, range);
|
||||||
|
|
||||||
|
// Remove invalid corpses and main target
|
||||||
|
nearbyCorpses.remove_if([&](Creature* c)
|
||||||
{
|
{
|
||||||
Creature* creature = *itr;
|
return !c ||
|
||||||
|
c->GetGUID() == targetGuid ||
|
||||||
|
!c->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE) ||
|
||||||
|
!player->isAllowedToLoot(c);
|
||||||
|
});
|
||||||
|
|
||||||
// Prevent infiny add items
|
// If no other corpses, process normally
|
||||||
if (creature->GetGUID() == guid)
|
if (nearbyCorpses.empty())
|
||||||
continue;
|
{
|
||||||
|
player->SendLoot(targetGuid, LOOT_CORPSE);
|
||||||
// Prevent steal loot
|
|
||||||
if (!player->GetMap()->Instanceable())
|
|
||||||
if (!player->isAllowedToLoot(creature))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Max 15 items per creature
|
|
||||||
if (mainloot->items.size() + mainloot->quest_items.size() > 15)
|
|
||||||
break;
|
|
||||||
|
|
||||||
Loot* loot = &(*itr)->loot;
|
|
||||||
|
|
||||||
// FILL QITEMS
|
|
||||||
if (!loot->quest_items.empty())
|
|
||||||
{
|
|
||||||
mainloot->items.insert(mainloot->items.end(), loot->quest_items.begin(), loot->quest_items.end());
|
|
||||||
loot->quest_items.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILL GOLD
|
|
||||||
if (loot->gold != 0)
|
|
||||||
{
|
|
||||||
mainloot->gold += loot->gold;
|
|
||||||
loot->gold = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILL ITEMS
|
|
||||||
if (!loot->items.empty())
|
|
||||||
{
|
|
||||||
mainloot->items.insert(mainloot->items.end(), loot->items.begin(), loot->items.end());
|
|
||||||
loot->items.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set flag for skinning
|
|
||||||
if (loot->items.empty() && loot->quest_items.empty())
|
|
||||||
{
|
|
||||||
creature->AllLootRemovedFromCorpse();
|
|
||||||
creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
player->SendLoot(guid, LOOT_CORPSE);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
// Get main loot
|
||||||
|
Loot* mainLoot = &mainCreature->loot;
|
||||||
|
|
||||||
|
// Limit number of corpses to process
|
||||||
|
size_t const maxCorpses = 10; // set to 10 to improve stability
|
||||||
|
size_t processedCorpses = 0;
|
||||||
|
|
||||||
|
// Track total gold to merge
|
||||||
|
uint32 totalGold = mainLoot->gold;
|
||||||
|
|
||||||
|
// Collect all items to merge (don't modify main loot directly)
|
||||||
|
std::vector<LootItem> itemsToAdd;
|
||||||
|
std::vector<LootItem> questItemsToAdd;
|
||||||
|
|
||||||
|
for (Creature* creature : nearbyCorpses)
|
||||||
|
{
|
||||||
|
if (processedCorpses >= maxCorpses)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!creature)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Loot* loot = &creature->loot;
|
||||||
|
|
||||||
|
// Skip already looted corpses
|
||||||
|
if (loot->isLooted())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Collect gold
|
||||||
|
if (loot->gold > 0)
|
||||||
|
{
|
||||||
|
// Prevent overflow
|
||||||
|
if (totalGold < (std::numeric_limits<uint32>::max() - loot->gold))
|
||||||
|
totalGold += loot->gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect regular items
|
||||||
|
for (size_t i = 0; i < loot->items.size(); ++i)
|
||||||
|
{
|
||||||
|
// Check if there's still space
|
||||||
|
if ((mainLoot->items.size() + itemsToAdd.size() + mainLoot->quest_items.size() + questItemsToAdd.size()) >= 15)
|
||||||
|
break;
|
||||||
|
|
||||||
|
itemsToAdd.push_back(loot->items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect quest items
|
||||||
|
for (size_t i = 0; i < loot->quest_items.size(); ++i)
|
||||||
|
{
|
||||||
|
// Check if there's still space
|
||||||
|
if ((mainLoot->items.size() + itemsToAdd.size() + mainLoot->quest_items.size() + questItemsToAdd.size()) >= 15)
|
||||||
|
break;
|
||||||
|
|
||||||
|
questItemsToAdd.push_back(loot->quest_items[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear source loot (but don't modify vector directly)
|
||||||
|
loot->clear();
|
||||||
|
creature->AllLootRemovedFromCorpse();
|
||||||
|
creature->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
|
||||||
|
|
||||||
|
processedCorpses++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now safely add collected items to main loot
|
||||||
|
// Update gold
|
||||||
|
mainLoot->gold = totalGold;
|
||||||
|
|
||||||
|
// Add regular items
|
||||||
|
for (const auto& item : itemsToAdd)
|
||||||
|
{
|
||||||
|
if (mainLoot->items.size() < 15)
|
||||||
|
mainLoot->items.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add quest items
|
||||||
|
for (const auto& item : questItemsToAdd)
|
||||||
|
{
|
||||||
|
if (mainLoot->quest_items.size() < 15)
|
||||||
|
mainLoot->quest_items.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send merged loot window
|
||||||
|
player->SendLoot(targetGuid, LOOT_CORPSE);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,16 @@
|
|||||||
#include "Chat.h"
|
#include "Chat.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "ScriptedGossip.h"
|
#include "ScriptedGossip.h"
|
||||||
|
#include "Group.h"
|
||||||
|
#include "LootMgr.h"
|
||||||
|
#include "Creature.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
// Maximum loot items count
|
||||||
|
constexpr size_t MAX_LOOT_ITEMS = 16;
|
||||||
|
|
||||||
enum AoeLootString
|
enum AoeLootString
|
||||||
{
|
{
|
||||||
@@ -33,7 +43,7 @@ enum AoeLootString
|
|||||||
class AOELootPlayer : public PlayerScript
|
class AOELootPlayer : public PlayerScript
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AOELootPlayer() : PlayerScript("AOELootPlayer") { }
|
AOELootPlayer() : PlayerScript("AOELootPlayer") {}
|
||||||
|
|
||||||
void OnPlayerLogin(Player* player) override;
|
void OnPlayerLogin(Player* player) override;
|
||||||
};
|
};
|
||||||
@@ -41,9 +51,53 @@ public:
|
|||||||
class AOELootServer : public ServerScript
|
class AOELootServer : public ServerScript
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AOELootServer() : ServerScript("AOELootServer") { }
|
AOELootServer() : ServerScript("AOELootServer") {}
|
||||||
|
|
||||||
bool CanPacketReceive(WorldSession* session, WorldPacket& packet) override;
|
bool CanPacketReceive(WorldSession* session, WorldPacket& packet) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Helper function - Check if loot is valid
|
||||||
|
bool IsLootValid(Loot* loot) const;
|
||||||
|
|
||||||
|
// Check if loot can be merged
|
||||||
|
bool CanMergeLoot(Player* player, Creature* creature) const;
|
||||||
|
|
||||||
|
// Safely get item count
|
||||||
|
size_t GetSafeItemCount(Loot* loot) const;
|
||||||
|
|
||||||
|
// Safely merge loot items
|
||||||
|
bool SafeMergeLootItems(Loot* mainLoot, Loot* sourceLoot, size_t& remainingSlots);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configuration options structure (optional, for better config management)
|
||||||
|
struct AOELootConfig
|
||||||
|
{
|
||||||
|
bool enabled = true;
|
||||||
|
bool messageOnLogin = true;
|
||||||
|
bool allowInGroup = true;
|
||||||
|
float range = 55.0f;
|
||||||
|
uint32 maxCorpses = 20;
|
||||||
|
|
||||||
|
static AOELootConfig* instance()
|
||||||
|
{
|
||||||
|
static AOELootConfig instance;
|
||||||
|
return &instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Load()
|
||||||
|
{
|
||||||
|
enabled = sConfigMgr->GetOption<bool>("AOELoot.Enable", true);
|
||||||
|
messageOnLogin = sConfigMgr->GetOption<bool>("AOELoot.Message", true);
|
||||||
|
allowInGroup = sConfigMgr->GetOption<bool>("AOELoot.Group", true);
|
||||||
|
range = sConfigMgr->GetOption<float>("AOELoot.Range", 55.0f);
|
||||||
|
maxCorpses = sConfigMgr->GetOption<uint32>("AOELoot.MaxCorpses", 20);
|
||||||
|
|
||||||
|
// Validate configuration values
|
||||||
|
if (range < 5.0f) range = 5.0f;
|
||||||
|
if (range > 100.0f) range = 100.0f;
|
||||||
|
if (maxCorpses < 1) maxCorpses = 1;
|
||||||
|
if (maxCorpses > 50) maxCorpses = 50;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddSC_AoeLoot()
|
void AddSC_AoeLoot()
|
||||||
|
|||||||
Reference in New Issue
Block a user