From ab02c36e67045e2c6a166cbd6db96ae466e061d0 Mon Sep 17 00:00:00 2001 From: Elmsroth Date: Fri, 15 Mar 2024 14:23:31 +0100 Subject: [PATCH] feat(Scripts/Commands): Implement ".reset items" command (#18393) Syntax : .reset items equiped|bags|bank|keyring|currency|vendor_buyback|all|allbags #playername Delete items in the player inventory (equiped, bank, bags etc...) depending on the chosen option. #playername : Optionnal target player name (if player is online only). If not provided the command will execute on the selected target player. Update src/server/scripts/Commands/cs_reset.cpp Accepted Co-authored-by: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Update data/sql/updates/pending_db_world/rev_1708782048020249700.sql Accepted Co-authored-by: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Update data/sql/updates/pending_db_world/rev_1708782048020249700.sql Accepted Co-authored-by: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> Update src/server/game/Miscellaneous/Language.h Accepted Co-authored-by: Benjamin Jackson <38561765+heyitsbench@users.noreply.github.com> fix uint16 vs uint16_t fix crash and code cleanup Fix typo sql fix Missing typo selected instead or selecter AC code style fix Re-Fix typos MISSING typos missing typos --- .../rev_1708782048020249700.sql | 122 +++++ src/server/game/Entities/Player/Player.h | 2 +- src/server/game/Miscellaneous/Language.h | 14 +- src/server/scripts/Commands/cs_reset.cpp | 425 ++++++++++++++++++ 4 files changed, 561 insertions(+), 2 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1708782048020249700.sql diff --git a/data/sql/updates/pending_db_world/rev_1708782048020249700.sql b/data/sql/updates/pending_db_world/rev_1708782048020249700.sql new file mode 100644 index 000000000..8c795b423 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1708782048020249700.sql @@ -0,0 +1,122 @@ +-- [START] // DB Update for .reset items command + +/*--------------------------------- + + Command and associated help + +-----------------------------------*/ + +-- Always delete before insert to ensure script repeatability : +-- One value per line to facilitate readability +DELETE FROM `command` WHERE `name` IN( +'reset items', +'reset items equipped', +'reset items bags', +'reset items bank', +'reset items keyring', +'reset items currency', +'reset items vendor_buyback', +'reset items all', +'reset items allbags'); + +-- GM Security level associated with the commands +SET @GM_SECURITY_LEVEL = 3; + +-- Insert values : +INSERT INTO `command`(`name`,`security`,`help`) +VALUES ( +-- .reset items (main command) +'reset items', @GM_SECURITY_LEVEL, 'Syntax : .reset items equipped|bags|bank|keyring|currency|vendor_buyback|all|allbags #playername +Delete items in the player inventory (equipped, bank, bags etc...) depending on the chosen option. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +-- .reset items _____ (Sub-commands) +('reset items equipped', @GM_SECURITY_LEVEL, 'Syntax : .reset items equipped #playername +Delete all items equipped on the target player. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +('reset items bags', @GM_SECURITY_LEVEL, 'Syntax : .reset items bags #playername +Delete all items in the selected player\'s bags. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +('reset items bank', @GM_SECURITY_LEVEL, 'Syntax : .reset items bank #playername +Delete all items in the selected player\'s bank. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +('reset items keyring', @GM_SECURITY_LEVEL, 'Syntax : .reset items keyring #playername +Delete all items in the selected player\'s keyring. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +('reset items currency', @GM_SECURITY_LEVEL, 'Syntax : .reset items currency #playername +Delete all items in the selected player\'s currencies list. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +('reset items vendor_buyback', @GM_SECURITY_LEVEL, 'Syntax : .reset items vendor_buyback #playername +Delete all items in the selected player\'s vendor buyback tab. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +('reset items all', @GM_SECURITY_LEVEL, 'Syntax : .reset items all #playername +Delete all items in the selected player\'s inventory (equipped, in bags, in bank, in keyring, in currency list and in vendor buy back tab). +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'), + +('reset items allbags', @GM_SECURITY_LEVEL, 'Syntax : .reset items allbags #playername +Delete all items in the selected player\'s inventory (equipped, in bags, in bank, in keyring, in currency list and in vendor buy back tab) +This command also deletes the bags. +#playername : Optional target player name (if player is online only). If not provided the command will execute on the selected target player.'); + +/*--------------------------------------------------------------------------------- + LANG_* strings used by the core at command use. + All of them are stored in table `acore_string` + Note : We should think to add a `enum_tag` column to the `acore_string` table + in order to automatize the rebuild of Language.h file +------------------------------------------------------------------------------------*/ + +-- Always delete before insert to ensure script repeatability : +DELETE FROM `acore_string` WHERE `entry` IN (365, 366, 367, 368, 369, 370, 371, 372); + +-- Insert values : +-- Attention : Need to translate in other languages. Since I'm French I will set only english and french ones :-) +INSERT INTO `acore_string` (`entry`, `content_default`, `locale_frFR`) +VALUES (365, '|cffffffff%d|r equipped items deleted for %s', '|cffffffff%d|r objets équipés supprimés pour %s'), + (366, '|cffffffff%d|r items in equipped bags deleted for %s', '|cffffffff%d|r objets supprimés dans les sacs de %s'), + (367, '|cffffffff%d|r items in bank deleted for %s', '|cffffffff%d|r objets supprimés de la banque de %s'), + (368, '|cffffffff%d|r keys in keyring deleted for %s', '|cffffffff%d|r objets supprimés du porte-clés de %s'), + (369, '|cffffffff%d|r currencies deleted for %s', '|cffffffff%d|r types de monnaies supprimées l\'inventaire de %s'), + (370, '|cffffffff%d|r items in vendors buyback deleted for %s', '|cffffffff%d|r objets supprimés dans l\'onglet rachat des vendeurs pour %s'), + (371, 'All items were deleted for %s : +|cffffffff%d|r items equipped +|cffffffff%d|r items in bags +|cffffffff%d|r items in bank +|cffffffff%d|r keys in keyring +|cffffffff%d|r currency types +|cffffffff%d|r items in vendor buyback', +'Tous les objets de %s ont été supprimés : +|cffffffff%d|r objet équipés +|cffffffff%d|r objets dans les sacs +|cffffffff%d|r objets en banque +|cffffffff%d|r clés dans le porte-clés +|cffffffff%d|r types de monnaies +|cffffffff%d|r objets dans l\'onglet rachat des vendeurs'), + (372, 'All items were deleted for %s (bags included): +|cffffffff%d|r equipped +|cffffffff%d|r items in bags +|cffffffff%d|r items in bank +|cffffffff%d|r keys in keyring +|cffffffff%d|r currency types +|cffffffff%d|r items in vendor buyback +|cffffffff%d|r standard bags +|cffffffff%d|r bank bags', +'Tous les objets de %s ont été supprimés (sacs y-compris): +|cffffffff%d|r objet équipés +|cffffffff%d|r objets dans les sacs +|cffffffff%d|r objets en banque +|cffffffff%d|r clés dans le porte-clés +|cffffffff%d|r types de monnaies +|cffffffff%d|r objets dans l\'onglet rachat des vendeurs +|cffffffff%d|r sacs standard +|cffffffff%d|r sacs de banque' +); + +-- [END] // DB Update for .reset items command; + + diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 0358d14f6..a25f8698a 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -721,7 +721,7 @@ enum BankBagSlots // 7 slots enum BuyBackSlots // 12 slots { - // stored in m_buybackitems + // stored in m_items, there is no more m_buybackitems BUYBACK_SLOT_START = 74, BUYBACK_SLOT_END = 86 }; diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index bf1911b72..88dfbeb11 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -403,7 +403,19 @@ enum AcoreStrings LANG_COMMAND_CHEAT_WW = 362, LANG_COMMAND_WHISPEROFFPLAYER = 363, LANG_COMMAND_CHEAT_TAXINODES = 364, - // Room for more level 2 365-399 not used + + // [START] .reset items command strings: + LANG_COMMAND_RESET_ITEMS_EQUIPPED = 365, + LANG_COMMAND_RESET_ITEMS_BAGS = 366, + LANG_COMMAND_RESET_ITEMS_BANK = 367, + LANG_COMMAND_RESET_ITEMS_KEYRING = 368, + LANG_COMMAND_RESET_ITEMS_CURRENCY = 369, + LANG_COMMAND_RESET_ITEMS_BUYBACK = 370, + LANG_COMMAND_RESET_ITEMS_ALL = 371, + LANG_COMMAND_RESET_ITEMS_ALL_BAGS = 372, + // [END] reset items command strings + + // Room for more level 2 373-399 not used // level 3 chat LANG_SCRIPTS_RELOADED = 400, diff --git a/src/server/scripts/Commands/cs_reset.cpp b/src/server/scripts/Commands/cs_reset.cpp index 81c4e742a..5ea17dca8 100644 --- a/src/server/scripts/Commands/cs_reset.cpp +++ b/src/server/scripts/Commands/cs_reset.cpp @@ -36,10 +36,22 @@ using namespace Acore::ChatCommands; class reset_commandscript : public CommandScript { public: + reset_commandscript() : CommandScript("reset_commandscript") { } ChatCommandTable GetCommands() const override { + static ChatCommandTable resetItemsCommandTable = + { + { "equipped", HandleResetItemsEquippedCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "bags", HandleResetItemsInBagsCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "bank", HandleResetItemsInBankCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "keyring", HandleResetItemsKeyringCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "currency", HandleResetItemsInCurrenciesListCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "vendor_buyback", HandleResetItemsInVendorBuyBackTabCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "all", HandleResetItemsAllCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "allbags", HandleResetItemsAllAndDeleteBagsCommand, SEC_ADMINISTRATOR, Console::Yes }, + }; static ChatCommandTable resetCommandTable = { { "achievements", HandleResetAchievementsCommand, SEC_CONSOLE, Console::Yes }, @@ -48,6 +60,7 @@ public: { "spells", HandleResetSpellsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "stats", HandleResetStatsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "talents", HandleResetTalentsCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "items", resetItemsCommandTable }, { "all", HandleResetAllCommand, SEC_CONSOLE, Console::Yes } }; static ChatCommandTable commandTable = @@ -296,6 +309,418 @@ public: return true; } + + static bool HandleResetItemsEquippedCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + int16 deletedItemsCount = ResetItemsEquipped(targetPlayer); + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_EQUIPPED, deletedItemsCount, handler->GetNameLink(targetPlayer).c_str()); + } + + return true; + } + + static bool HandleResetItemsInBagsCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + int16 deletedItemsCount = ResetItemsInBags(targetPlayer); + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_BAGS, deletedItemsCount, handler->GetNameLink(targetPlayer).c_str()); + } + + return true; + } + + static bool HandleResetItemsKeyringCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + int16 deletedItemsCount = ResetItemsInKeyring(targetPlayer); + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_KEYRING, deletedItemsCount, handler->GetNameLink(targetPlayer).c_str()); + } + + return true; + } + + static bool HandleResetItemsInCurrenciesListCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + int16 deletedItemsCount = ResetItemsInCurrenciesList(targetPlayer); + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_CURRENCY, deletedItemsCount, handler->GetNameLink(targetPlayer).c_str()); + } + + return true; + } + + static bool HandleResetItemsInBankCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + int16 deletedItemsCount = ResetItemsInBank(targetPlayer); + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_BANK, deletedItemsCount, handler->GetNameLink(targetPlayer).c_str()); + } + + return true; + } + + static bool HandleResetItemsInVendorBuyBackTabCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + int16 deletedItemsCount = ResetItemsInVendorBuyBackTab(targetPlayer); + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_BUYBACK, deletedItemsCount, handler->GetNameLink(targetPlayer).c_str()); + } + + return true; + } + + static bool HandleResetItemsAllCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + + // Delete all items destinations + int16 deletedItemsEquippedCount = ResetItemsEquipped(targetPlayer); + int16 deletedItemsInBagsCount = ResetItemsInBags(targetPlayer); + int16 deletedItemsInBankCount = ResetItemsInBank(targetPlayer); + int16 deletedItemsInKeyringCount = ResetItemsInKeyring(targetPlayer); + int16 deletedItemsInCurrenciesListCount = ResetItemsInCurrenciesList(targetPlayer); + int16 deletedItemsInVendorBuyBackTabCount = ResetItemsInVendorBuyBackTab(targetPlayer); + + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_ALL, handler->GetNameLink(targetPlayer).c_str(), + deletedItemsEquippedCount, + deletedItemsInBagsCount, + deletedItemsInBankCount, + deletedItemsInKeyringCount, + deletedItemsInCurrenciesListCount, + deletedItemsInVendorBuyBackTabCount); + } + + return true; + } + + static bool HandleResetItemsAllAndDeleteBagsCommand(ChatHandler* handler, Optional target) + { + Player* targetPlayer = GetPlayerFromIdentifierOrSelectedTarget(handler, target); + + if (!targetPlayer) + { + return false; + } + else + { + + // Delete all items destinations + int16 deletedItemsEquippedCount = ResetItemsEquipped(targetPlayer); + int16 deletedItemsInBagsCount = ResetItemsInBags(targetPlayer); + int16 deletedItemsInBankCount = ResetItemsInBank(targetPlayer); + int16 deletedItemsInKeyringCount = ResetItemsInKeyring(targetPlayer); + int16 deletedItemsInCurrenciesListCount = ResetItemsInCurrenciesList(targetPlayer); + int16 deletedItemsInVendorBuyBackTabCount = ResetItemsInVendorBuyBackTab(targetPlayer); + int16 deletedItemsStandardBagsCount = ResetItemsDeleteStandardBags(targetPlayer); + int16 deletedItemsBankBagsCount = ResetItemsDeleteBankBags(targetPlayer); + + handler->PSendSysMessage(LANG_COMMAND_RESET_ITEMS_ALL_BAGS, handler->GetNameLink(targetPlayer).c_str(), + deletedItemsEquippedCount, + deletedItemsInBagsCount, + deletedItemsInBankCount, + deletedItemsInKeyringCount, + deletedItemsInCurrenciesListCount, + deletedItemsInVendorBuyBackTabCount, + deletedItemsStandardBagsCount, + deletedItemsBankBagsCount); + } + + return true; + } + +private: + static Player* GetPlayerFromIdentifierOrSelectedTarget(ChatHandler* handler, Optional target) + { + Player* targetPlayer = nullptr; + + // Check if there is an optional target player name + // Do not use TargetOrSelf, we must be sure to select ourself + if (!target) + { + // No optional target, so try to get selected target + target = PlayerIdentifier::FromTarget(handler); + + if (!target) + { + // No character selected + handler->SendSysMessage(LANG_NO_CHAR_SELECTED); + return targetPlayer; + } + + targetPlayer = target->GetConnectedPlayer(); + } + else + { + targetPlayer = target->GetConnectedPlayer(); + + if (!targetPlayer || !target->IsConnected()) + { + // No character selected + handler->SendSysMessage(LANG_PLAYER_NOT_EXIST_OR_OFFLINE); + } + } + + return targetPlayer; + } + + static int16 ResetItemsEquipped(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) + { + Item* pItem = playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pItem) + { + playerTarget->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++count; + } + } + + return count; + } + + static int16 ResetItemsInBags(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + // Default bagpack : + for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + Item* pItem = playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pItem) + { + playerTarget->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++count; + } + } + + // Bag slots + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + Bag* pBag = (Bag*)playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pBag) + { + for (uint8 j = 0; j < pBag->GetBagSize(); ++j) + { + Item* pItem = pBag->GetItemByPos(j); + if (pItem) + { + playerTarget->DestroyItem(i, j, true); + ++count; + } + } + } + } + + return count; + } + + static int16 ResetItemsInBank(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + // Normal bank slot + for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i) + { + Item* pItem = playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pItem) + { + playerTarget->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++count; + } + } + + // Bank bagslots + for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) + { + Bag* pBag = (Bag*)playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pBag) + { + for (uint8 j = 0; j < pBag->GetBagSize(); ++j) + { + Item* pItem = pBag->GetItemByPos(j); + if (pItem) + { + playerTarget->DestroyItem(i, j, true); + ++count; + } + } + } + } + + return count; + } + + static int16 ResetItemsInKeyring(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + for (uint8 i = KEYRING_SLOT_START; i < KEYRING_SLOT_END; ++i) + { + Item* pItem = playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pItem) + { + playerTarget->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++count; + } + } + + return count; + } + + static int16 ResetItemsInCurrenciesList(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + for (uint8 i = CURRENCYTOKEN_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i) + { + Item* pItem = playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pItem) + { + playerTarget->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++count; + } + } + + return count; + } + + static int16 ResetItemsInVendorBuyBackTab(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; ++i) + { + Item* pItem = playerTarget->GetItemFromBuyBackSlot(i); + if (pItem) + { + playerTarget->RemoveItemFromBuyBackSlot(i, true); + ++count; + } + } + + return count; + } + + static int16 ResetItemsDeleteStandardBags(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + // Standard bag slots + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + Bag* pBag = (Bag*)playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pBag) + { + playerTarget->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++count; + } + } + + return count; + } + + static int16 ResetItemsDeleteBankBags(Player* playerTarget) + { + if (!playerTarget) + { + return -1; + } + + int16 count = 0; + // Bank bags + for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) + { + Bag* pBag = (Bag*)playerTarget->GetItemByPos(INVENTORY_SLOT_BAG_0, i); + if (pBag) + { + // prevent no empty ? + playerTarget->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++count; + } + } + + return count; + } }; void AddSC_reset_commandscript()