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.Debug
# Description: Enables debugging mode.
# Values: 0 = Disabled
# 1 = Enabled
# Default: 0 (Disabled)
AoeLoot.Debug = 0
# Chat Commands
# .AoeLoot off Disables AoE looting for player
# .AoeLoot on Enables AoE looting for player (requires module to be enabled)

View File

@@ -1,6 +1,5 @@
#include "aoe_loot.h"
#include "ScriptMgr.h"
#include "World.h"
#include "LootMgr.h"
#include "ServerScript.h"
#include "WorldSession.h"
@@ -9,12 +8,10 @@
#include "Chat.h"
#include "ChatCommand.h"
#include "ChatCommandArgs.h"
#include "WorldObjectScript.h"
#include "Creature.h"
#include "Config.h"
#include "Log.h"
#include "Map.h"
#include <fmt/format.h>
#include "Corpse.h"
#include "Group.h"
#include "ObjectMgr.h"
@@ -39,19 +36,12 @@ LootMethod GetLootMethodFromConfig(uint32 configValue)
{
switch (configValue)
{
case 0:
return FREE_FOR_ALL;
case 1:
return ROUND_ROBIN;
case 2:
return MASTER_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;
case 0: return FREE_FOR_ALL;
case 1: return ROUND_ROBIN;
case 2: return MASTER_LOOT;
case 3: return GROUP_LOOT;
case 4: return NEED_BEFORE_GREED;
default: return GROUP_LOOT;
}
}
@@ -98,8 +88,7 @@ bool AoeLootCommandScript::IsAoeLootEnabledForPlayer(Player* player)
case 2: // Enabled for both solo and group play
return true;
default: // Invalid value, default to solo + group
LOG_WARN("module.aoe_loot", "Invalid AoeLoot.EnableAOELoot value: {}. Using default (2).", AoeLootMode);
default: // Enabled for both solo and group play
return true;
}
}
@@ -202,37 +191,14 @@ bool AoeLootCommandScript::EnableAoeLootCommand(ChatHandler* handler, Optional<s
return true;
Player* player = handler->GetSession()->GetPlayer();
if (!player)
if (!player || !IsAoeLootEnabledForPlayer(player))
return true;
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);
playerAoeLootPreferences[guid] = true;
}
handler->PSendSysMessage("AOE looting has been enabled for your character. Type: '.AoeLoot off' to turn AoE Looting Off.");
return true;
}
@@ -253,7 +219,6 @@ bool AoeLootCommandScript::DisableAoeLootCommand(ChatHandler* handler, Optional<
playerAoeLootPreferences[guid] = false;
}
handler->PSendSysMessage("AOE looting has been disabled for your character. Type: '.AoeLoot on' to turn AoE Looting on.");
return true;
}
@@ -642,21 +607,14 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
// Check if AOE loot is enabled for this player's context
if (!IsAoeLootEnabledForPlayer(player))
{
handler->PSendSysMessage("AOE looting is not available in your current context.");
return true;
}
float range = sConfigMgr->GetOption<float>("AoeLoot.Range", 55.0);
bool debugMode = sConfigMgr->GetOption<bool>("AoeLoot.Debug", false);
std::list<Creature*> nearbyCorpses;
player->GetDeadCreatureListInGrid(nearbyCorpses, range);
if (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} nearby corpses within range {}.", nearbyCorpses.size(), range);
}
// Filter valid corpses
std::list<Creature*> validCorpses;
for (auto* creature : nearbyCorpses)
@@ -664,15 +622,16 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
if (!player || !creature)
continue;
// Check if creature is valid for looting by this player
if (!player->isAllowedToLoot(creature))
{
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not your loot", creature->GetGUID().ToString());
continue;
}
if (!creature->hasLootRecipient() || !creature->isTappedBy(player))
if (!creature->HasDynamicFlag(UNIT_DYNFLAG_LOOTABLE))
continue;
if (!creature->hasLootRecipient())
continue;
if (!creature->isTappedBy(player))
continue;
// 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 (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not your turn (Round Robin)", creature->GetGUID().ToString());
continue;
}
}
@@ -697,30 +653,14 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
{
if (group->GetMasterLooterGuid() != player->GetGUID())
{
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - not master looter", creature->GetGUID().ToString());
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);
}
if (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: Found {} valid nearby corpses within range {}.", validCorpses.size(), range);
}
// Process all valid corpses
for (auto* creature : validCorpses)
{
@@ -733,35 +673,22 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
// Double-check distance validation for security
if (!ValidateLootingDistance(player, lguid))
{
if (debugMode)
LOG_DEBUG("module.aoe_loot", "AOE Loot: Skipping creature {} - too far away", lguid.ToString());
continue;
}
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)
{
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
if (loot->gold > 0)
{
uint32 goldAmount = loot->gold;
ProcessCreatureGold(player, creature);
if (debugMode)
{
LOG_DEBUG("module.aoe_loot", "AOE Loot: Looted {} copper from {}", goldAmount, lguid.ToString());
}
}
if (loot->isLooted())
@@ -772,7 +699,6 @@ bool AoeLootCommandScript::TriggerAoeLootCommand(ChatHandler* handler, Optional<
return true;
}
// Display login message to player
void AoeLootPlayer::OnPlayerLogin(Player* player)
{
if (!IsAoeLootModuleEnabled())
@@ -801,7 +727,6 @@ void AoeLootPlayer::OnPlayerLogin(Player* player)
}
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);
}
// Quest item processing functions
bool AoeLootCommandScript::IsQuestItemForPlayer(Player* player, uint32 itemId)
class AoeLootQuestParty : public PlayerScript
{
if (!player)
return false;
public:
AoeLootQuestParty() : PlayerScript("AoeLootQuestParty") { }
const ItemTemplate* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
if (!itemTemplate)
return false;
// Check if this item starts a quest
if (itemTemplate->StartQuest != 0)
void OnPlayerBeforeFillQuestLootItem(Player* /*player*/, LootItem& item) override
{
uint32 questId = itemTemplate->StartQuest;
// Player must NOT have the quest, must NOT have completed it, and must NOT already have the item
if (!player->HasQuest(questId) &&
player->GetQuestStatus(questId) != QUEST_STATUS_COMPLETE &&
player->GetItemCount(itemId, true) == 0) // true = include bank
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(item.itemid);
if (itemTemplate &&
itemTemplate->Quality == ITEM_QUALITY_NORMAL &&
itemTemplate->Class == ITEM_CLASS_QUEST &&
itemTemplate->SubClass == ITEM_SUBCLASS_QUEST &&
itemTemplate->Bonding == BIND_QUEST_ITEM)
{
return 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;
}
}
item.freeforall = 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()
{
new AoeLootPlayer();
new AoeLootServer();
new AoeLootCommandScript();
new AoeLootGroupScript();
new AoeLootQuestParty();
}

View File

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