mirror of
https://github.com/brighton-chi/mod-aoe-loot.git
synced 2026-01-13 00:58:34 +00:00
complete refactor
This commit is contained in:
@@ -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)
|
||||
|
||||
201
src/aoe_loot.cpp
201
src/aoe_loot.cpp
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -199,40 +188,17 @@ ChatCommandTable AoeLootCommandScript::GetCommands() const
|
||||
bool AoeLootCommandScript::EnableAoeLootCommand(ChatHandler* handler, Optional<std::string>)
|
||||
{
|
||||
if (!IsAoeLootModuleEnabled())
|
||||
return true;
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user