complete refactor

This commit is contained in:
crow
2025-08-28 19:53:59 -05:00
parent 6525d3912a
commit 801b0d1fe6
3 changed files with 38 additions and 203 deletions

View File

@@ -54,14 +54,6 @@ AoeLoot.DefaultLootMethod = 2
AoeLoot.DefaultLootThreshold = 2 AoeLoot.DefaultLootThreshold = 2
# AoeLoot.Debug
# Description: Enables debugging mode.
# Values: 0 = Disabled
# 1 = Enabled
# Default: 0 (Disabled)
AoeLoot.Debug = 0
# Chat Commands # Chat Commands
# .AoeLoot off Disables AoE looting for player # .AoeLoot off Disables AoE looting for player
# .AoeLoot on Enables AoE looting for player (requires module to be enabled) # .AoeLoot on Enables AoE looting for player (requires module to be enabled)

View File

@@ -1,6 +1,5 @@
#include "aoe_loot.h" #include "aoe_loot.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "World.h"
#include "LootMgr.h" #include "LootMgr.h"
#include "ServerScript.h" #include "ServerScript.h"
#include "WorldSession.h" #include "WorldSession.h"
@@ -9,12 +8,10 @@
#include "Chat.h" #include "Chat.h"
#include "ChatCommand.h" #include "ChatCommand.h"
#include "ChatCommandArgs.h" #include "ChatCommandArgs.h"
#include "WorldObjectScript.h"
#include "Creature.h" #include "Creature.h"
#include "Config.h" #include "Config.h"
#include "Log.h" #include "Log.h"
#include "Map.h" #include "Map.h"
#include <fmt/format.h>
#include "Corpse.h" #include "Corpse.h"
#include "Group.h" #include "Group.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
@@ -39,19 +36,12 @@ LootMethod GetLootMethodFromConfig(uint32 configValue)
{ {
switch (configValue) switch (configValue)
{ {
case 0: case 0: return FREE_FOR_ALL;
return FREE_FOR_ALL; case 1: return ROUND_ROBIN;
case 1: case 2: return MASTER_LOOT;
return ROUND_ROBIN; case 3: return GROUP_LOOT;
case 2: case 4: return NEED_BEFORE_GREED;
return MASTER_LOOT; default: return GROUP_LOOT;
case 3:
return GROUP_LOOT;
case 4:
return NEED_BEFORE_GREED;
default:
LOG_WARN("module.aoe_loot", "Invalid AoeLoot.DefaultLootMethod value: {}. Using Group Loot.", configValue);
return GROUP_LOOT;
} }
} }
@@ -98,8 +88,7 @@ bool AoeLootCommandScript::IsAoeLootEnabledForPlayer(Player* player)
case 2: // Enabled for both solo and group play case 2: // Enabled for both solo and group play
return true; return true;
default: // Invalid value, default to solo + group default: // Enabled for both solo and group play
LOG_WARN("module.aoe_loot", "Invalid AoeLoot.EnableAOELoot value: {}. Using default (2).", AoeLootMode);
return true; return true;
} }
} }
@@ -202,37 +191,14 @@ bool AoeLootCommandScript::EnableAoeLootCommand(ChatHandler* handler, Optional<s
return true; return true;
Player* player = handler->GetSession()->GetPlayer(); Player* player = handler->GetSession()->GetPlayer();
if (!player) if (!player || !IsAoeLootEnabledForPlayer(player))
return true; return true;
uint64 guid = player->GetGUID().GetRawValue(); uint64 guid = player->GetGUID().GetRawValue();
// Check if AOE loot is enabled server-side
if (!IsAoeLootEnabledForPlayer(player))
{
uint32 AoeLootMode = sConfigMgr->GetOption<uint32>("AoeLoot.EnableAOELoot", 2);
switch (AoeLootMode)
{
case 0:
handler->PSendSysMessage("AOE looting is completely disabled on this server.");
break;
case 1:
handler->PSendSysMessage("AOE looting is only available for solo play (you are currently in a group).");
break;
default:
handler->PSendSysMessage("AOE looting is not available in your current context.");
break;
}
return true;
}
// Thread-safe update
{ {
std::lock_guard<std::mutex> lock(AoeLootPreferencesMutex); std::lock_guard<std::mutex> lock(AoeLootPreferencesMutex);
playerAoeLootPreferences[guid] = true; playerAoeLootPreferences[guid] = true;
} }
handler->PSendSysMessage("AOE looting has been enabled for your character. Type: '.AoeLoot off' to turn AoE Looting Off.");
return true; return true;
} }
@@ -253,7 +219,6 @@ bool AoeLootCommandScript::DisableAoeLootCommand(ChatHandler* handler, Optional<
playerAoeLootPreferences[guid] = false; playerAoeLootPreferences[guid] = false;
} }
handler->PSendSysMessage("AOE looting has been disabled for your character. Type: '.AoeLoot on' to turn AoE Looting on.");
return true; return true;
} }
@@ -642,21 +607,14 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
// Check if AOE loot is enabled for this player's context // Check if AOE loot is enabled for this player's context
if (!IsAoeLootEnabledForPlayer(player)) if (!IsAoeLootEnabledForPlayer(player))
{ {
handler->PSendSysMessage("AOE looting is not available in your current context.");
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 (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} nearby corpses within range {}.", nearbyCorpses.size(), range);
}
// Filter valid corpses // Filter valid corpses
std::list<Creature*> validCorpses; std::list<Creature*> validCorpses;
for (auto* creature : nearbyCorpses) for (auto* creature : nearbyCorpses)
@@ -664,15 +622,16 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
if (!player || !creature) if (!player || !creature)
continue; continue;
// Check if creature is valid for looting by this player
if (!player->isAllowedToLoot(creature)) if (!player->isAllowedToLoot(creature))
{
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not your loot", creature->GetGUID().ToString());
continue; continue;
}
if (!creature->hasLootRecipient() || !creature->isTappedBy(player)) if (!creature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE))
continue;
if (!creature->hasLootRecipient())
continue;
if (!creature->isTappedBy(player))
continue; continue;
// Get player's group and check loot permissions based on group loot method // Get player's group and check loot permissions based on group loot method
@@ -686,9 +645,6 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
{ {
if (loot->roundRobinPlayer && loot->roundRobinPlayer != player->GetGUID()) if (loot->roundRobinPlayer && loot->roundRobinPlayer != player->GetGUID())
{ {
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not your turn (Round Robin)", creature->GetGUID().ToString());
continue; continue;
} }
} }
@@ -697,30 +653,14 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
{ {
if (group->GetMasterLooterGuid() != player->GetGUID()) if (group->GetMasterLooterGuid() != player->GetGUID())
{ {
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not master looter", creature->GetGUID().ToString());
continue; continue;
} }
} }
} }
// Skip if corpse is not lootable
if (!creature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE))
{
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not lootable", creature->GetGUID().ToString());
continue;
}
validCorpses.push_back(creature); validCorpses.push_back(creature);
} }
if (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} valid nearby corpses within range {}.", validCorpses.size(), range);
}
// Process all valid corpses // Process all valid corpses
for (auto* creature : validCorpses) for (auto* creature : validCorpses)
{ {
@@ -733,35 +673,22 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
// Double-check distance validation for security // Double-check distance validation for security
if (!ValidateLootingDistance(player, lguid)) if (!ValidateLootingDistance(player, lguid))
{ {
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - too far away", lguid.ToString());
continue; continue;
} }
player->SetLootGUID(lguid); player->SetLootGUID(lguid);
// Process all regular items (includes quest items and FFA items automatically) // Process all loot items
for (uint8 lootSlot = 0; lootSlot < loot->items.size(); ++lootSlot) for (uint8 lootSlot = 0; lootSlot < loot->items.size(); ++lootSlot)
{ {
ProcessSingleLootSlot(player, lguid, lootSlot); ProcessSingleLootSlot(player, lguid, lootSlot);
if (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: looted item from slot {} (ID: {}) from {}", lootSlot, loot->items[lootSlot].itemid, lguid.ToString());
} }
}
// Always process quest items using Blizzard logic (only for players who need them)
ProcessQuestItemsForPlayer(player, lguid, loot);
// Handle money // Handle money
if (loot->gold > 0) if (loot->gold > 0)
{ {
uint32 goldAmount = loot->gold; uint32 goldAmount = loot->gold;
ProcessCreatureGold(player, creature); ProcessCreatureGold(player, creature);
if (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: Looted {} copper from {}", goldAmount, lguid.ToString());
}
} }
if (loot->isLooted()) if (loot->isLooted())
@@ -772,7 +699,6 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
return true; return true;
} }
// Display login message to player
void AoeLootPlayer::OnPlayerLogin(Player* player) void AoeLootPlayer::OnPlayerLogin(Player* player)
{ {
if (!IsAoeLootModuleEnabled()) if (!IsAoeLootModuleEnabled())
@@ -801,7 +727,6 @@ void AoeLootPlayer::OnPlayerLogin(Player* player)
} }
message += ". Type: '.AoeLoot off' to turn AoE Looting Off."; message += ". Type: '.AoeLoot off' to turn AoE Looting Off.";
ChatHandler(player->GetSession()).PSendSysMessage(message.c_str());
} }
} }
@@ -817,96 +742,30 @@ void AoeLootGroupScript::OnCreate(Group* group, Player* leader)
ApplyDefaultLootSettings(group, leader); ApplyDefaultLootSettings(group, leader);
} }
// Quest item processing functions class AoeLootQuestParty : public PlayerScript
bool AoeLootCommandScript::IsQuestItemForPlayer(Player* player, uint32 itemId)
{ {
if (!player) public:
return false; AoeLootQuestParty() : PlayerScript("AoeLootQuestParty") { }
const ItemTemplate* itemTemplate = sObjectMgr->GetItemTemplate(itemId); void OnPlayerBeforeFillQuestLootItem(Player* /*player*/, LootItem& item) override
if (!itemTemplate)
return false;
// Check if this item starts a quest
if (itemTemplate->StartQuest != 0)
{ {
uint32 questId = itemTemplate->StartQuest; ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item.itemid);
// Player must NOT have the quest, must NOT have completed it, and must NOT already have the item if (itemTemplate &&
if (!player->HasQuest(questId) && itemTemplate->Quality == ITEM_QUALITY_NORMAL &&
player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE && itemTemplate->Class == ITEM_CLASS_QUEST &&
player->GetItemCount(itemId, true) == 0) // true = include bank itemTemplate->SubClass == ITEM_SUBCLASS_QUEST &&
itemTemplate->Bonding == BIND_QUEST_ITEM)
{ {
return true; item.freeforall = true;
}
return false;
}
// Check if player has quests requiring this item
for (uint8 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
{
uint32 questId = player->GetQuestSlotQuestId(slot);
if (questId == 0)
continue;
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
if (!quest)
continue;
// Check quest objectives for this item
for (uint8 i = 0; i < QUEST_OBJECTIVES_COUNT; ++i)
{
if (quest->RequiredItemId[i] == itemId)
{
// Check if player still needs this item for the quest
uint32 currentCount = player->GetItemCount(itemId, true);
uint32 requiredCount = quest->RequiredItemCount[i];
if (currentCount < requiredCount)
{
return true;
}
}
} }
} }
};
return false;
}
bool AoeLootCommandScript::ProcessQuestItemsForPlayer(Player* player, ObjectGuid lguid, Loot* loot)
{
if (!player || !loot)
return false;
bool processedAny = false;
bool debugMode = sConfigMgr->GetOption<bool>("AoeLoot.Debug", false);
for (uint8 i = 0; i < loot->quest_items.size(); ++i)
{
LootItem& questItem = loot->quest_items[i];
// Check if this quest item is for the current player
if (IsQuestItemForPlayer(player, questItem.itemid))
{
uint8 questLootSlot = loot->items.size() + i;
ProcessSingleLootSlot(player, lguid, questLootSlot);
processedAny = true;
if (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: looted quest item {} from slot {} for player {}",
questItem.itemid, questLootSlot, player->GetName());
}
}
}
return processedAny;
}
// Add script registrations
void AddSC_AoeLoot() void AddSC_AoeLoot()
{ {
new AoeLootPlayer(); new AoeLootPlayer();
new AoeLootServer(); new AoeLootServer();
new AoeLootCommandScript(); new AoeLootCommandScript();
new AoeLootGroupScript(); new AoeLootGroupScript();
new AoeLootQuestParty();
} }

View File

@@ -2,22 +2,14 @@
#define MODULE_AoeLoot_H #define MODULE_AoeLoot_H
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "Config.h"
#include "ServerScript.h" #include "ServerScript.h"
#include "Chat.h"
#include "Player.h"
#include "Item.h"
#include "ScriptedGossip.h"
#include "ChatCommand.h" #include "ChatCommand.h"
#include "ChatCommandArgs.h"
#include "AccountMgr.h" class Player;
#include "ObjectMgr.h" class Group;
#include "QuestDef.h" class Loot;
#include <vector> class Creature;
#include <list> class ObjectGuid;
#include <map>
#include <ObjectGuid.h>
#include <mutex>
using namespace Acore::ChatCommands; using namespace Acore::ChatCommands;
@@ -50,10 +42,6 @@ public:
static bool ProcessCreatureGold(Player* player, Creature* creature); static bool ProcessCreatureGold(Player* player, Creature* creature);
static void ReleaseAndCleanupLoot(ObjectGuid lguid, Player* player, Loot* loot); static void ReleaseAndCleanupLoot(ObjectGuid lguid, Player* player, Loot* loot);
// Quest item processing functions
static bool IsQuestItemForPlayer(Player* player, uint32 itemId);
static bool ProcessQuestItemsForPlayer(Player* player, ObjectGuid lguid, Loot* loot);
// Validation functions // Validation functions
static bool ValidateLootingDistance(Player* player, ObjectGuid lguid, float maxDistance = 0.0f); static bool ValidateLootingDistance(Player* player, ObjectGuid lguid, float maxDistance = 0.0f);
static bool IsAoeLootEnabledForPlayer(Player* player); static bool IsAoeLootEnabledForPlayer(Player* player);
@@ -64,10 +52,6 @@ class AoeLootGroupScript : public GroupScript
public: public:
AoeLootGroupScript() : GroupScript("AoeLootGroupScript") {} AoeLootGroupScript() : GroupScript("AoeLootGroupScript") {}
void OnCreate(Group* group, Player* leader) override; void OnCreate(Group* group, Player* leader) override;
private:
// Helper function to convert config value to LootMethod enum
LootMethod GetLootMethodFromConfig(uint32 configValue);
}; };
void AddSC_AoeLoot(); void AddSC_AoeLoot();