fixed gold dupping, empty corpses now reliably show as empty once opened

This commit is contained in:
ElderShell 2026-05-03 02:19:13 -06:00
parent 48a8d0c620
commit 9715afee68
3 changed files with 139 additions and 29 deletions

View file

@ -41,6 +41,7 @@
#include "Config.h"
#include "CreatureAI.h"
#include "DatabaseEnv.h"
#include "DatabaseEnvFwd.h"
#include "DisableMgr.h"
#include "Formulas.h"
#include "GameEventMgr.h"
@ -60,6 +61,7 @@
#include "MapMgr.h"
#include "MiscPackets.h"
#include "ObjectAccessor.h"
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "OutdoorPvP.h"
#include "OutdoorPvPMgr.h"
@ -8079,6 +8081,9 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
permission = NONE_PERMISSION;
ObjectGuid corpseGUID = bones->GetGUID();
CheckCorpseByGUID(corpseGUID);
if (Corpse* bones = ObjectAccessor::GetCorpse(*this, guid))
{
if (bones->GetOwnerGUID() != GetGUID())
@ -8304,11 +8309,16 @@ void Player::LoadLostCorpseLoot(ObjectGuid playerGuid, Loot& loot)
return;
QueryResult corpseResult = CharacterDatabase.Query(
"SELECT lost_corpse_id, money "
"SELECT lost_corpse_id, money, money_collected "
"FROM lost_corpses "
"WHERE player_guid = {} "
"AND SQRT(POW(position_x - {}, 2) + POW(position_y - {}, 2) + POW(position_z - {}, 2)) <= 5 "
"AND active = 1 "
"ORDER BY lost_corpse_id DESC LIMIT 1",
playerGuid.GetCounter()
playerGuid.GetCounter(),
GetPositionX(),
GetPositionY(),
GetPositionZ()
);
if (!corpseResult)
@ -8318,8 +8328,12 @@ void Player::LoadLostCorpseLoot(ObjectGuid playerGuid, Loot& loot)
uint32 lostCorpseId = corpseFields[0].Get<uint32>();
uint32 money = corpseFields[1].Get<uint32>();
bool moneyCollected = corpseFields[2].Get<uint8>();
loot.gold = money;
if (!moneyCollected)
{
loot.gold = money;
}
QueryResult result = CharacterDatabase.Query(
"SELECT id, lost_corpse_id, item_entry, count, durability "
@ -8360,6 +8374,80 @@ void Player::LoadLostCorpseLoot(ObjectGuid playerGuid, Loot& loot)
} while (result->NextRow());
}
void Player::CheckCorpse(uint32 lostCorpseId, ObjectGuid corpseGuid)
{
// Check if any items remain unlooted
QueryResult remaining = CharacterDatabase.Query(
"SELECT COUNT(*) FROM lost_corpse_items "
"WHERE lost_corpse_id = {} AND looted = 0",
lostCorpseId
);
if (remaining)
{
uint32 count = remaining->Fetch()[0].Get<uint32>();
if (count == 0)
{
QueryResult moneyCheck = CharacterDatabase.Query(
"SELECT money_collected, money FROM lost_corpses "
"WHERE lost_corpse_id = {} OR money = 0",
lostCorpseId
);
if (moneyCheck)
{
bool moneyCollected = moneyCheck->Fetch()[0].Get<uint8>();
uint32 money = moneyCheck->Fetch()[1].Get<uint32>();
if (moneyCollected || money == 0)
{
// No items left, deactivate corpse
CharacterDatabase.Execute(
"UPDATE lost_corpses SET active = 0 WHERE lost_corpse_id = {}",
lostCorpseId
);
ObjectGuid guidToUse = corpseGuid.IsEmpty() ? GetLootGUID() : corpseGuid;
// Remove lootability in-game
if (Corpse* corpse = ObjectAccessor::GetCorpse(*this, guidToUse))
{
corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE);
}
}
}
}
}
}
void Player::CheckCorpseByGUID(ObjectGuid corpseGuid)
{
uint32 guid = corpseGuid.GetCounter();
uint32 playerGUID = GetGUID().GetCounter();
float player_x = GetPositionX();
float player_y = GetPositionY();
float player_z = GetPositionZ();
QueryResult result = CharacterDatabase.Query(
"SELECT lost_corpse_id "
"FROM lost_corpses "
"WHERE corpse_guid = {} AND player_guid = {} "
"AND SQRT(POW(position_x - {}, 2) + POW(position_y - {}, 2) + POW(position_z - {}, 2)) <= 5",
guid,
playerGUID,
player_x,
player_y,
player_z
);
if (result)
{
uint32 lostCorpseId = result->Fetch()[0].Get<uint32>();
CheckCorpse(lostCorpseId, corpseGuid);
}
}
void Player::SendLootError(ObjectGuid guid, LootError error)
{
WorldPacket data(SMSG_LOOT_RESPONSE, 10);
@ -13801,32 +13889,7 @@ LootItem* Player::StoreLootItem(uint8 lootSlot, Loot* loot, InventoryResult& msg
dbId
);
// Check if any items remain unlooted
QueryResult remaining = CharacterDatabase.Query(
"SELECT COUNT(*) FROM lost_corpse_items "
"WHERE lost_corpse_id = {} AND looted = 0",
corpseId
);
if (remaining)
{
uint32 count = remaining->Fetch()[0].Get<uint32>();
if (count == 0)
{
// No items left, deactivate corpse
CharacterDatabase.Execute(
"UPDATE lost_corpses SET active = 0 WHERE lost_corpse_id = {}",
corpseId
);
// Remove lootability in-game
if (Corpse* corpse = ObjectAccessor::GetCorpse(*this, GetLootGUID()))
{
corpse->RemoveFlag(CORPSE_FIELD_DYNAMIC_FLAGS, CORPSE_DYNFLAG_LOOTABLE);
}
}
}
CheckCorpse(corpseId);
}
}

View file

@ -1101,6 +1101,9 @@ public:
explicit Player(WorldSession* session);
~Player() override;
void CheckCorpse(uint32 lostCorpseId, ObjectGuid corpseGuid = ObjectGuid::Empty);
void CheckCorpseByGUID(ObjectGuid corpseGuid);
void CleanupsBeforeDelete(bool finalCleanup = true) override;
void AddToWorld() override;

View file

@ -17,12 +17,14 @@
#include "Corpse.h"
#include "Creature.h"
#include "DatabaseEnvFwd.h"
#include "GameObject.h"
#include "Group.h"
#include "LootItemStorage.h"
#include "LootMgr.h"
#include "Object.h"
#include "ObjectAccessor.h"
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
@ -146,7 +148,46 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
loot = &bones->loot;
shareMoney = false;
}
else
{
player->SendLootError(guid, LOOT_ERROR_DIDNT_KILL);
break;
}
QueryResult result = CharacterDatabase.Query(
"SELECT lost_corpse_id, money "
"FROM lost_corpses "
"WHERE corpse_guid = {} AND player_guid = {} "
"AND active = 1 AND money_collected = 0 "
"AND SQRT(POW(position_x - {}, 2) + POW(position_y - {}, 2) + POW(position_z - {}, 2)) <= 5",
bones->GetGUID().GetCounter(),
player->GetGUID().GetCounter(),
player->GetPositionX(),
player->GetPositionY(),
player->GetPositionZ()
);
if (result)
{
Field* fields = result->Fetch();
uint32 lostCorpseId = fields[0].Get<uint32>();
uint32 totalMoney = fields[1].Get<uint32>();
loot->gold = totalMoney;
CharacterDatabase.Execute(
"UPDATE lost_corpses SET money_collected = 1 "
"WHERE lost_corpse_id = {}",
lostCorpseId
);
player->CheckCorpse(lostCorpseId);
}
else
{
loot->gold = 0;
}
break;
}
case HighGuid::Item:
@ -342,6 +383,9 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
loot = &corpse->loot;
ObjectGuid corpseGUID = corpse->GetGUID();
player->CheckCorpseByGUID(corpseGUID);
// Xinef: Buggs client? (Opening loot after closing)
//if (loot->isLooted())
//{