From 4d62cc70d6a7726d6619ba5c722fcb74d1123396 Mon Sep 17 00:00:00 2001 From: Treeston Date: Fri, 4 Sep 2020 00:58:23 +0200 Subject: Scripts/Commands: Convert argument parsing of .npc commands (And I snuck some chat command cleanup in there, more de-cluttering!) (cherry picked from commit 88d446dadf65bf47c72d3042834281233b1174ac) --- src/server/game/AI/CreatureAI.h | 3 +- src/server/game/AI/enuminfo_CreatureAI.cpp | 73 +++ src/server/game/Chat/ChatCommands/ChatCommand.h | 26 - .../game/Chat/ChatCommands/ChatCommandArgs.cpp | 17 +- .../game/Chat/ChatCommands/ChatCommandArgs.h | 408 +++++++------ .../game/Chat/ChatCommands/ChatCommandHelpers.h | 6 + .../game/Chat/ChatCommands/ChatCommandTags.h | 6 +- src/server/game/Chat/Hyperlinks.h | 2 +- src/server/game/Entities/Player/Player.cpp | 8 +- src/server/game/Entities/Player/Player.h | 8 +- src/server/game/Entities/Unit/Unit.cpp | 10 +- src/server/game/Entities/Unit/Unit.h | 10 +- src/server/game/Globals/ObjectAccessor.cpp | 40 +- src/server/game/Globals/ObjectAccessor.h | 4 +- src/server/game/Movement/MovementDefines.h | 3 +- .../game/Movement/enuminfo_MovementDefines.cpp | 115 ++++ src/server/game/Texts/ChatTextBuilder.h | 2 +- src/server/scripts/Commands/cs_gobject.cpp | 8 +- src/server/scripts/Commands/cs_npc.cpp | 630 +++++++-------------- 19 files changed, 680 insertions(+), 699 deletions(-) create mode 100644 src/server/game/AI/enuminfo_CreatureAI.cpp create mode 100644 src/server/game/Movement/enuminfo_MovementDefines.cpp (limited to 'src') diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h index 0f488e4925a..984cbab6da8 100644 --- a/src/server/game/AI/CreatureAI.h +++ b/src/server/game/AI/CreatureAI.h @@ -68,13 +68,14 @@ class TC_GAME_API CreatureAI : public UnitAI Creature* DoSummonFlyer(uint32 entry, WorldObject* obj, float flightZ, float radius = 5.0f, Milliseconds despawnTime = 30s, TempSummonType summonType = TEMPSUMMON_CORPSE_TIMED_DESPAWN); public: + // EnumUtils: DESCRIBE THIS (in CreatureAI::) enum EvadeReason { EVADE_REASON_NO_HOSTILES, // the creature's threat list is empty EVADE_REASON_BOUNDARY, // the creature has moved outside its evade boundary EVADE_REASON_NO_PATH, // the creature was unable to reach its target for over 5 seconds EVADE_REASON_SEQUENCE_BREAK, // this is a boss and the pre-requisite encounters for engaging it are not defeated yet - EVADE_REASON_OTHER + EVADE_REASON_OTHER, // anything else }; explicit CreatureAI(Creature* creature, uint32 scriptId = {}); diff --git a/src/server/game/AI/enuminfo_CreatureAI.cpp b/src/server/game/AI/enuminfo_CreatureAI.cpp new file mode 100644 index 00000000000..c2865d4ebc4 --- /dev/null +++ b/src/server/game/AI/enuminfo_CreatureAI.cpp @@ -0,0 +1,73 @@ +/* + * This file is part of the TrinityCore 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 General Public License as published by the + * Free Software Foundation; either version 2 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 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 . + */ + +#include "CreatureAI.h" +#include "Define.h" +#include "SmartEnum.h" +#include + +namespace Trinity::Impl::EnumUtilsImpl +{ + +/****************************************************************************\ +|* data for enum 'CreatureAI::EvadeReason' in 'CreatureAI.h' auto-generated *| +\****************************************************************************/ +template <> +TC_API_EXPORT EnumText EnumUtils::ToString(CreatureAI::EvadeReason value) +{ + switch (value) + { + case CreatureAI::EVADE_REASON_NO_HOSTILES: return { "EVADE_REASON_NO_HOSTILES", "EVADE_REASON_NO_HOSTILES", "the creature's threat list is empty" }; + case CreatureAI::EVADE_REASON_BOUNDARY: return { "EVADE_REASON_BOUNDARY", "EVADE_REASON_BOUNDARY", "the creature has moved outside its evade boundary" }; + case CreatureAI::EVADE_REASON_NO_PATH: return { "EVADE_REASON_NO_PATH", "EVADE_REASON_NO_PATH", "the creature was unable to reach its target for over 5 seconds" }; + case CreatureAI::EVADE_REASON_SEQUENCE_BREAK: return { "EVADE_REASON_SEQUENCE_BREAK", "EVADE_REASON_SEQUENCE_BREAK", "this is a boss and the pre-requisite encounters for engaging it are not defeated yet" }; + case CreatureAI::EVADE_REASON_OTHER: return { "EVADE_REASON_OTHER", "EVADE_REASON_OTHER", "anything else" }; + default: throw std::out_of_range("value"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils::Count() { return 5; } + +template <> +TC_API_EXPORT CreatureAI::EvadeReason EnumUtils::FromIndex(size_t index) +{ + switch (index) + { + case 0: return CreatureAI::EVADE_REASON_NO_HOSTILES; + case 1: return CreatureAI::EVADE_REASON_BOUNDARY; + case 2: return CreatureAI::EVADE_REASON_NO_PATH; + case 3: return CreatureAI::EVADE_REASON_SEQUENCE_BREAK; + case 4: return CreatureAI::EVADE_REASON_OTHER; + default: throw std::out_of_range("index"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils::ToIndex(CreatureAI::EvadeReason value) +{ + switch (value) + { + case CreatureAI::EVADE_REASON_NO_HOSTILES: return 0; + case CreatureAI::EVADE_REASON_BOUNDARY: return 1; + case CreatureAI::EVADE_REASON_NO_PATH: return 2; + case CreatureAI::EVADE_REASON_SEQUENCE_BREAK: return 3; + case CreatureAI::EVADE_REASON_OTHER: return 4; + default: throw std::out_of_range("value"); + } +} +} diff --git a/src/server/game/Chat/ChatCommands/ChatCommand.h b/src/server/game/Chat/ChatCommands/ChatCommand.h index 616b4984460..28d84629eea 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommand.h +++ b/src/server/game/Chat/ChatCommands/ChatCommand.h @@ -44,32 +44,6 @@ namespace Trinity::Impl::ChatCommands } }; - template - struct SingleConsumer> - { - using V = std::variant; - static constexpr size_t N = std::variant_size_v; - - template - static Optional TryAtIndex(Trinity::ChatCommands::Variant& val, [[maybe_unused]] std::string_view args) - { - if constexpr (I < N) - { - if (Optional next = SingleConsumer>::TryConsumeTo(val.template emplace(), args)) - return next; - else - return TryAtIndex(val, args); - } - else - return std::nullopt; - } - - static Optional TryConsumeTo(Trinity::ChatCommands::Variant& val, std::string_view args) - { - return TryAtIndex<0>(val, args); - } - }; - /* for backwards compatibility, consumes the rest of the string new code should use the Tail/WTail tags defined in ChatCommandTags diff --git a/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp b/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp index df74ac40e26..e3454bc5240 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp +++ b/src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp @@ -51,7 +51,7 @@ Optional Trinity::Impl::ChatCommands::ArgInfo next = SingleConsumer::TryConsumeTo(val, args); if (next) data = val.visit(CurrencyTypesVisitor()); - return args; + return next; } struct GameTeleVisitor @@ -69,6 +69,21 @@ Optional Trinity::Impl::ChatCommands::ArgInfo return next; } +struct ItemTemplateVisitor +{ + using value_type = ItemTemplate const*; + value_type operator()(Hyperlink item) const { return item->Item; } + value_type operator()(uint32 item) const { return sObjectMgr->GetItemTemplate(item); } +}; +Optional Trinity::Impl::ChatCommands::ArgInfo::TryConsume(ItemTemplate const*& data, std::string_view args) +{ + Variant, uint32> val; + Optional next = SingleConsumer::TryConsumeTo(val, args); + if (next) + data = val.visit(ItemTemplateVisitor()); + return next; +} + struct SpellInfoVisitor { using value_type = SpellInfo const*; diff --git a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h index bdd0be0aace..21f27b45752 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandArgs.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandArgs.h @@ -33,238 +33,274 @@ struct GameTele; namespace Trinity::Impl::ChatCommands { -/************************** ARGUMENT HANDLERS *******************************************\ -|* Define how to extract contents of a certain requested type from a string *| -|* Must implement the following: *| -|* - TryConsume: T&, std::string_view -> Optional *| -|* returns nullopt if no match, otherwise tail of argument string *| -|* - if nullopt is returned, state of T& is indeterminate *| -|* - otherwise, T& should be initialized to the intended return value *| -|* *| -\****************************************************************************************/ -template -struct ArgInfo { static_assert(Trinity::dependant_false_v, "Invalid command parameter type - see ChatCommandArgs.h for possible types"); }; - -// catch-all for number types -template -struct ArgInfo || std::is_floating_point_v>> -{ - static Optional TryConsume(T& val, std::string_view args) + /************************** ARGUMENT HANDLERS *******************************************\ + |* Define how to extract contents of a certain requested type from a string *| + |* Must implement the following: *| + |* - TryConsume: T&, std::string_view -> Optional *| + |* returns nullopt if no match, otherwise tail of argument string *| + |* - if nullopt is returned, state of T& is indeterminate *| + |* - otherwise, T& should be initialized to the intended return value *| + |* *| + \****************************************************************************************/ + template + struct ArgInfo { static_assert(Trinity::dependant_false_v, "Invalid command parameter type - see ChatCommandArgs.h for possible types"); }; + + // catch-all for number types + template + struct ArgInfo || std::is_floating_point_v>> { - auto [token, tail] = tokenize(args); - if (token.empty()) - return std::nullopt; + static Optional TryConsume(T& val, std::string_view args) + { + auto [token, tail] = tokenize(args); + if (token.empty()) + return std::nullopt; - if (Optional v = StringTo(token, 0)) - val = *v; - else - return std::nullopt; + if (Optional v = StringTo(token, 0)) + val = *v; + else + return std::nullopt; + + if constexpr (std::is_floating_point_v) + { + if (!std::isfinite(val)) + return std::nullopt; + } + + return tail; + } + }; - if constexpr (std::is_floating_point_v) + // string_view + template <> + struct ArgInfo + { + static Optional TryConsume(std::string_view& val, std::string_view args) { - if (!std::isfinite(val)) + auto [token, next] = tokenize(args); + if (token.empty()) return std::nullopt; + val = token; + return next; } + }; - return tail; - } -}; - -// string_view -template <> -struct ArgInfo -{ - static Optional TryConsume(std::string_view& val, std::string_view args) - { - auto [token, next] = tokenize(args); - if (token.empty()) - return std::nullopt; - val = token; - return next; - } -}; - -// string -template <> -struct ArgInfo -{ - static Optional TryConsume(std::string& val, std::string_view args) - { - std::string_view view; - Optional next = ArgInfo::TryConsume(view, args); - if (next) - val.assign(view); - return next; - } -}; - -// wstring -template <> -struct ArgInfo -{ - static Optional TryConsume(std::wstring& val, std::string_view args) + // string + template <> + struct ArgInfo { - std::string_view utf8view; - Optional next = ArgInfo::TryConsume(utf8view, args); - - if (next && Utf8toWStr(utf8view, val)) + static Optional TryConsume(std::string& val, std::string_view args) + { + std::string_view view; + Optional next = ArgInfo::TryConsume(view, args); + if (next) + val.assign(view); return next; - else - return std::nullopt; - } -}; + } + }; -// enum -template -struct ArgInfo>> -{ - static std::map> MakeSearchMap() + // wstring + template <> + struct ArgInfo { - std::map> map; - for (T val : EnumUtils::Iterate()) + static Optional TryConsume(std::wstring& val, std::string_view args) { - EnumText text = EnumUtils::ToString(val); + std::string_view utf8view; + Optional next = ArgInfo::TryConsume(utf8view, args); - std::string title(text.Title); - strToLower(title); - std::string constant(text.Constant); - strToLower(constant); - - auto [constantIt, constantNew] = map.try_emplace(constant, val); - if (!constantNew) - constantIt->second = std::nullopt; + if (next && Utf8toWStr(utf8view, val)) + return next; + else + return std::nullopt; + } + }; - if (title != constant) + // enum + template + struct ArgInfo>> + { + static std::map> MakeSearchMap() + { + std::map> map; + for (T val : EnumUtils::Iterate()) { - auto [titleIt, titleNew] = map.try_emplace(title, val); - if (!titleNew) - titleIt->second = std::nullopt; + EnumText text = EnumUtils::ToString(val); + + std::string title(text.Title); + strToLower(title); + std::string constant(text.Constant); + strToLower(constant); + + auto [constantIt, constantNew] = map.try_emplace(constant, val); + if (!constantNew) + constantIt->second = std::nullopt; + + if (title != constant) + { + auto [titleIt, titleNew] = map.try_emplace(title, val); + if (!titleNew) + titleIt->second = std::nullopt; + } } + return map; } - return map; - } - static inline std::map> const SearchMap = MakeSearchMap(); + static inline std::map> const SearchMap = MakeSearchMap(); - static T const* Match(std::string s) - { - strToLower(s); + static T const* Match(std::string s) + { + strToLower(s); - auto it = SearchMap.lower_bound(s); - if (it == SearchMap.end() || !StringStartsWith(it->first, s)) // not a match - return nullptr; + auto it = SearchMap.lower_bound(s); + if (it == SearchMap.end() || !StringStartsWith(it->first, s)) // not a match + return nullptr; - if (it->first != s) // we don't have an exact match - check if it is unique - { - auto it2 = it; - ++it2; - if (it2 != SearchMap.end() && StringStartsWith(it2->first, s)) // not unique + if (it->first != s) // we don't have an exact match - check if it is unique + { + auto it2 = it; + ++it2; + if (it2 != SearchMap.end() && StringStartsWith(it2->first, s)) // not unique + return nullptr; + } + + if (it->second) + return &*it->second; + else return nullptr; } - if (it->second) - return &*it->second; - else - return nullptr; - } + static Optional TryConsume(T& val, std::string_view args) + { + std::string strVal; + Optional next = ArgInfo::TryConsume(strVal, args); - static Optional TryConsume(T& val, std::string_view args) - { - std::string strVal; - Optional next = ArgInfo::TryConsume(strVal, args); + if (next) + { + if (T const* match = Match(strVal)) + { + val = *match; + return next; + } + } - if (next) - { - if (T const* match = Match(strVal)) + // Value not found. Try to parse arg as underlying type and cast it to enum type + using U = std::underlying_type_t; + U uVal = 0; + next = ArgInfo::TryConsume(uVal, args); + if (next && EnumUtils::IsValid(uVal)) { - val = *match; + val = static_cast(uVal); return next; } + + return std::nullopt; } + }; - // Value not found. Try to parse arg as underlying type and cast it to enum type - using U = std::underlying_type_t; - U uVal = 0; - next = ArgInfo::TryConsume(uVal, args); - if (next && EnumUtils::IsValid(uVal)) + // a container tag + template + struct ArgInfo>> + { + static Optional TryConsume(T& tag, std::string_view args) { - val = static_cast(uVal); - return next; + return tag.TryConsume(args); } + }; - return std::nullopt; - } -}; - -// a container tag -template -struct ArgInfo>> -{ - static Optional TryConsume(T& tag, std::string_view args) + // non-empty vector + template + struct ArgInfo, void> { - return tag.TryConsume(args); - } -}; + static Optional TryConsume(std::vector& val, std::string_view args) + { + val.clear(); + Optional next = ArgInfo::TryConsume(val.emplace_back(), args); -template -struct ArgInfo, void> -{ - static Optional TryConsume(std::vector& val, std::string_view args) - { - val.clear(); - Optional next = ArgInfo::TryConsume(val.emplace_back(), args); + if (!next) + return std::nullopt; - if (!next) - return std::nullopt; + while (Optional next2 = ArgInfo::TryConsume(val.emplace_back(), *next)) + next = next2; - while (Optional next2 = ArgInfo::TryConsume(val.emplace_back(), *next)) - next = next2; + val.pop_back(); + return next; + } + }; - val.pop_back(); - return next; - } -}; + // fixed-size array + template + struct ArgInfo, void> + { + static Optional TryConsume(std::array& val, std::string_view args) + { + Optional next = args; + for (T& t : val) + if (!(next = ArgInfo::TryConsume(t, *next))) + return std::nullopt; + return next; + } + }; -template -struct ArgInfo, void> -{ - static Optional TryConsume(std::array& val, std::string_view args) + // variant + template + struct ArgInfo> { - Optional next = args; - for (T& t : val) - if (!(next = ArgInfo::TryConsume(t, *next))) + using V = std::variant; + static constexpr size_t N = std::variant_size_v; + + template + static Optional TryAtIndex(Trinity::ChatCommands::Variant& val, [[maybe_unused]] std::string_view args) + { + if constexpr (I < N) + { + if (Optional next = ArgInfo>::TryConsume(val.template emplace(), args)) + return next; + else + return TryAtIndex(val, args); + } + else return std::nullopt; - return next; - } -}; + } -// AchievementEntry* from numeric id or link -template <> -struct TC_GAME_API ArgInfo -{ - static Optional TryConsume(AchievementEntry const*&, std::string_view); -}; + static Optional TryConsume(Trinity::ChatCommands::Variant& val, std::string_view args) + { + return TryAtIndex<0>(val, args); + } + }; -// CurrencyTypesEntry* from numeric id or link -template <> -struct TC_GAME_API ArgInfo -{ - static Optional TryConsume(CurrencyTypesEntry const*&, std::string_view); -}; + // AchievementEntry* from numeric id or link + template <> + struct TC_GAME_API ArgInfo + { + static Optional TryConsume(AchievementEntry const*&, std::string_view); + }; -// GameTele* from string name or link -template <> -struct TC_GAME_API ArgInfo -{ - static Optional TryConsume(GameTele const*&, std::string_view); -}; + // CurrencyTypesEntry* from numeric id or link + template <> + struct TC_GAME_API ArgInfo + { + static Optional TryConsume(CurrencyTypesEntry const*&, std::string_view); + }; -// SpellInfo const* from spell id or link -template <> -struct TC_GAME_API ArgInfo -{ - static Optional TryConsume(SpellInfo const*&, std::string_view); -}; + // GameTele* from string name or link + template <> + struct TC_GAME_API ArgInfo + { + static Optional TryConsume(GameTele const*&, std::string_view); + }; + + // ItemTemplate* from numeric id or link + template <> + struct TC_GAME_API ArgInfo + { + static Optional TryConsume(ItemTemplate const*&, std::string_view); + }; + + // SpellInfo const* from spell id or link + template <> + struct TC_GAME_API ArgInfo + { + static Optional TryConsume(SpellInfo const*&, std::string_view); + }; } diff --git a/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h b/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h index c6cf4f8ad94..712d0c37d48 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandHelpers.h @@ -65,6 +65,12 @@ namespace Trinity::Impl::ChatCommands static constexpr bool value = (std::is_assignable_v && ...); }; + template + struct are_all_assignable + { + static constexpr bool value = false; + }; + template struct get_nth : get_nth { }; diff --git a/src/server/game/Chat/ChatCommands/ChatCommandTags.h b/src/server/game/Chat/ChatCommands/ChatCommandTags.h index 3c8c778d5ea..cf6df77da8d 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommandTags.h +++ b/src/server/game/Chat/ChatCommands/ChatCommandTags.h @@ -65,7 +65,7 @@ namespace Trinity::ChatCommands static bool Match(char const* pos) { - if (*(pos++) != c1) + if (std::toupper(*(pos++)) != std::toupper(c1)) return false; else if constexpr (sizeof...(chars) > 0) return ExactSequence::Match(pos); @@ -151,10 +151,6 @@ namespace Trinity::ChatCommands using namespace ::Trinity::Hyperlinks::LinkTags; } -/************************** VARIANT TAG LOGIC *********************************\ -|* This has some special handling over in ChatCommand.h *| -\******************************************************************************/ - namespace Trinity::Impl { template diff --git a/src/server/game/Chat/Hyperlinks.h b/src/server/game/Chat/Hyperlinks.h index 963262018d5..4b04e706e75 100644 --- a/src/server/game/Chat/Hyperlinks.h +++ b/src/server/game/Chat/Hyperlinks.h @@ -263,7 +263,7 @@ namespace Trinity::Hyperlinks make_base_tag(gameobject, ObjectGuid::LowType); make_base_tag(gameobject_entry, uint32); make_base_tag(itemset, uint32); - make_base_tag(player, std::string const&); + make_base_tag(player, std::string_view); make_base_tag(skill, uint32); make_base_tag(taxinode, uint32); make_base_tag(tele, uint32); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 740811c3132..3324a836751 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22034,7 +22034,7 @@ void Player::StopCastingCharm() } } -void Player::Say(std::string const& text, Language language, WorldObject const* /*= nullptr*/) +void Player::Say(std::string_view text, Language language, WorldObject const* /*= nullptr*/) { std::string _text(text); sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text); @@ -22060,7 +22060,7 @@ void Player::Say(uint32 textId, WorldObject const* target /*= nullptr*/) Talk(textId, CHAT_MSG_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target); } -void Player::Yell(std::string const& text, Language language, WorldObject const* /*= nullptr*/) +void Player::Yell(std::string_view text, Language language, WorldObject const* /*= nullptr*/) { std::string _text(text); sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text); @@ -22073,7 +22073,7 @@ void Player::Yell(uint32 textId, WorldObject const* target /*= nullptr*/) Talk(textId, CHAT_MSG_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target); } -void Player::TextEmote(std::string const& text, WorldObject const* /*= nullptr*/, bool /*= false*/) +void Player::TextEmote(std::string_view text, WorldObject const* /*= nullptr*/, bool /*= false*/) { std::string _text(text); sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text); @@ -22101,7 +22101,7 @@ void Player::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, b Talk(textId, CHAT_MSG_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target); } -void Player::Whisper(std::string const& text, Language language, Player* target, bool /*= false*/) +void Player::Whisper(std::string_view text, Language language, Player* target, bool /*= false*/) { ASSERT(target); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index f79818ffec8..1a69fb98b8d 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1224,16 +1224,16 @@ class TC_GAME_API Player : public Unit, public GridObject void SetBattlePetData(BattlePets::BattlePet const* pet = nullptr); /// Handles said message in regular chat based on declared language and in config pre-defined Range. - void Say(std::string const& text, Language language, WorldObject const* = nullptr) override; + void Say(std::string_view text, Language language, WorldObject const* = nullptr) override; void Say(uint32 textId, WorldObject const* target = nullptr) override; /// Handles yelled message in regular chat based on declared language and in config pre-defined Range. - void Yell(std::string const& text, Language language, WorldObject const* = nullptr) override; + void Yell(std::string_view text, Language language, WorldObject const* = nullptr) override; void Yell(uint32 textId, WorldObject const* target = nullptr) override; /// Outputs an universal text which is supposed to be an action. - void TextEmote(std::string const& text, WorldObject const* = nullptr, bool = false) override; + void TextEmote(std::string_view text, WorldObject const* = nullptr, bool = false) override; void TextEmote(uint32 textId, WorldObject const* target = nullptr, bool isBossEmote = false) override; /// Handles whispers from Addons and players based on sender, receiver's guid and language. - void Whisper(std::string const& text, Language language, Player* receiver, bool = false) override; + void Whisper(std::string_view text, Language language, Player* receiver, bool = false) override; void Whisper(uint32 textId, Player* target, bool isBossWhisper = false) override; void WhisperAddon(std::string const& text, std::string const& prefix, bool isLogged, Player* receiver); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b582cb833c9..8e490b828c8 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -13160,7 +13160,7 @@ bool Unit::IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType aur return true; } -void Unit::Talk(std::string const& text, ChatMsg msgType, Language language, float textRange, WorldObject const* target) +void Unit::Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target) { Trinity::CustomChatTextBuilder builder(this, msgType, text, language, target); Trinity::LocalizedDo localizer(builder); @@ -13168,22 +13168,22 @@ void Unit::Talk(std::string const& text, ChatMsg msgType, Language language, flo Cell::VisitWorldObjects(this, worker, textRange); } -void Unit::Say(std::string const& text, Language language, WorldObject const* target /*= nullptr*/) +void Unit::Say(std::string_view text, Language language, WorldObject const* target /*= nullptr*/) { Talk(text, CHAT_MSG_MONSTER_SAY, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target); } -void Unit::Yell(std::string const& text, Language language, WorldObject const* target /*= nullptr*/) +void Unit::Yell(std::string_view text, Language language, WorldObject const* target /*= nullptr*/) { Talk(text, CHAT_MSG_MONSTER_YELL, language, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target); } -void Unit::TextEmote(std::string const& text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/) +void Unit::TextEmote(std::string_view text, WorldObject const* target /*= nullptr*/, bool isBossEmote /*= false*/) { Talk(text, isBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, LANG_UNIVERSAL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target); } -void Unit::Whisper(std::string const& text, Language language, Player* target, bool isBossWhisper /*= false*/) +void Unit::Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper /*= false*/) { if (!target) return; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index b1fcabf673a..50e27c7f32b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1833,11 +1833,11 @@ class TC_GAME_API Unit : public WorldObject bool IsHighestExclusiveAura(Aura const* aura, bool removeOtherAuraApplications = false); bool IsHighestExclusiveAuraEffect(SpellInfo const* spellInfo, AuraType auraType, int32 effectAmount, uint32 auraEffectMask, bool removeOtherAuraApplications = false); - virtual void Talk(std::string const& text, ChatMsg msgType, Language language, float textRange, WorldObject const* target); - virtual void Say(std::string const& text, Language language, WorldObject const* target = nullptr); - virtual void Yell(std::string const& text, Language language, WorldObject const* target = nullptr); - virtual void TextEmote(std::string const& text, WorldObject const* target = nullptr, bool isBossEmote = false); - virtual void Whisper(std::string const& text, Language language, Player* target, bool isBossWhisper = false); + virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const* target); + virtual void Say(std::string_view text, Language language, WorldObject const* target = nullptr); + virtual void Yell(std::string_view text, Language language, WorldObject const* target = nullptr); + virtual void TextEmote(std::string_view text, WorldObject const* target = nullptr, bool isBossEmote = false); + virtual void Whisper(std::string_view text, Language language, Player* target, bool isBossWhisper = false); virtual void Talk(uint32 textId, ChatMsg msgType, float textRange, WorldObject const* target); virtual void Say(uint32 textId, WorldObject const* target = nullptr); virtual void Yell(uint32 textId, WorldObject const* target = nullptr); diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index 19545d81b7c..d7e8739d9ca 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -78,28 +78,28 @@ template class TC_GAME_API HashMapHolder; namespace PlayerNameMapHolder { -typedef std::unordered_map MapType; -static MapType PlayerNameMap; + typedef std::unordered_map MapType; + static MapType PlayerNameMap; -void Insert(Player* p) -{ - PlayerNameMap[p->GetName()] = p; -} + void Insert(Player* p) + { + PlayerNameMap[p->GetName()] = p; + } -void Remove(Player* p) -{ - PlayerNameMap.erase(p->GetName()); -} + void Remove(Player* p) + { + PlayerNameMap.erase(p->GetName()); + } -Player* Find(std::string const& name) -{ - std::string charName(name); - if (!normalizePlayerName(charName)) - return nullptr; + Player* Find(std::string_view name) + { + std::string charName(name); + if (!normalizePlayerName(charName)) + return nullptr; - auto itr = PlayerNameMap.find(charName); - return (itr != PlayerNameMap.end()) ? itr->second : nullptr; -} + auto itr = PlayerNameMap.find(charName); + return (itr != PlayerNameMap.end()) ? itr->second : nullptr; + } } // namespace PlayerNameMapHolder WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, ObjectGuid const& guid) @@ -264,7 +264,7 @@ Player* ObjectAccessor::FindPlayer(ObjectGuid const& guid) return player && player->IsInWorld() ? player : nullptr; } -Player* ObjectAccessor::FindPlayerByName(std::string const& name) +Player* ObjectAccessor::FindPlayerByName(std::string_view name) { Player* player = PlayerNameMapHolder::Find(name); if (!player || !player->IsInWorld()) @@ -284,7 +284,7 @@ Player* ObjectAccessor::FindConnectedPlayer(ObjectGuid const& guid) return HashMapHolder::Find(guid); } -Player* ObjectAccessor::FindConnectedPlayerByName(std::string const& name) +Player* ObjectAccessor::FindConnectedPlayerByName(std::string_view name) { return PlayerNameMapHolder::Find(name); } diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index b5bb368041d..1ff11bb6b77 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -81,12 +81,12 @@ namespace ObjectAccessor // these functions return objects if found in whole world // ACCESS LIKE THAT IS NOT THREAD SAFE TC_GAME_API Player* FindPlayer(ObjectGuid const&); - TC_GAME_API Player* FindPlayerByName(std::string const& name); + TC_GAME_API Player* FindPlayerByName(std::string_view name); TC_GAME_API Player* FindPlayerByLowGUID(ObjectGuid::LowType lowguid); // this returns Player even if he is not in world, for example teleporting TC_GAME_API Player* FindConnectedPlayer(ObjectGuid const&); - TC_GAME_API Player* FindConnectedPlayerByName(std::string const& name); + TC_GAME_API Player* FindConnectedPlayerByName(std::string_view name); // when using this, you must use the hashmapholder's lock TC_GAME_API HashMapHolder::MapType const& GetPlayers(); diff --git a/src/server/game/Movement/MovementDefines.h b/src/server/game/Movement/MovementDefines.h index 224d1399a31..51c588c703b 100644 --- a/src/server/game/Movement/MovementDefines.h +++ b/src/server/game/Movement/MovementDefines.h @@ -24,6 +24,7 @@ #define SPEED_CHARGE 42.0f // assume it is 25 yard per 0.6 second +// EnumUtils: DESCRIBE THIS enum MovementGeneratorType : uint8 { IDLE_MOTION_TYPE = 0, // IdleMovementGenerator.h @@ -45,7 +46,7 @@ enum MovementGeneratorType : uint8 EFFECT_MOTION_TYPE = 16, SPLINE_CHAIN_MOTION_TYPE = 17, // SplineChainMovementGenerator.h FORMATION_MOTION_TYPE = 18, // FormationMovementGenerator.h - MAX_MOTION_TYPE // limit + MAX_MOTION_TYPE // SKIP }; enum MovementGeneratorMode : uint8 diff --git a/src/server/game/Movement/enuminfo_MovementDefines.cpp b/src/server/game/Movement/enuminfo_MovementDefines.cpp new file mode 100644 index 00000000000..e22c45c5174 --- /dev/null +++ b/src/server/game/Movement/enuminfo_MovementDefines.cpp @@ -0,0 +1,115 @@ +/* + * This file is part of the TrinityCore 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 General Public License as published by the + * Free Software Foundation; either version 2 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 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 . + */ + +#include "MovementDefines.h" +#include "Define.h" +#include "SmartEnum.h" +#include + +namespace Trinity::Impl::EnumUtilsImpl +{ + +/*******************************************************************************\ +|* data for enum 'MovementGeneratorType' in 'MovementDefines.h' auto-generated *| +\*******************************************************************************/ +template <> +TC_API_EXPORT EnumText EnumUtils::ToString(MovementGeneratorType value) +{ + switch (value) + { + case IDLE_MOTION_TYPE: return { "IDLE_MOTION_TYPE", "IDLE_MOTION_TYPE", "IdleMovementGenerator.h" }; + case RANDOM_MOTION_TYPE: return { "RANDOM_MOTION_TYPE", "RANDOM_MOTION_TYPE", "RandomMovementGenerator.h" }; + case WAYPOINT_MOTION_TYPE: return { "WAYPOINT_MOTION_TYPE", "WAYPOINT_MOTION_TYPE", "WaypointMovementGenerator.h" }; + case MAX_DB_MOTION_TYPE: return { "MAX_DB_MOTION_TYPE", "MAX_DB_MOTION_TYPE", "Below motion types can't be set in DB." }; + case CONFUSED_MOTION_TYPE: return { "CONFUSED_MOTION_TYPE", "CONFUSED_MOTION_TYPE", "ConfusedMovementGenerator.h" }; + case CHASE_MOTION_TYPE: return { "CHASE_MOTION_TYPE", "CHASE_MOTION_TYPE", "ChaseMovementGenerator.h" }; + case HOME_MOTION_TYPE: return { "HOME_MOTION_TYPE", "HOME_MOTION_TYPE", "HomeMovementGenerator.h" }; + case FLIGHT_MOTION_TYPE: return { "FLIGHT_MOTION_TYPE", "FLIGHT_MOTION_TYPE", "FlightPathMovementGenerator.h" }; + case POINT_MOTION_TYPE: return { "POINT_MOTION_TYPE", "POINT_MOTION_TYPE", "PointMovementGenerator.h" }; + case FLEEING_MOTION_TYPE: return { "FLEEING_MOTION_TYPE", "FLEEING_MOTION_TYPE", "FleeingMovementGenerator.h" }; + case DISTRACT_MOTION_TYPE: return { "DISTRACT_MOTION_TYPE", "DISTRACT_MOTION_TYPE", "IdleMovementGenerator.h" }; + case ASSISTANCE_MOTION_TYPE: return { "ASSISTANCE_MOTION_TYPE", "ASSISTANCE_MOTION_TYPE", "PointMovementGenerator.h" }; + case ASSISTANCE_DISTRACT_MOTION_TYPE: return { "ASSISTANCE_DISTRACT_MOTION_TYPE", "ASSISTANCE_DISTRACT_MOTION_TYPE", "IdleMovementGenerator.h" }; + case TIMED_FLEEING_MOTION_TYPE: return { "TIMED_FLEEING_MOTION_TYPE", "TIMED_FLEEING_MOTION_TYPE", "FleeingMovementGenerator.h" }; + case FOLLOW_MOTION_TYPE: return { "FOLLOW_MOTION_TYPE", "FOLLOW_MOTION_TYPE", "FollowMovementGenerator.h" }; + case ROTATE_MOTION_TYPE: return { "ROTATE_MOTION_TYPE", "ROTATE_MOTION_TYPE", "IdleMovementGenerator.h" }; + case EFFECT_MOTION_TYPE: return { "EFFECT_MOTION_TYPE", "EFFECT_MOTION_TYPE", "" }; + case SPLINE_CHAIN_MOTION_TYPE: return { "SPLINE_CHAIN_MOTION_TYPE", "SPLINE_CHAIN_MOTION_TYPE", "SplineChainMovementGenerator.h" }; + case FORMATION_MOTION_TYPE: return { "FORMATION_MOTION_TYPE", "FORMATION_MOTION_TYPE", "FormationMovementGenerator.h" }; + default: throw std::out_of_range("value"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils::Count() { return 19; } + +template <> +TC_API_EXPORT MovementGeneratorType EnumUtils::FromIndex(size_t index) +{ + switch (index) + { + case 0: return IDLE_MOTION_TYPE; + case 1: return RANDOM_MOTION_TYPE; + case 2: return WAYPOINT_MOTION_TYPE; + case 3: return MAX_DB_MOTION_TYPE; + case 4: return CONFUSED_MOTION_TYPE; + case 5: return CHASE_MOTION_TYPE; + case 6: return HOME_MOTION_TYPE; + case 7: return FLIGHT_MOTION_TYPE; + case 8: return POINT_MOTION_TYPE; + case 9: return FLEEING_MOTION_TYPE; + case 10: return DISTRACT_MOTION_TYPE; + case 11: return ASSISTANCE_MOTION_TYPE; + case 12: return ASSISTANCE_DISTRACT_MOTION_TYPE; + case 13: return TIMED_FLEEING_MOTION_TYPE; + case 14: return FOLLOW_MOTION_TYPE; + case 15: return ROTATE_MOTION_TYPE; + case 16: return EFFECT_MOTION_TYPE; + case 17: return SPLINE_CHAIN_MOTION_TYPE; + case 18: return FORMATION_MOTION_TYPE; + default: throw std::out_of_range("index"); + } +} + +template <> +TC_API_EXPORT size_t EnumUtils::ToIndex(MovementGeneratorType value) +{ + switch (value) + { + case IDLE_MOTION_TYPE: return 0; + case RANDOM_MOTION_TYPE: return 1; + case WAYPOINT_MOTION_TYPE: return 2; + case MAX_DB_MOTION_TYPE: return 3; + case CONFUSED_MOTION_TYPE: return 4; + case CHASE_MOTION_TYPE: return 5; + case HOME_MOTION_TYPE: return 6; + case FLIGHT_MOTION_TYPE: return 7; + case POINT_MOTION_TYPE: return 8; + case FLEEING_MOTION_TYPE: return 9; + case DISTRACT_MOTION_TYPE: return 10; + case ASSISTANCE_MOTION_TYPE: return 11; + case ASSISTANCE_DISTRACT_MOTION_TYPE: return 12; + case TIMED_FLEEING_MOTION_TYPE: return 13; + case FOLLOW_MOTION_TYPE: return 14; + case ROTATE_MOTION_TYPE: return 15; + case EFFECT_MOTION_TYPE: return 16; + case SPLINE_CHAIN_MOTION_TYPE: return 17; + case FORMATION_MOTION_TYPE: return 18; + default: throw std::out_of_range("value"); + } +} +} diff --git a/src/server/game/Texts/ChatTextBuilder.h b/src/server/game/Texts/ChatTextBuilder.h index 94ae1339652..40edaeebae7 100644 --- a/src/server/game/Texts/ChatTextBuilder.h +++ b/src/server/game/Texts/ChatTextBuilder.h @@ -71,7 +71,7 @@ namespace Trinity class CustomChatTextBuilder { public: - CustomChatTextBuilder(WorldObject const* obj, ChatMsg msgType, std::string const& text, Language language = LANG_UNIVERSAL, WorldObject const* target = nullptr) + CustomChatTextBuilder(WorldObject const* obj, ChatMsg msgType, std::string_view text, Language language = LANG_UNIVERSAL, WorldObject const* target = nullptr) : _source(obj), _msgType(msgType), _text(text), _language(language), _target(target) { } ChatPacketSender* operator()(LocaleConstant locale) const; diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 93dfac2992e..f2556ba8804 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -45,13 +45,15 @@ EndScriptData */ #include #include -// definitions are over in cs_npc.cpp -bool HandleNpcSpawnGroup(ChatHandler* handler, char const* args); -bool HandleNpcDespawnGroup(ChatHandler* handler, char const* args); using namespace Trinity::ChatCommands; using GameObjectSpawnId = Variant, ObjectGuid::LowType>; using GameObjectEntry = Variant, uint32>; + +// definitions are over in cs_npc.cpp +bool HandleNpcSpawnGroup(ChatHandler* handler, std::vector, ExactSequence<'i','g','n','o','r','e','r','e','s','p','a','w','n'>>> const& opts); +bool HandleNpcDespawnGroup(ChatHandler* handler, std::vector>> const& opts); + class gobject_commandscript : public CommandScript { public: diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 8107ef086d6..b4bd7f6fc51 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -48,87 +48,14 @@ EndScriptData */ #include #include -bool HandleNpcSpawnGroup(ChatHandler* handler, char const* args) -{ - if (!*args) - return false; - - bool ignoreRespawn = false; - bool force = false; - uint32 groupId = 0; - - // Decode arguments - char* arg = strtok((char*)args, " "); - while (arg) - { - std::string thisArg = arg; - std::transform(thisArg.begin(), thisArg.end(), thisArg.begin(), ::tolower); - if (thisArg == "ignorerespawn") - ignoreRespawn = true; - else if (thisArg == "force") - force = true; - else if (thisArg.empty() || !(std::count_if(thisArg.begin(), thisArg.end(), ::isdigit) == (int)thisArg.size())) - return false; - else - groupId = atoi(thisArg.c_str()); - - arg = strtok(nullptr, " "); - } - - Player* player = handler->GetSession()->GetPlayer(); - - std::vector creatureList; - if (!player->GetMap()->SpawnGroupSpawn(groupId, ignoreRespawn, force, &creatureList)) - { - handler->PSendSysMessage(LANG_SPAWNGROUP_BADGROUP, groupId); - handler->SetSentErrorMessage(true); - return false; - } - - handler->PSendSysMessage(LANG_SPAWNGROUP_SPAWNCOUNT, creatureList.size()); - - return true; -} - -bool HandleNpcDespawnGroup(ChatHandler* handler, char const* args) -{ - if (!*args) - return false; - - bool deleteRespawnTimes = false; - uint32 groupId = 0; - - // Decode arguments - char* arg = strtok((char*)args, " "); - while (arg) - { - std::string thisArg = arg; - std::transform(thisArg.begin(), thisArg.end(), thisArg.begin(), ::tolower); - if (thisArg == "removerespawntime") - deleteRespawnTimes = true; - else if (thisArg.empty() || !(std::count_if(thisArg.begin(), thisArg.end(), ::isdigit) == (int)thisArg.size())) - return false; - else - groupId = atoi(thisArg.c_str()); - - arg = strtok(nullptr, " "); - } - - Player* player = handler->GetSession()->GetPlayer(); - - size_t n = 0; - if (!player->GetMap()->SpawnGroupDespawn(groupId, deleteRespawnTimes, &n)) - { - handler->PSendSysMessage(LANG_SPAWNGROUP_BADGROUP, groupId); - handler->SetSentErrorMessage(true); - return false; - } - handler->PSendSysMessage("Despawned a total of %zu objects.", n); +using namespace Trinity::ChatCommands; +using CreatureSpawnId = Variant, ObjectGuid::LowType>; +using CreatureEntry = Variant, uint32>; - return true; -} +// shared with cs_gobject.cpp, definitions are at the bottom of this file +bool HandleNpcSpawnGroup(ChatHandler* handler, std::vector, ExactSequence<'i','g','n','o','r','e','r','e','s','p','a','w','n'>>> const& opts); +bool HandleNpcDespawnGroup(ChatHandler* handler, std::vector>> const& opts); -using namespace Trinity::ChatCommands; class npc_commandscript : public CommandScript { public: @@ -199,16 +126,8 @@ public: } //add spawn of creature - static bool HandleNpcAddCommand(ChatHandler* handler, char const* args) + static bool HandleNpcAddCommand(ChatHandler* handler, CreatureEntry id) { - if (!*args) - return false; - - char* charID = handler->extractKeyFromLink((char*)args, "Hcreature_entry"); - if (!charID) - return false; - - uint32 id = atoul(charID); if (!sObjectMgr->GetCreatureTemplate(id)) return false; @@ -254,38 +173,15 @@ public: } //add item in vendorlist - static bool HandleNpcAddVendorItemCommand(ChatHandler* handler, char const* args) + static bool HandleNpcAddVendorItemCommand(ChatHandler* handler, ItemTemplate const* item, Optional mc, Optional it, Optional ec, Optional bonusListIDs) { - if (!*args) - return false; - - const uint8 type = 1; // FIXME: make type (1 item, 2 currency) an argument - - char* pitem = handler->extractKeyFromLink((char*)args, "Hitem"); - if (!pitem) + if (!item) { handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND); handler->SetSentErrorMessage(true); return false; } - uint32 itemId = atoull(pitem); - if (!itemId) - return false; - - char* fmaxcount = strtok(nullptr, " "); //add maxcount, default: 0 - uint32 maxcount = 0; - if (fmaxcount) - maxcount = atoul(fmaxcount); - - char* fincrtime = strtok(nullptr, " "); //add incrtime, default: 0 - uint32 incrtime = 0; - if (fincrtime) - incrtime = atoul(fincrtime); - - char* fextendedcost = strtok(nullptr, " "); //add ExtendedCost, default: 0 - uint32 extendedcost = fextendedcost ? atoul(fextendedcost) : 0; - char const* fbonuslist = strtok(nullptr, " "); Creature* vendor = handler->getSelectedCreature(); if (!vendor) { @@ -294,6 +190,10 @@ public: return false; } + uint32 itemId = item->GetId(); + uint32 maxcount = mc.value_or(0); + uint32 incrtime = it.value_or(0); + uint32 extendedcost = ec.value_or(0); uint32 vendor_entry = vendor->GetEntry(); VendorItem vItem; @@ -301,10 +201,10 @@ public: vItem.maxcount = maxcount; vItem.incrtime = incrtime; vItem.ExtendedCost = extendedcost; - vItem.Type = type; + vItem.Type = ITEM_VENDOR_TYPE_ITEM; - if (fbonuslist) - for (std::string_view token : Trinity::Tokenize(fbonuslist, ';', false)) + if (bonusListIDs) + for (std::string_view token : Trinity::Tokenize(*bonusListIDs, ';', false)) if (Optional bonusListID = Trinity::StringTo(token)) vItem.BonusListIDs.push_back(*bonusListID); @@ -323,16 +223,8 @@ public: } //add move for creature - static bool HandleNpcAddMoveCommand(ChatHandler* handler, char const* args) + static bool HandleNpcAddMoveCommand(ChatHandler* handler, CreatureSpawnId lowGuid) { - if (!*args) - return false; - - char* guidStr = strtok((char*)args, " "); - char* waitStr = strtok((char*)nullptr, " "); - - ObjectGuid::LowType lowGuid = atoull(guidStr); - // attempt check creature existence by DB data CreatureData const* data = sObjectMgr->GetCreatureData(lowGuid); if (!data) @@ -342,11 +234,6 @@ public: return false; } - int wait = waitStr ? atoi(waitStr) : 0; - - if (wait < 0) - wait = 0; - // Update movement type WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_MOVEMENT_TYPE); @@ -360,7 +247,7 @@ public: return true; } - static bool HandleNpcSetAllowMovementCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleNpcSetAllowMovementCommand(ChatHandler* handler) { if (sWorld->getAllowMovement()) { @@ -375,12 +262,8 @@ public: return true; } - static bool HandleNpcSetEntryCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetEntryCommand(ChatHandler* handler, CreatureEntry newEntryNum) { - if (!*args) - return false; - - uint32 newEntryNum = atoul(args); if (!newEntryNum) return false; @@ -400,12 +283,8 @@ public: } //change level of creature or pet - static bool HandleNpcSetLevelCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetLevelCommand(ChatHandler* handler, uint8 lvl) { - if (!*args) - return false; - - uint8 lvl = (uint8) atoi(args); if (lvl < 1 || lvl > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL) + 3) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -429,7 +308,7 @@ public: return true; } - static bool HandleNpcDeleteCommand(ChatHandler* handler, Optional, ObjectGuid::LowType>> spawnIdArg) + static bool HandleNpcDeleteCommand(ChatHandler* handler, Optional spawnIdArg) { ObjectGuid::LowType spawnId; if (spawnIdArg) @@ -466,11 +345,8 @@ public: } //del item from vendor list - static bool HandleNpcDeleteVendorItemCommand(ChatHandler* handler, char const* args) + static bool HandleNpcDeleteVendorItemCommand(ChatHandler* handler, ItemTemplate const* item) { - if (!*args) - return false; - Creature* vendor = handler->getSelectedCreature(); if (!vendor || !vendor->IsVendor()) { @@ -479,18 +355,15 @@ public: return false; } - char* pitem = handler->extractKeyFromLink((char*)args, "Hitem"); - if (!pitem) + if (!item) { handler->SendSysMessage(LANG_COMMAND_NEEDITEMSEND); handler->SetSentErrorMessage(true); return false; } - uint32 itemId = atoul(pitem); - - const uint8 type = 1; // FIXME: make type (1 item, 2 currency) an argument - if (!sObjectMgr->RemoveVendorItem(vendor->GetEntry(), itemId, type)) + uint32 itemId = item->GetId(); + if (!sObjectMgr->RemoveVendorItem(vendor->GetEntry(), ITEM_VENDOR_TYPE_ITEM, itemId)) { handler->PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId); handler->SetSentErrorMessage(true); @@ -504,13 +377,8 @@ public: } //set faction of creature - static bool HandleNpcSetFactionIdCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetFactionIdCommand(ChatHandler* handler, uint32 factionId) { - if (!*args) - return false; - - uint32 factionId = atoul(args); - if (!sFactionTemplateStore.LookupEntry(factionId)) { handler->PSendSysMessage(LANG_WRONG_FACTION, factionId); @@ -574,23 +442,8 @@ public: } //set data of creature for testing scripting - static bool HandleNpcSetDataCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetDataCommand(ChatHandler* handler, uint32 data_1, uint32 data_2) { - if (!*args) - return false; - - char* arg1 = strtok((char*)args, " "); - char* arg2 = strtok((char*)nullptr, ""); - - if (!arg1 || !arg2) - return false; - - uint32 data_1 = (uint32)atoi(arg1); - uint32 data_2 = (uint32)atoi(arg2); - - if (!data_1 || !data_2) - return false; - Creature* creature = handler->getSelectedCreature(); if (!creature) @@ -607,7 +460,7 @@ public: } //npc follow handling - static bool HandleNpcFollowCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleNpcFollowCommand(ChatHandler* handler) { Player* player = handler->GetSession()->GetPlayer(); Creature* creature = handler->getSelectedCreature(); @@ -626,7 +479,7 @@ public: return true; } - static bool HandleNpcInfoCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleNpcInfoCommand(ChatHandler* handler) { Creature* target = handler->getSelectedCreature(); @@ -720,9 +573,9 @@ public: return true; } - static bool HandleNpcNearCommand(ChatHandler* handler, char const* args) + static bool HandleNpcNearCommand(ChatHandler* handler, Optional dist) { - float distance = (!*args) ? 10.0f : float((atof(args))); + float distance = dist.value_or(10.0f); uint32 count = 0; Player* player = handler->GetSession()->GetPlayer(); @@ -767,26 +620,17 @@ public: } //move selected creature - static bool HandleNpcMoveCommand(ChatHandler* handler, char const* args) + static bool HandleNpcMoveCommand(ChatHandler* handler, Optional spawnid) { - ObjectGuid::LowType lowguid = UI64LIT(0); - Creature* creature = handler->getSelectedCreature(); Player const* player = handler->GetSession()->GetPlayer(); if (!player) return false; - if (creature) - lowguid = creature->GetSpawnId(); - else - { - // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r - char* cId = handler->extractKeyFromLink((char*)args, "Hcreature"); - if (!cId) - return false; + if (!spawnid && !creature) + return false; - lowguid = atoull(cId); - } + ObjectGuid::LowType lowguid = spawnid ? *spawnid : creature->GetSpawnId(); // Attempting creature load from DB data CreatureData const* data = sObjectMgr->GetCreatureData(lowguid); if (!data) @@ -819,23 +663,15 @@ public: // respawn selected creature at the new location if (creature) - { - if (creature->IsAlive()) - creature->setDeathState(JUST_DIED); - creature->Respawn(true); - if (!creature->GetRespawnCompatibilityMode()) - creature->AddObjectToRemoveList(); - } + creature->DespawnOrUnsummon(0s, 1s); handler->PSendSysMessage(LANG_COMMAND_CREATUREMOVED); return true; } //play npc emote - static bool HandleNpcPlayEmoteCommand(ChatHandler* handler, char const* args) + static bool HandleNpcPlayEmoteCommand(ChatHandler* handler, uint32 emote) { - uint32 emote = atoi((char*)args); - Creature* target = handler->getSelectedCreature(); if (!target) { @@ -850,13 +686,8 @@ public: } //set model of creature - static bool HandleNpcSetModelCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetModelCommand(ChatHandler* handler, uint32 displayId) { - if (!*args) - return false; - - uint32 displayId = atoul(args); - Creature* creature = handler->getSelectedCreature(); if (!creature || creature->IsPet()) @@ -868,7 +699,7 @@ public: if (!sCreatureDisplayInfoStore.LookupEntry(displayId)) { - handler->PSendSysMessage(LANG_COMMAND_INVALID_PARAM, args); + handler->PSendSysMessage(LANG_COMMAND_INVALID_PARAM, Trinity::ToString(displayId).c_str()); handler->SetSentErrorMessage(true); return false; } @@ -893,11 +724,8 @@ public: * additional parameter: NODEL - so no waypoints are deleted, if you * change the movement type */ - static bool HandleNpcSetMoveTypeCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetMoveTypeCommand(ChatHandler* handler, Optional lowGuid, Variant, ExactSequence<'r','a','n','d','o','m'>, ExactSequence<'w','a','y'>> type, Optional> nodel) { - if (!*args) - return false; - // 3 arguments: // GUID (optional - you can also select the creature) // stay|random|way (determines the kind of movement) @@ -905,50 +733,14 @@ public: // this is very handy if you want to do waypoints, that are // later switched on/off according to special events (like escort // quests, etc) - char* guid_str = strtok((char*)args, " "); - char* type_str = strtok((char*)nullptr, " "); - char* dontdel_str = strtok((char*)nullptr, " "); - - bool doNotDelete = false; - if (!guid_str) - return false; + bool doNotDelete = nodel.has_value(); ObjectGuid::LowType lowguid = UI64LIT(0); Creature* creature = nullptr; - if (dontdel_str) + if (!lowGuid) // case .setmovetype $move_type (with selected creature) { - //TC_LOG_ERROR("misc", "DEBUG: All 3 params are set"); - - // All 3 params are set - // GUID - // type - // doNotDEL - if (stricmp(dontdel_str, "NODEL") == 0) - { - //TC_LOG_ERROR("misc", "DEBUG: doNotDelete = true;"); - doNotDelete = true; - } - } - else - { - // Only 2 params - but maybe NODEL is set - if (type_str) - { - TC_LOG_ERROR("misc", "DEBUG: Only 2 params "); - if (stricmp(type_str, "NODEL") == 0) - { - //TC_LOG_ERROR("misc", "DEBUG: type_str, NODEL "); - doNotDelete = true; - type_str = nullptr; - } - } - } - - if (!type_str) // case .setmovetype $move_type (with selected creature) - { - type_str = guid_str; creature = handler->getSelectedCreature(); if (!creature || creature->IsPet()) return false; @@ -956,7 +748,7 @@ public: } else // case .setmovetype #creature_guid $move_type (with selected creature) { - lowguid = atoull(guid_str); + lowguid = *lowGuid; if (lowguid) creature = handler->GetCreatureFromPlayerMapByDbGuid(lowguid); @@ -982,17 +774,20 @@ public: // and creature point (maybe) to this creature or nullptr MovementGeneratorType move_type; - - std::string type = type_str; - - if (type == "stay") - move_type = IDLE_MOTION_TYPE; - else if (type == "random") - move_type = RANDOM_MOTION_TYPE; - else if (type == "way") - move_type = WAYPOINT_MOTION_TYPE; - else - return false; + switch (type.index()) + { + case 0: + move_type = IDLE_MOTION_TYPE; + break; + case 1: + move_type = RANDOM_MOTION_TYPE; + break; + case 2: + move_type = WAYPOINT_MOTION_TYPE; + break; + default: + return false; + } // update movement type //if (doNotDelete == false) @@ -1015,11 +810,11 @@ public: } if (doNotDelete == false) { - handler->PSendSysMessage(LANG_MOVE_TYPE_SET, type_str); + handler->PSendSysMessage(LANG_MOVE_TYPE_SET, EnumUtils::ToTitle(move_type)); } else { - handler->PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL, type_str); + handler->PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL, EnumUtils::ToTitle(move_type)); } return true; @@ -1053,13 +848,9 @@ public: //npc phase handling //change phase of creature - static bool HandleNpcSetPhaseCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetPhaseCommand(ChatHandler* handler, uint32 phaseID) { - if (!*args) - return false; - - uint32 phaseID = atoul(args); - if (!sPhaseStore.LookupEntry(phaseID)) + if (phaseID == 0) { handler->SendSysMessage(LANG_PHASE_NOTFOUND); handler->SetSentErrorMessage(true); @@ -1084,12 +875,8 @@ public: } //set spawn dist of creature - static bool HandleNpcSetWanderDistanceCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetWanderDistanceCommand(ChatHandler* handler, float option) { - if (!*args) - return false; - - float option = (float)(atof((char*)args)); if (option < 0.0f) { handler->SendSysMessage(LANG_BAD_VALUE); @@ -1097,7 +884,7 @@ public: } MovementGeneratorType mtype = IDLE_MOTION_TYPE; - if (option >0.0f) + if (option > 0.0f) mtype = RANDOM_MOTION_TYPE; Creature* creature = handler->getSelectedCreature(); @@ -1130,28 +917,15 @@ public: } //spawn time handling - static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, uint32 spawnTime) { - if (!*args) - return false; - - char* stime = strtok((char*)args, " "); - - if (!stime) - return false; - - uint32 spawnTime = atoul(stime); - Creature* creature = handler->getSelectedCreature(); if (!creature) return false; - ObjectGuid::LowType guidLow = creature->GetSpawnId(); - WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS); stmt->setUInt32(0, spawnTime); - stmt->setUInt64(1, guidLow); - + stmt->setUInt64(1, creature->GetSpawnId()); WorldDatabase.Execute(stmt); creature->SetRespawnDelay(spawnTime); @@ -1160,9 +934,9 @@ public: return true; } - static bool HandleNpcSayCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSayCommand(ChatHandler* handler, Tail text) { - if (!*args) + if (text.empty()) return false; Creature* creature = handler->getSelectedCreature(); @@ -1173,24 +947,23 @@ public: return false; } - creature->Say(args, LANG_UNIVERSAL); + creature->Say(text, LANG_UNIVERSAL); // make some emotes - char lastchar = args[strlen(args) - 1]; - switch (lastchar) + switch (text.back()) { - case '?': creature->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); break; - case '!': creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); break; - default: creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); break; + case '?': creature->HandleEmoteCommand(EMOTE_ONESHOT_QUESTION); break; + case '!': creature->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION); break; + default: creature->HandleEmoteCommand(EMOTE_ONESHOT_TALK); break; } return true; } //show text emote by creature in chat - static bool HandleNpcTextEmoteCommand(ChatHandler* handler, char const* args) + static bool HandleNpcTextEmoteCommand(ChatHandler* handler, Tail text) { - if (!*args) + if (text.empty()) return false; Creature* creature = handler->getSelectedCreature(); @@ -1202,13 +975,13 @@ public: return false; } - creature->TextEmote(args); + creature->TextEmote(text); return true; } // npc unfollow handling - static bool HandleNpcUnFollowCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleNpcUnFollowCommand(ChatHandler* handler) { Player* player = handler->GetSession()->GetPlayer(); Creature* creature = handler->getSelectedCreature(); @@ -1243,24 +1016,10 @@ public: } // make npc whisper to player - static bool HandleNpcWhisperCommand(ChatHandler* handler, char const* args) + static bool HandleNpcWhisperCommand(ChatHandler* handler, Variant, std::string_view> recv, Tail text) { - if (!*args) - { - handler->SendSysMessage(LANG_CMD_SYNTAX); - handler->SetSentErrorMessage(true); + if (text.empty()) return false; - } - - char* receiver_str = strtok((char*)args, " "); - char* text = strtok(nullptr, ""); - - if (!receiver_str || !text) - { - handler->SendSysMessage(LANG_CMD_SYNTAX); - handler->SetSentErrorMessage(true); - return false; - } Creature* creature = handler->getSelectedCreature(); if (!creature) @@ -1270,10 +1029,8 @@ public: return false; } - ObjectGuid receiver_guid = ObjectGuid::Create(strtoull(receiver_str, nullptr, 10)); - // check online security - Player* receiver = ObjectAccessor::FindPlayer(receiver_guid); + Player* receiver = ObjectAccessor::FindPlayerByName(recv); if (handler->HasLowerSecurity(receiver, ObjectGuid::Empty)) return false; @@ -1281,14 +1038,10 @@ public: return true; } - static bool HandleNpcYellCommand(ChatHandler* handler, char const* args) + static bool HandleNpcYellCommand(ChatHandler* handler, Tail text) { - if (!*args) - { - handler->SendSysMessage(LANG_CMD_SYNTAX); - handler->SetSentErrorMessage(true); + if (text.empty()) return false; - } Creature* creature = handler->getSelectedCreature(); if (!creature) @@ -1298,7 +1051,7 @@ public: return false; } - creature->Yell(args, LANG_UNIVERSAL); + creature->Yell(text, LANG_UNIVERSAL); // make an emote creature->HandleEmoteCommand(EMOTE_ONESHOT_SHOUT); @@ -1307,40 +1060,30 @@ public: } // add creature, temp only - static bool HandleNpcAddTempSpawnCommand(ChatHandler* handler, char const* args) + static bool HandleNpcAddTempSpawnCommand(ChatHandler* handler, Optional lootStr, CreatureEntry id) { - if (!*args) - return false; - bool loot = false; - char const* spawntype_str = strtok((char*)args, " "); - char const* entry_str = strtok(nullptr, ""); - if (stricmp(spawntype_str, "LOOT") == 0) - loot = true; - else if (stricmp(spawntype_str, "NOLOOT") == 0) - loot = false; - else - entry_str = args; - char* charID = handler->extractKeyFromLink((char*)entry_str, "Hcreature_entry"); - if (!charID) - return false; + if (lootStr) + { + if (StringEqualI(*lootStr, "loot")) + loot = true; + else if (StringEqualI(*lootStr, "noloot")) + loot = false; + else + return false; + } Player* chr = handler->GetSession()->GetPlayer(); - - uint32 id = atoul(charID); - if (!id) - return false; - if (!sObjectMgr->GetCreatureTemplate(id)) return false; - chr->SummonCreature(id, *chr, loot ? TEMPSUMMON_CORPSE_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN, 30s); + chr->SummonCreature(id, chr->GetPosition(), loot ? TEMPSUMMON_CORPSE_TIMED_DESPAWN : TEMPSUMMON_CORPSE_DESPAWN, 30s); return true; } //npc tame handling - static bool HandleNpcTameCommand(ChatHandler* handler, char const* /*args*/) + static bool HandleNpcTameCommand(ChatHandler* handler) { Creature* creatureTarget = handler->getSelectedCreature(); if (!creatureTarget || creatureTarget->IsPet()) @@ -1406,7 +1149,7 @@ public: return true; } - static bool HandleNpcEvadeCommand(ChatHandler* handler, char const* args) + static bool HandleNpcEvadeCommand(ChatHandler* handler, Optional why, Optional> force) { Creature* creatureTarget = handler->getSelectedCreature(); if (!creatureTarget || creatureTarget->IsPet()) @@ -1423,30 +1166,9 @@ public: return false; } - char* type_str = args ? strtok((char*)args, " ") : nullptr; - char* force_str = args ? strtok(nullptr, " ") : nullptr; - - CreatureAI::EvadeReason why = CreatureAI::EVADE_REASON_OTHER; - bool force = false; - if (type_str) - { - if (stricmp(type_str, "NO_HOSTILES") == 0 || stricmp(type_str, "EVADE_REASON_NO_HOSTILES") == 0) - why = CreatureAI::EVADE_REASON_NO_HOSTILES; - else if (stricmp(type_str, "BOUNDARY") == 0 || stricmp(type_str, "EVADE_REASON_BOUNDARY") == 0) - why = CreatureAI::EVADE_REASON_BOUNDARY; - else if (stricmp(type_str, "SEQUENCE_BREAK") == 0 || stricmp(type_str, "EVADE_REASON_SEQUENCE_BREAK") == 0) - why = CreatureAI::EVADE_REASON_SEQUENCE_BREAK; - else if (stricmp(type_str, "FORCE") == 0) - force = true; - - if (!force && force_str) - if (stricmp(force_str, "FORCE") == 0) - force = true; - } - if (force) creatureTarget->ClearUnitState(UNIT_STATE_EVADE); - creatureTarget->AI()->EnterEvadeMode(why); + creatureTarget->AI()->EnterEvadeMode(why.value_or(CreatureAI::EVADE_REASON_OTHER)); return true; } @@ -1480,7 +1202,7 @@ public: } } } - static bool HandleNpcShowLootCommand(ChatHandler* handler, char const* args) + static bool HandleNpcShowLootCommand(ChatHandler* handler, Optional> all) { Creature* creatureTarget = handler->getSelectedCreature(); if (!creatureTarget || creatureTarget->IsPet()) @@ -1501,7 +1223,7 @@ public: handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_HEADER, creatureTarget->GetName(), creatureTarget->GetEntry()); handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_MONEY, loot.gold / GOLD, (loot.gold%GOLD) / SILVER, loot.gold%SILVER); - if (strcmp(args, "all")) // nonzero from strcmp <-> not equal + if (!all) { handler->PSendSysMessage(LANG_COMMAND_NPC_SHOWLOOT_LABEL, "Standard items", loot.items.size()); for (LootItem const& item : loot.items) @@ -1542,12 +1264,8 @@ public: return true; } - static bool HandleNpcAddFormationCommand(ChatHandler* handler, char const* args) + static bool HandleNpcAddFormationCommand(ChatHandler* handler, ObjectGuid::LowType leaderGUID) { - if (!*args) - return false; - - ObjectGuid::LowType leaderGUID = atoull(args); Creature* creature = handler->getSelectedCreature(); if (!creature || !creature->GetSpawnId()) @@ -1589,13 +1307,8 @@ public: return true; } - static bool HandleNpcSetLinkCommand(ChatHandler* handler, char const* args) + static bool HandleNpcSetLinkCommand(ChatHandler* handler, ObjectGuid::LowType linkguid) { - if (!*args) - return false; - - ObjectGuid::LowType linkguid = atoull(args); - Creature* creature = handler->getSelectedCreature(); if (!creature) @@ -1624,16 +1337,18 @@ public: } /// @todo NpcCommands that need to be fixed : - static bool HandleNpcAddWeaponCommand(ChatHandler* /*handler*/, char const* /*args*/) + static bool HandleNpcAddWeaponCommand([[maybe_unused]] ChatHandler* handler, [[maybe_unused]] uint32 SlotID, [[maybe_unused]] ItemTemplate const* tmpItem) { - /*if (!*args) - return false; + /* + if (!tmpItem) + return; uint64 guid = handler->GetSession()->GetPlayer()->GetSelection(); if (guid == 0) { handler->SendSysMessage(LANG_NO_SELECTION); - return true; + handler->SetSentErrorMessage(true); + return false; } Creature* creature = ObjectAccessor::GetCreature(*handler->GetSession()->GetPlayer(), guid); @@ -1641,53 +1356,28 @@ public: if (!creature) { handler->SendSysMessage(LANG_SELECT_CREATURE); - return true; - } - - char* pSlotID = strtok((char*)args, " "); - if (!pSlotID) - return false; - - char* pItemID = strtok(nullptr, " "); - if (!pItemID) + handler->SetSentErrorMessage(true); return false; - - uint32 ItemID = atoi(pItemID); - uint32 SlotID = atoi(pSlotID); - - ItemTemplate* tmpItem = sObjectMgr->GetItemTemplate(ItemID); - - bool added = false; - if (tmpItem) - { - switch (SlotID) - { - case 1: - creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, ItemID); - added = true; - break; - case 2: - creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID); - added = true; - break; - case 3: - creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID); - added = true; - break; - default: - handler->PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST, SlotID); - added = false; - break; - } - - if (added) - handler->PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT, ItemID, tmpItem->Name1, SlotID); } - else + + switch (SlotID) { - handler->PSendSysMessage(LANG_ITEM_NOT_FOUND, ItemID); - return true; + case 1: + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, tmpItem->ItemId); + break; + case 2: + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, tmpItem->ItemId); + break; + case 3: + creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, tmpItem->ItemId); + break; + default: + handler->PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST, SlotID); + handler->SetSentErrorMessage(true); + return false; } + + handler->PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT, tmpItem->ItemID, tmpItem->Name1, SlotID); */ return true; } @@ -1697,3 +1387,75 @@ void AddSC_npc_commandscript() { new npc_commandscript(); } + +bool HandleNpcSpawnGroup(ChatHandler* handler, std::vector, ExactSequence<'i','g','n','o','r','e','r','e','s','p','a','w','n'>>> const& opts) +{ + if (opts.empty()) + return false; + + bool ignoreRespawn = false; + bool force = false; + uint32 groupId = 0; + + // Decode arguments + for (auto const& variant : opts) + { + switch (variant.index()) + { + case 0: + groupId = variant.get(); + break; + case 1: + force = true; + break; + case 2: + ignoreRespawn = true; + break; + } + } + + Player* player = handler->GetSession()->GetPlayer(); + + std::vector creatureList; + if (!player->GetMap()->SpawnGroupSpawn(groupId, ignoreRespawn, force, &creatureList)) + { + handler->PSendSysMessage(LANG_SPAWNGROUP_BADGROUP, groupId); + handler->SetSentErrorMessage(true); + return false; + } + + handler->PSendSysMessage(LANG_SPAWNGROUP_SPAWNCOUNT, creatureList.size()); + + return true; +} + +bool HandleNpcDespawnGroup(ChatHandler* handler, std::vector>> const& opts) +{ + if (opts.empty()) + return false; + + bool deleteRespawnTimes = false; + uint32 groupId = 0; + + // Decode arguments + for (auto const& variant : opts) + { + if (variant.holds_alternative()) + groupId = variant.get(); + else + deleteRespawnTimes = true; + } + + Player* player = handler->GetSession()->GetPlayer(); + + size_t n = 0; + if (!player->GetMap()->SpawnGroupDespawn(groupId, deleteRespawnTimes, &n)) + { + handler->PSendSysMessage(LANG_SPAWNGROUP_BADGROUP, groupId); + handler->SetSentErrorMessage(true); + return false; + } + handler->PSendSysMessage("Despawned a total of %zu objects.", n); + + return true; +} -- cgit v1.2.3