aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2020-09-04 00:58:23 +0200
committerShauren <shauren.trinity@gmail.com>2022-02-05 00:43:55 +0100
commit4d62cc70d6a7726d6619ba5c722fcb74d1123396 (patch)
tree723da75a1eac12b687b570fffbfaa7fa093b7b47
parent6fded37e86bc77cd54be63139fb434708223da98 (diff)
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)
-rw-r--r--contrib/enumutils_describe.py23
-rw-r--r--src/server/game/AI/CreatureAI.h3
-rw-r--r--src/server/game/AI/enuminfo_CreatureAI.cpp73
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommand.h26
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandArgs.cpp17
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandArgs.h408
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandHelpers.h6
-rw-r--r--src/server/game/Chat/ChatCommands/ChatCommandTags.h6
-rw-r--r--src/server/game/Chat/Hyperlinks.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp8
-rw-r--r--src/server/game/Entities/Player/Player.h8
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp10
-rw-r--r--src/server/game/Entities/Unit/Unit.h10
-rw-r--r--src/server/game/Globals/ObjectAccessor.cpp40
-rw-r--r--src/server/game/Globals/ObjectAccessor.h4
-rw-r--r--src/server/game/Movement/MovementDefines.h3
-rw-r--r--src/server/game/Movement/enuminfo_MovementDefines.cpp115
-rw-r--r--src/server/game/Texts/ChatTextBuilder.h2
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp8
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp630
20 files changed, 692 insertions, 710 deletions
diff --git a/contrib/enumutils_describe.py b/contrib/enumutils_describe.py
index 60e36cdf6fd..3f20c75df4d 100644
--- a/contrib/enumutils_describe.py
+++ b/contrib/enumutils_describe.py
@@ -25,8 +25,8 @@ if not getcwd().endswith('src'):
print('(Invoke as \'python ../contrib/enumutils_describe.py\')')
exit(1)
-EnumPattern = compile(r'//\s*EnumUtils: DESCRIBE THIS\s+enum\s+([0-9A-Za-z]+)[^\n]*\s*{([^}]+)};')
-EnumValuesPattern = compile(r'\s+.+?(,|$)[^\n]*')
+EnumPattern = compile(r'//\s*EnumUtils: DESCRIBE THIS(?:\s*\(in ([^\)]+)\))?\s+enum\s+([0-9A-Za-z]+)[^\n]*\s*{([^}]+)};')
+EnumValuesPattern = compile(r'\s+\S.+?(,|$)[^\n]*')
EnumValueNamePattern = compile(r'^\s*([a-zA-Z0-9_]+)', flags=MULTILINE)
EnumValueSkipLinePattern = compile(r'^\s*//')
EnumValueCommentPattern = compile(r'//,?[ \t]*([^\n]+)$')
@@ -52,9 +52,10 @@ def processFile(path, filename):
enums = []
for enum in EnumPattern.finditer(file):
- name = enum.group(1)
+ prefix = enum.group(1) or ''
+ name = enum.group(2)
values = []
- for value in EnumValuesPattern.finditer(enum.group(2)):
+ for value in EnumValuesPattern.finditer(enum.group(3)):
valueData = value.group(0)
valueNameMatch = EnumValueNamePattern.search(valueData)
@@ -89,7 +90,7 @@ def processFile(path, filename):
values.append((valueName, valueTitle, valueDescription))
- enums.append((name, values))
+ enums.append((prefix + name, prefix, values))
print('%s.h: Enum %s parsed with %d values' % (filename, name, len(values)))
if not enums:
@@ -110,7 +111,7 @@ def processFile(path, filename):
output.write('\n')
output.write('namespace Trinity::Impl::EnumUtilsImpl\n')
output.write('{\n')
- for name, values in enums:
+ for name, prefix, values in enums:
tag = ('data for enum \'%s\' in \'%s.h\' auto-generated' % (name, filename))
output.write('\n')
output.write('/*' + ('*'*(len(tag)+2)) + '*\\\n')
@@ -122,7 +123,7 @@ def processFile(path, filename):
output.write(' switch (value)\n')
output.write(' {\n')
for label, title, description in values:
- output.write(' case %s: return { %s, %s, %s };\n' % (label, strescape(label), strescape(title), strescape(description)))
+ output.write(' case %s: return { %s, %s, %s };\n' % (prefix + label, strescape(label), strescape(title), strescape(description)))
output.write(' default: throw std::out_of_range("value");\n')
output.write(' }\n')
output.write('}\n')
@@ -135,8 +136,8 @@ def processFile(path, filename):
output.write('{\n')
output.write(' switch (index)\n')
output.write(' {\n')
- for i in range(len(values)):
- output.write(' case %d: return %s;\n' % (i, values[i][0]))
+ for (i, (label, title, description)) in enumerate(values):
+ output.write(' case %d: return %s;\n' % (i, prefix + label))
output.write(' default: throw std::out_of_range("index");\n')
output.write(' }\n')
output.write('}\n')
@@ -146,8 +147,8 @@ def processFile(path, filename):
output.write('{\n')
output.write(' switch (value)\n')
output.write(' {\n')
- for i in range(len(values)):
- output.write(' case %s: return %d;\n' % (values[i][0], i))
+ for (i, (label, title, description)) in enumerate(values):
+ output.write(' case %s: return %d;\n' % (prefix + label, i))
output.write(' default: throw std::out_of_range("value");\n')
output.write(' }\n')
output.write('}\n')
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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "CreatureAI.h"
+#include "Define.h"
+#include "SmartEnum.h"
+#include <stdexcept>
+
+namespace Trinity::Impl::EnumUtilsImpl
+{
+
+/****************************************************************************\
+|* data for enum 'CreatureAI::EvadeReason' in 'CreatureAI.h' auto-generated *|
+\****************************************************************************/
+template <>
+TC_API_EXPORT EnumText EnumUtils<CreatureAI::EvadeReason>::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<CreatureAI::EvadeReason>::Count() { return 5; }
+
+template <>
+TC_API_EXPORT CreatureAI::EvadeReason EnumUtils<CreatureAI::EvadeReason>::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<CreatureAI::EvadeReason>::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 <typename... Ts>
- struct SingleConsumer<Trinity::ChatCommands::Variant<Ts...>>
- {
- using V = std::variant<Ts...>;
- static constexpr size_t N = std::variant_size_v<V>;
-
- template <size_t I>
- static Optional<std::string_view> TryAtIndex(Trinity::ChatCommands::Variant<Ts...>& val, [[maybe_unused]] std::string_view args)
- {
- if constexpr (I < N)
- {
- if (Optional<std::string_view> next = SingleConsumer<std::variant_alternative_t<I, V>>::TryConsumeTo(val.template emplace<I>(), args))
- return next;
- else
- return TryAtIndex<I+1>(val, args);
- }
- else
- return std::nullopt;
- }
-
- static Optional<std::string_view> TryConsumeTo(Trinity::ChatCommands::Variant<Ts...>& 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<std::string_view> Trinity::Impl::ChatCommands::ArgInfo<CurrencyTypesEnt
Optional<std::string_view> next = SingleConsumer<decltype(val)>::TryConsumeTo(val, args);
if (next)
data = val.visit(CurrencyTypesVisitor());
- return args;
+ return next;
}
struct GameTeleVisitor
@@ -69,6 +69,21 @@ Optional<std::string_view> Trinity::Impl::ChatCommands::ArgInfo<GameTele const*>
return next;
}
+struct ItemTemplateVisitor
+{
+ using value_type = ItemTemplate const*;
+ value_type operator()(Hyperlink<item> item) const { return item->Item; }
+ value_type operator()(uint32 item) const { return sObjectMgr->GetItemTemplate(item); }
+};
+Optional<std::string_view> Trinity::Impl::ChatCommands::ArgInfo<ItemTemplate const*>::TryConsume(ItemTemplate const*& data, std::string_view args)
+{
+ Variant<Hyperlink<item>, uint32> val;
+ Optional<std::string_view> next = SingleConsumer<decltype(val)>::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<std::string_view> *|
-|* 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 <typename T, typename = void>
-struct ArgInfo { static_assert(Trinity::dependant_false_v<T>, "Invalid command parameter type - see ChatCommandArgs.h for possible types"); };
-
-// catch-all for number types
-template <typename T>
-struct ArgInfo<T, std::enable_if_t<std::is_integral_v<T> || std::is_floating_point_v<T>>>
-{
- static Optional<std::string_view> 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<std::string_view> *|
+ |* 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 <typename T, typename = void>
+ struct ArgInfo { static_assert(Trinity::dependant_false_v<T>, "Invalid command parameter type - see ChatCommandArgs.h for possible types"); };
+
+ // catch-all for number types
+ template <typename T>
+ struct ArgInfo<T, std::enable_if_t<std::is_integral_v<T> || std::is_floating_point_v<T>>>
{
- auto [token, tail] = tokenize(args);
- if (token.empty())
- return std::nullopt;
+ static Optional<std::string_view> TryConsume(T& val, std::string_view args)
+ {
+ auto [token, tail] = tokenize(args);
+ if (token.empty())
+ return std::nullopt;
- if (Optional<T> v = StringTo<T>(token, 0))
- val = *v;
- else
- return std::nullopt;
+ if (Optional<T> v = StringTo<T>(token, 0))
+ val = *v;
+ else
+ return std::nullopt;
+
+ if constexpr (std::is_floating_point_v<T>)
+ {
+ if (!std::isfinite(val))
+ return std::nullopt;
+ }
+
+ return tail;
+ }
+ };
- if constexpr (std::is_floating_point_v<T>)
+ // string_view
+ template <>
+ struct ArgInfo<std::string_view, void>
+ {
+ static Optional<std::string_view> 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<std::string_view, void>
-{
- static Optional<std::string_view> 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<std::string, void>
-{
- static Optional<std::string_view> TryConsume(std::string& val, std::string_view args)
- {
- std::string_view view;
- Optional<std::string_view> next = ArgInfo<std::string_view>::TryConsume(view, args);
- if (next)
- val.assign(view);
- return next;
- }
-};
-
-// wstring
-template <>
-struct ArgInfo<std::wstring, void>
-{
- static Optional<std::string_view> TryConsume(std::wstring& val, std::string_view args)
+ // string
+ template <>
+ struct ArgInfo<std::string, void>
{
- std::string_view utf8view;
- Optional<std::string_view> next = ArgInfo<std::string_view>::TryConsume(utf8view, args);
-
- if (next && Utf8toWStr(utf8view, val))
+ static Optional<std::string_view> TryConsume(std::string& val, std::string_view args)
+ {
+ std::string_view view;
+ Optional<std::string_view> next = ArgInfo<std::string_view>::TryConsume(view, args);
+ if (next)
+ val.assign(view);
return next;
- else
- return std::nullopt;
- }
-};
+ }
+ };
-// enum
-template <typename T>
-struct ArgInfo<T, std::enable_if_t<std::is_enum_v<T>>>
-{
- static std::map<std::string, Optional<T>> MakeSearchMap()
+ // wstring
+ template <>
+ struct ArgInfo<std::wstring, void>
{
- std::map<std::string, Optional<T>> map;
- for (T val : EnumUtils::Iterate<T>())
+ static Optional<std::string_view> TryConsume(std::wstring& val, std::string_view args)
{
- EnumText text = EnumUtils::ToString(val);
+ std::string_view utf8view;
+ Optional<std::string_view> next = ArgInfo<std::string_view>::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 <typename T>
+ struct ArgInfo<T, std::enable_if_t<std::is_enum_v<T>>>
+ {
+ static std::map<std::string, Optional<T>> MakeSearchMap()
+ {
+ std::map<std::string, Optional<T>> map;
+ for (T val : EnumUtils::Iterate<T>())
{
- 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<std::string, Optional<T>> const SearchMap = MakeSearchMap();
+ static inline std::map<std::string, Optional<T>> 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<std::string_view> TryConsume(T& val, std::string_view args)
+ {
+ std::string strVal;
+ Optional<std::string_view> next = ArgInfo<std::string>::TryConsume(strVal, args);
- static Optional<std::string_view> TryConsume(T& val, std::string_view args)
- {
- std::string strVal;
- Optional<std::string_view> next = ArgInfo<std::string>::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<T>;
+ U uVal = 0;
+ next = ArgInfo<U>::TryConsume(uVal, args);
+ if (next && EnumUtils::IsValid<T>(uVal))
{
- val = *match;
+ val = static_cast<T>(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<T>;
- U uVal = 0;
- next = ArgInfo<U>::TryConsume(uVal, args);
- if (next && EnumUtils::IsValid<T>(uVal))
+ // a container tag
+ template <typename T>
+ struct ArgInfo<T, std::enable_if_t<std::is_base_of_v<ContainerTag, T>>>
+ {
+ static Optional<std::string_view> TryConsume(T& tag, std::string_view args)
{
- val = static_cast<T>(uVal);
- return next;
+ return tag.TryConsume(args);
}
+ };
- return std::nullopt;
- }
-};
-
-// a container tag
-template <typename T>
-struct ArgInfo<T, std::enable_if_t<std::is_base_of_v<ContainerTag, T>>>
-{
- static Optional<std::string_view> TryConsume(T& tag, std::string_view args)
+ // non-empty vector
+ template <typename T>
+ struct ArgInfo<std::vector<T>, void>
{
- return tag.TryConsume(args);
- }
-};
+ static Optional<std::string_view> TryConsume(std::vector<T>& val, std::string_view args)
+ {
+ val.clear();
+ Optional<std::string_view> next = ArgInfo<T>::TryConsume(val.emplace_back(), args);
-template <typename T>
-struct ArgInfo<std::vector<T>, void>
-{
- static Optional<std::string_view> TryConsume(std::vector<T>& val, std::string_view args)
- {
- val.clear();
- Optional<std::string_view> next = ArgInfo<T>::TryConsume(val.emplace_back(), args);
+ if (!next)
+ return std::nullopt;
- if (!next)
- return std::nullopt;
+ while (Optional<std::string_view> next2 = ArgInfo<T>::TryConsume(val.emplace_back(), *next))
+ next = next2;
- while (Optional<std::string_view> next2 = ArgInfo<T>::TryConsume(val.emplace_back(), *next))
- next = next2;
+ val.pop_back();
+ return next;
+ }
+ };
- val.pop_back();
- return next;
- }
-};
+ // fixed-size array
+ template <typename T, size_t N>
+ struct ArgInfo<std::array<T, N>, void>
+ {
+ static Optional<std::string_view> TryConsume(std::array<T, N>& val, std::string_view args)
+ {
+ Optional<std::string_view> next = args;
+ for (T& t : val)
+ if (!(next = ArgInfo<T>::TryConsume(t, *next)))
+ return std::nullopt;
+ return next;
+ }
+ };
-template <typename T, size_t N>
-struct ArgInfo<std::array<T, N>, void>
-{
- static Optional<std::string_view> TryConsume(std::array<T, N>& val, std::string_view args)
+ // variant
+ template <typename... Ts>
+ struct ArgInfo<Trinity::ChatCommands::Variant<Ts...>>
{
- Optional<std::string_view> next = args;
- for (T& t : val)
- if (!(next = ArgInfo<T>::TryConsume(t, *next)))
+ using V = std::variant<Ts...>;
+ static constexpr size_t N = std::variant_size_v<V>;
+
+ template <size_t I>
+ static Optional<std::string_view> TryAtIndex(Trinity::ChatCommands::Variant<Ts...>& val, [[maybe_unused]] std::string_view args)
+ {
+ if constexpr (I < N)
+ {
+ if (Optional<std::string_view> next = ArgInfo<std::variant_alternative_t<I, V>>::TryConsume(val.template emplace<I>(), args))
+ return next;
+ else
+ return TryAtIndex<I + 1>(val, args);
+ }
+ else
return std::nullopt;
- return next;
- }
-};
+ }
-// AchievementEntry* from numeric id or link
-template <>
-struct TC_GAME_API ArgInfo<AchievementEntry const*>
-{
- static Optional<std::string_view> TryConsume(AchievementEntry const*&, std::string_view);
-};
+ static Optional<std::string_view> TryConsume(Trinity::ChatCommands::Variant<Ts...>& val, std::string_view args)
+ {
+ return TryAtIndex<0>(val, args);
+ }
+ };
-// CurrencyTypesEntry* from numeric id or link
-template <>
-struct TC_GAME_API ArgInfo<CurrencyTypesEntry const*>
-{
- static Optional<std::string_view> TryConsume(CurrencyTypesEntry const*&, std::string_view);
-};
+ // AchievementEntry* from numeric id or link
+ template <>
+ struct TC_GAME_API ArgInfo<AchievementEntry const*>
+ {
+ static Optional<std::string_view> TryConsume(AchievementEntry const*&, std::string_view);
+ };
-// GameTele* from string name or link
-template <>
-struct TC_GAME_API ArgInfo<GameTele const*>
-{
- static Optional<std::string_view> TryConsume(GameTele const*&, std::string_view);
-};
+ // CurrencyTypesEntry* from numeric id or link
+ template <>
+ struct TC_GAME_API ArgInfo<CurrencyTypesEntry const*>
+ {
+ static Optional<std::string_view> TryConsume(CurrencyTypesEntry const*&, std::string_view);
+ };
-// SpellInfo const* from spell id or link
-template <>
-struct TC_GAME_API ArgInfo<SpellInfo const*>
-{
- static Optional<std::string_view> TryConsume(SpellInfo const*&, std::string_view);
-};
+ // GameTele* from string name or link
+ template <>
+ struct TC_GAME_API ArgInfo<GameTele const*>
+ {
+ static Optional<std::string_view> TryConsume(GameTele const*&, std::string_view);
+ };
+
+ // ItemTemplate* from numeric id or link
+ template <>
+ struct TC_GAME_API ArgInfo<ItemTemplate const*>
+ {
+ static Optional<std::string_view> TryConsume(ItemTemplate const*&, std::string_view);
+ };
+
+ // SpellInfo const* from spell id or link
+ template <>
+ struct TC_GAME_API ArgInfo<SpellInfo const*>
+ {
+ static Optional<std::string_view> 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<T&, Ts> && ...);
};
+ template <typename... Ts>
+ struct are_all_assignable<void, Ts...>
+ {
+ static constexpr bool value = false;
+ };
+
template <std::size_t index, typename T1, typename... Ts>
struct get_nth : get_nth<index-1, Ts...> { };
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<chars...>::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 <typename T>
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<Player>
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<Trinity::CustomChatTextBuilder> 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<Transport>;
namespace PlayerNameMapHolder
{
-typedef std::unordered_map<std::string, Player*> MapType;
-static MapType PlayerNameMap;
+ typedef std::unordered_map<std::string, Player*> 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<Player>::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<Player>::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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "MovementDefines.h"
+#include "Define.h"
+#include "SmartEnum.h"
+#include <stdexcept>
+
+namespace Trinity::Impl::EnumUtilsImpl
+{
+
+/*******************************************************************************\
+|* data for enum 'MovementGeneratorType' in 'MovementDefines.h' auto-generated *|
+\*******************************************************************************/
+template <>
+TC_API_EXPORT EnumText EnumUtils<MovementGeneratorType>::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<MovementGeneratorType>::Count() { return 19; }
+
+template <>
+TC_API_EXPORT MovementGeneratorType EnumUtils<MovementGeneratorType>::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<MovementGeneratorType>::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 <sstream>
#include <typeinfo>
-// 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<Hyperlink<gameobject>, ObjectGuid::LowType>;
using GameObjectEntry = Variant<Hyperlink<gameobject_entry>, uint32>;
+
+// definitions are over in cs_npc.cpp
+bool HandleNpcSpawnGroup(ChatHandler* handler, std::vector<Variant<uint32, ExactSequence<'f','o','r','c','e'>, ExactSequence<'i','g','n','o','r','e','r','e','s','p','a','w','n'>>> const& opts);
+bool HandleNpcDespawnGroup(ChatHandler* handler, std::vector<Variant<uint32, ExactSequence<'r','e','m','o','v','e','r','e','s','p','a','w','n','t','i','m','e'>>> 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 <boost/core/demangle.hpp>
#include <typeinfo>
-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 <WorldObject*> 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<Hyperlink<creature>, ObjectGuid::LowType>;
+using CreatureEntry = Variant<Hyperlink<creature_entry>, uint32>;
- return true;
-}
+// shared with cs_gobject.cpp, definitions are at the bottom of this file
+bool HandleNpcSpawnGroup(ChatHandler* handler, std::vector<Variant<uint32, ExactSequence<'f','o','r','c','e'>, ExactSequence<'i','g','n','o','r','e','r','e','s','p','a','w','n'>>> const& opts);
+bool HandleNpcDespawnGroup(ChatHandler* handler, std::vector<Variant<uint32, ExactSequence<'r','e','m','o','v','e','r','e','s','p','a','w','n','t','i','m','e'>>> 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<uint32> mc, Optional<uint32> it, Optional<uint32> ec, Optional<std::string_view> 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<int32> bonusListID = Trinity::StringTo<int32>(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<Variant<Hyperlink<creature>, ObjectGuid::LowType>> spawnIdArg)
+ static bool HandleNpcDeleteCommand(ChatHandler* handler, Optional<CreatureSpawnId> 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<float> 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<CreatureSpawnId> 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<CreatureSpawnId> lowGuid, Variant<ExactSequence<'s','t','a','y'>, ExactSequence<'r','a','n','d','o','m'>, ExactSequence<'w','a','y'>> type, Optional<ExactSequence<'n','o','d','e','l'>> 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<Hyperlink<player>, 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<HighGuid::Player>(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<std::string_view> 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<CreatureAI::EvadeReason> why, Optional<ExactSequence<'f','o','r','c','e'>> 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<ExactSequence<'a','l','l'>> 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<Variant<uint32, ExactSequence<'f','o','r','c','e'>, 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<uint32>();
+ break;
+ case 1:
+ force = true;
+ break;
+ case 2:
+ ignoreRespawn = true;
+ break;
+ }
+ }
+
+ Player* player = handler->GetSession()->GetPlayer();
+
+ std::vector <WorldObject*> 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<Variant<uint32, ExactSequence<'r','e','m','o','v','e','r','e','s','p','a','w','n','t','i','m','e'>>> const& opts)
+{
+ if (opts.empty())
+ return false;
+
+ bool deleteRespawnTimes = false;
+ uint32 groupId = 0;
+
+ // Decode arguments
+ for (auto const& variant : opts)
+ {
+ if (variant.holds_alternative<uint32>())
+ groupId = variant.get<uint32>();
+ 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;
+}