diff options
-rw-r--r-- | .vscode/settings.json | 3 | ||||
-rw-r--r-- | src/server/game/Chat/Chat.cpp | 12 | ||||
-rw-r--r-- | src/server/game/Chat/Chat.h | 12 | ||||
-rw-r--r-- | src/server/game/Chat/Hyperlinks.h | 6 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptDefines/CommandSC.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.h | 4 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_bag.cpp | 161 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_gear.cpp | 128 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_group.cpp | 268 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_inventory.cpp | 187 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_item.cpp | 4 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_misc.cpp | 2578 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_pet.cpp | 210 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_script_loader.cpp | 16 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_send.cpp | 220 |
15 files changed, 2142 insertions, 1671 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index e48b4f25d1..19347a5284 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -66,7 +66,8 @@ "cfenv": "cpp", "typeinfo": "cpp", "codecvt": "cpp", - "xstring": "cpp" + "xstring": "cpp", + "variant": "cpp" }, "deno.enable": true, "deno.path": "deps/deno/bin/deno", diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 5edb60e57c..96f0343bda 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -298,7 +298,7 @@ size_t ChatHandler::BuildChatPacket(WorldPacket& data, ChatMsg chatType, Languag return BuildChatPacket(data, chatType, language, senderGUID, receiverGUID, message, chatTag, senderName, receiverName, achievementId, gmMessage, channelName); } -Player* ChatHandler::getSelectedPlayer() +Player* ChatHandler::getSelectedPlayer() const { if (!m_session) return nullptr; @@ -310,7 +310,7 @@ Player* ChatHandler::getSelectedPlayer() return ObjectAccessor::FindConnectedPlayer(selected); } -Unit* ChatHandler::getSelectedUnit() +Unit* ChatHandler::getSelectedUnit() const { if (!m_session) return nullptr; @@ -321,7 +321,7 @@ Unit* ChatHandler::getSelectedUnit() return m_session->GetPlayer(); } -WorldObject* ChatHandler::getSelectedObject() +WorldObject* ChatHandler::getSelectedObject() const { if (!m_session) return nullptr; @@ -334,7 +334,7 @@ WorldObject* ChatHandler::getSelectedObject() return ObjectAccessor::GetUnit(*m_session->GetPlayer(), guid); } -Creature* ChatHandler::getSelectedCreature() +Creature* ChatHandler::getSelectedCreature() const { if (!m_session) return nullptr; @@ -342,7 +342,7 @@ Creature* ChatHandler::getSelectedCreature() return ObjectAccessor::GetCreatureOrPetOrVehicle(*m_session->GetPlayer(), m_session->GetPlayer()->GetTarget()); } -Player* ChatHandler::getSelectedPlayerOrSelf() +Player* ChatHandler::getSelectedPlayerOrSelf() const { if (!m_session) return nullptr; @@ -472,7 +472,7 @@ char* ChatHandler::extractKeyFromLink(char* text, char const* const* linkTypes, return nullptr; } -GameObject* ChatHandler::GetNearbyGameObject() +GameObject* ChatHandler::GetNearbyGameObject() const { if (!m_session) return nullptr; diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index d8c73611fd..8972125dd5 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -90,12 +90,12 @@ public: bool HasLowerSecurityAccount(WorldSession* target, uint32 account, bool strong = false); void SendGlobalGMSysMessage(const char* str); - Player* getSelectedPlayer(); - Creature* getSelectedCreature(); - Unit* getSelectedUnit(); - WorldObject* getSelectedObject(); + Player* getSelectedPlayer() const; + Creature* getSelectedCreature() const; + Unit* getSelectedUnit() const; + WorldObject* getSelectedObject() const; // Returns either the selected player or self if there is no selected player - Player* getSelectedPlayerOrSelf(); + Player* getSelectedPlayerOrSelf() const; char* extractKeyFromLink(char* text, char const* linkType, char** something1 = nullptr); char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = nullptr); @@ -111,7 +111,7 @@ public: std::string playerLink(std::string const& name) const { return m_session ? "|cffffffff|Hplayer:" + name + "|h[" + name + "]|h|r" : name; } std::string GetNameLink(Player* chr) const; - GameObject* GetNearbyGameObject(); + GameObject* GetNearbyGameObject() const; GameObject* GetObjectFromPlayerMapByDbGuid(ObjectGuid::LowType lowguid); Creature* GetCreatureFromPlayerMapByDbGuid(ObjectGuid::LowType lowguid); bool HasSentErrorMessage() const { return sentErrorMessage; } diff --git a/src/server/game/Chat/Hyperlinks.h b/src/server/game/Chat/Hyperlinks.h index 07c8f901ca..245a70bb7e 100644 --- a/src/server/game/Chat/Hyperlinks.h +++ b/src/server/game/Chat/Hyperlinks.h @@ -38,7 +38,6 @@ struct TalentEntry; namespace Acore::Hyperlinks { - struct AchievementLinkData { AchievementEntry const* Achievement; @@ -90,7 +89,8 @@ namespace Acore::Hyperlinks std::string KnownRecipes; }; - namespace LinkTags { + namespace LinkTags + { /************************** LINK TAGS ***************************************************\ |* Link tags must abide by the following: *| @@ -247,9 +247,9 @@ namespace Acore::Hyperlinks std::string_view const data; std::string_view const text; }; + HyperlinkInfo AC_GAME_API ParseSingleHyperlink(std::string_view str); bool AC_GAME_API CheckAllLinks(std::string_view str); - } #endif diff --git a/src/server/game/Scripting/ScriptDefines/CommandSC.cpp b/src/server/game/Scripting/ScriptDefines/CommandSC.cpp index a92ff22977..22cb02592c 100644 --- a/src/server/game/Scripting/ScriptDefines/CommandSC.cpp +++ b/src/server/game/Scripting/ScriptDefines/CommandSC.cpp @@ -18,11 +18,11 @@ #include "ScriptMgr.h" #include "ScriptMgrMacros.h" -void ScriptMgr::OnHandleDevCommand(Player* player, std::string& argstr) +void ScriptMgr::OnHandleDevCommand(Player* player, bool& enable) { ExecuteScript<CommandSC>([&](CommandSC* script) { - script->OnHandleDevCommand(player, argstr); + script->OnHandleDevCommand(player, enable); }); } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index bb68ca822e..6aa23bee74 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -1842,7 +1842,7 @@ public: bool IsDatabaseBound() const { return false; } - virtual void OnHandleDevCommand(Player* /*player*/, std::string& /*argstr*/) { } + virtual void OnHandleDevCommand(Player* /*player*/, bool& /*enable*/) { } /** * @brief This hook runs execute chat command @@ -2464,7 +2464,7 @@ public: /* MiscScript */ public: /* CommandSC */ - void OnHandleDevCommand(Player* player, std::string& argstr); + void OnHandleDevCommand(Player* player, bool& enable); bool CanExecuteCommand(ChatHandler& handler, std::string_view cmdStr); public: /* DatabaseScript */ diff --git a/src/server/scripts/Commands/cs_bag.cpp b/src/server/scripts/Commands/cs_bag.cpp new file mode 100644 index 0000000000..20c0cb1a2c --- /dev/null +++ b/src/server/scripts/Commands/cs_bag.cpp @@ -0,0 +1,161 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Chat.h" +#include "Language.h" +#include "ObjectMgr.h" +#include "Player.h" +#include "ScriptMgr.h" + +constexpr std::array<std::string_view, MAX_ITEM_QUALITY> itemQualityToString = +{ + "poor", + "normal", + "uncommon", + "rare", + "epic", + "legendary", + "artifact", + "all" +}; + +using namespace Acore::ChatCommands; + +class bg_commandscript : public CommandScript +{ +public: + bg_commandscript() : CommandScript("bg_commandscript") { } + + ChatCommandTable GetCommands() const override + { + static ChatCommandTable commandTable = + { + { "bags clear", HandleBagsClearCommand, SEC_GAMEMASTER, Console::No }, + }; + + return commandTable; + } + + static bool HandleBagsClearCommand(ChatHandler* handler, std::string_view args) + { + if (args.empty()) + { + return false; + } + + Player* player = handler->GetSession()->GetPlayer(); + if (!player) + { + return false; + } + + uint8 itemQuality = MAX_ITEM_QUALITY; + for (uint8 i = ITEM_QUALITY_POOR; i < MAX_ITEM_QUALITY; ++i) + { + if (args == itemQualityToString[i]) + { + itemQuality = i; + break; + } + } + + if (itemQuality == MAX_ITEM_QUALITY) + { + return false; + } + + std::array<uint32, MAX_ITEM_QUALITY> removedItems = { }; + + // in inventory + for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + if (ItemTemplate const* itemTemplate = item->GetTemplate()) + { + if (itemTemplate->Quality <= itemQuality) + { + player->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); + ++removedItems[itemTemplate->Quality]; + } + } + } + } + + // in inventory bags + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + if (Bag* bag = player->GetBagByPos(i)) + { + for (uint32 j = 0; j < bag->GetBagSize(); j++) + { + if (Item* item = bag->GetItemByPos(j)) + { + if (ItemTemplate const* itemTemplate = item->GetTemplate()) + { + if (itemTemplate->Quality <= itemQuality) + { + player->DestroyItem(i, j, true); + ++removedItems[itemTemplate->Quality]; + } + } + } + } + } + } + + std::ostringstream str; + str << "Removed "; + if (itemQuality == ITEM_QUALITY_HEIRLOOM) + { + str << "all"; + } + else + { + bool initialize = true; + for (uint8 i = ITEM_QUALITY_POOR; i < MAX_ITEM_QUALITY; ++i) + { + if (uint32 itemCount = removedItems[i]) + { + std::string_view itemQualityString = itemQualityToString[i]; + + if (!initialize) + { + str << ", "; + } + + str << "|c"; + str << std::hex << ItemQualityColors[i] << std::dec; + str << itemCount << " " << itemQualityString << "|r"; + + initialize = false; + } + } + } + + str << " items from your bags."; + + handler->SendSysMessage(str.str().c_str()); + + return true; + }; +}; + +void AddSC_bag_commandscript() +{ + new bg_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_gear.cpp b/src/server/scripts/Commands/cs_gear.cpp new file mode 100644 index 0000000000..d3783e9ff4 --- /dev/null +++ b/src/server/scripts/Commands/cs_gear.cpp @@ -0,0 +1,128 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "Language.h" +#include "Log.h" +#include "Player.h" +#include "WorldSession.h" + +using namespace Acore::ChatCommands; + +class gear_commandscript : public CommandScript +{ +public: + gear_commandscript() : CommandScript("gear_commandscript") { } + + ChatCommandTable GetCommands() const override + { + static ChatCommandTable gearCommandTable = + { + { "repair", HandleGearRepairCommand, SEC_GAMEMASTER, Console::No }, + { "stats", HandleGearStatsCommand, SEC_PLAYER, Console::No } + }; + + static ChatCommandTable commandTable = + { + { "gear", gearCommandTable } + }; + + return commandTable; + } + + static bool HandleGearRepairCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target || !target->IsConnected()) + { + return false; + } + + // check online security + if (handler->HasLowerSecurity(target->GetConnectedPlayer())) + { + return false; + } + + // Repair items + target->GetConnectedPlayer()->DurabilityRepairAll(false, 0, false); + + std::string nameLink = handler->playerLink(target->GetName()); + + handler->PSendSysMessage(LANG_YOU_REPAIR_ITEMS, nameLink.c_str()); + + if (handler->needReportToTarget(target->GetConnectedPlayer())) + { + ChatHandler(target->GetConnectedPlayer()->GetSession()).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, nameLink.c_str()); + } + + return true; + } + + static bool HandleGearStatsCommand(ChatHandler* handler) + { + Player* player = handler->getSelectedPlayerOrSelf(); + + if (!player) + { + return false; + } + + handler->PSendSysMessage("Character: %s", player->GetPlayerName().c_str()); + handler->PSendSysMessage("Current equipment average item level: |cff00ffff%u|r", (int16)player->GetAverageItemLevel()); + + if (sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE)) + { + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_STATS); + stmt->setUInt32(0, player->GetGUID().GetCounter()); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + + if (result) + { + Field* fields = result->Fetch(); + uint32 MaxHealth = fields[0].GetUInt32(); + uint32 Strength = fields[1].GetUInt32(); + uint32 Agility = fields[2].GetUInt32(); + uint32 Stamina = fields[3].GetUInt32(); + uint32 Intellect = fields[4].GetUInt32(); + uint32 Spirit = fields[5].GetUInt32(); + uint32 Armor = fields[6].GetUInt32(); + uint32 AttackPower = fields[7].GetUInt32(); + uint32 SpellPower = fields[8].GetUInt32(); + uint32 Resilience = fields[9].GetUInt32(); + + handler->PSendSysMessage("Health: |cff00ffff%u|r - Stamina: |cff00ffff%u|r", MaxHealth, Stamina); + handler->PSendSysMessage("Strength: |cff00ffff%u|r - Agility: |cff00ffff%u|r", Strength, Agility); + handler->PSendSysMessage("Intellect: |cff00ffff%u|r - Spirit: |cff00ffff%u|r", Intellect, Spirit); + handler->PSendSysMessage("AttackPower: |cff00ffff%u|r - SpellPower: |cff00ffff%u|r", AttackPower, SpellPower); + handler->PSendSysMessage("Armor: |cff00ffff%u|r - Resilience: |cff00ffff%u|r", Armor, Resilience); + } + } + + return true; + } +}; + +void AddSC_gear_commandscript() +{ + new gear_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp new file mode 100644 index 0000000000..85d699b2b7 --- /dev/null +++ b/src/server/scripts/Commands/cs_group.cpp @@ -0,0 +1,268 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "DatabaseEnv.h" +#include "GroupMgr.h" +#include "Language.h" +#include "LFG.h" +#include "ObjectAccessor.h" +#include "Player.h" + +using namespace Acore::ChatCommands; + +class group_commandscript : public CommandScript +{ +public: + group_commandscript() : CommandScript("group_commandscript") { } + + ChatCommandTable GetCommands() const override + { + static ChatCommandTable groupCommandTable = + { + { "list", HandleGroupListCommand, SEC_GAMEMASTER, Console::No }, + { "join", HandleGroupJoinCommand, SEC_GAMEMASTER, Console::No }, + { "remove", HandleGroupRemoveCommand, SEC_GAMEMASTER, Console::No }, + { "disband", HandleGroupDisbandCommand, SEC_GAMEMASTER, Console::No }, + { "leader", HandleGroupLeaderCommand, SEC_GAMEMASTER, Console::No } + }; + + static ChatCommandTable commandTable = + { + { "group", groupCommandTable } + }; + + return commandTable; + } + + static bool HandleGroupLeaderCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { + return false; + } + + Player* player = nullptr; + Group* group = nullptr; + ObjectGuid guid; + + if (handler->GetPlayerGroupAndGUIDByName(target->GetName().c_str(), player, group, guid)) + { + if (group && group->GetLeaderGUID() != guid) + { + group->ChangeLeader(guid); + group->SendUpdate(); + } + } + + return true; + } + + static bool HandleGroupDisbandCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target || !target->IsConnected()) + { + return false; + } + + Player* player = nullptr; + Group* group = nullptr; + ObjectGuid guid; + + if (handler->GetPlayerGroupAndGUIDByName(target->GetName().c_str(), player, group, guid)) + { + if (group) + { + group->Disband(); + } + } + + return true; + } + + static bool HandleGroupRemoveCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target || !target->IsConnected()) + { + return false; + } + + Player* player = nullptr; + Group* group = nullptr; + ObjectGuid guid; + + if (handler->GetPlayerGroupAndGUIDByName(target->GetName().c_str(), player, group, guid, true)) + { + if (group) + { + group->RemoveMember(guid); + } + } + + return true; + } + + static bool HandleGroupJoinCommand(ChatHandler* handler, std::string const& playerInGroup, std::string const& playerName) + { + if (playerInGroup.empty() || playerName.empty()) + { + return false; + } + + Player* playerSource = nullptr; + Group* groupSource = nullptr; + ObjectGuid guidSource; + ObjectGuid guidTarget; + + if (handler->GetPlayerGroupAndGUIDByName(playerInGroup.c_str(), playerSource, groupSource, guidSource, true)) + { + if (groupSource) + { + Group* groupTarget = nullptr; + Player* playerTarget = nullptr; + + if (handler->GetPlayerGroupAndGUIDByName(playerName.c_str(), playerTarget, groupTarget, guidTarget, true)) + { + if (!groupTarget && playerTarget->GetGroup() != groupSource) + { + if (!groupSource->IsFull()) + { + groupSource->AddMember(playerTarget); + groupSource->BroadcastGroupUpdate(); + handler->PSendSysMessage(LANG_GROUP_PLAYER_JOINED, playerTarget->GetName().c_str(), playerSource->GetName().c_str()); + return true; + } + else + { + // group is full + handler->PSendSysMessage(LANG_GROUP_FULL); + return true; + } + } + else + { + // group is full or target player already in a group + handler->PSendSysMessage(LANG_GROUP_ALREADY_IN_GROUP, playerTarget->GetName().c_str()); + return true; + } + } + } + else + { + // specified source player is not in a group + handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, playerSource->GetName().c_str()); + return true; + } + } + + return true; + } + + static bool HandleGroupListCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { + return false; + } + + Group* groupTarget = nullptr; + + if (target->IsConnected()) + { + groupTarget = target->GetConnectedPlayer()->GetGroup(); + } + + if (!groupTarget) + { + if (ObjectGuid groupGUID = sCharacterCache->GetCharacterGroupGuidByGuid(target->GetGUID())) + { + groupTarget = sGroupMgr->GetGroupByGUID(groupGUID.GetCounter()); + } + } + + if (!groupTarget) + { + handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, target->GetName().c_str()); + return true; + } + + handler->PSendSysMessage(LANG_GROUP_TYPE, (groupTarget->isRaidGroup() ? "raid" : "party")); + + for (auto const& slot : groupTarget->GetMemberSlots()) + { + std::string flags; + + if (slot.flags & MEMBER_FLAG_ASSISTANT) + { + flags = "Assistant"; + } + + if (slot.flags & MEMBER_FLAG_MAINTANK) + { + if (!flags.empty()) + { + flags.append(", "); + } + + flags.append("MainTank"); + } + + if (slot.flags & MEMBER_FLAG_MAINASSIST) + { + if (!flags.empty()) + { + flags.append(", "); + } + + flags.append("MainAssist"); + } + + if (flags.empty()) + { + flags = "None"; + } + } + + return true; + } +}; + +void AddSC_group_commandscript() +{ + new group_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_inventory.cpp b/src/server/scripts/Commands/cs_inventory.cpp new file mode 100644 index 0000000000..b5040f5ca9 --- /dev/null +++ b/src/server/scripts/Commands/cs_inventory.cpp @@ -0,0 +1,187 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "Language.h" +#include "Player.h" +#include "WorldSession.h" + +constexpr std::array<const char*, MAX_ITEM_SUBCLASS_CONTAINER> bagSpecsToString = +{ + "normal", + "soul", + "herb", + "enchanting", + "engineering", + "gem", + "mining", + "leatherworking", + "inscription" +}; + +constexpr std::array<uint32, MAX_ITEM_SUBCLASS_CONTAINER> bagSpecsColors = +{ + 0xfff0de18, // YELLOW - Normal + 0xffa335ee, // PURPLE - Souls + 0xff1eff00, // GREEN - Herb + 0xffe37166, // PINK - Enchanting + 0xffa68b30, // BROWN - Engineering + 0xff0070dd, // BLUE - Gem + 0xffc1c8c9, // GREY - Mining + 0xfff5a925, // ORANGE - Leatherworking + 0xff54504f // DARK GREY - Inscription +}; + +//constexpr std::array<const char*, MAX_ITEM_SUBCLASS_CONTAINER> bagSpecsColorToString = +//{ +// "normal", +// "soul", +// "herb", +// "enchanting", +// "engineering", +// "gem", +// "mining", +// "leatherworking", +// "inscription" +//}; + +using namespace Acore::ChatCommands; + +class inventory_commandscript : public CommandScript +{ +public: + inventory_commandscript() : CommandScript("inventory_commandscript") { } + + ChatCommandTable GetCommands() const override + { + static ChatCommandTable inventoryCommandTable = + { + { "count", HandleInventoryCountCommand, SEC_MODERATOR, Console::No } + }; + + static ChatCommandTable commandTable = + { + { "inventory", inventoryCommandTable } + }; + + return commandTable; + } + + static bool HandleInventoryCountCommand(ChatHandler* handler, Optional<PlayerIdentifier> player) + { + if (!player) + { + player = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!player) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + handler->SetSentErrorMessage(true); + return false; + } + + Player* target = player->GetConnectedPlayer(); + if (!target) + { + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); + handler->SetSentErrorMessage(true); + return false; + } + + std::array<uint32, MAX_ITEM_SUBCLASS_CONTAINER> freeSlotsInBags = { }; + uint32 freeSlotsForBags = 0; + bool haveFreeSlot = false; + + // Check backpack + for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot) + { + if (!target->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) + { + haveFreeSlot = true; + ++freeSlotsInBags[ITEM_SUBCLASS_CONTAINER]; + } + } + + // Check bags + for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) + { + if (Bag* bag = target->GetBagByPos(i)) + { + if (ItemTemplate const* bagTemplate = bag->GetTemplate()) + { + if (bagTemplate->Class == ITEM_CLASS_CONTAINER || bagTemplate->Class == ITEM_CLASS_QUIVER) + { + haveFreeSlot = true; + freeSlotsInBags[bagTemplate->SubClass] += bag->GetFreeSlots(); + } + } + } + else + { + ++freeSlotsForBags; + } + } + + std::ostringstream str; + + if (haveFreeSlot) + { + str << "Player " << target->GetName() << " have "; + bool initialize = true; + + for (uint8 i = ITEM_SUBCLASS_CONTAINER; i < MAX_ITEM_SUBCLASS_CONTAINER; ++i) + { + if (uint32 freeSlots = freeSlotsInBags[i]) + { + std::string bagSpecString = bagSpecsToString[i]; + if (!initialize) + { + str << ", "; + } + + str << "|c"; + str << std::hex << bagSpecsColors[i] << std::dec; + str << freeSlots << " in " << bagSpecString << " bags|r"; + + initialize = false; + } + } + } + else + { + str << "Player " << target->GetName() << " does not have free slots in their bags"; + } + + if (freeSlotsForBags) + { + str << " and also has " << freeSlotsForBags << " free slots for bags"; + } + + str << "."; + + handler->SendSysMessage(str.str().c_str()); + + return true; + } +}; + +void AddSC_inventory_commandscript() +{ + new inventory_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_item.cpp b/src/server/scripts/Commands/cs_item.cpp index c22b2e3f91..a248121bd6 100644 --- a/src/server/scripts/Commands/cs_item.cpp +++ b/src/server/scripts/Commands/cs_item.cpp @@ -140,7 +140,8 @@ public: return false; } - do { + do + { Field* fields = disposedItems->Fetch(); uint32 id = fields[0].GetUInt32(); uint32 itemId = fields[1].GetUInt32(); @@ -161,7 +162,6 @@ public: // TODO - move item to other slot static bool HandleItemMoveCommand(ChatHandler* handler, uint8 srcSlot, uint8 dstSlot) { - if (srcSlot == dstSlot) return true; diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 1a994b169c..13c5e230cb 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -24,7 +24,6 @@ #include "GameGraveyard.h" #include "GridNotifiers.h" #include "Group.h" -#include "GroupMgr.h" #include "GuildMgr.h" #include "IPLocation.h" #include "InstanceSaveMgr.h" @@ -41,6 +40,7 @@ #include "SpellAuras.h" #include "TargetedMovementGenerator.h" #include "WeatherMgr.h" +#include "Tokenize.h" // TODO: this import is not necessary for compilation and marked as unused by the IDE // however, for some reasons removing it would cause a damn linking issue @@ -48,62 +48,34 @@ // see: https://github.com/azerothcore/azerothcore-wotlk/issues/9766 #include "GridNotifiersImpl.h" -#if AC_COMPILER == AC_COMPILER_GNU -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#endif +constexpr auto SPELL_STUCK = 7355; +constexpr auto SPELL_FREEZE = 9454; -using namespace Acore::ChatCommands; - -static std::array<std::string, MAX_ITEM_QUALITY> itemQualityToString = -{ { - "poor", - "normal", - "uncommon", - "rare", - "epic", - "legendary", - "artifact", - "all" -} }; - -static std::array<std::string, MAX_ITEM_SUBCLASS_CONTAINER> bagSpecsToString = -{ { - "normal", - "soul", - "herb", - "enchanting", - "engineering", - "gem", - "mining", - "leatherworking", - "inscription" -} }; - -constexpr uint32 bagSpecsColors[MAX_ITEM_SUBCLASS_CONTAINER] = +std::string const GetLocalizeCreatureName(Creature* creature, LocaleConstant locale) { - 0xfff0de18, //YELLOW - Normal - 0xffa335ee, //PURPLE - Souls - 0xff1eff00, //GREEN - Herb - 0xffe37166, //PINK - Enchanting - 0xffa68b30, //BROWN - Engineering - 0xff0070dd, //BLUE - Gem - 0xffc1c8c9, //GREY - Mining - 0xfff5a925, //ORANGE - Leatherworking - 0xff54504f //DARK GREY - Inscription -}; + auto creatureTemplate = sObjectMgr->GetCreatureTemplate(creature->GetEntry()); + auto cretureLocale = sObjectMgr->GetCreatureLocale(creature->GetEntry()); + std::string name; + + if (cretureLocale) + { + name = cretureLocale->Name[locale]; + } + + if (name.empty() && creatureTemplate) + { + name = creatureTemplate->Name; + } -static std::array<std::string, MAX_ITEM_SUBCLASS_CONTAINER> bagSpecsColorToString = -{ { - "normal", - "soul", - "herb", - "enchanting", - "engineering", - "gem", - "mining", - "leatherworking", - "inscription" -} }; + if (name.empty()) + { + name = "Unknown creature"; + } + + return name; +} + +using namespace Acore::ChatCommands; class misc_commandscript : public CommandScript { @@ -112,124 +84,84 @@ public: ChatCommandTable GetCommands() const override { - static ChatCommandTable groupCommandTable = - { - { "leader", SEC_GAMEMASTER, false, &HandleGroupLeaderCommand, "" }, - { "disband", SEC_GAMEMASTER, false, &HandleGroupDisbandCommand, "" }, - { "remove", SEC_GAMEMASTER, false, &HandleGroupRemoveCommand, "" }, - { "join", SEC_GAMEMASTER, false, &HandleGroupJoinCommand, "" }, - { "list", SEC_GAMEMASTER, false, &HandleGroupListCommand, "" } - }; - static ChatCommandTable petCommandTable = - { - { "create", SEC_GAMEMASTER, false, &HandleCreatePetCommand, "" }, - { "learn", SEC_GAMEMASTER, false, &HandlePetLearnCommand, "" }, - { "unlearn", SEC_GAMEMASTER, false, &HandlePetUnlearnCommand, "" } - }; - static ChatCommandTable sendCommandTable = - { - { "items", SEC_GAMEMASTER, true, &HandleSendItemsCommand, "" }, - { "mail", SEC_GAMEMASTER, true, &HandleSendMailCommand, "" }, - { "message", SEC_ADMINISTRATOR, true, &HandleSendMessageCommand, "" }, - { "money", SEC_GAMEMASTER, true, &HandleSendMoneyCommand, "" } - }; - static ChatCommandTable gearCommandTable = - { - { "repair", SEC_GAMEMASTER, false, &HandleGearRepairCommand, "" }, - { "stats", SEC_PLAYER, false, &HandleGearStatsCommand, "" } - }; - static ChatCommandTable bagsCommandTable = - { - { "clear", SEC_GAMEMASTER, false, &HandleBagsClearCommand, "" }, - }; - static ChatCommandTable inventoryCommandTable = - { - { "count", HandleInventoryCountCommand, SEC_MODERATOR, Console::No } - }; static ChatCommandTable commandTable = { - { "dev", SEC_ADMINISTRATOR, false, &HandleDevCommand, "" }, - { "gps", SEC_MODERATOR, false, &HandleGPSCommand, "" }, - { "aura", SEC_GAMEMASTER, false, &HandleAuraCommand, "" }, - { "unaura", SEC_GAMEMASTER, false, &HandleUnAuraCommand, "" }, - { "appear", SEC_MODERATOR, false, &HandleAppearCommand, "" }, - { "summon", SEC_GAMEMASTER, false, &HandleSummonCommand, "" }, - { "groupsummon", SEC_GAMEMASTER, false, &HandleGroupSummonCommand, "" }, - { "commands", SEC_PLAYER, true, &HandleCommandsCommand, "" }, - { "die", SEC_GAMEMASTER, false, &HandleDieCommand, "" }, - { "revive", SEC_GAMEMASTER, true, &HandleReviveCommand, "" }, - { "dismount", SEC_PLAYER, false, &HandleDismountCommand, "" }, - { "guid", SEC_GAMEMASTER, false, &HandleGUIDCommand, "" }, - { "help", SEC_PLAYER, true, &HandleHelpCommand, "" }, - { "cooldown", SEC_GAMEMASTER, false, &HandleCooldownCommand, "" }, - { "distance", SEC_ADMINISTRATOR, false, &HandleGetDistanceCommand, "" }, - { "recall", SEC_GAMEMASTER, false, &HandleRecallCommand, "" }, - { "save", SEC_PLAYER, false, &HandleSaveCommand, "" }, - { "saveall", SEC_GAMEMASTER, true, &HandleSaveAllCommand, "" }, - { "kick", SEC_GAMEMASTER, true, &HandleKickPlayerCommand, "" }, - { "unstuck", SEC_GAMEMASTER, true, &HandleUnstuckCommand, "" }, - { "linkgrave", SEC_ADMINISTRATOR, false, &HandleLinkGraveCommand, "" }, - { "neargrave", SEC_GAMEMASTER, false, &HandleNearGraveCommand, "" }, - { "showarea", SEC_GAMEMASTER, false, &HandleShowAreaCommand, "" }, - { "hidearea", SEC_ADMINISTRATOR, false, &HandleHideAreaCommand, "" }, - { "additem", SEC_GAMEMASTER, false, &HandleAddItemCommand, "" }, - { "additemset", SEC_GAMEMASTER, false, &HandleAddItemSetCommand, "" }, - { "wchange", SEC_ADMINISTRATOR, false, &HandleChangeWeather, "" }, - { "maxskill", SEC_GAMEMASTER, false, &HandleMaxSkillCommand, "" }, - { "setskill", SEC_GAMEMASTER, false, &HandleSetSkillCommand, "" }, - { "pinfo", SEC_GAMEMASTER, true, &HandlePInfoCommand, "" }, - { "respawn", SEC_GAMEMASTER, false, &HandleRespawnCommand, "" }, - { "send", SEC_GAMEMASTER, true, nullptr, "", sendCommandTable }, - { "pet", SEC_GAMEMASTER, false, nullptr, "", petCommandTable }, - { "mute", SEC_GAMEMASTER, true, &HandleMuteCommand, "" }, - { "mutehistory", SEC_GAMEMASTER, true, &HandleMuteInfoCommand, "" }, - { "unmute", SEC_GAMEMASTER, true, &HandleUnmuteCommand, "" }, - { "movegens", SEC_ADMINISTRATOR, false, &HandleMovegensCommand, "" }, - { "cometome", SEC_ADMINISTRATOR, false, &HandleComeToMeCommand, "" }, - { "damage", SEC_GAMEMASTER, false, &HandleDamageCommand, "" }, - { "combatstop", SEC_GAMEMASTER, true, &HandleCombatStopCommand, "" }, - { "flusharenapoints", SEC_ADMINISTRATOR, false, &HandleFlushArenaPointsCommand, "" }, - { "freeze", SEC_GAMEMASTER, false, &HandleFreezeCommand, "" }, - { "unfreeze", SEC_GAMEMASTER, false, &HandleUnFreezeCommand, "" }, - { "group", SEC_GAMEMASTER, false, nullptr, "", groupCommandTable }, - { "gear", SEC_PLAYER, false, nullptr, "", gearCommandTable }, - { "possess", SEC_GAMEMASTER, false, HandlePossessCommand, "" }, - { "unpossess", SEC_GAMEMASTER, false, HandleUnPossessCommand, "" }, - { "bindsight", SEC_ADMINISTRATOR, false, HandleBindSightCommand, "" }, - { "unbindsight", SEC_ADMINISTRATOR, false, HandleUnbindSightCommand, "" }, - { "playall", SEC_GAMEMASTER, false, HandlePlayAllCommand, "" }, - { "skirmish", SEC_ADMINISTRATOR, false, HandleSkirmishCommand, "" }, - { "mailbox", SEC_MODERATOR, false, &HandleMailBoxCommand, "" }, - { "string", SEC_GAMEMASTER, false, &HandleStringCommand, "" }, - { "bags", SEC_GAMEMASTER, false, nullptr, "", bagsCommandTable }, - { "inventory", SEC_MODERATOR, false, nullptr, "", inventoryCommandTable } + { "dev", HandleDevCommand, SEC_ADMINISTRATOR, Console::No }, + { "gps", HandleGPSCommand, SEC_MODERATOR, Console::No }, + { "aura", HandleAuraCommand, SEC_GAMEMASTER, Console::No }, + { "unaura", HandleUnAuraCommand, SEC_GAMEMASTER, Console::No }, + { "appear", HandleAppearCommand, SEC_MODERATOR, Console::No }, + { "summon", HandleSummonCommand, SEC_GAMEMASTER, Console::No }, + { "groupsummon", HandleGroupSummonCommand, SEC_GAMEMASTER, Console::No }, + { "commands", HandleCommandsCommand, SEC_PLAYER, Console::Yes }, + { "die", HandleDieCommand, SEC_GAMEMASTER, Console::No }, + { "revive", HandleReviveCommand, SEC_GAMEMASTER, Console::Yes }, + { "dismount", HandleDismountCommand, SEC_PLAYER, Console::No }, + { "guid", HandleGUIDCommand, SEC_GAMEMASTER, Console::No }, + { "help", HandleHelpCommand, SEC_PLAYER, Console::Yes }, + { "cooldown", HandleCooldownCommand, SEC_GAMEMASTER, Console::No }, + { "distance", HandleGetDistanceCommand, SEC_ADMINISTRATOR, Console::No }, + { "recall", HandleRecallCommand, SEC_GAMEMASTER, Console::No }, + { "save", HandleSaveCommand, SEC_PLAYER, Console::No }, + { "saveall", HandleSaveAllCommand, SEC_GAMEMASTER, Console::Yes }, + { "kick", HandleKickPlayerCommand, SEC_GAMEMASTER, Console::Yes }, + { "unstuck", HandleUnstuckCommand, SEC_GAMEMASTER, Console::Yes }, + { "linkgrave", HandleLinkGraveCommand, SEC_ADMINISTRATOR, Console::No }, + { "neargrave", HandleNearGraveCommand, SEC_GAMEMASTER, Console::No }, + { "showarea", HandleShowAreaCommand, SEC_GAMEMASTER, Console::No }, + { "hidearea", HandleHideAreaCommand, SEC_ADMINISTRATOR, Console::No }, + { "additem", HandleAddItemCommand, SEC_GAMEMASTER, Console::No }, + { "additemset", HandleAddItemSetCommand, SEC_GAMEMASTER, Console::No }, + { "wchange", HandleChangeWeather, SEC_ADMINISTRATOR, Console::No }, + { "maxskill", HandleMaxSkillCommand, SEC_GAMEMASTER, Console::No }, + { "setskill", HandleSetSkillCommand, SEC_GAMEMASTER, Console::No }, + { "pinfo", HandlePInfoCommand, SEC_GAMEMASTER, Console::Yes }, + { "respawn", HandleRespawnCommand, SEC_GAMEMASTER, Console::No }, + { "mute", HandleMuteCommand, SEC_GAMEMASTER, Console::Yes }, + { "mutehistory", HandleMuteInfoCommand, SEC_GAMEMASTER, Console::Yes }, + { "unmute", HandleUnmuteCommand, SEC_GAMEMASTER, Console::Yes }, + { "movegens", HandleMovegensCommand, SEC_ADMINISTRATOR, Console::No }, + { "cometome", HandleComeToMeCommand, SEC_ADMINISTRATOR, Console::No }, + { "damage", HandleDamageCommand, SEC_GAMEMASTER, Console::No }, + { "combatstop", HandleCombatStopCommand, SEC_GAMEMASTER, Console::Yes }, + { "flusharenapoints", HandleFlushArenaPointsCommand, SEC_ADMINISTRATOR, Console::No }, + { "freeze", HandleFreezeCommand, SEC_GAMEMASTER, Console::No }, + { "unfreeze", HandleUnFreezeCommand, SEC_GAMEMASTER, Console::No }, + { "possess", HandlePossessCommand, SEC_GAMEMASTER, Console::No }, + { "unpossess", HandleUnPossessCommand, SEC_GAMEMASTER, Console::No }, + { "bindsight", HandleBindSightCommand, SEC_ADMINISTRATOR, Console::No }, + { "unbindsight", HandleUnbindSightCommand, SEC_ADMINISTRATOR, Console::No }, + { "playall", HandlePlayAllCommand, SEC_GAMEMASTER, Console::No }, + { "skirmish", HandleSkirmishCommand, SEC_ADMINISTRATOR, Console::No }, + { "mailbox", HandleMailBoxCommand, SEC_MODERATOR, Console::No }, + { "string", HandleStringCommand, SEC_GAMEMASTER, Console::No } }; + return commandTable; } - static bool HandleSkirmishCommand(ChatHandler* handler, char const* args) + static bool HandleSkirmishCommand(ChatHandler* handler, std::string_view args) { - Tokenizer tokens(args, ' '); + auto tokens = Acore::Tokenize(args, ' ', true); - if (!*args || !tokens.size()) + if (args.empty() || !tokens.size()) { handler->PSendSysMessage("Usage: .skirmish [arena] [XvX] [Nick1] [Nick2] ... [NickN]"); - handler->PSendSysMessage("[arena] can be \"all\" or comma-separated list of possible arenas (NA,BE,RL,DS,RV)."); + handler->PSendSysMessage("[arena] can be \"all\" or comma-separated list of possible arenas (NA, BE, RL, DS, RV)."); handler->PSendSysMessage("[XvX] can be 1v1, 2v2, 3v3, 5v5. After [XvX] specify enough nicknames for that mode."); handler->SetSentErrorMessage(true); return false; } - Tokenizer::const_iterator tokensItr = tokens.begin(); + auto tokensItr = tokens.begin(); + + std::vector<BattlegroundTypeId> allowedArenas; + std::string_view arenasStr = *(tokensItr++); - std::set<BattlegroundTypeId> allowedArenas; - std::string arenasStr = *(tokensItr++); - std::string tmpStr; - Tokenizer arenaTokens(arenasStr, ','); - for (Tokenizer::const_iterator itr = arenaTokens.begin(); itr != arenaTokens.end(); ++itr) + auto arenaTokens = Acore::Tokenize(arenasStr, ',', false); + for (auto const& arenaName : arenaTokens) { - tmpStr = std::string(*itr); - if (tmpStr == "all") + if (arenaName == "all") { if (arenaTokens.size() > 1) { @@ -237,22 +169,33 @@ public: handler->SetSentErrorMessage(true); return false; } - allowedArenas.insert(BATTLEGROUND_NA); - allowedArenas.insert(BATTLEGROUND_BE); - allowedArenas.insert(BATTLEGROUND_RL); - allowedArenas.insert(BATTLEGROUND_DS); - allowedArenas.insert(BATTLEGROUND_RV); - } - else if (tmpStr == "NA") - allowedArenas.insert(BATTLEGROUND_NA); - else if (tmpStr == "BE") - allowedArenas.insert(BATTLEGROUND_BE); - else if (tmpStr == "RL") - allowedArenas.insert(BATTLEGROUND_RL); - else if (tmpStr == "DS") - allowedArenas.insert(BATTLEGROUND_DS); - else if (tmpStr == "RV") - allowedArenas.insert(BATTLEGROUND_RV); + + allowedArenas.emplace_back(BATTLEGROUND_NA); + allowedArenas.emplace_back(BATTLEGROUND_BE); + allowedArenas.emplace_back(BATTLEGROUND_RL); + allowedArenas.emplace_back(BATTLEGROUND_DS); + allowedArenas.emplace_back(BATTLEGROUND_RV); + } + else if (arenaName == "NA") + { + allowedArenas.emplace_back(BATTLEGROUND_NA); + } + else if (arenaName == "BE") + { + allowedArenas.emplace_back(BATTLEGROUND_BE); + } + else if (arenaName == "RL") + { + allowedArenas.emplace_back(BATTLEGROUND_RL); + } + else if (arenaName == "DS") + { + allowedArenas.emplace_back(BATTLEGROUND_DS); + } + else if (arenaName == "RV") + { + allowedArenas.emplace_back(BATTLEGROUND_RV); + } else { handler->PSendSysMessage("Invalid [arena] specified."); @@ -260,17 +203,31 @@ public: return false; } } + ASSERT(!allowedArenas.empty()); BattlegroundTypeId randomizedArenaBgTypeId = Acore::Containers::SelectRandomContainerElement(allowedArenas); uint8 count = 0; if (tokensItr != tokens.end()) { - std::string mode = *(tokensItr++); - if (mode == "1v1") count = 2; - else if (mode == "2v2") count = 4; - else if (mode == "3v3") count = 6; - else if (mode == "5v5") count = 10; + std::string_view mode = *(tokensItr++); + + if (mode == "1v1") + { + count = 2; + } + else if (mode == "2v2") + { + count = 4; + } + else if (mode == "3v3") + { + count = 6; + } + else if (mode == "5v5") + { + count = 10; + } } if (!count) @@ -291,34 +248,95 @@ public: uint8 error = 0; std::string last_name; Player* plr = nullptr; - Player* players[10] = {nullptr}; + std::array<Player*, 10> players = {}; uint8 cnt = 0; + for (; tokensItr != tokens.end(); ++tokensItr) { last_name = std::string(*tokensItr); plr = ObjectAccessor::FindPlayerByName(last_name, false); - if (!plr) { error = 1; break; } - if (!plr->IsInWorld() || !plr->FindMap() || plr->IsBeingTeleported()) { error = 2; break; } - if (plr->GetMap()->GetEntry()->Instanceable()) { error = 3; break; } - if (plr->isUsingLfg()) { error = 4; break; } - if (plr->InBattlegroundQueue()) { error = 5; break; } - if (plr->IsInFlight()) { error = 10; break; } - if (!plr->IsAlive()) { error = 11; break; } + + if (!plr) + { + error = 1; + break; + } + + if (!plr->IsInWorld() || !plr->FindMap() || plr->IsBeingTeleported()) + { + error = 2; + break; + } + + if (plr->GetMap()->GetEntry()->Instanceable()) + { + error = 3; + break; + } + + if (plr->isUsingLfg()) + { + error = 4; + break; + } + + if (plr->InBattlegroundQueue()) + { + error = 5; + break; + } + + if (plr->IsInFlight()) + { + error = 10; + break; + } + + if (!plr->IsAlive()) + { + error = 11; + break; + } + const Group* g = plr->GetGroup(); + if (hcnt > 1) { - if (!g) { error = 6; break; } - if (g->isRaidGroup() || g->isBGGroup() || g->isBFGroup() || g->isLFGGroup()) { error = 7; break; } - if (g->GetMembersCount() != hcnt) { error = 8; break; } + if (!g) + { + error = 6; + break; + } + + if (g->isRaidGroup() || g->isBGGroup() || g->isBFGroup() || g->isLFGGroup()) + { + error = 7; + break; + } + + if (g->GetMembersCount() != hcnt) + { + error = 8; + break; + } uint8 sti = (cnt < hcnt ? 0 : hcnt); - if (sti != cnt) - if (players[sti]->GetGroup() != plr->GetGroup()) { error = 9; last_name += " and " + players[sti]->GetName(); break; } + if (sti != cnt && players[sti]->GetGroup() != plr->GetGroup()) + { + error = 9; + last_name += " and " + players[sti]->GetName(); + break; + } } else // 1v1 { - if (g) { error = 12; break; } + if (g) + { + error = 12; + break; + } } + players[cnt++] = plr; } @@ -406,6 +424,7 @@ public: TeamId teamId1 = Player::TeamIdForRace(players[0]->getRace()); TeamId teamId2 = (teamId1 == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE); + for (uint8 i = 0; i < cnt; ++i) { Player* player = players[i]; @@ -426,31 +445,48 @@ public: return true; } - static bool HandleDevCommand(ChatHandler* handler, char const* enable) + static bool HandleDevCommand(ChatHandler* handler, Optional<bool> enableArg) { - Player* player = handler->GetSession()->GetPlayer(); + WorldSession* session = handler->GetSession(); - if (!*enable) + if (!session) { - handler->GetSession()->SendNotification(player->IsDeveloper() ? LANG_DEV_ON : LANG_DEV_OFF); - return true; + return false; } - std::string enablestr = (char*)enable; - - if (enablestr == "on") + auto SetDevMod = [&](bool enable) { - player->SetDeveloper(true); - handler->GetSession()->SendNotification(LANG_DEV_ON); - sScriptMgr->OnHandleDevCommand(handler->GetSession()->GetPlayer(), enablestr); - return true; - } - else if (enablestr == "off") + session->SendNotification(enable ? LANG_DEV_ON : LANG_DEV_OFF); + session->GetPlayer()->SetDeveloper(enable); + sScriptMgr->OnHandleDevCommand(handler->GetSession()->GetPlayer(), enable); + }; + + if (WorldSession* session = handler->GetSession()) { - player->SetDeveloper(false); - handler->GetSession()->SendNotification(LANG_DEV_OFF); - sScriptMgr->OnHandleDevCommand(handler->GetSession()->GetPlayer(), enablestr); - return true; + if (!enableArg) + { + if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsDeveloper()) + { + SetDevMod(true); + } + else + { + SetDevMod(false); + } + + return true; + } + + if (*enableArg) + { + SetDevMod(true); + return true; + } + else + { + SetDevMod(false); + return true; + } } handler->SendSysMessage(LANG_USE_BOL); @@ -458,68 +494,31 @@ public: return false; } - static bool HandleGPSCommand(ChatHandler* handler, char const* args) + static bool HandleGPSCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - WorldObject* object = nullptr; - if (*args) + if (!target) { - HighGuid guidHigh; - ObjectGuid::LowType guidLow = handler->extractLowGuidFromLink((char*)args, guidHigh); - if (!guidLow) - return false; + target = PlayerIdentifier::FromTargetOrSelf(handler); + } - switch (guidHigh) - { - case HighGuid::Player: - { - object = ObjectAccessor::FindPlayerByLowGUID(guidLow); - if (!object) - { - handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); - } - break; - } - case HighGuid::Unit: - { - object = handler->GetCreatureFromPlayerMapByDbGuid(guidLow); - if (!object) - { - handler->SendSysMessage(LANG_COMMAND_NOCREATUREFOUND); - handler->SetSentErrorMessage(true); - } - break; - } - case HighGuid::GameObject: - { - object = handler->GetObjectFromPlayerMapByDbGuid(guidLow); - if (!object) - { - handler->SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND); - handler->SetSentErrorMessage(true); - } - break; - } - default: - return false; - } - if (!object) - return false; + WorldObject* object = handler->getSelectedUnit(); + + if (!object && !target) + { + return false; } - else + + if (!object && target && target->IsConnected()) { - object = handler->getSelectedUnit(); + object = target->GetConnectedPlayer(); + } - if (!object) - { - handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - handler->SetSentErrorMessage(true); - return false; - } + if (!object) + { + return false; } - CellCoord cellCoord = Acore::ComputeCellCoord(object->GetPositionX(), object->GetPositionY()); - Cell cell(cellCoord); + Cell cell(Acore::ComputeCellCoord(object->GetPositionX(), object->GetPositionY())); uint32 zoneId, areaId; object->GetZoneAndAreaId(zoneId, areaId); @@ -549,12 +548,18 @@ public: if (haveVMap) { if (object->IsOutdoors()) + { handler->PSendSysMessage("You are outdoors"); + } else + { handler->PSendSysMessage("You are indoors"); + } } else + { handler->PSendSysMessage("no VMAP available for area info"); + } handler->PSendSysMessage(LANG_MAP_POSITION, object->GetMapId(), (mapEntry ? mapEntry->name[handler->GetSessionDbcLocale()] : "<unknown>"), @@ -568,50 +573,48 @@ public: LiquidData const& liquidData = object->GetLiquidData(); if (liquidData.Status) + { handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidData.Level, liquidData.DepthLevel, liquidData.Entry, liquidData.Flags, liquidData.Status); + } if (object->GetTransport()) + { handler->PSendSysMessage("Transport offset: %.2f, %.2f, %.2f, %.2f", object->m_movementInfo.transport.pos.GetPositionX(), object->m_movementInfo.transport.pos.GetPositionY(), object->m_movementInfo.transport.pos.GetPositionZ(), object->m_movementInfo.transport.pos.GetOrientation()); + } return true; } - static bool HandleAuraCommand(ChatHandler* handler, char const* args) + static bool HandleAuraCommand(ChatHandler* handler, SpellInfo const* spell) { - Unit* target = handler->getSelectedUnit(); - if (!target) + if (!spell) { - handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); handler->SetSentErrorMessage(true); return false; } - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spellId = handler->extractSpellIdFromLink((char*)args); - if (!spellId) - return false; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) + if (!SpellMgr::IsSpellValid(spell)) { - handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spell->Id); handler->SetSentErrorMessage(true); return false; } - if (!SpellMgr::IsSpellValid(spellInfo)) + Unit* target = handler->getSelectedUnit(); + if (!target) { - handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spellId); + handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); handler->SetSentErrorMessage(true); return false; } - Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, target, target); + Aura::TryRefreshStackOrCreate(spell, MAX_EFFECT_MASK, target, target); return true; } - static bool HandleUnAuraCommand(ChatHandler* handler, char const* args) + static bool HandleUnAuraCommand(ChatHandler* handler, Variant<SpellInfo const*, std::string_view> spells) { Unit* target = handler->getSelectedUnit(); if (!target) @@ -621,62 +624,82 @@ public: return false; } - std::string argstr = args; - if (argstr == "all") + if (spells.holds_alternative<std::string_view>() && spells.get<std::string_view>() == "all") { target->RemoveAllAuras(); return true; } - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spellId = handler->extractSpellIdFromLink((char*)args); - if (!spellId) + if (!spells.holds_alternative<SpellInfo const*>()) + { + handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + handler->SetSentErrorMessage(true); + return false; + } + + auto spell = spells.get<SpellInfo const*>(); + + if (!SpellMgr::IsSpellValid(spell)) + { + handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spell->Id); + handler->SetSentErrorMessage(true); return false; + } - target->RemoveAurasDueToSpell(spellId); + target->RemoveAurasDueToSpell(spell->Id); return true; } // Teleport to Player - static bool HandleAppearCommand(ChatHandler* handler, char const* args) + static bool HandleAppearCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + if (!target) + { + target = PlayerIdentifier::FromTarget(handler); + } + + if (!target) + { return false; + } Player* _player = handler->GetSession()->GetPlayer(); - if (target == _player || targetGuid == _player->GetGUID()) + if (target->GetGUID() == _player->GetGUID()) { handler->SendSysMessage(LANG_CANT_TELEPORT_SELF); handler->SetSentErrorMessage(true); return false; } - if (target) + std::string nameLink = handler->playerLink(target->GetName()); + + if (target->IsConnected()) { + auto targetPlayer = target->GetConnectedPlayer(); + // check online security - if (handler->HasLowerSecurity(target)) + if (handler->HasLowerSecurity(targetPlayer)) + { return false; + } - std::string chrNameLink = handler->playerLink(targetName); - - Map* map = target->GetMap(); + Map* map = targetPlayer->GetMap(); if (map->IsBattlegroundOrArena()) { // only allow if gm mode is on if (!_player->IsGameMaster()) { - handler->PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM, chrNameLink.c_str()); + handler->PSendSysMessage(LANG_CANNOT_GO_TO_BG_GM, nameLink.c_str()); handler->SetSentErrorMessage(true); return false; } if (!_player->GetMap()->IsBattlegroundOrArena()) + { _player->SetEntryPoint(); + } - _player->SetBattlegroundId(target->GetBattlegroundId(), target->GetBattlegroundTypeId(), PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL); + _player->SetBattlegroundId(targetPlayer->GetBattlegroundId(), targetPlayer->GetBattlegroundTypeId(), PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL); } else if (map->IsDungeon()) { @@ -686,9 +709,9 @@ public: if (_player->GetGroup()) { // we are in group, we can go only if we are in the player group - if (_player->GetGroup() != target->GetGroup()) + if (_player->GetGroup() != targetPlayer->GetGroup()) { - handler->PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY, chrNameLink.c_str()); + handler->PSendSysMessage(LANG_CANNOT_GO_TO_INST_PARTY, nameLink.c_str()); handler->SetSentErrorMessage(true); return false; } @@ -698,25 +721,33 @@ public: // we are not in group, let's verify our GM mode if (!_player->IsGameMaster()) { - handler->PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM, chrNameLink.c_str()); + handler->PSendSysMessage(LANG_CANNOT_GO_TO_INST_GM, nameLink.c_str()); handler->SetSentErrorMessage(true); return false; } } // if the GM is bound to another instance, he will not be bound to another one - InstancePlayerBind* bind = sInstanceSaveMgr->PlayerGetBoundInstance(_player->GetGUID(), target->GetMapId(), target->GetDifficulty(map->IsRaid())); + InstancePlayerBind* bind = sInstanceSaveMgr->PlayerGetBoundInstance(_player->GetGUID(), targetPlayer->GetMapId(), targetPlayer->GetDifficulty(map->IsRaid())); if (!bind) - if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(target->GetInstanceId())) + { + if (InstanceSave* save = sInstanceSaveMgr->GetInstanceSave(target->GetConnectedPlayer()->GetInstanceId())) + { sInstanceSaveMgr->PlayerBindToInstance(_player->GetGUID(), save, !save->CanReset(), _player); + } + } if (map->IsRaid()) - _player->SetRaidDifficulty(target->GetRaidDifficulty()); + { + _player->SetRaidDifficulty(targetPlayer->GetRaidDifficulty()); + } else - _player->SetDungeonDifficulty(target->GetDungeonDifficulty()); + { + _player->SetDungeonDifficulty(targetPlayer->GetDungeonDifficulty()); + } } - handler->PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str()); + handler->PSendSysMessage(LANG_APPEARING_AT, nameLink.c_str()); // stop flight if need if (_player->IsInFlight()) @@ -724,20 +755,23 @@ public: _player->GetMotionMaster()->MovementExpired(); _player->CleanupAfterTaxiFlight(); } - // save only in non-flight case - else + else // save only in non-flight case + { _player->SaveRecallPosition(); + } - if (_player->TeleportTo(target->GetMapId(), target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 0.25f, _player->GetOrientation(), TELE_TO_GM_MODE, target)) - _player->SetPhaseMask(target->GetPhaseMask() | 1, false); + if (_player->TeleportTo(targetPlayer->GetMapId(), targetPlayer->GetPositionX(), targetPlayer->GetPositionY(), targetPlayer->GetPositionZ() + 0.25f, _player->GetOrientation(), TELE_TO_GM_MODE, targetPlayer)) + { + _player->SetPhaseMask(targetPlayer->GetPhaseMask() | 1, false); + } } else { // check offline security - if (handler->HasLowerSecurity(nullptr, targetGuid)) + if (handler->HasLowerSecurity(nullptr, target->GetGUID())) + { return false; - - std::string nameLink = handler->playerLink(targetName); + } handler->PSendSysMessage(LANG_APPEARING_AT, nameLink.c_str()); @@ -745,8 +779,11 @@ public: float x, y, z, o; uint32 map; bool in_flight; - if (!Player::LoadPositionFromDB(map, x, y, z, o, in_flight, targetGuid.GetCounter())) + + if (!Player::LoadPositionFromDB(map, x, y, z, o, in_flight, target->GetGUID().GetCounter())) + { return false; + } // stop flight if need if (_player->IsInFlight()) @@ -756,38 +793,50 @@ public: } // save only in non-flight case else + { _player->SaveRecallPosition(); + } _player->TeleportTo(map, x, y, z, _player->GetOrientation()); } return true; } + // Summon Player - static bool HandleSummonCommand(ChatHandler* handler, char const* args) + static bool HandleSummonCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + if (!target) + { + target = PlayerIdentifier::FromTarget(handler); + } + + if (!target) + { return false; + } Player* _player = handler->GetSession()->GetPlayer(); - if (target == _player || targetGuid == _player->GetGUID()) + if (target->GetGUID() == _player->GetGUID()) { handler->PSendSysMessage(LANG_CANT_TELEPORT_SELF); handler->SetSentErrorMessage(true); return false; } - if (target) + std::string nameLink = handler->playerLink(target->GetName()); + + if (target->IsConnected()) { - std::string nameLink = handler->playerLink(targetName); + auto targetPlayer = target->GetConnectedPlayer(); + // check online security - if (handler->HasLowerSecurity(target)) + if (handler->HasLowerSecurity(targetPlayer)) + { return false; + } - if (target->IsBeingTeleported()) + if (targetPlayer->IsBeingTeleported()) { handler->PSendSysMessage(LANG_IS_TELEPORTED, nameLink.c_str()); handler->SetSentErrorMessage(true); @@ -808,7 +857,7 @@ public: if (!sWorld->getBoolConfig(CONFIG_INSTANCE_GMSUMMON_PLAYER)) { // pussywizard: prevent unbinding normal player's perm bind by just summoning him >_> - if (!target->GetSession()->GetSecurity()) + if (!targetPlayer->GetSession()->GetSecurity()) { handler->PSendSysMessage("Only GMs can be summoned to an instance!"); handler->SetSentErrorMessage(true); @@ -816,14 +865,16 @@ public: } } - Map* destMap = target->GetMap(); + Map* destMap = targetPlayer->GetMap(); if (destMap->Instanceable() && destMap->GetInstanceId() != map->GetInstanceId()) - sInstanceSaveMgr->PlayerUnbindInstance(target->GetGUID(), map->GetInstanceId(), target->GetDungeonDifficulty(), true, target); + { + sInstanceSaveMgr->PlayerUnbindInstance(target->GetGUID(), map->GetInstanceId(), targetPlayer->GetDungeonDifficulty(), true, targetPlayer); + } // we are in an instance, and can only summon players in our group with us as leader - if (!handler->GetSession()->GetPlayer()->GetGroup() || !target->GetGroup() || - (target->GetGroup()->GetLeaderGUID() != handler->GetSession()->GetPlayer()->GetGUID()) || + if (!handler->GetSession()->GetPlayer()->GetGroup() || !targetPlayer->GetGroup() || + (targetPlayer->GetGroup()->GetLeaderGUID() != handler->GetSession()->GetPlayer()->GetGUID()) || (handler->GetSession()->GetPlayer()->GetGroup()->GetLeaderGUID() != handler->GetSession()->GetPlayer()->GetGUID())) // the last check is a bit excessive, but let it be, just in case { @@ -834,31 +885,35 @@ public: } handler->PSendSysMessage(LANG_SUMMONING, nameLink.c_str(), ""); - if (handler->needReportToTarget(target)) - ChatHandler(target->GetSession()).PSendSysMessage(LANG_SUMMONED_BY, handler->playerLink(_player->GetName()).c_str()); + if (handler->needReportToTarget(targetPlayer)) + { + ChatHandler(targetPlayer->GetSession()).PSendSysMessage(LANG_SUMMONED_BY, handler->playerLink(_player->GetName()).c_str()); + } // stop flight if need - if (target->IsInFlight()) + if (targetPlayer->IsInFlight()) { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); + targetPlayer->GetMotionMaster()->MovementExpired(); + targetPlayer->CleanupAfterTaxiFlight(); } // save only in non-flight case else - target->SaveRecallPosition(); + { + targetPlayer->SaveRecallPosition(); + } // before GM float x, y, z; - handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, target->GetObjectSize()); - target->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, target->GetOrientation(), 0, handler->GetSession()->GetPlayer()); + handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, targetPlayer->GetObjectSize()); + targetPlayer->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, targetPlayer->GetOrientation(), 0, handler->GetSession()->GetPlayer()); } else { // check offline security - if (handler->HasLowerSecurity(nullptr, targetGuid)) + if (handler->HasLowerSecurity(nullptr, target->GetGUID())) + { return false; - - std::string nameLink = handler->playerLink(targetName); + } handler->PSendSysMessage(LANG_SUMMONING, nameLink.c_str(), handler->GetAcoreString(LANG_OFFLINE)); @@ -869,25 +924,36 @@ public: handler->GetSession()->GetPlayer()->GetPositionZ(), handler->GetSession()->GetPlayer()->GetOrientation(), handler->GetSession()->GetPlayer()->GetZoneId(), - targetGuid); + target->GetGUID()); } return true; } + // Summon group of player - static bool HandleGroupSummonCommand(ChatHandler* handler, char const* args) + static bool HandleGroupSummonCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - Player* target; - if (!handler->extractPlayerTarget((char*)args, &target)) + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target || !target->IsConnected()) + { return false; + } // check online security - if (handler->HasLowerSecurity(target)) + if (handler->HasLowerSecurity(target->GetConnectedPlayer())) + { return false; + } - Group* group = target->GetGroup(); + auto targetPlayer = target->GetConnectedPlayer(); - std::string nameLink = handler->GetNameLink(target); + Group* group = targetPlayer->GetGroup(); + + std::string nameLink = handler->playerLink(target->GetName()); if (!group) { @@ -915,11 +981,15 @@ public: Player* player = itr->GetSource(); if (!player || player == handler->GetSession()->GetPlayer() || !player->GetSession()) + { continue; + } // check online security if (handler->HasLowerSecurity(player)) + { return false; + } std::string plNameLink = handler->GetNameLink(player); @@ -945,7 +1015,9 @@ public: handler->PSendSysMessage(LANG_SUMMONING, plNameLink.c_str(), ""); if (handler->needReportToTarget(player)) + { ChatHandler(player->GetSession()).PSendSysMessage(LANG_SUMMONED_BY, handler->GetNameLink().c_str()); + } // stop flight if need if (player->IsInFlight()) @@ -955,7 +1027,9 @@ public: } // save only in non-flight case else + { player->SaveRecallPosition(); + } // before GM float x, y, z; @@ -966,13 +1040,13 @@ public: return true; } - static bool HandleCommandsCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleCommandsCommand(ChatHandler* handler) { SendCommandHelpFor(*handler, ""); return true; } - static bool HandleDieCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleDieCommand(ChatHandler* handler) { Unit* target = handler->getSelectedUnit(); @@ -986,7 +1060,9 @@ public: if (target->GetTypeId() == TYPEID_PLAYER) { if (handler->HasLowerSecurity(target->ToPlayer())) + { return false; + } } if (target->IsAlive()) @@ -994,39 +1070,50 @@ public: if (sWorld->getBoolConfig(CONFIG_DIE_COMMAND_MODE)) { if (target->GetTypeId() == TYPEID_UNIT && handler->GetSession()->GetSecurity() == SEC_CONSOLE) // pussywizard + { target->ToCreature()->LowerPlayerDamageReq(target->GetMaxHealth()); + } Unit::Kill(handler->GetSession()->GetPlayer(), target); } else + { Unit::DealDamage(handler->GetSession()->GetPlayer(), target, target->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false, true); + } } return true; } - static bool HandleReviveCommand(ChatHandler* handler, char const* args) + static bool HandleReviveCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - Player* target; - ObjectGuid targetGuid; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid)) + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { return false; + } - if (target) + if (target->IsConnected()) { - target->ResurrectPlayer(!AccountMgr::IsPlayerAccount(target->GetSession()->GetSecurity()) ? 1.0f : 0.5f); - target->SpawnCorpseBones(); - target->SaveToDB(false, false); + auto targetPlayer = target->GetConnectedPlayer(); + + targetPlayer->ResurrectPlayer(!AccountMgr::IsPlayerAccount(targetPlayer->GetSession()->GetSecurity()) ? 1.0f : 0.5f); + targetPlayer->SpawnCorpseBones(); + targetPlayer->SaveToDB(false, false); } else { CharacterDatabaseTransaction trans(nullptr); - Player::OfflineResurrect(targetGuid, trans); + Player::OfflineResurrect(target->GetGUID(), trans); } return true; } - static bool HandleDismountCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleDismountCommand(ChatHandler* handler) { Player* player = handler->GetSession()->GetPlayer(); @@ -1052,7 +1139,7 @@ public: return true; } - static bool HandleGUIDCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleGUIDCommand(ChatHandler* handler) { ObjectGuid guid = handler->GetSession()->GetPlayer()->GetTarget(); @@ -1072,12 +1159,14 @@ public: Acore::ChatCommands::SendCommandHelpFor(*handler, cmd); if (cmd.empty()) + { Acore::ChatCommands::SendCommandHelpFor(*handler, "help"); + } return true; } - static bool HandleCooldownCommand(ChatHandler* handler, char const* args) + static bool HandleCooldownCommand(ChatHandler* handler, Optional<SpellInfo const*> spell) { Player* target = handler->getSelectedPlayer(); if (!target) @@ -1089,124 +1178,93 @@ public: std::string nameLink = handler->GetNameLink(target); - if (!*args) + if (!spell) { target->RemoveAllSpellCooldown(); handler->PSendSysMessage(LANG_REMOVEALL_COOLDOWN, nameLink.c_str()); } else { - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r or Htalent form - uint32 spellIid = handler->extractSpellIdFromLink((char*)args); - if (!spellIid) - return false; - - if (!sSpellMgr->GetSpellInfo(spellIid)) + if (!SpellMgr::IsSpellValid(*spell)) { - handler->PSendSysMessage(LANG_UNKNOWN_SPELL, target == handler->GetSession()->GetPlayer() ? handler->GetAcoreString(LANG_YOU) : nameLink.c_str()); + handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spell.value()->Id); handler->SetSentErrorMessage(true); return false; } - target->RemoveSpellCooldown(spellIid, true); - handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spellIid, target == handler->GetSession()->GetPlayer() ? handler->GetAcoreString(LANG_YOU) : nameLink.c_str()); + target->RemoveSpellCooldown(spell.value()->Id, true); + handler->PSendSysMessage(LANG_REMOVE_COOLDOWN, spell.value()->Id, target == handler->GetSession()->GetPlayer() ? handler->GetAcoreString(LANG_YOU) : nameLink.c_str()); } return true; } - static bool HandleGetDistanceCommand(ChatHandler* handler, char const* args) + static bool HandleGetDistanceCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - WorldObject* obj = nullptr; - if (*args) + if (!target) { - HighGuid guidHigh; - ObjectGuid::LowType guidLow = handler->extractLowGuidFromLink((char*)args, guidHigh); - if (!guidLow) - return false; + target = PlayerIdentifier::FromTargetOrSelf(handler); + } - switch (guidHigh) - { - case HighGuid::Player: - { - obj = ObjectAccessor::FindPlayerByLowGUID(guidLow); - if (!obj) - { - handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); - } - break; - } - case HighGuid::Unit: - { - obj = handler->GetCreatureFromPlayerMapByDbGuid(guidLow); - if (!obj) - { - handler->SendSysMessage(LANG_COMMAND_NOCREATUREFOUND); - handler->SetSentErrorMessage(true); - } - break; - } - case HighGuid::GameObject: - { - obj = handler->GetObjectFromPlayerMapByDbGuid(guidLow); - if (!obj) - { - handler->SendSysMessage(LANG_COMMAND_NOGAMEOBJECTFOUND); - handler->SetSentErrorMessage(true); - } - break; - } - default: - return false; - } - if (!obj) - return false; + WorldObject* object = handler->getSelectedUnit(); + + if (!object && !target) + { + return false; } - else + + if (!object && target && target->IsConnected()) { - obj = handler->getSelectedUnit(); + object = target->GetConnectedPlayer(); + } - if (!obj) - { - handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); - handler->SetSentErrorMessage(true); - return false; - } + if (!object) + { + return false; } - handler->PSendSysMessage(LANG_DISTANCE, handler->GetSession()->GetPlayer()->GetDistance(obj), handler->GetSession()->GetPlayer()->GetDistance2d(obj), handler->GetSession()->GetPlayer()->GetExactDist(obj), handler->GetSession()->GetPlayer()->GetExactDist2d(obj)); + handler->PSendSysMessage(LANG_DISTANCE, handler->GetSession()->GetPlayer()->GetDistance(object), handler->GetSession()->GetPlayer()->GetDistance2d(object), handler->GetSession()->GetPlayer()->GetExactDist(object), handler->GetSession()->GetPlayer()->GetExactDist2d(object)); return true; } // Teleport player to last position - static bool HandleRecallCommand(ChatHandler* handler, char const* args) + static bool HandleRecallCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - Player* target; - if (!handler->extractPlayerTarget((char*)args, &target)) + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target || !target->IsConnected()) + { return false; + } + + auto targetPlayer = target->GetConnectedPlayer(); // check online security - if (handler->HasLowerSecurity(target)) + if (handler->HasLowerSecurity(targetPlayer)) + { return false; + } - if (target->IsBeingTeleported()) + if (targetPlayer->IsBeingTeleported()) { - handler->PSendSysMessage(LANG_IS_TELEPORTED, handler->GetNameLink(target).c_str()); + handler->PSendSysMessage(LANG_IS_TELEPORTED, handler->playerLink(target->GetName()).c_str()); handler->SetSentErrorMessage(true); return false; } // stop flight if need - if (target->IsInFlight()) + if (targetPlayer->IsInFlight()) { - target->GetMotionMaster()->MovementExpired(); - target->CleanupAfterTaxiFlight(); + targetPlayer->GetMotionMaster()->MovementExpired(); + targetPlayer->CleanupAfterTaxiFlight(); } - target->TeleportTo(target->m_recallMap, target->m_recallX, target->m_recallY, target->m_recallZ, target->m_recallO); + targetPlayer->TeleportTo(targetPlayer->m_recallMap, targetPlayer->m_recallX, targetPlayer->m_recallY, targetPlayer->m_recallZ, targetPlayer->m_recallO); return true; } - static bool HandleSaveCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleSaveCommand(ChatHandler* handler) { Player* player = handler->GetSession()->GetPlayer(); @@ -1221,6 +1279,7 @@ public: { player->SaveToDB(false, false); } + handler->SendSysMessage(LANG_PLAYER_SAVED); return true; } @@ -1236,7 +1295,7 @@ public: } // Save all players in the world - static bool HandleSaveAllCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleSaveAllCommand(ChatHandler* handler) { ObjectAccessor::SaveAllPlayers(); handler->SendSysMessage(LANG_PLAYERS_SAVED); @@ -1244,14 +1303,21 @@ public: } // kick player - static bool HandleKickPlayerCommand(ChatHandler* handler, char const* args) + static bool HandleKickPlayerCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, Optional<std::string_view> reason) { - Player* target = nullptr; - std::string playerName; - if (!handler->extractPlayerTarget((char*)args, &target, nullptr, &playerName)) + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target || !target->IsConnected()) + { return false; + } - if (handler->GetSession() && target == handler->GetSession()->GetPlayer()) + auto targetPlayer = target->GetConnectedPlayer(); + + if (handler->GetSession() && target->GetGUID() == handler->GetSession()->GetPlayer()->GetGUID()) { handler->SendSysMessage(LANG_COMMAND_KICKSELF); handler->SetSentErrorMessage(true); @@ -1259,78 +1325,85 @@ public: } // check online security - if (handler->HasLowerSecurity(target)) + if (handler->HasLowerSecurity(targetPlayer)) + { return false; + } std::string kickReasonStr = handler->GetAcoreString(LANG_NO_REASON); - if (*args != '\0') + if (reason && !reason->empty()) { - char const* kickReason = strtok(nullptr, "\r"); - if (kickReason != nullptr) - kickReasonStr = kickReason; + kickReasonStr = std::string{ *reason }; } if (sWorld->getBoolConfig(CONFIG_SHOW_KICK_IN_WORLD)) - sWorld->SendWorldText(LANG_COMMAND_KICKMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), playerName.c_str(), kickReasonStr.c_str()); + { + sWorld->SendWorldText(LANG_COMMAND_KICKMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), target->GetName().c_str(), kickReasonStr.c_str()); + } else - handler->PSendSysMessage(LANG_COMMAND_KICKMESSAGE, playerName.c_str()); + { + handler->PSendSysMessage(LANG_COMMAND_KICKMESSAGE, target->GetName().c_str()); + } - target->GetSession()->KickPlayer("HandleKickPlayerCommand"); + targetPlayer->GetSession()->KickPlayer("HandleKickPlayerCommand"); return true; } - static bool HandleUnstuckCommand(ChatHandler* handler, char const* args) + static bool HandleUnstuckCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, Optional<std::string_view> location) { - //No args required for players + // No args required for players if (handler->GetSession() && AccountMgr::IsPlayerAccount(handler->GetSession()->GetSecurity())) { - // 7355: "Stuck" if (Player* player = handler->GetSession()->GetPlayer()) - player->CastSpell(player, 7355, false); + { + player->CastSpell(player, SPELL_STUCK, false); + } + return true; } - if (!*args) - return false; + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } - char* player_str = strtok((char*)args, " "); - if (!player_str) + if (!target || !target->IsConnected()) + { return false; + } - std::string location_str = "inn"; - if (char const* loc = strtok(nullptr, " ")) - location_str = loc; - - Player* player = nullptr; - if (!handler->extractPlayerTarget(player_str, &player)) - return false; + Player* player = target->GetConnectedPlayer(); if (player->IsInFlight() || player->IsInCombat()) { SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(7355); if (!spellInfo) + { return false; + } if (Player* caster = handler->GetSession()->GetPlayer()) + { Spell::SendCastResult(caster, spellInfo, 0, SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW); + } return false; } - if (location_str == "inn") + if (location->empty() || *location == "inn") { player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation()); return true; } - if (location_str == "graveyard") + if (*location == "graveyard") { player->RepopAtGraveyard(); return true; } - if (location_str == "startzone") + if (*location == "startzone") { player->TeleportTo(player->GetStartPosition()); return true; @@ -1340,29 +1413,26 @@ public: return false; } - static bool HandleLinkGraveCommand(ChatHandler* handler, char const* args) + static bool HandleLinkGraveCommand(ChatHandler* handler, uint32 graveyardId, Optional<std::string_view> team) { - if (!*args) - return false; - - char* px = strtok((char*)args, " "); - if (!px) - return false; - - uint32 graveyardId = uint32(atoi(px)); - TeamId teamId; - char* px2 = strtok(nullptr, " "); - - if (!px2) + if (!team) + { teamId = TEAM_NEUTRAL; - else if (strncmp(px2, "horde", 6) == 0) + } + else if (StringEqualI(team->substr(0, 6), "horde")) + { teamId = TEAM_HORDE; - else if (strncmp(px2, "alliance", 9) == 0) + } + else if (StringEqualI(team->substr(0, 9), "alliance")) + { teamId = TEAM_ALLIANCE; + } else + { return false; + } GraveyardStruct const* graveyard = sGraveyard->GetGraveyard(graveyardId); @@ -1374,7 +1444,6 @@ public: } Player* player = handler->GetSession()->GetPlayer(); - uint32 zoneId = player->GetZoneId(); AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId); @@ -1386,27 +1455,37 @@ public: } if (sGraveyard->AddGraveyardLink(graveyardId, zoneId, teamId)) + { handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDLINKED, graveyardId, zoneId); + } else + { handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDALRLINKED, graveyardId, zoneId); + } return true; } - static bool HandleNearGraveCommand(ChatHandler* handler, char const* args) + static bool HandleNearGraveCommand(ChatHandler* handler, Optional<std::string_view> team) { TeamId teamId; - size_t argStr = strlen(args); - - if (!*args) + if (!team) + { teamId = TEAM_NEUTRAL; - else if (strncmp((char*)args, "horde", argStr) == 0) + } + else if (StringEqualI(team->substr(0, 6), "horde")) + { teamId = TEAM_HORDE; - else if (strncmp((char*)args, "alliance", argStr) == 0) + } + else if (StringEqualI(team->substr(0, 9), "alliance")) + { teamId = TEAM_ALLIANCE; + } else + { return false; + } Player* player = handler->GetSession()->GetPlayer(); uint32 zone_id = player->GetZoneId(); @@ -1428,11 +1507,17 @@ public: std::string team_name = handler->GetAcoreString(LANG_COMMAND_GRAVEYARD_NOTEAM); if (data->teamId == TEAM_NEUTRAL) + { team_name = handler->GetAcoreString(LANG_COMMAND_GRAVEYARD_ANY); + } else if (data->teamId == TEAM_HORDE) + { team_name = handler->GetAcoreString(LANG_COMMAND_GRAVEYARD_HORDE); + } else if (data->teamId == TEAM_ALLIANCE) + { team_name = handler->GetAcoreString(LANG_COMMAND_GRAVEYARD_ALLIANCE); + } handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDNEAREST, graveyardId, team_name.c_str(), zone_id); } @@ -1441,26 +1526,26 @@ public: std::string team_name; if (teamId == TEAM_NEUTRAL) + { team_name = handler->GetAcoreString(LANG_COMMAND_GRAVEYARD_ANY); + } else if (teamId == TEAM_HORDE) + { team_name = handler->GetAcoreString(LANG_COMMAND_GRAVEYARD_HORDE); + } else if (teamId == TEAM_ALLIANCE) + { team_name = handler->GetAcoreString(LANG_COMMAND_GRAVEYARD_ALLIANCE); + } - //if (team == ~uint32(0)) - // handler->PSendSysMessage(LANG_COMMAND_ZONENOGRAVEYARDS, zone_id); - //else handler->PSendSysMessage(LANG_COMMAND_ZONENOGRAFACTION, zone_id, team_name.c_str()); } return true; } - static bool HandleShowAreaCommand(ChatHandler* handler, char const* args) + static bool HandleShowAreaCommand(ChatHandler* handler, uint32 areaID) { - if (!*args) - return false; - Player* playerTarget = handler->getSelectedPlayer(); if (!playerTarget) { @@ -1469,7 +1554,7 @@ public: return false; } - AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaID); if (!area) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -1493,11 +1578,8 @@ public: return true; } - static bool HandleHideAreaCommand(ChatHandler* handler, char const* args) + static bool HandleHideAreaCommand(ChatHandler* handler, uint32 areaID) { - if (!*args) - return false; - Player* playerTarget = handler->getSelectedPlayer(); if (!playerTarget) { @@ -1506,7 +1588,7 @@ public: return false; } - AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); + AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaID); if (!area) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -1530,65 +1612,34 @@ public: return true; } - static bool HandleAddItemCommand(ChatHandler* handler, char const* args) + static bool HandleAddItemCommand(ChatHandler* handler, ItemTemplate const* itemTemplate, Optional<int32> _count) { - if (!*args) + if (!sObjectMgr->GetItemTemplate(itemTemplate->ItemId)) + { + handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemTemplate->ItemId); + handler->SetSentErrorMessage(true); return false; + } uint32 itemId = 0; + int32 count = 1; - if (args[0] == '[') // [name] manual form - { - char const* itemNameStr = strtok((char*)args, "]"); - - if (itemNameStr && itemNameStr[0]) - { - std::string itemName = itemNameStr + 1; - - WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME); - stmt->setString(0, itemName); - PreparedQueryResult result = WorldDatabase.Query(stmt); - - if (!result) - { - handler->PSendSysMessage(LANG_COMMAND_COULDNOTFIND, itemNameStr + 1); - handler->SetSentErrorMessage(true); - return false; - } - itemId = result->Fetch()->GetUInt32(); - } - else - return false; - } - else // item_id or [name] Shift-click form |color|Hitem:item_id:0:0:0|h[name]|h|r + if (_count) { - char const* id = handler->extractKeyFromLink((char*)args, "Hitem"); - if (!id) - return false; - itemId = uint32(atol(id)); + count = *_count; } - char const* ccount = strtok(nullptr, " "); - - int32 count = 1; - - if (ccount) - count = strtol(ccount, nullptr, 10); - - if (count == 0) + if (!count) + { count = 1; + } Player* player = handler->GetSession()->GetPlayer(); Player* playerTarget = handler->getSelectedPlayer(); - if (!playerTarget) - playerTarget = player; - ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId); - if (!itemTemplate) + if (!playerTarget) { - handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId); - handler->SetSentErrorMessage(true); - return false; + playerTarget = player; } // Subtract @@ -1624,10 +1675,13 @@ public: // check space and find places ItemPosCountVec dest; InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount); - if (msg != EQUIP_ERR_OK) // convert to possible store amount + + if (msg != EQUIP_ERR_OK) // convert to possible store amount + { count -= noSpaceForCount; + } - if (count == 0 || dest.empty()) // can't add any + if (!count || dest.empty()) // can't add any { handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); handler->SetSentErrorMessage(true); @@ -1638,79 +1692,90 @@ public: // remove binding (let GM give it to another player later) if (player == playerTarget) - for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); ++itr) - if (Item* item1 = player->GetItemByPos(itr->pos)) + { + for (auto const& itemPos : dest) + { + if (Item* item1 = player->GetItemByPos(itemPos.pos)) + { item1->SetBinding(false); + } + } + } - if (count > 0 && item) + if (count && item) { player->SendNewItem(item, count, false, true); + if (player != playerTarget) + { playerTarget->SendNewItem(item, count, true, false); + } } - if (noSpaceForCount > 0) + if (noSpaceForCount) + { handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemId, noSpaceForCount); + } return true; } - static bool HandleAddItemSetCommand(ChatHandler* handler, char const* args) + static bool HandleAddItemSetCommand(ChatHandler* handler, Variant<Hyperlink<itemset>, uint32> itemSetId) { - if (!*args) - return false; - - char const* id = handler->extractKeyFromLink((char*)args, "Hitemset"); // number or [name] Shift-click form |color|Hitemset:itemset_id|h[name]|h|r - if (!id) - return false; - - uint32 itemSetId = atol(id); - // prevent generation all items with itemset field value '0' - if (itemSetId == 0) + if (!*itemSetId) { - handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, itemSetId); + handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, uint32(itemSetId)); handler->SetSentErrorMessage(true); return false; } Player* player = handler->GetSession()->GetPlayer(); Player* playerTarget = handler->getSelectedPlayer(); + if (!playerTarget) + { playerTarget = player; + } bool found = false; - ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore(); - for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr) + + for (auto const& [itemid, itemTemplate] : *sObjectMgr->GetItemTemplateStore()) { - if (itr->second.ItemSet == itemSetId) + if (itemTemplate.ItemSet == uint32(itemSetId)) { found = true; ItemPosCountVec dest; - InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itr->second.ItemId, 1); + InventoryResult msg = playerTarget->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemTemplate.ItemId, 1); + if (msg == EQUIP_ERR_OK) { - Item* item = playerTarget->StoreNewItem(dest, itr->second.ItemId, true); + Item* item = playerTarget->StoreNewItem(dest, itemTemplate.ItemId, true); // remove binding (let GM give it to another player later) if (player == playerTarget) + { item->SetBinding(false); + } player->SendNewItem(item, 1, false, true); + if (player != playerTarget) + { playerTarget->SendNewItem(item, 1, true, false); + } } else { - player->SendEquipError(msg, nullptr, nullptr, itr->second.ItemId); - handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itr->second.ItemId, 1); + player->SendEquipError(msg, nullptr, nullptr, itemTemplate.ItemId); + handler->PSendSysMessage(LANG_ITEM_CANNOT_CREATE, itemTemplate.ItemId, 1); } } } if (!found) { - handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, itemSetId); + handler->PSendSysMessage(LANG_NO_ITEMS_FROM_ITEMSET_FOUND, uint32(itemSetId)); handler->SetSentErrorMessage(true); return false; } @@ -1718,11 +1783,8 @@ public: return true; } - static bool HandleChangeWeather(ChatHandler* handler, char const* args) + static bool HandleChangeWeather(ChatHandler* handler, uint32 type, float grade) { - if (!*args) - return false; - // Weather is OFF if (!sWorld->getBoolConfig(CONFIG_WEATHER)) { @@ -1731,23 +1793,16 @@ public: return false; } - // *Change the weather of a cell - char const* px = strtok((char*)args, " "); - char const* py = strtok(nullptr, " "); - - if (!px || !py) - return false; - - uint32 type = uint32(atoi(px)); //0 to 3, 0: fine, 1: rain, 2: snow, 3: sand - float grade = float(atof(py)); //0 to 1, sending -1 is instand good weather - Player* player = handler->GetSession()->GetPlayer(); uint32 zoneid = player->GetZoneId(); Weather* weather = WeatherMgr::FindWeather(zoneid); if (!weather) + { weather = WeatherMgr::AddWeather(zoneid); + } + if (!weather) { handler->SendSysMessage(LANG_NO_WEATHER); @@ -1760,7 +1815,7 @@ public: return true; } - static bool HandleMaxSkillCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleMaxSkillCommand(ChatHandler* handler) { Player* SelectedPlayer = handler->getSelectedPlayer(); if (!SelectedPlayer) @@ -1775,29 +1830,17 @@ public: return true; } - static bool HandleSetSkillCommand(ChatHandler* handler, char const* args) + static bool HandleSetSkillCommand(ChatHandler* handler, Variant<Hyperlink<skill>, uint32> skillId, int32 level, Optional<uint16> maxPureSkill) { - // number or [name] Shift-click form |color|Hskill:skill_id|h[name]|h|r - char const* skillStr = handler->extractKeyFromLink((char*)args, "Hskill"); - if (!skillStr) - return false; - - char const* levelStr = strtok(nullptr, " "); - if (!levelStr) - return false; - - char const* maxPureSkill = strtok(nullptr, " "); + uint32 skillID = uint32(skillId); - int32 skill = atoi(skillStr); - if (skill <= 0) + if (skillID <= 0) { - handler->PSendSysMessage(LANG_INVALID_SKILL_ID, skill); + handler->PSendSysMessage(LANG_INVALID_SKILL_ID, skillID); handler->SetSentErrorMessage(true); return false; } - int32 level = uint32(atol(levelStr)); - Player* target = handler->getSelectedPlayer(); if (!target) { @@ -1806,53 +1849,54 @@ public: return false; } - SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skill); + SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillID); if (!skillLine) { - handler->PSendSysMessage(LANG_INVALID_SKILL_ID, skill); + handler->PSendSysMessage(LANG_INVALID_SKILL_ID, uint32(skillID)); handler->SetSentErrorMessage(true); return false; } - bool targetHasSkill = target->GetSkillValue(skill); + bool targetHasSkill = target->GetSkillValue(skillID); // If our target does not yet have the skill they are trying to add to them, the chosen level also becomes // the max level of the new profession. - uint16 max = maxPureSkill ? atol (maxPureSkill) : targetHasSkill ? target->GetPureMaxSkillValue(skill) : uint16(level); + uint16 max = maxPureSkill ? *maxPureSkill : targetHasSkill ? target->GetPureMaxSkillValue(skillID) : uint16(level); if (level <= 0 || level > max || max <= 0) + { return false; + } // If the player has the skill, we get the current skill step. If they don't have the skill, we // add the skill to the player's book with step 1 (which is the first rank, in most cases something // like 'Apprentice <skill>'. - target->SetSkill(skill, targetHasSkill ? target->GetSkillStep(skill) : 1, level, max); - handler->PSendSysMessage(LANG_SET_SKILL, skill, skillLine->name[handler->GetSessionDbcLocale()], handler->GetNameLink(target).c_str(), level, max); + target->SetSkill(skillID, targetHasSkill ? target->GetSkillStep(skillID) : 1, level, max); + handler->PSendSysMessage(LANG_SET_SKILL, skillID, skillLine->name[handler->GetSessionDbcLocale()], handler->GetNameLink(target).c_str(), level, max); return true; } // show info of player - static bool HandlePInfoCommand(ChatHandler* handler, char const* args) + static bool HandlePInfoCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - CharacterDatabasePreparedStatement* stmt = nullptr; - LoginDatabasePreparedStatement* loginStmt = nullptr; - - ObjectGuid parseGUID = ObjectGuid::Create<HighGuid::Player>(atol((char*)args)); - - if (sCharacterCache->GetCharacterNameByGuid(parseGUID, targetName)) + if (!target) { - target = ObjectAccessor::FindConnectedPlayer(parseGUID); - targetGuid = parseGUID; + target = PlayerIdentifier::FromTargetOrSelf(handler); } - else if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + + if (!target) + { return false; + } + + Player* playerTarget = target->GetConnectedPlayer(); + + CharacterDatabasePreparedStatement* stmt = nullptr; + LoginDatabasePreparedStatement* loginStmt = nullptr; // Account data print variables std::string userName = handler->GetAcoreString(LANG_ERROR); - ObjectGuid::LowType lowguid = targetGuid.GetCounter(); + ObjectGuid::LowType lowguid = target->GetGUID().GetCounter(); uint32 accId = 0; std::string eMail = handler->GetAcoreString(LANG_ERROR); std::string regMail = handler->GetAcoreString(LANG_ERROR); @@ -1903,32 +1947,36 @@ public: std::string officeNote; // get additional information from Player object - if (target) + if (playerTarget) { // check online security - if (handler->HasLowerSecurity(target)) + if (handler->HasLowerSecurity(playerTarget)) + { return false; + } - accId = target->GetSession()->GetAccountId(); - money = target->GetMoney(); - totalPlayerTime = target->GetTotalPlayedTime(); - level = target->getLevel(); - latency = target->GetSession()->GetLatency(); - raceid = target->getRace(); - classid = target->getClass(); - muteTime = target->GetSession()->m_muteTime; - mapId = target->GetMapId(); - areaId = target->GetAreaId(); - alive = target->IsAlive() ? handler->GetAcoreString(LANG_YES) : handler->GetAcoreString(LANG_NO); - gender = target->getGender(); - phase = target->GetPhaseMask(); + accId = playerTarget->GetSession()->GetAccountId(); + money = playerTarget->GetMoney(); + totalPlayerTime = playerTarget->GetTotalPlayedTime(); + level = playerTarget->getLevel(); + latency = playerTarget->GetSession()->GetLatency(); + raceid = playerTarget->getRace(); + classid = playerTarget->getClass(); + muteTime = playerTarget->GetSession()->m_muteTime; + mapId = playerTarget->GetMapId(); + areaId = playerTarget->GetAreaId(); + alive = playerTarget->IsAlive() ? handler->GetAcoreString(LANG_YES) : handler->GetAcoreString(LANG_NO); + gender = playerTarget->getGender(); + phase = playerTarget->GetPhaseMask(); } // get additional information from DB else { // check offline security - if (handler->HasLowerSecurity(nullptr, targetGuid)) + if (handler->HasLowerSecurity(nullptr, target->GetGUID())) + { return false; + } // Query informations from the DB stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PINFO); @@ -1936,7 +1984,9 @@ public: PreparedQueryResult charInfoResult = CharacterDatabase.Query(stmt); if (!charInfoResult) + { return false; + } Field* fields = charInfoResult->Fetch(); totalPlayerTime = fields[0].GetUInt32(); @@ -1952,9 +2002,13 @@ public: uint32 playerFlags = fields[10].GetUInt32(); if (!health || playerFlags & PLAYER_FLAGS_GHOST) + { alive = handler->GetAcoreString(LANG_NO); + } else + { alive = handler->GetAcoreString(LANG_YES); + } } // Query the prepared statement for login data @@ -1991,6 +2045,7 @@ public: lastIp = handler->GetAcoreString(LANG_UNAUTHORIZED); lastLogin = handler->GetAcoreString(LANG_UNAUTHORIZED); } + muteTime = fields[6].GetUInt64(); muteReason = fields[7].GetString(); muteBy = fields[8].GetString(); @@ -2000,7 +2055,7 @@ public: } // Creates a chat link to the character. Returns nameLink - std::string nameLink = handler->playerLink(targetName); + std::string nameLink = handler->playerLink(target->GetName()); // Returns banType, banTime, bannedBy, banreason LoginDatabasePreparedStatement* banQuery = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO_BANS); @@ -2065,19 +2120,25 @@ public: // Initiate output // Output I. LANG_PINFO_PLAYER - handler->PSendSysMessage(LANG_PINFO_PLAYER, target ? "" : handler->GetAcoreString(LANG_OFFLINE), nameLink.c_str(), targetGuid.GetCounter()); + handler->PSendSysMessage(LANG_PINFO_PLAYER, playerTarget ? "" : handler->GetAcoreString(LANG_OFFLINE), nameLink.c_str(), target->GetGUID().GetCounter()); // Output II. LANG_PINFO_GM_ACTIVE if character is gamemaster - if (target && target->IsGameMaster()) + if (playerTarget && playerTarget->IsGameMaster()) + { handler->PSendSysMessage(LANG_PINFO_GM_ACTIVE); + } // Output III. LANG_PINFO_BANNED if ban exists and is applied if (banTime >= 0) + { handler->PSendSysMessage(LANG_PINFO_BANNED, banType.c_str(), banReason.c_str(), banTime > 0 ? secsToTimeString(banTime - time(nullptr), true).c_str() : handler->GetAcoreString(LANG_PERMANENTLY), bannedBy.c_str()); + } // Output IV. LANG_PINFO_MUTED if mute is applied if (muteTime > 0) + { handler->PSendSysMessage(LANG_PINFO_MUTED, muteReason.c_str(), secsToTimeString(muteTime - time(nullptr), true).c_str(), muteBy.c_str()); + } // Output V. LANG_PINFO_ACC_ACCOUNT handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security); @@ -2096,9 +2157,13 @@ public: // Output X. LANG_PINFO_CHR_LEVEL if (level != sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { handler->PSendSysMessage(LANG_PINFO_CHR_LEVEL_LOW, level, xp, xptotal, (xptotal - xp)); + } else + { handler->PSendSysMessage(LANG_PINFO_CHR_LEVEL_HIGH, level); + } // Output XI. LANG_PINFO_CHR_RACE switch (raceid) @@ -2175,18 +2240,22 @@ public: handler->PSendSysMessage(LANG_PINFO_CHR_ALIVE, alive.c_str()); // Output XIII. LANG_PINFO_CHR_PHASE if player is not in GM mode (GM is in every phase) - if (target && !target->IsGameMaster()) // IsInWorld() returns false on loadingscreen, so it's more - handler->PSendSysMessage(LANG_PINFO_CHR_PHASE, phase); // precise than just target (safer ?). + if (playerTarget && !playerTarget->IsGameMaster()) // IsInWorld() returns false on loadingscreen, so it's more + { + handler->PSendSysMessage(LANG_PINFO_CHR_PHASE, phase); // precise than just target (safer ?). + } + // However, as we usually just require a target here, we use target instead. // Output XIV. LANG_PINFO_CHR_MONEY - uint32 gold = money / GOLD; - uint32 silv = (money % GOLD) / SILVER; - uint32 copp = (money % GOLD) % SILVER; + uint32 gold = money / GOLD; + uint32 silv = (money % GOLD) / SILVER; + uint32 copp = (money % GOLD) % SILVER; handler->PSendSysMessage(LANG_PINFO_CHR_MONEY, gold, silv, copp); // Position data MapEntry const* map = sMapStore.LookupEntry(mapId); AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId); + if (area) { zoneName = area->area_name[locale]; @@ -2200,22 +2269,34 @@ public: } if (!zoneName) + { zoneName = handler->GetAcoreString(LANG_UNKNOWN); + } if (areaName) + { handler->PSendSysMessage(LANG_PINFO_CHR_MAP_WITH_AREA, map->name[locale], zoneName, areaName); + } else + { handler->PSendSysMessage(LANG_PINFO_CHR_MAP, map->name[locale], zoneName); + } // Output XVII. - XVIX. if they are not empty if (!guildName.empty()) { handler->PSendSysMessage(LANG_PINFO_CHR_GUILD, guildName.c_str(), guildId); handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_RANK, guildRank.c_str(), uint32(guildRankId)); + if (!note.empty()) + { handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_NOTE, note.c_str()); + } + if (!officeNote.empty()) + { handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_ONOTE, officeNote.c_str()); + } } // Output XX. LANG_PINFO_CHR_PLAYEDTIME @@ -2235,13 +2316,15 @@ public: // Output XXI. LANG_INFO_CHR_MAILS if at least one mail is given if (totalmail >= 1) + { handler->PSendSysMessage(LANG_PINFO_CHR_MAILS, readmail, totalmail); + } } return true; } - static bool HandleRespawnCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleRespawnCommand(ChatHandler* handler) { Player* player = handler->GetSession()->GetPlayer(); @@ -2257,7 +2340,9 @@ public: } if (target->isDead()) + { target->ToCreature()->Respawn(); + } return true; } @@ -2271,16 +2356,21 @@ public: return true; } + // mute player for some times static bool HandleMuteCommand(ChatHandler* handler, Optional<PlayerIdentifier> player, uint32 notSpeakTime, Tail muteReason) { std::string muteReasonStr{ muteReason }; if (muteReason.empty()) + { muteReasonStr = handler->GetAcoreString(LANG_NO_REASON); + } if (!player) + { player = PlayerIdentifier::FromTarget(handler); + } if (!player) { @@ -2295,18 +2385,26 @@ public: // find only player from same account if any if (!target) if (WorldSession* session = sWorld->FindSession(accountId)) + { target = session->GetPlayer(); + } // must have strong lesser security level if (handler->HasLowerSecurity(target, player->GetGUID(), true)) + { return false; + } LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); std::string muteBy = ""; if (handler->GetSession()) + { muteBy = handler->GetSession()->GetPlayerName(); + } else + { muteBy = handler->GetAcoreString(LANG_CONSOLE); + } if (target) { @@ -2317,7 +2415,9 @@ public: std::string nameLink = handler->playerLink(player->GetName()); if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD)) + { sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); + } ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notSpeakTime, muteBy.c_str(), muteReasonStr.c_str()); } @@ -2342,7 +2442,9 @@ public: std::string nameLink = handler->playerLink(player->GetName()); if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD) && !target) + { sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); + } else { // pussywizard: notify all online GMs @@ -2351,42 +2453,53 @@ public: for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr) if (itr->second->GetSession()->GetSecurity()) ChatHandler(itr->second->GetSession()).PSendSysMessage(target ? LANG_YOU_DISABLE_CHAT : LANG_COMMAND_DISABLE_CHAT_DELAYED, - (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : handler->GetAcoreString(LANG_CONSOLE)), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); + (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : handler->GetAcoreString(LANG_CONSOLE)), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); } return true; } // unmute player - static bool HandleUnmuteCommand(ChatHandler* handler, char const* args) + static bool HandleUnmuteCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { return false; + } - uint32 accountId = target ? target->GetSession()->GetAccountId() : sCharacterCache->GetCharacterAccountIdByGuid(targetGuid); + Player* playerTarget = target->GetConnectedPlayer(); + uint32 accountId = playerTarget ? playerTarget->GetSession()->GetAccountId() : sCharacterCache->GetCharacterAccountIdByGuid(target->GetGUID()); // find only player from same account if any - if (!target) + if (!playerTarget) + { if (WorldSession* session = sWorld->FindSession(accountId)) - target = session->GetPlayer(); + { + playerTarget = session->GetPlayer(); + } + } // must have strong lesser security level - if (handler->HasLowerSecurity (target, targetGuid, true)) + if (handler->HasLowerSecurity(playerTarget, target->GetGUID(), true)) + { return false; + } - if (target) + if (playerTarget) { - if (target->CanSpeak()) + if (playerTarget->CanSpeak()) { handler->SendSysMessage(LANG_CHAT_ALREADY_ENABLED); handler->SetSentErrorMessage(true); return false; } - target->GetSession()->m_muteTime = 0; + playerTarget->GetSession()->m_muteTime = 0; } LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); @@ -2396,27 +2509,19 @@ public: stmt->setUInt32(3, accountId); LoginDatabase.Execute(stmt); - if (target) - ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); - - std::string nameLink = handler->playerLink(targetName); + if (playerTarget) + { + ChatHandler(playerTarget->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_ENABLED); + } - handler->PSendSysMessage(LANG_YOU_ENABLE_CHAT, nameLink.c_str()); + handler->PSendSysMessage(LANG_YOU_ENABLE_CHAT, handler->playerLink(target->GetName().c_str())); return true; } // mutehistory command - static bool HandleMuteInfoCommand(ChatHandler* handler, char const* args) + static bool HandleMuteInfoCommand(ChatHandler* handler, std::string accountName) { - if (!*args) - return false; - - char* nameStr = strtok((char*)args, ""); - if (!nameStr) - return false; - - std::string accountName = nameStr; if (!Utf8ToUpperOnlyLatin(accountName)) { handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str()); @@ -2431,11 +2536,11 @@ public: return false; } - return HandleMuteInfoHelper(accountId, accountName.c_str(), handler); + return HandleMuteInfoHelper(handler, accountId, accountName.c_str()); } // helper for mutehistory - static bool HandleMuteInfoHelper(uint32 accountId, char const* accountName, ChatHandler* handler) + static bool HandleMuteInfoHelper(ChatHandler* handler, uint32 accountId, char const* accountName) { LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO); stmt->setUInt16(0, accountId); @@ -2463,10 +2568,11 @@ public: handler->PSendSysMessage(LANG_COMMAND_MUTEHISTORY_OUTPUT, buffer, fields[1].GetUInt32(), fields[2].GetCString(), fields[3].GetCString()); } while (result->NextRow()); + return true; } - static bool HandleMovegensCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleMovegensCommand(ChatHandler* handler) { Unit* unit = handler->getSelectedUnit(); if (!unit) @@ -2509,53 +2615,77 @@ public: handler->SendSysMessage(LANG_MOVEGENS_CONFUSED); break; case CHASE_MOTION_TYPE: + { + Unit* target = nullptr; + if (unit->GetTypeId() == TYPEID_PLAYER) + { + target = static_cast<ChaseMovementGenerator<Player> const*>(movementGenerator)->GetTarget(); + } + else + { + target = static_cast<ChaseMovementGenerator<Creature> const*>(movementGenerator)->GetTarget(); + } + + if (!target) { - Unit* target = nullptr; - if (unit->GetTypeId() == TYPEID_PLAYER) - target = static_cast<ChaseMovementGenerator<Player> const*>(movementGenerator)->GetTarget(); - else - target = static_cast<ChaseMovementGenerator<Creature> const*>(movementGenerator)->GetTarget(); - - if (!target) - handler->SendSysMessage(LANG_MOVEGENS_CHASE_NULL); - else if (target->GetTypeId() == TYPEID_PLAYER) - handler->PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, target->GetName().c_str(), target->GetGUID().GetCounter()); - else - handler->PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, target->GetName().c_str(), target->GetGUID().GetCounter()); - break; + handler->SendSysMessage(LANG_MOVEGENS_CHASE_NULL); } + else if (target->GetTypeId() == TYPEID_PLAYER) + { + handler->PSendSysMessage(LANG_MOVEGENS_CHASE_PLAYER, target->GetName().c_str(), target->GetGUID().GetCounter()); + } + else + { + handler->PSendSysMessage(LANG_MOVEGENS_CHASE_CREATURE, target->GetName().c_str(), target->GetGUID().GetCounter()); + } + break; + } case FOLLOW_MOTION_TYPE: + { + Unit* target = nullptr; + if (unit->GetTypeId() == TYPEID_PLAYER) { - Unit* target = nullptr; - if (unit->GetTypeId() == TYPEID_PLAYER) - target = static_cast<FollowMovementGenerator<Player> const*>(movementGenerator)->GetTarget(); - else - target = static_cast<FollowMovementGenerator<Creature> const*>(movementGenerator)->GetTarget(); - - if (!target) - handler->SendSysMessage(LANG_MOVEGENS_FOLLOW_NULL); - else if (target->GetTypeId() == TYPEID_PLAYER) - handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, target->GetName().c_str(), target->GetGUID().GetCounter()); - else - handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, target->GetName().c_str(), target->GetGUID().GetCounter()); - break; + target = static_cast<FollowMovementGenerator<Player> const*>(movementGenerator)->GetTarget(); } + else + { + target = static_cast<FollowMovementGenerator<Creature> const*>(movementGenerator)->GetTarget(); + } + + if (!target) + { + handler->SendSysMessage(LANG_MOVEGENS_FOLLOW_NULL); + } + else if (target->GetTypeId() == TYPEID_PLAYER) + { + handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_PLAYER, target->GetName().c_str(), target->GetGUID().GetCounter()); + } + else + { + handler->PSendSysMessage(LANG_MOVEGENS_FOLLOW_CREATURE, target->GetName().c_str(), target->GetGUID().GetCounter()); + } + break; + } case HOME_MOTION_TYPE: + { + if (unit->GetTypeId() == TYPEID_UNIT) { - if (unit->GetTypeId() == TYPEID_UNIT) - handler->PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE, x, y, z); - else - handler->SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); - break; + handler->PSendSysMessage(LANG_MOVEGENS_HOME_CREATURE, x, y, z); } + else + { + handler->SendSysMessage(LANG_MOVEGENS_HOME_PLAYER); + } + break; + } case FLIGHT_MOTION_TYPE: handler->SendSysMessage(LANG_MOVEGENS_FLIGHT); break; case POINT_MOTION_TYPE: - { - handler->PSendSysMessage(LANG_MOVEGENS_POINT, x, y, z); - break; - } + { + handler->PSendSysMessage(LANG_MOVEGENS_POINT, x, y, z); + break; + } case FLEEING_MOTION_TYPE: handler->SendSysMessage(LANG_MOVEGENS_FEAR); break; @@ -2577,12 +2707,8 @@ public: Without this function 3rd party scripting library will get linking errors (unresolved external) when attempting to use the PointMovementGenerator */ - static bool HandleComeToMeCommand(ChatHandler* handler, char const* args) + static bool HandleComeToMeCommand(ChatHandler* handler) { - char const* newFlagStr = strtok((char*)args, " "); - if (!newFlagStr) - return false; - Creature* caster = handler->getSelectedCreature(); if (!caster) { @@ -2598,11 +2724,8 @@ public: return true; } - static bool HandleDamageCommand(ChatHandler* handler, char const* args) + static bool HandleDamageCommand(ChatHandler* handler, uint32 damage) { - if (!*args) - return false; - Unit* target = handler->getSelectedUnit(); if (!target || !handler->GetSession()->GetPlayer()->GetTarget()) { @@ -2614,749 +2737,159 @@ public: if (target->GetTypeId() == TYPEID_PLAYER) { if (handler->HasLowerSecurity(target->ToPlayer())) - return false; - } - - if (!target->IsAlive()) - return true; - - int32 damage_int = atoi(args); - if (damage_int <= 0) - return true; - - uint32 damage = damage_int; - - if (target->GetTypeId() == TYPEID_UNIT && handler->GetSession()->GetSecurity() == SEC_CONSOLE) // pussywizard - target->ToCreature()->LowerPlayerDamageReq(target->GetMaxHealth()); - Unit::DealDamage(handler->GetSession()->GetPlayer(), target, damage, nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false, true); - if (target != handler->GetSession()->GetPlayer()) - handler->GetSession()->GetPlayer()->SendAttackStateUpdate (HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0); - return true; - } - - static bool HandleCombatStopCommand(ChatHandler* handler, char const* args) - { - Player* target = nullptr; - - if (args && strlen(args) > 0) - { - target = ObjectAccessor::FindPlayerByName(args); - if (!target) { - handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); return false; } } - if (!target) - { - if (!handler->extractPlayerTarget((char*)args, &target)) - return false; - } - - // check online security - if (handler->HasLowerSecurity(target)) - return false; - - target->CombatStop(); - target->getHostileRefMgr().deleteReferences(); - return true; - } - - static bool HandleFlushArenaPointsCommand(ChatHandler* /*handler*/, char const* /*args*/) - { - sArenaTeamMgr->DistributeArenaPoints(); - return true; - } - - static bool HandleGearRepairCommand(ChatHandler* handler, char const* args) - { - Player* target; - if (!handler->extractPlayerTarget((char*)args, &target)) - return false; - - // check online security - if (handler->HasLowerSecurity(target)) - return false; - - // Repair items - target->DurabilityRepairAll(false, 0, false); - - handler->PSendSysMessage(LANG_YOU_REPAIR_ITEMS, handler->GetNameLink(target).c_str()); - if (handler->needReportToTarget(target)) - ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, handler->GetNameLink().c_str()); - - return true; - } - - // Send mail by command - static bool HandleSendMailCommand(ChatHandler* handler, char const* args) - { - // format: name "subject text" "mail text" - Player* target; - ObjectGuid targetGuid; - std::string targetName; - if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) - return false; - - char* tail1 = strtok(nullptr, ""); - if (!tail1) - return false; - - char const* msgSubject = handler->extractQuotedArg(tail1); - if (!msgSubject) - return false; - - char* tail2 = strtok(nullptr, ""); - if (!tail2) - return false; - - char const* msgText = handler->extractQuotedArg(tail2); - if (!msgText) - return false; - - // msgSubject, msgText isn't NUL after prev. check - std::string subject = msgSubject; - std::string text = msgText; - - ObjectGuid::LowType senderGuid; - // If the message is sent from console, set it as sent by the target itself, like the other Customer Support mails. - senderGuid = handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : targetGuid.GetCounter(); - MailSender sender(MAIL_NORMAL, senderGuid, MAIL_STATIONERY_GM); - - //- TODO: Fix poor design - CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - MailDraft(subject, text) - .SendMailTo(trans, MailReceiver(target, targetGuid.GetCounter()), sender); - - CharacterDatabase.CommitTransaction(trans); - - std::string nameLink = handler->playerLink(targetName); - handler->PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); - return true; - } - // Send items by mail - static bool HandleSendItemsCommand(ChatHandler* handler, char const* args) - { - // format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12] - Player* receiver; - ObjectGuid receiverGuid; - std::string receiverName; - if (!handler->extractPlayerTarget((char*)args, &receiver, &receiverGuid, &receiverName)) - return false; - - char* tail1 = strtok(nullptr, ""); - if (!tail1) - return false; - - char const* msgSubject = handler->extractQuotedArg(tail1); - if (!msgSubject) - return false; - - char* tail2 = strtok(nullptr, ""); - if (!tail2) - return false; - - char const* msgText = handler->extractQuotedArg(tail2); - if (!msgText) - return false; - - // msgSubject, msgText isn't NUL after prev. check - std::string subject = msgSubject; - std::string text = msgText; - - // extract items - typedef std::pair<uint32, uint32> ItemPair; - typedef std::list< ItemPair > ItemPairs; - ItemPairs items; - - // get all tail string - char* tail = strtok(nullptr, ""); - - // get from tail next item str - while (char* itemStr = strtok(tail, " ")) - { - // and get new tail - tail = strtok(nullptr, ""); - - // parse item str - char const* itemIdStr = strtok(itemStr, ":"); - char const* itemCountStr = strtok(nullptr, " "); - - uint32 itemId = atoi(itemIdStr); - if (!itemId) - return false; - - ItemTemplate const* item_proto = sObjectMgr->GetItemTemplate(itemId); - if (!item_proto) - { - handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemId); - handler->SetSentErrorMessage(true); - return false; - } - - uint32 itemCount = itemCountStr ? atoi(itemCountStr) : 1; - if (itemCount < 1 || (item_proto->MaxCount > 0 && itemCount > uint32(item_proto->MaxCount))) - { - handler->PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, itemCount, itemId); - handler->SetSentErrorMessage(true); - return false; - } - - while (itemCount > item_proto->GetMaxStackSize()) - { - items.push_back(ItemPair(itemId, item_proto->GetMaxStackSize())); - itemCount -= item_proto->GetMaxStackSize(); - } - - items.push_back(ItemPair(itemId, itemCount)); - - if (items.size() > MAX_MAIL_ITEMS) - { - handler->PSendSysMessage(LANG_COMMAND_MAIL_ITEMS_LIMIT, MAX_MAIL_ITEMS); - handler->SetSentErrorMessage(true); - return false; - } - } - - ObjectGuid::LowType senderGuid; - // If the message is sent from console, set it as sent by the target itself, like the other Customer Support mails. - senderGuid = handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : receiverGuid.GetCounter(); - MailSender sender(MAIL_NORMAL, senderGuid, MAIL_STATIONERY_GM); - - // fill mail - MailDraft draft(subject, text); - - CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - - for (ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr) - { - if (Item* item = Item::CreateItem(itr->first, itr->second, handler->GetSession() ? handler->GetSession()->GetPlayer() : 0)) - { - item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted - draft.AddItem(item); - } - } - - draft.SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), sender); - CharacterDatabase.CommitTransaction(trans); - - std::string nameLink = handler->playerLink(receiverName); - handler->PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); - return true; - } - /// Send money by mail - static bool HandleSendMoneyCommand(ChatHandler* handler, char const* args) - { - /// format: name "subject text" "mail text" money - - Player* receiver; - ObjectGuid receiverGuid; - std::string receiverName; - if (!handler->extractPlayerTarget((char*)args, &receiver, &receiverGuid, &receiverName)) - return false; - - char* tail1 = strtok(nullptr, ""); - if (!tail1) - return false; - - char* msgSubject = handler->extractQuotedArg(tail1); - if (!msgSubject) - return false; - - char* tail2 = strtok(nullptr, ""); - if (!tail2) - return false; - - char* msgText = handler->extractQuotedArg(tail2); - if (!msgText) - return false; - - char* moneyStr = strtok(nullptr, ""); - int32 money = moneyStr ? atoi(moneyStr) : 0; - if (money <= 0) - return false; - - // msgSubject, msgText isn't NUL after prev. check - std::string subject = msgSubject; - std::string text = msgText; - - // from console show not existed sender - MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : 0, MAIL_STATIONERY_GM); - - CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - - MailDraft(subject, text) - .AddMoney(money) - .SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), sender); - - CharacterDatabase.CommitTransaction(trans); - - std::string nameLink = handler->playerLink(receiverName); - handler->PSendSysMessage(LANG_MAIL_SENT, nameLink.c_str()); - return true; - } - /// Send a message to a player in game - static bool HandleSendMessageCommand(ChatHandler* handler, char const* args) - { - /// - Find the player - Player* player = nullptr; - if (!handler->extractPlayerTarget((char*)args, &player)) - return false; - - if (!player) - return false; - - char* msgStr = strtok(nullptr, ""); - if (!msgStr) - return false; - - /// - Send the message - // Use SendAreaTriggerMessage for fastest delivery. - player->GetSession()->SendAreaTriggerMessage("%s", msgStr); - player->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r"); - - // Confirmation message - std::string nameLink = handler->GetNameLink(player); - handler->PSendSysMessage(LANG_SENDMESSAGE, nameLink.c_str(), msgStr); - - return true; - } - - static bool HandleCreatePetCommand(ChatHandler* handler, char const* /*args*/) - { - Player* player = handler->GetSession()->GetPlayer(); - Creature* creatureTarget = handler->getSelectedCreature(); - - if (!creatureTarget || creatureTarget->IsPet() || creatureTarget->GetTypeId() == TYPEID_PLAYER) - { - handler->PSendSysMessage(LANG_SELECT_CREATURE); - handler->SetSentErrorMessage(true); - return false; - } - - CreatureTemplate const* creatrueTemplate = sObjectMgr->GetCreatureTemplate(creatureTarget->GetEntry()); - // Creatures with family 0 crashes the server - if (!creatrueTemplate->family) + if (!target->IsAlive()) { - handler->PSendSysMessage("This creature cannot be tamed. (family id: 0)."); - handler->SetSentErrorMessage(true); - return false; + return true; } - if (player->GetPetGUID()) + if (!damage) { - handler->PSendSysMessage("You already have a pet"); - handler->SetSentErrorMessage(true); - return false; + return true; } - // Everything looks OK, create new pet - Pet* pet = new Pet(player, HUNTER_PET); - if (!pet->CreateBaseAtCreature(creatureTarget)) + if (target->GetTypeId() == TYPEID_UNIT && handler->GetSession()->GetSecurity() == SEC_CONSOLE) // pussywizard { - delete pet; - handler->PSendSysMessage("Error 1"); - return false; + target->ToCreature()->LowerPlayerDamageReq(target->GetMaxHealth()); } - creatureTarget->setDeathState(JUST_DIED); - creatureTarget->RemoveCorpse(); - creatureTarget->SetHealth(0); // just for nice GM-mode view - - pet->SetGuidValue(UNIT_FIELD_CREATEDBY, player->GetGUID()); - pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, player->GetFaction()); + Unit::DealDamage(handler->GetSession()->GetPlayer(), target, damage, nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false, true); - if (!pet->InitStatsForLevel(creatureTarget->getLevel())) + if (target != handler->GetSession()->GetPlayer()) { - LOG_ERROR("misc", "InitStatsForLevel() in EffectTameCreature failed! Pet deleted."); - handler->PSendSysMessage("Error 2"); - delete pet; - return false; + handler->GetSession()->GetPlayer()->SendAttackStateUpdate(HITINFO_AFFECTS_VICTIM, target, 1, SPELL_SCHOOL_MASK_NORMAL, damage, 0, 0, VICTIMSTATE_HIT, 0); } - // prepare visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, creatureTarget->getLevel() - 1); - - pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true); - // this enables pet details window (Shift+P) - pet->InitPetCreateSpells(); - pet->SetFullHealth(); - - pet->GetMap()->AddToMap(pet->ToCreature()); - - // visual effect for levelup - pet->SetUInt32Value(UNIT_FIELD_LEVEL, creatureTarget->getLevel()); - - player->SetMinion(pet, true); - pet->SavePetToDB(PET_SAVE_AS_CURRENT, false); - player->PetSpellInitialize(); - return true; } - static bool HandlePetLearnCommand(ChatHandler* handler, char const* args) + static bool HandleCombatStopCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - if (!*args) - return false; - - Player* player = handler->GetSession()->GetPlayer(); - Pet* pet = player->GetPet(); - - if (!pet) + if (!target) { - handler->PSendSysMessage("You have no pet"); - handler->SetSentErrorMessage(true); - return false; + target = PlayerIdentifier::FromTargetOrSelf(handler); } - uint32 spellId = handler->extractSpellIdFromLink((char*)args); - if (!spellId) - return false; - - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (!spellInfo) + if (!target || !target->IsConnected()) { - handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); - handler->SetSentErrorMessage(true); - return false; - } - - if (!SpellMgr::IsSpellValid(spellInfo)) - { - handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spellId); + handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); handler->SetSentErrorMessage(true); return false; } - SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spellId); - uint32 spellDifficultyId = sSpellMgr->GetSpellDifficultyId(spellId); - if (bounds.first != bounds.second || spellDifficultyId) - { - handler->PSendSysMessage("Spell %u cannot be learnt using a command!", spellId); - handler->SetSentErrorMessage(true); - return false; - } + Player* playerTarget = target->GetConnectedPlayer(); - // Check if pet already has it - if (pet->HasSpell(spellId)) + // check online security + if (handler->HasLowerSecurity(playerTarget)) { - handler->PSendSysMessage("Pet already has spell: %u", spellId); - handler->SetSentErrorMessage(true); return false; } - pet->learnSpell(spellId); - - handler->PSendSysMessage("Pet has learned spell %u", spellId); + playerTarget->CombatStop(); + playerTarget->getHostileRefMgr().deleteReferences(); return true; } - static bool HandlePetUnlearnCommand(ChatHandler* handler, char const* args) + static bool HandleFlushArenaPointsCommand(ChatHandler* /*handler*/) { - if (!*args) - return false; - - Player* player = handler->GetSession()->GetPlayer(); - Pet* pet = player->GetPet(); - if (!pet) - { - handler->PSendSysMessage("You have no pet"); - handler->SetSentErrorMessage(true); - return false; - } - - uint32 spellId = handler->extractSpellIdFromLink((char*)args); - - if (pet->HasSpell(spellId)) - pet->removeSpell(spellId, false); - else - handler->PSendSysMessage("Pet doesn't have that spell"); - + sArenaTeamMgr->DistributeArenaPoints(); return true; } - static bool HandleFreezeCommand(ChatHandler* handler, char const* args) + static bool HandleFreezeCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - std::string name; - Unit* target = handler->getSelectedUnit(); - Player* player; - constexpr int Freeze = 9454; - char const* TargetName = strtok((char*)args, " "); // get entered name - if (!TargetName) // if no name entered use target - { - player = handler->getSelectedPlayer(); - if (player) //prevent crash with creature as target - { - name = player->GetName(); - normalizePlayerName(name); - } - } - else // if name entered - { - name = TargetName; - normalizePlayerName(name); - player = ObjectAccessor::FindPlayerByName(name); - } - - if (player == handler->GetSession()->GetPlayer()) - { - handler->SendSysMessage(LANG_COMMAND_FREEZE_ERROR); - return true; - } + Creature* creatureTarget = handler->getSelectedCreature(); - if (player && (player != handler->GetSession()->GetPlayer())) + if (!target && !creatureTarget) { - handler->PSendSysMessage(LANG_COMMAND_FREEZE, name.c_str()); - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(Freeze)) - Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, player, player); + target = PlayerIdentifier::FromTargetOrSelf(handler); } - if (!target || !handler->GetSession()->GetPlayer()->GetTarget()) + if (!target && !creatureTarget) { handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); handler->SetSentErrorMessage(true); return false; } - if (target->IsAlive()) - { - handler->PSendSysMessage(LANG_COMMAND_FREEZE, name.c_str()); - if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(Freeze)) - Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, target, target); - } - - return true; - } - - static bool HandleUnFreezeCommand(ChatHandler* handler, char const* args) - { - std::string name; - Unit* target = handler->getSelectedUnit(); - Player* player; - constexpr int Freeze = 9454; - char* targetName = strtok((char*)args, " "); // Get entered name - - if (target->HasAura(Freeze)) + Player* playerTarget = target->GetConnectedPlayer(); + if (playerTarget && !creatureTarget) { - handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str()); - target->RemoveAurasDueToSpell(Freeze); - return true; - } + handler->PSendSysMessage(LANG_COMMAND_FREEZE, target->GetName().c_str()); - if (targetName) - { - name = targetName; - normalizePlayerName(name); - player = ObjectAccessor::FindPlayerByName(name); - } - else // If no name was entered - use target - { - player = handler->getSelectedPlayer(); - if (player) - name = player->GetName(); - } + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_FREEZE)) + { + Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, playerTarget, playerTarget); + } - if (player) - { - handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str()); - player->RemoveAurasDueToSpell(9454); return true; } - else if (targetName) + else if (creatureTarget && creatureTarget->IsAlive()) { - if (ObjectGuid playerGUID = sCharacterCache->GetCharacterGuidByName(name)) - { - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_FROZEN); - stmt->setUInt32(0, playerGUID.GetCounter()); - CharacterDatabase.Execute(stmt); - handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, name.c_str()); - return true; - } - } + handler->PSendSysMessage(LANG_COMMAND_FREEZE, GetLocalizeCreatureName(creatureTarget, handler->GetSessionDbcLocale()).c_str()); - handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG); - return true; - } - - static bool HandleGroupLeaderCommand(ChatHandler* handler, char const* args) - { - Player* player = nullptr; - Group* group = nullptr; - ObjectGuid guid; - char* nameStr = strtok((char*)args, " "); - - if (handler->GetPlayerGroupAndGUIDByName(nameStr, player, group, guid)) - if (group && group->GetLeaderGUID() != guid) + if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_FREEZE)) { - group->ChangeLeader(guid); - group->SendUpdate(); + Aura::TryRefreshStackOrCreate(spellInfo, MAX_EFFECT_MASK, creatureTarget, creatureTarget); } - return true; - } - - static bool HandleGroupDisbandCommand(ChatHandler* handler, char const* args) - { - Player* player = nullptr; - Group* group = nullptr; - ObjectGuid guid; - char* nameStr = strtok((char*)args, " "); - - if (handler->GetPlayerGroupAndGUIDByName(nameStr, player, group, guid)) - if (group) - group->Disband(); - - return true; - } - - static bool HandleGroupRemoveCommand(ChatHandler* handler, char const* args) - { - Player* player = nullptr; - Group* group = nullptr; - ObjectGuid guid; - char* nameStr = strtok((char*)args, " "); - - if (handler->GetPlayerGroupAndGUIDByName(nameStr, player, group, guid, true)) - if (group) - group->RemoveMember(guid); + return true; + } - return true; + handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + handler->SetSentErrorMessage(true); + return false; } - static bool HandleGroupJoinCommand(ChatHandler* handler, char const* args) + static bool HandleUnFreezeCommand(ChatHandler* handler, Optional<PlayerIdentifier> target) { - if (!*args) - return false; - - Player* playerSource = nullptr; - Group* groupSource = nullptr; - ObjectGuid guidSource; - ObjectGuid guidTarget; - char* nameplgrStr = strtok((char*)args, " "); - char* nameplStr = strtok(nullptr, " "); + Creature* creatureTarget = handler->getSelectedCreature(); - if (handler->GetPlayerGroupAndGUIDByName(nameplgrStr, playerSource, groupSource, guidSource, true)) + if (!target && !creatureTarget) { - if (groupSource) - { - Group* groupTarget = nullptr; - Player* playerTarget = nullptr; - if (handler->GetPlayerGroupAndGUIDByName(nameplStr, playerTarget, groupTarget, guidTarget, true)) - { - if (!groupTarget && playerTarget->GetGroup() != groupSource) - { - if (!groupSource->IsFull()) - { - groupSource->AddMember(playerTarget); - groupSource->BroadcastGroupUpdate(); - handler->PSendSysMessage(LANG_GROUP_PLAYER_JOINED, playerTarget->GetName().c_str(), playerSource->GetName().c_str()); - return true; - } - else - { - // group is full - handler->PSendSysMessage(LANG_GROUP_FULL); - return true; - } - } - else - { - // group is full or target player already in a group - handler->PSendSysMessage(LANG_GROUP_ALREADY_IN_GROUP, playerTarget->GetName().c_str()); - return true; - } - } - } - else - { - // specified source player is not in a group - handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, playerSource->GetName().c_str()); - return true; - } + target = PlayerIdentifier::FromTargetOrSelf(handler); } - return true; - } - - static bool HandleGroupListCommand(ChatHandler* handler, char const* args) - { - Player* playerTarget; - ObjectGuid guidTarget; - std::string nameTarget; - - ObjectGuid parseGUID = ObjectGuid::Create<HighGuid::Player>(atol((char*)args)); - - if (sCharacterCache->GetCharacterNameByGuid(parseGUID, nameTarget)) + if (!target && !creatureTarget) { - playerTarget = ObjectAccessor::FindConnectedPlayer(parseGUID); - guidTarget = parseGUID; - } - else if (!handler->extractPlayerTarget((char*)args, &playerTarget, &guidTarget, &nameTarget)) + handler->SendSysMessage(LANG_SELECT_CHAR_OR_CREATURE); + handler->SetSentErrorMessage(true); return false; + } - Group* groupTarget = nullptr; - if (playerTarget) - groupTarget = playerTarget->GetGroup(); + Player* playerTarget = target->GetConnectedPlayer(); - if (!groupTarget && guidTarget) + if (!creatureTarget && playerTarget && playerTarget->HasAura(SPELL_FREEZE)) { - if (ObjectGuid groupGUID = sCharacterCache->GetCharacterGroupGuidByGuid(guidTarget)) - { - groupTarget = sGroupMgr->GetGroupByGUID(groupGUID.GetCounter()); - } + handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, target->GetName().c_str()); + playerTarget->RemoveAurasDueToSpell(SPELL_FREEZE); + return true; } - - if (groupTarget) + else if (creatureTarget && creatureTarget->HasAura(SPELL_FREEZE)) { - handler->PSendSysMessage(LANG_GROUP_TYPE, (groupTarget->isRaidGroup() ? "raid" : "party")); - Group::MemberSlotList const& members = groupTarget->GetMemberSlots(); - for (Group::MemberSlotList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - Group::MemberSlot const& slot = *itr; - - std::string flags; - if (slot.flags & MEMBER_FLAG_ASSISTANT) - flags = "Assistant"; - - if (slot.flags & MEMBER_FLAG_MAINTANK) - { - if (!flags.empty()) - flags.append(", "); - flags.append("MainTank"); - } - - if (slot.flags & MEMBER_FLAG_MAINASSIST) - { - if (!flags.empty()) - flags.append(", "); - flags.append("MainAssist"); - } - - if (flags.empty()) - flags = "None"; - - /*Player* p = ObjectAccessor::FindConnectedPlayer((*itr).guid); - const char* onlineState = p ? "online" : "offline"; - - handler->PSendSysMessage(LANG_GROUP_PLAYER_NAME_GUID, slot.name.c_str(), onlineState, - slot.guid.GetCounter(), flags.c_str(), lfg::GetRolesString(slot.roles).c_str());*/ - } + handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, GetLocalizeCreatureName(creatureTarget, handler->GetSessionDbcLocale()).c_str()); + creatureTarget->RemoveAurasDueToSpell(SPELL_FREEZE); + return true; + } + else if (!creatureTarget && target && !target->IsConnected()) + { + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_FROZEN); + stmt->setUInt32(0, target->GetGUID().GetCounter()); + CharacterDatabase.Execute(stmt); + handler->PSendSysMessage(LANG_COMMAND_UNFREEZE, target->GetName().c_str()); + return true; } - else - handler->PSendSysMessage(LANG_GROUP_NOT_IN_GROUP, nameTarget.c_str()); + handler->SendSysMessage(LANG_COMMAND_FREEZE_WRONG); return true; } - static bool HandlePlayAllCommand(ChatHandler* handler, char const* args) + static bool HandlePlayAllCommand(ChatHandler* handler, uint32 soundId) { - if (!*args) - return false; - - uint32 soundId = atoi((char*)args); - if (!sSoundEntriesStore.LookupEntry(soundId)) { handler->PSendSysMessage(LANG_SOUND_NOT_EXIST, soundId); @@ -3372,81 +2905,73 @@ public: return true; } - static bool HandlePossessCommand(ChatHandler* handler, char const* /*args*/) + static bool HandlePossessCommand(ChatHandler* handler) { Unit* unit = handler->getSelectedUnit(); if (!unit) + { return false; + } handler->GetSession()->GetPlayer()->CastSpell(unit, 530, true); return true; } - static bool HandleUnPossessCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleUnPossessCommand(ChatHandler* handler) { Unit* unit = handler->getSelectedUnit(); if (!unit) + { unit = handler->GetSession()->GetPlayer(); + } unit->RemoveCharmAuras(); - return true; } - static bool HandleBindSightCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleBindSightCommand(ChatHandler* handler) { Unit* unit = handler->getSelectedUnit(); if (!unit) + { return false; + } handler->GetSession()->GetPlayer()->CastSpell(unit, 6277, true); return true; } - static bool HandleUnbindSightCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleUnbindSightCommand(ChatHandler* handler) { Player* player = handler->GetSession()->GetPlayer(); if (player->isPossessing()) + { return false; + } player->StopCastingBindSight(); return true; } - static bool HandleMailBoxCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleMailBoxCommand(ChatHandler* handler) { Player* player = handler->GetSession()->GetPlayer(); - handler->GetSession()->SendShowMailBox(player->GetGUID()); return true; } - static bool HandleStringCommand(ChatHandler *handler, char const *args) + static bool HandleStringCommand(ChatHandler* handler, uint32 id, Optional<uint8> locale) { - if (!*args) - { - handler->SendSysMessage(LANG_CMD_SYNTAX); - return false; - } - - uint32 id = atoi(strtok((char*)args, " ")); - if (id == 0) + if (!id) { handler->SendSysMessage(LANG_CMD_SYNTAX); return false; } - uint32 locale = 0; - char* localeString = strtok(nullptr, " "); - if (localeString != nullptr) - { - locale = atoi(localeString); - } + const char* str = sObjectMgr->GetAcoreString(id, locale ? static_cast<LocaleConstant>(*locale) : DEFAULT_LOCALE); - const char* str = sObjectMgr->GetAcoreString(id, static_cast<LocaleConstant>(locale)); - - if (strcmp(str, "<error>") == 0) + if (!strcmp(str, "<error>")) { handler->PSendSysMessage(LANG_NO_ACORE_STRING_FOUND, id); return true; @@ -3457,247 +2982,6 @@ public: return true; } } - - static bool HandleGearStatsCommand(ChatHandler* handler, char const* /*args*/) - { - Player* player = handler->getSelectedPlayerOrSelf(); - - if (!player) - { - return false; - } - - handler->PSendSysMessage("Character: %s", player->GetPlayerName().c_str()); - handler->PSendSysMessage("Current equipment average item level: |cff00ffff%u|r", (int16)player->GetAverageItemLevel()); - - if (sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE)) - { - CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_STATS); - stmt->setUInt32(0, player->GetGUID().GetCounter()); - PreparedQueryResult result = CharacterDatabase.Query(stmt); - - if (result) - { - Field* fields = result->Fetch(); - uint32 MaxHealth = fields[0].GetUInt32(); - uint32 Strength = fields[1].GetUInt32(); - uint32 Agility = fields[2].GetUInt32(); - uint32 Stamina = fields[3].GetUInt32(); - uint32 Intellect = fields[4].GetUInt32(); - uint32 Spirit = fields[5].GetUInt32(); - uint32 Armor = fields[6].GetUInt32(); - uint32 AttackPower = fields[7].GetUInt32(); - uint32 SpellPower = fields[8].GetUInt32(); - uint32 Resilience = fields[9].GetUInt32(); - - handler->PSendSysMessage("Health: |cff00ffff%u|r - Stamina: |cff00ffff%u|r", MaxHealth, Stamina); - handler->PSendSysMessage("Strength: |cff00ffff%u|r - Agility: |cff00ffff%u|r", Strength, Agility); - handler->PSendSysMessage("Intellect: |cff00ffff%u|r - Spirit: |cff00ffff%u|r", Intellect, Spirit); - handler->PSendSysMessage("AttackPower: |cff00ffff%u|r - SpellPower: |cff00ffff%u|r", AttackPower, SpellPower); - handler->PSendSysMessage("Armor: |cff00ffff%u|r - Resilience: |cff00ffff%u|r", Armor, Resilience); - } - } - - return true; - } - - static bool HandleBagsClearCommand(ChatHandler* handler, char const* args) - { - if (!*args) - { - return false; - } - - Player* player = handler->GetSession()->GetPlayer(); - if (!player) - { - return false; - } - - uint8 itemQuality = MAX_ITEM_QUALITY; - std::string argstr = args; - for (uint8 i = ITEM_QUALITY_POOR; i < MAX_ITEM_QUALITY; ++i) - { - if (argstr == itemQualityToString[i]) - { - itemQuality = i; - break; - } - } - - if (itemQuality == MAX_ITEM_QUALITY) - { - return false; - } - - std::array<uint32, MAX_ITEM_QUALITY> removedItems = { }; - - // in inventory - for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) - { - if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i)) - { - if (ItemTemplate const* itemTemplate = item->GetTemplate()) - { - if (itemTemplate->Quality <= itemQuality) - { - player->DestroyItem(INVENTORY_SLOT_BAG_0, i, true); - ++removedItems[itemTemplate->Quality]; - } - } - } - } - - // in inventory bags - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - if (Bag* bag = player->GetBagByPos(i)) - { - for (uint32 j = 0; j < bag->GetBagSize(); j++) - { - if (Item* item = bag->GetItemByPos(j)) - { - if (ItemTemplate const* itemTemplate = item->GetTemplate()) - { - if (itemTemplate->Quality <= itemQuality) - { - player->DestroyItem(i, j, true); - ++removedItems[itemTemplate->Quality]; - } - } - } - } - } - } - - std::ostringstream str; - str << "Removed "; - if (itemQuality == ITEM_QUALITY_HEIRLOOM) - { - str << "all"; - } - else - { - bool initialize = true; - for (uint8 i = ITEM_QUALITY_POOR; i < MAX_ITEM_QUALITY; ++i) - { - if (uint32 itemCount = removedItems[i]) - { - std::string itemQualityString = itemQualityToString[i]; - - if (!initialize) - { - str << ", "; - } - - str << "|c"; - str << std::hex << ItemQualityColors[i] << std::dec; - str << itemCount << " " << itemQualityString << "|r"; - - initialize = false; - } - } - } - - str << " items from your bags."; - - handler->SendSysMessage(str.str().c_str()); - - return true; - }; - - static bool HandleInventoryCountCommand(ChatHandler* handler, Optional<PlayerIdentifier> player) - { - if (!player) - player = PlayerIdentifier::FromTargetOrSelf(handler); - - if (!player) - { - handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); - return false; - } - - Player* target = player->GetConnectedPlayer(); - if (!target) - { - handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); - handler->SetSentErrorMessage(true); - return false; - } - - std::array<uint32, MAX_ITEM_SUBCLASS_CONTAINER> freeSlotsInBags = { }; - uint32 freeSlotsForBags = 0; - bool haveFreeSlot = false; - // Check backpack - for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot) - { - if (!target->GetItemByPos(INVENTORY_SLOT_BAG_0, slot)) - { - haveFreeSlot = true; - ++freeSlotsInBags[ITEM_SUBCLASS_CONTAINER]; - } - } - - // Check bags - for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++) - { - if (Bag* bag = target->GetBagByPos(i)) - { - if (ItemTemplate const* bagTemplate = bag->GetTemplate()) - { - if (bagTemplate->Class == ITEM_CLASS_CONTAINER || bagTemplate->Class == ITEM_CLASS_QUIVER) - { - haveFreeSlot = true; - freeSlotsInBags[bagTemplate->SubClass] += bag->GetFreeSlots(); - } - } - } - else - { - ++freeSlotsForBags; - } - } - - std::ostringstream str; - if (haveFreeSlot) - { - str << "Player " << target->GetName() << " have "; - bool initialize = true; - for (uint8 i = ITEM_SUBCLASS_CONTAINER; i < MAX_ITEM_SUBCLASS_CONTAINER; ++i) - { - if (uint32 freeSlots = freeSlotsInBags[i]) - { - std::string bagSpecString = bagSpecsToString[i]; - if (!initialize) - { - str << ", "; - } - - str << "|c"; - str << std::hex << bagSpecsColors[i] << std::dec; - str << freeSlots << " in " << bagSpecString << " bags|r"; - - initialize = false; - } - } - } - else - { - str << "Player " << target->GetName() << " does not have free slots in their bags"; - } - - if (freeSlotsForBags) - { - str << " and also has " << freeSlotsForBags << " free slots for bags"; - } - - str << "."; - - handler->SendSysMessage(str.str().c_str()); - - return true; - } }; void AddSC_misc_commandscript() diff --git a/src/server/scripts/Commands/cs_pet.cpp b/src/server/scripts/Commands/cs_pet.cpp new file mode 100644 index 0000000000..18e7a8b4ce --- /dev/null +++ b/src/server/scripts/Commands/cs_pet.cpp @@ -0,0 +1,210 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "Language.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Pet.h" +#include "Player.h" +#include "SpellMgr.h" +#include "SpellInfo.h" +#include "WorldSession.h" + +using namespace Acore::ChatCommands; + +class pet_commandscript : public CommandScript +{ +public: + pet_commandscript() : CommandScript("pet_commandscript") { } + + ChatCommandTable GetCommands() const override + { + static ChatCommandTable petCommandTable = + { + { "create", HandlePetCreateCommand, SEC_GAMEMASTER, Console::No }, + { "learn", HandlePetLearnCommand, SEC_GAMEMASTER, Console::No }, + { "unlearn", HandlePetUnlearnCommand, SEC_GAMEMASTER, Console::No } + }; + + static ChatCommandTable commandTable = + { + { "pet", petCommandTable } + }; + + return commandTable; + } + + static bool HandlePetCreateCommand(ChatHandler* handler) + { + Player* player = handler->GetSession()->GetPlayer(); + Creature* creatureTarget = handler->getSelectedCreature(); + + if (!creatureTarget || creatureTarget->IsPet() || creatureTarget->GetTypeId() == TYPEID_PLAYER) + { + handler->PSendSysMessage(LANG_SELECT_CREATURE); + handler->SetSentErrorMessage(true); + return false; + } + + CreatureTemplate const* creatrueTemplate = sObjectMgr->GetCreatureTemplate(creatureTarget->GetEntry()); + // Creatures with family 0 crashes the server + if (!creatrueTemplate->family) + { + handler->PSendSysMessage("This creature cannot be tamed. (family id: 0)."); + handler->SetSentErrorMessage(true); + return false; + } + + if (player->GetPetGUID()) + { + handler->PSendSysMessage("You already have a pet"); + handler->SetSentErrorMessage(true); + return false; + } + + // Everything looks OK, create new pet + Pet* pet = new Pet(player, HUNTER_PET); + if (!pet->CreateBaseAtCreature(creatureTarget)) + { + delete pet; + handler->PSendSysMessage("Error 1"); + return false; + } + + creatureTarget->setDeathState(JUST_DIED); + creatureTarget->RemoveCorpse(); + creatureTarget->SetHealth(0); // just for nice GM-mode view + + pet->SetGuidValue(UNIT_FIELD_CREATEDBY, player->GetGUID()); + pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, player->GetFaction()); + + if (!pet->InitStatsForLevel(creatureTarget->getLevel())) + { + LOG_ERROR("misc", "InitStatsForLevel() in EffectTameCreature failed! Pet deleted."); + handler->PSendSysMessage("Error 2"); + delete pet; + return false; + } + + // prepare visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, creatureTarget->getLevel() - 1); + pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true); + + // this enables pet details window (Shift+P) + pet->InitPetCreateSpells(); + pet->SetFullHealth(); + pet->GetMap()->AddToMap(pet->ToCreature()); + + // visual effect for levelup + pet->SetUInt32Value(UNIT_FIELD_LEVEL, creatureTarget->getLevel()); + player->SetMinion(pet, true); + pet->SavePetToDB(PET_SAVE_AS_CURRENT, false); + player->PetSpellInitialize(); + + return true; + } + + static bool HandlePetLearnCommand(ChatHandler* handler, SpellInfo const* spell) + { + if (!spell) + { + handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + handler->SetSentErrorMessage(true); + return false; + } + + if (!SpellMgr::IsSpellValid(spell)) + { + handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spell->Id); + handler->SetSentErrorMessage(true); + return false; + } + + Pet* pet = handler->GetSession()->GetPlayer()->GetPet(); + if (!pet) + { + handler->PSendSysMessage("You have no pet"); + handler->SetSentErrorMessage(true); + return false; + } + + SpellScriptsBounds bounds = sObjectMgr->GetSpellScriptsBounds(spell->Id); + uint32 spellDifficultyId = sSpellMgr->GetSpellDifficultyId(spell->Id); + if (bounds.first != bounds.second || spellDifficultyId) + { + handler->PSendSysMessage("Spell %u cannot be learnt using a command!", spell->Id); + handler->SetSentErrorMessage(true); + return false; + } + + // Check if pet already has it + if (pet->HasSpell(spell->Id)) + { + handler->PSendSysMessage("Pet already has spell: %u", spell->Id); + handler->SetSentErrorMessage(true); + return false; + } + + pet->learnSpell(spell->Id); + handler->PSendSysMessage("Pet has learned spell %u", spell->Id); + + return true; + } + + static bool HandlePetUnlearnCommand(ChatHandler* handler, SpellInfo const* spell) + { + if (!spell) + { + handler->PSendSysMessage(LANG_COMMAND_NOSPELLFOUND); + handler->SetSentErrorMessage(true); + return false; + } + + if (!SpellMgr::IsSpellValid(spell)) + { + handler->PSendSysMessage(LANG_COMMAND_SPELL_BROKEN, spell->Id); + handler->SetSentErrorMessage(true); + return false; + } + + Pet* pet = handler->GetSession()->GetPlayer()->GetPet(); + if (!pet) + { + handler->PSendSysMessage("You have no pet"); + handler->SetSentErrorMessage(true); + return false; + } + + if (pet->HasSpell(spell->Id)) + { + pet->removeSpell(spell->Id, false); + } + else + { + handler->PSendSysMessage("Pet doesn't have that spell"); + } + + return true; + } +}; + +void AddSC_pet_commandscript() +{ + new pet_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_script_loader.cpp b/src/server/scripts/Commands/cs_script_loader.cpp index 04cf78ec9a..1d40846ef5 100644 --- a/src/server/scripts/Commands/cs_script_loader.cpp +++ b/src/server/scripts/Commands/cs_script_loader.cpp @@ -19,6 +19,7 @@ void AddSC_account_commandscript(); void AddSC_achievement_commandscript(); void AddSC_arena_commandscript(); +void AddSC_bag_commandscript(); void AddSC_ban_commandscript(); void AddSC_bf_commandscript(); void AddSC_cast_commandscript(); @@ -28,12 +29,15 @@ void AddSC_debug_commandscript(); void AddSC_deserter_commandscript(); void AddSC_disable_commandscript(); void AddSC_event_commandscript(); +void AddSC_gear_commandscript(); void AddSC_gm_commandscript(); void AddSC_go_commandscript(); void AddSC_gobject_commandscript(); +void AddSC_group_commandscript(); void AddSC_guild_commandscript(); void AddSC_honor_commandscript(); void AddSC_instance_commandscript(); +void AddSC_inventory_commandscript(); void AddSC_learn_commandscript(); void AddSC_lfg_commandscript(); void AddSC_list_commandscript(); @@ -43,16 +47,18 @@ void AddSC_misc_commandscript(); void AddSC_mmaps_commandscript(); void AddSC_modify_commandscript(); void AddSC_npc_commandscript(); +void AddSC_pet_commandscript(); +void AddSC_player_commandscript(); void AddSC_quest_commandscript(); void AddSC_reload_commandscript(); void AddSC_reset_commandscript(); +void AddSC_send_commandscript(); void AddSC_server_commandscript(); void AddSC_spectator_commandscript(); void AddSC_tele_commandscript(); void AddSC_ticket_commandscript(); void AddSC_titles_commandscript(); void AddSC_wp_commandscript(); -void AddSC_player_commandscript(); void AddSC_cache_commandscript(); void AddSC_item_commandscript(); @@ -63,6 +69,7 @@ void AddCommandsScripts() AddSC_account_commandscript(); AddSC_achievement_commandscript(); AddSC_arena_commandscript(); + AddSC_bag_commandscript(); AddSC_ban_commandscript(); AddSC_bf_commandscript(); AddSC_cast_commandscript(); @@ -72,12 +79,15 @@ void AddCommandsScripts() AddSC_deserter_commandscript(); AddSC_disable_commandscript(); AddSC_event_commandscript(); + AddSC_gear_commandscript(); AddSC_gm_commandscript(); AddSC_go_commandscript(); AddSC_gobject_commandscript(); + AddSC_group_commandscript(); AddSC_guild_commandscript(); AddSC_honor_commandscript(); AddSC_instance_commandscript(); + AddSC_inventory_commandscript(); AddSC_learn_commandscript(); AddSC_lfg_commandscript(); AddSC_list_commandscript(); @@ -87,16 +97,18 @@ void AddCommandsScripts() AddSC_mmaps_commandscript(); AddSC_modify_commandscript(); AddSC_npc_commandscript(); + AddSC_pet_commandscript(); + AddSC_player_commandscript(); AddSC_quest_commandscript(); AddSC_reload_commandscript(); AddSC_reset_commandscript(); + AddSC_send_commandscript(); AddSC_server_commandscript(); AddSC_spectator_commandscript(); AddSC_tele_commandscript(); AddSC_ticket_commandscript(); AddSC_titles_commandscript(); AddSC_wp_commandscript(); - AddSC_player_commandscript(); AddSC_cache_commandscript(); AddSC_item_commandscript(); } diff --git a/src/server/scripts/Commands/cs_send.cpp b/src/server/scripts/Commands/cs_send.cpp new file mode 100644 index 0000000000..6e69304dc4 --- /dev/null +++ b/src/server/scripts/Commands/cs_send.cpp @@ -0,0 +1,220 @@ +/* + * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by the + * Free Software Foundation; either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "DatabaseEnv.h" +#include "Item.h" +#include "Language.h" +#include "Mail.h" +#include "ObjectMgr.h" +#include "Pet.h" +#include "Player.h" +#include "WorldSession.h" +#include "Tokenize.h" + +using namespace Acore::ChatCommands; + +class send_commandscript : public CommandScript +{ +public: + send_commandscript() : CommandScript("send_commandscript") { } + + ChatCommandTable GetCommands() const override + { + static ChatCommandTable sendCommandTable = + { + { "items", HandleSendItemsCommand, SEC_GAMEMASTER, Console::Yes }, + { "mail", HandleSendMailCommand, SEC_GAMEMASTER, Console::Yes }, + { "message", HandleSendMessageCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "money", HandleSendMoneyCommand, SEC_GAMEMASTER, Console::Yes } + }; + + static ChatCommandTable commandTable = + { + { "send", sendCommandTable } + }; + + return commandTable; + } + + static bool HandleSendItemsCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, QuotedString subject, QuotedString text, Tail items) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { + return false; + } + + // extract items + std::vector<std::pair<uint32, uint32>> itemList; + + for (auto const& itemString : Acore::Tokenize(items, ' ', true)) + { + auto itemTokens = Acore::Tokenize(itemString, ':', false); + + if (itemTokens.size() != 2) + { + handler->SendSysMessage(Acore::StringFormatFmt("> Incorrect item list format for '{}'", itemString)); + continue; + } + + uint32 itemID = *Acore::StringTo<uint32>(itemTokens.at(0)); + uint32 itemCount = *Acore::StringTo<uint32>(itemTokens.at(1)); + + ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemID); + if (!itemTemplate) + { + handler->PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, itemID); + handler->SetSentErrorMessage(true); + return false; + } + + if (!itemCount || (itemTemplate->MaxCount > 0 && itemCount > uint32(itemTemplate->MaxCount))) + { + handler->PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, itemCount, itemID); + handler->SetSentErrorMessage(true); + return false; + } + + while (itemCount > itemTemplate->GetMaxStackSize()) + { + itemList.emplace_back(itemID, itemTemplate->GetMaxStackSize()); + itemCount -= itemTemplate->GetMaxStackSize(); + } + + itemList.emplace_back(itemID, itemCount); + + if (itemList.size() > MAX_MAIL_ITEMS) + { + handler->PSendSysMessage(LANG_COMMAND_MAIL_ITEMS_LIMIT, MAX_MAIL_ITEMS); + handler->SetSentErrorMessage(true); + return false; + } + } + + // If the message is sent from console, set it as sent by the target itself, like the other Customer Support mails. + ObjectGuid::LowType senderGuid = handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : target->GetGUID().GetCounter(); + + // fill mail + MailDraft draft(subject, text); + MailSender sender(MAIL_NORMAL, senderGuid, MAIL_STATIONERY_GM); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + + for (auto const& [itemID, itemCount] : itemList) + { + if (Item* item = Item::CreateItem(itemID, itemCount, handler->GetSession() ? handler->GetSession()->GetPlayer() : 0)) + { + item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted + draft.AddItem(item); + } + } + + draft.SendMailTo(trans, MailReceiver(target->GetConnectedPlayer(), target->GetGUID().GetCounter()), sender); + CharacterDatabase.CommitTransaction(trans); + + handler->PSendSysMessage(LANG_MAIL_SENT, handler->playerLink(target->GetName()).c_str()); + return true; + } + + static bool HandleSendMailCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, QuotedString subject, QuotedString text) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { + return false; + } + + ObjectGuid::LowType senderGuid = handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : target->GetGUID().GetCounter(); + + // If the message is sent from console, set it as sent by the target itself, like the other Customer Support mails. + MailSender sender(MAIL_NORMAL, senderGuid, MAIL_STATIONERY_GM); + MailDraft draft(subject, text); + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + draft.SendMailTo(trans, MailReceiver(target->GetConnectedPlayer(), target->GetGUID().GetCounter()), sender); + CharacterDatabase.CommitTransaction(trans); + + handler->PSendSysMessage(LANG_MAIL_SENT, handler->playerLink(target->GetName()).c_str()); + return true; + } + + static bool HandleSendMessageCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, Tail message) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target || !target->IsConnected()) + { + return false; + } + + Player* player = target->GetConnectedPlayer(); + std::string msg = std::string{ message }; + + /// - Send the message + // Use SendAreaTriggerMessage for fastest delivery. + player->GetSession()->SendAreaTriggerMessage("%s", msg.c_str()); + player->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r"); + + // Confirmation message + handler->PSendSysMessage(LANG_SENDMESSAGE, handler->playerLink(target->GetName()).c_str(), msg.c_str()); + + return true; + } + + static bool HandleSendMoneyCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, QuotedString subject, QuotedString text, uint32 money) + { + if (!target) + { + target = PlayerIdentifier::FromTargetOrSelf(handler); + } + + if (!target) + { + return false; + } + + // from console show not existed sender + MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : 0, MAIL_STATIONERY_GM); + + CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); + + MailDraft(subject, text) + .AddMoney(money) + .SendMailTo(trans, MailReceiver(target->GetConnectedPlayer(), target->GetGUID().GetCounter()), sender); + + CharacterDatabase.CommitTransaction(trans); + + handler->PSendSysMessage(LANG_MAIL_SENT, handler->playerLink(target->GetName()).c_str()); + return true; + } +}; + +void AddSC_send_commandscript() +{ + new send_commandscript(); +} |