diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 0e2b664c9..1805c42b2 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -13442,7 +13442,10 @@ LootItem* Player::StoreLootItem(uint8 lootSlot, Loot* loot, InventoryResult& msg LootItem* item = loot->LootItemInSlot(lootSlot, this, &qitem, &ffaitem, &conditem); if (!item || item->is_looted) { - SendEquipError(EQUIP_ERR_ALREADY_LOOTED, nullptr, nullptr); + if (!sScriptMgr->CanSendErrorAlreadyLooted(this)) + { + SendEquipError(EQUIP_ERR_ALREADY_LOOTED, nullptr, nullptr); + } return nullptr; } diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index b5d36cc65..e4a1b3c3c 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -93,6 +93,8 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData) loot = &creature->loot; } + sScriptMgr->OnAfterCreatureLoot(player); + InventoryResult msg; LootItem* lootItem = player->StoreLootItem(lootSlot, loot, msg); if (msg != EQUIP_ERR_OK && lguid.IsItem() && loot->loot_type != LOOT_CORPSE) @@ -209,6 +211,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/) } else { + sScriptMgr->OnAfterCreatureLootMoney(player); player->ModifyMoney(loot->gold); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY, loot->gold); diff --git a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp index 2682193d4..eaa3b95a7 100644 --- a/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp +++ b/src/server/game/Scripting/ScriptDefines/PlayerScript.cpp @@ -905,6 +905,37 @@ bool ScriptMgr::CanSendMail(Player* player, ObjectGuid receiverGuid, ObjectGuid return true; } +bool ScriptMgr::CanSendErrorAlreadyLooted(Player* player) +{ + auto ret = IsValidBoolScript([&](PlayerScript* script) + { + return !script->CanSendErrorAlreadyLooted(player); + }); + + if (ret && *ret) + { + return false; + } + + return true; +} + +void ScriptMgr::OnAfterCreatureLoot(Player* player) +{ + ExecuteScript([&](PlayerScript* script) + { + script->OnAfterCreatureLoot(player); + }); +} + +void ScriptMgr::OnAfterCreatureLootMoney(Player* player) +{ + ExecuteScript([&](PlayerScript* script) + { + script->OnAfterCreatureLootMoney(player); + }); +} + void ScriptMgr::PetitionBuy(Player* player, Creature* creature, uint32& charterid, uint32& cost, uint32& type) { ExecuteScript([&](PlayerScript* script) diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 3a543c2c3..e4fcd3f96 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -1481,6 +1481,30 @@ public: virtual void AnticheatUpdateMovementInfo(Player* /*player*/, MovementInfo const& /*movementInfo*/) { } [[nodiscard]] virtual bool AnticheatHandleDoubleJump(Player* /*player*/, Unit* /*mover*/) { return true; } [[nodiscard]] virtual bool AnticheatCheckMovementInfo(Player* /*player*/, MovementInfo const& /*movementInfo*/, Unit* /*mover*/, bool /*jump*/) { return true; } + + /** + * @brief This hook is called, to avoid displaying the error message that the body has already been stripped + * + * @param player Contains information about the Player + * + * @return true Avoiding displaying the error message that the loot has already been taken. + */ + virtual bool CanSendErrorAlreadyLooted(Player* /*player*/) { return true; } + + /** + * @brief It is used when an item is taken from a creature. + * + * @param player Contains information about the Player + * + */ + virtual void OnAfterCreatureLoot(Player* /*player*/) { } + + /** + * @brief After a creature's money is taken + * + * @param player Contains information about the Player + */ + virtual void OnAfterCreatureLootMoney(Player* /*player*/) { } }; class AccountScript : public ScriptObject @@ -2406,6 +2430,9 @@ public: /* PlayerScript */ void OnPlayerEnterCombat(Player* player, Unit* enemy); void OnPlayerLeaveCombat(Player* player); void OnQuestAbandon(Player* player, uint32 questId); + bool CanSendErrorAlreadyLooted(Player* player); + void OnAfterCreatureLoot(Player* player); + void OnAfterCreatureLootMoney(Player* player); // Anti cheat void AnticheatSetSkipOnePacketForASH(Player* player, bool apply);