refactor(Core/Misc): port gossip validation, StringFormat APIs, and spell attribute naming from TC (#24789)

Co-authored-by: Rochet2 <tqbattlenet@gmail.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: tobmaps <spambot42@yandex.ru>
This commit is contained in:
Francesco Borzì
2026-03-11 00:50:32 +01:00
committed by GitHub
parent 47e6aed9a7
commit 6ffe41dd59
8 changed files with 67 additions and 10 deletions

View File

@@ -29,6 +29,16 @@ namespace Acore
template<typename... Args>
using FormatString = fmt::format_string<Args...>;
using FormatStringView = fmt::string_view;
using FormatArgs = fmt::format_args;
template<typename... Args>
constexpr auto MakeFormatArgs(Args&&... args)
{
return fmt::make_format_args(args...);
}
/// Default AC string format function.
template<typename... Args>
inline std::string StringFormat(FormatString<Args...> fmt, Args&&... args)
@@ -43,6 +53,47 @@ namespace Acore
}
}
/// Format directly to an output iterator.
template<typename OutputIt, typename... Args>
inline OutputIt StringFormatTo(OutputIt out, FormatString<Args...> fmt, Args&&... args)
{
try
{
return fmt::format_to(out, fmt, std::forward<Args>(args)...);
}
catch (std::exception const& e)
{
return fmt::format_to(out, "Wrong format occurred ({}). Fmt string: '{}'", e.what(), fmt.get());
}
}
/// Format with pre-built format args.
inline std::string StringVFormat(FormatStringView fmt, FormatArgs args)
{
try
{
return fmt::vformat(fmt, args);
}
catch (std::exception const& e)
{
return fmt::format("Wrong format occurred ({}). Fmt string: '{}'", e.what(), fmt);
}
}
/// Format with pre-built format args directly to an output iterator.
template<typename OutputIt>
inline OutputIt StringVFormatTo(OutputIt out, FormatStringView fmt, FormatArgs args)
{
try
{
return fmt::vformat_to(out, fmt, args);
}
catch (std::exception const& e)
{
return fmt::format_to(out, "Wrong format occurred ({}). Fmt string: '{}'", e.what(), fmt);
}
}
/// Returns true if the given char pointer is null.
inline bool IsFormatEmptyOrNull(char const* fmt)
{

View File

@@ -733,7 +733,7 @@ bool PetAI::CanAttack(Unit* target, SpellInfo const* spellInfo)
return me->GetCharmInfo()->IsCommandAttack();
// CC - mobs under crowd control can be attacked if owner commanded
if (target->HasBreakableByDamageCrowdControlAura() && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR4_REACTIVE_DAMAGE_PROC)))
if (target->HasBreakableByDamageCrowdControlAura() && (!spellInfo || !spellInfo->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS)))
return me->GetCharmInfo()->IsCommandAttack();
// Returning - pets ignore attacks only if owner clicked follow

View File

@@ -978,7 +978,7 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
if (attacker && damagetype != DOT && spellProto->DmgClass == SPELL_DAMAGE_CLASS_MELEE && !(spellProto->GetSchoolMask() & SPELL_SCHOOL_MASK_HOLY))
attacker->DealDamageShieldDamage(victim);
if (!spellProto->HasAttribute(SPELL_ATTR4_REACTIVE_DAMAGE_PROC))
if (!spellProto->HasAttribute(SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS))
victim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TAKE_DAMAGE, spellProto->Id);
}
else

View File

@@ -96,6 +96,12 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket& recv_data)
recv_data >> guid >> menuId >> gossipListId;
if (!_player->PlayerTalkClass->GetGossipMenu().GetItem(gossipListId))
{
recv_data.rfinish();
return;
}
if (_player->PlayerTalkClass->IsGossipOptionCoded(gossipListId))
recv_data >> code;

View File

@@ -64,9 +64,9 @@ public:
uint8 GetSlot() const { return _slot; }
uint8 GetFlags() const { return _flags; }
uint8 GetEffectMask() const { return _flags & (AFLAG_EFF_INDEX_0 | AFLAG_EFF_INDEX_1 | AFLAG_EFF_INDEX_2); }
bool HasEffect(uint8 effect) const { ASSERT(effect < MAX_SPELL_EFFECTS); return _flags & (1 << effect); }
bool IsPositive() const { return _flags & AFLAG_POSITIVE; }
bool IsSelfcasted() const { return _flags & AFLAG_CASTER; }
bool HasEffect(uint8 effect) const { ASSERT(effect < MAX_SPELL_EFFECTS); return (_flags & (1 << effect)) != 0; }
bool IsPositive() const { return (_flags & AFLAG_POSITIVE) != 0; }
bool IsSelfcasted() const { return (_flags & AFLAG_CASTER) != 0; }
uint8 GetEffectsToApply() const { return _effectsToApply; }
void SetRemoveMode(AuraRemoveMode mode) { _removeMode = mode; }

View File

@@ -1063,7 +1063,7 @@ void SpellMgr::LoadSpellInfoCorrections()
ApplySpellFix({ 44461, 55361, 55362 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx3 |= SPELL_ATTR3_SUPPRESS_TARGET_PROCS;
spellInfo->AttributesEx4 |= SPELL_ATTR4_REACTIVE_DAMAGE_PROC;
spellInfo->AttributesEx4 |= SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS;
});
// Evocation

View File

@@ -529,7 +529,7 @@ enum SpellAttr4 : uint32
SPELL_ATTR4_NO_PARTIAL_IMMUNITY = 0x00000800, // TITLE Unknown attribute 11@Attr4
SPELL_ATTR4_AURA_IS_BUFF = 0x00001000, // TITLE Unknown attribute 12@Attr4
SPELL_ATTR4_DO_NOT_LOG_CASTER = 0x00002000, // TITLE Unknown attribute 13@Attr4
SPELL_ATTR4_REACTIVE_DAMAGE_PROC = 0x00004000, // TITLE Damage does not break auras
SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS = 0x00004000, // TITLE Damage does not break auras
SPELL_ATTR4_NOT_IN_SPELLBOOK = 0x00008000, // TITLE Unknown attribute 15@Attr4
SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND = 0x00010000, // TITLE Not usable in arena DESCRIPTION Makes spell unusable despite CD <= 10min
SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS = 0x00020000, // TITLE Usable in arena DESCRIPTION Makes spell usable despite CD > 10min

View File

@@ -688,7 +688,7 @@ AC_API_EXPORT EnumText EnumUtils<SpellAttr4>::ToString(SpellAttr4 value)
case SPELL_ATTR4_NO_PARTIAL_IMMUNITY: return { "SPELL_ATTR4_NO_PARTIAL_IMMUNITY", "Unknown attribute 11@Attr4", "" };
case SPELL_ATTR4_AURA_IS_BUFF: return { "SPELL_ATTR4_AURA_IS_BUFF", "Unknown attribute 12@Attr4", "" };
case SPELL_ATTR4_DO_NOT_LOG_CASTER: return { "SPELL_ATTR4_DO_NOT_LOG_CASTER", "Unknown attribute 13@Attr4", "" };
case SPELL_ATTR4_REACTIVE_DAMAGE_PROC: return { "SPELL_ATTR4_REACTIVE_DAMAGE_PROC", "Damage does not break auras", "" };
case SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS: return { "SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS", "Damage does not break auras", "" };
case SPELL_ATTR4_NOT_IN_SPELLBOOK: return { "SPELL_ATTR4_NOT_IN_SPELLBOOK", "Unknown attribute 15@Attr4", "" };
case SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND: return { "SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND", "Not usable in arena", "Makes spell unusable despite CD <= 10min" };
case SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS: return { "SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS", "Usable in arena", "Makes spell usable despite CD > 10min" };
@@ -732,7 +732,7 @@ AC_API_EXPORT SpellAttr4 EnumUtils<SpellAttr4>::FromIndex(std::size_t index)
case 11: return SPELL_ATTR4_NO_PARTIAL_IMMUNITY;
case 12: return SPELL_ATTR4_AURA_IS_BUFF;
case 13: return SPELL_ATTR4_DO_NOT_LOG_CASTER;
case 14: return SPELL_ATTR4_REACTIVE_DAMAGE_PROC;
case 14: return SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS;
case 15: return SPELL_ATTR4_NOT_IN_SPELLBOOK;
case 16: return SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND;
case 17: return SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS;
@@ -773,7 +773,7 @@ AC_API_EXPORT std::size_t EnumUtils<SpellAttr4>::ToIndex(SpellAttr4 value)
case SPELL_ATTR4_NO_PARTIAL_IMMUNITY: return 11;
case SPELL_ATTR4_AURA_IS_BUFF: return 12;
case SPELL_ATTR4_DO_NOT_LOG_CASTER: return 13;
case SPELL_ATTR4_REACTIVE_DAMAGE_PROC: return 14;
case SPELL_ATTR4_DAMAGE_DOESNT_BREAK_AURAS: return 14;
case SPELL_ATTR4_NOT_IN_SPELLBOOK: return 15;
case SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND: return 16;
case SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS: return 17;