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)
This commit is contained in:
Treeston
2022-02-05 00:43:55 +01:00
committed by Shauren
parent 6fded37e86
commit 4d62cc70d6
20 changed files with 704 additions and 722 deletions
+12 -11
View File
@@ -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')
+2 -1
View File
@@ -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 = {});
@@ -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");
}
}
}
@@ -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
@@ -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*;
@@ -33,22 +33,22 @@ 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"); };
/************************** 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>>>
{
// 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)
{
auto [token, tail] = tokenize(args);
@@ -68,12 +68,12 @@ struct ArgInfo<T, std::enable_if_t<std::is_integral_v<T> || std::is_floating_poi
return tail;
}
};
};
// string_view
template <>
struct ArgInfo<std::string_view, void>
{
// 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);
@@ -82,12 +82,12 @@ struct ArgInfo<std::string_view, void>
val = token;
return next;
}
};
};
// string
template <>
struct ArgInfo<std::string, void>
{
// string
template <>
struct ArgInfo<std::string, void>
{
static Optional<std::string_view> TryConsume(std::string& val, std::string_view args)
{
std::string_view view;
@@ -96,12 +96,12 @@ struct ArgInfo<std::string, void>
val.assign(view);
return next;
}
};
};
// wstring
template <>
struct ArgInfo<std::wstring, void>
{
// wstring
template <>
struct ArgInfo<std::wstring, void>
{
static Optional<std::string_view> TryConsume(std::wstring& val, std::string_view args)
{
std::string_view utf8view;
@@ -112,12 +112,12 @@ struct ArgInfo<std::wstring, void>
else
return std::nullopt;
}
};
};
// enum
template <typename T>
struct ArgInfo<T, std::enable_if_t<std::is_enum_v<T>>>
{
// 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;
@@ -194,21 +194,22 @@ struct ArgInfo<T, std::enable_if_t<std::is_enum_v<T>>>
return std::nullopt;
}
};
};
// a container tag
template <typename T>
struct ArgInfo<T, std::enable_if_t<std::is_base_of_v<ContainerTag, T>>>
{
// 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)
{
return tag.TryConsume(args);
}
};
};
template <typename T>
struct ArgInfo<std::vector<T>, void>
{
// non-empty vector
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();
@@ -223,11 +224,12 @@ struct ArgInfo<std::vector<T>, void>
val.pop_back();
return next;
}
};
};
template <typename T, size_t N>
struct ArgInfo<std::array<T, N>, void>
{
// 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;
@@ -236,35 +238,69 @@ struct ArgInfo<std::array<T, N>, void>
return std::nullopt;
return next;
}
};
};
// AchievementEntry* from numeric id or link
template <>
struct TC_GAME_API ArgInfo<AchievementEntry const*>
{
// variant
template <typename... Ts>
struct ArgInfo<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 = 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;
}
static Optional<std::string_view> TryConsume(Trinity::ChatCommands::Variant<Ts...>& val, std::string_view args)
{
return TryAtIndex<0>(val, args);
}
};
// 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);
};
};
// CurrencyTypesEntry* from numeric id or link
template <>
struct TC_GAME_API ArgInfo<CurrencyTypesEntry const*>
{
// 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);
};
};
// GameTele* from string name or link
template <>
struct TC_GAME_API ArgInfo<GameTele const*>
{
// 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);
};
};
// SpellInfo const* from spell id or link
template <>
struct TC_GAME_API ArgInfo<SpellInfo const*>
{
// 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);
};
};
}
@@ -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...> { };
@@ -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>
+1 -1
View File
@@ -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);
+4 -4
View File
@@ -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);
+4 -4
View File
@@ -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);
+5 -5
View File
@@ -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;
+5 -5
View File
@@ -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);
+13 -13
View File
@@ -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)
{
void Insert(Player* p)
{
PlayerNameMap[p->GetName()] = p;
}
}
void Remove(Player* p)
{
void Remove(Player* p)
{
PlayerNameMap.erase(p->GetName());
}
}
Player* Find(std::string const& name)
{
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;
}
}
} // 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);
}
+2 -2
View File
@@ -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();
+2 -1
View File
@@ -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
@@ -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");
}
}
}
+1 -1
View File
@@ -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;
+5 -3
View File
@@ -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:
+175 -413
View File
@@ -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);
return true;
}
using namespace Trinity::ChatCommands;
using CreatureSpawnId = Variant<Hyperlink<creature>, ObjectGuid::LowType>;
using CreatureEntry = Variant<Hyperlink<creature_entry>, uint32>;
// 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);
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)
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")
switch (type.index())
{
case 0:
move_type = IDLE_MOTION_TYPE;
else if (type == "random")
break;
case 1:
move_type = RANDOM_MOTION_TYPE;
else if (type == "way")
break;
case 2:
move_type = WAYPOINT_MOTION_TYPE;
else
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,11 +947,10 @@ 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;
@@ -1188,9 +961,9 @@ public:
}
//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)
if (lootStr)
{
if (StringEqualI(*lootStr, "loot"))
loot = true;
else if (stricmp(spawntype_str, "NOLOOT") == 0)
else if (StringEqualI(*lootStr, "noloot"))
loot = false;
else
entry_str = args;
char* charID = handler->extractKeyFromLink((char*)entry_str, "Hcreature_entry");
if (!charID)
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;
handler->SetSentErrorMessage(true);
return false;
}
char* pSlotID = strtok((char*)args, " ");
if (!pSlotID)
return false;
char* pItemID = strtok(nullptr, " ");
if (!pItemID)
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;
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, tmpItem->ItemId);
break;
case 2:
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, ItemID);
added = true;
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_01, tmpItem->ItemId);
break;
case 3:
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, ItemID);
added = true;
creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY_02, tmpItem->ItemId);
break;
default:
handler->PSendSysMessage(LANG_ITEM_SLOT_NOT_EXIST, SlotID);
added = false;
break;
handler->SetSentErrorMessage(true);
return false;
}
if (added)
handler->PSendSysMessage(LANG_ITEM_ADDED_TO_SLOT, ItemID, tmpItem->Name1, SlotID);
}
else
{
handler->PSendSysMessage(LANG_ITEM_NOT_FOUND, ItemID);
return true;
}
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;
}