TrinityCore
Loading...
Searching...
No Matches
HyperlinkTags.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Hyperlinks.h"
19#include "DBCStores.h"
20#include "ObjectMgr.h"
21#include "SpellInfo.h"
22#include "SpellMgr.h"
23#include <limits>
24
25static constexpr char HYPERLINK_DATA_DELIMITER = ':';
26
28{
29 public:
30 HyperlinkDataTokenizer(std::string_view str) : _str(str) {}
31
32 template <typename T>
33 bool TryConsumeTo(T& val)
34 {
35 if (IsEmpty())
36 return false;
37
38 if (size_t off = _str.find(HYPERLINK_DATA_DELIMITER); off != std::string_view::npos)
39 {
41 return false;
42 _str = _str.substr(off+1);
43 }
44 else
45 {
47 return false;
48 _str = std::string_view();
49 }
50 return true;
51 }
52
53 bool IsEmpty() { return _str.empty(); }
54
55 private:
56 std::string_view _str;
57};
58
60{
62
63 uint32 achievementId;
64 if (!t.TryConsumeTo(achievementId))
65 return false;
66 val.Achievement = sAchievementStore.LookupEntry(achievementId);
67
68 if (!(val.Achievement && t.TryConsumeTo(val.CharacterId) && t.TryConsumeTo(val.IsFinished) && t.TryConsumeTo(val.Month) && t.TryConsumeTo(val.Day)))
69 return false;
70 if ((12 < val.Month) || (31 < val.Day))
71 return false;
72
73 int8 year;
74 if (!t.TryConsumeTo(year))
75 return false;
76 if (val.IsFinished) // if finished, year must be >= 0
77 {
78 if (year < 0)
79 return false;
80 val.Year = static_cast<uint8>(year);
81 }
82 else
83 val.Year = 0;
84
85 return (t.TryConsumeTo(val.Criteria[0]) && t.TryConsumeTo(val.Criteria[1]) && t.TryConsumeTo(val.Criteria[2]) && t.TryConsumeTo(val.Criteria[3]) && t.IsEmpty());
86}
87
88bool Trinity::Hyperlinks::LinkTags::enchant::StoreTo(SpellInfo const*& val, std::string_view text)
89{
91 uint32 spellId;
92 if (!(t.TryConsumeTo(spellId) && t.IsEmpty()))
93 return false;
94 return (val = sSpellMgr->GetSpellInfo(spellId)) && val->HasAttribute(SPELL_ATTR0_TRADESPELL);
95}
96
98{
100 uint32 slot, prop;
101 if (!(t.TryConsumeTo(slot) && t.TryConsumeTo(prop) && t.IsEmpty()))
102 return false;
103 if (!(val.Slot = sGlyphSlotStore.LookupEntry(slot)))
104 return false;
105 if (!(val.Glyph = sGlyphPropertiesStore.LookupEntry(prop)))
106 return false;
107 return true;
108}
109
111{
113 uint32 itemId, dummy;
114 if (!t.TryConsumeTo(itemId))
115 return false;
116 val.Item = sObjectMgr->GetItemTemplate(itemId);
117 val.IsBuggedInspectLink = false;
118
119 // randomPropertyId is actually a int16 in the client
120 // positive values index ItemRandomSuffix.dbc, while negative values index ItemRandomProperties.dbc
121 // however, there is also a client bug in inspect packet handling that causes a int16 to be cast to uint16, then int32 (dropping sign extension along the way)
122 // this results in the wrong value being sent in the link; DBC lookup clientside fails, so it sends the link without suffix
123 // to detect and allow these invalid links, we first read randomPropertyId as a full int32
124 int32 randomPropertyId;
125 if (!(val.Item && t.TryConsumeTo(val.EnchantId) && t.TryConsumeTo(val.GemEnchantId[0]) && t.TryConsumeTo(val.GemEnchantId[1]) &&
126 t.TryConsumeTo(val.GemEnchantId[2]) && t.TryConsumeTo(dummy) && t.TryConsumeTo(randomPropertyId) && t.TryConsumeTo(val.RandomSuffixBaseAmount) &&
127 t.TryConsumeTo(val.RenderLevel) && t.IsEmpty() && !dummy))
128 return false;
129
130 if ((static_cast<int32>(std::numeric_limits<int16>::max()) < randomPropertyId) && (randomPropertyId <= std::numeric_limits<uint16>::max()))
131 { // this is the bug case, the id we received is actually static_cast<uint16>(i16RandomPropertyId)
132 randomPropertyId = static_cast<int16>(randomPropertyId);
133 val.IsBuggedInspectLink = true;
134 }
135
136 if (randomPropertyId < 0)
137 {
138 if (!val.Item->RandomSuffix)
139 return false;
140 if (randomPropertyId < -static_cast<int32>(sItemRandomSuffixStore.GetNumRows()))
141 return false;
142 if (ItemRandomSuffixEntry const* suffixEntry = sItemRandomSuffixStore.LookupEntry(-randomPropertyId))
143 {
144 val.RandomSuffix = suffixEntry;
145 val.RandomProperty = nullptr;
146 }
147 else
148 return false;
149 }
150 else if (randomPropertyId > 0)
151 {
152 if (!val.Item->RandomProperty)
153 return false;
154 if (ItemRandomPropertiesEntry const* propEntry = sItemRandomPropertiesStore.LookupEntry(randomPropertyId))
155 {
156 val.RandomSuffix = nullptr;
157 val.RandomProperty = propEntry;
158 }
159 else
160 return false;
161 }
162 else
163 {
164 val.RandomSuffix = nullptr;
165 val.RandomProperty = nullptr;
166 }
167
169 return false;
170
171 return true;
172}
173
175{
177 uint32 questId;
178 if (!t.TryConsumeTo(questId))
179 return false;
180 return (val.Quest = sObjectMgr->GetQuestTemplate(questId)) && t.TryConsumeTo(val.QuestLevel) && (val.QuestLevel >= -1) && t.IsEmpty();
181}
182
183bool Trinity::Hyperlinks::LinkTags::spell::StoreTo(SpellInfo const*& val, std::string_view text)
184{
186 uint32 spellId;
187 if (!(t.TryConsumeTo(spellId) && t.IsEmpty()))
188 return false;
189 return !!(val = sSpellMgr->GetSpellInfo(spellId));
190}
191
193{
195 uint32 talentId;
196 int8 rank; // talent links contain <learned rank>-1, we store <learned rank>
197 if (!(t.TryConsumeTo(talentId) && t.TryConsumeTo(rank) && t.IsEmpty()))
198 return false;
199 if (rank < -1 || rank >= MAX_TALENT_RANK)
200 return false;
201 val.Talent = sTalentStore.LookupEntry(talentId);
202 val.Rank = rank + 1;
203 if (!val.Talent)
204 return false;
205 val.Spell = sSpellMgr->GetSpellInfo(val.Talent->SpellRank[std::max<int32>(rank, 0)]);
206 if (!val.Spell)
207 return false;
208 return true;
209}
210
212{
214 uint32 spellId;
215 if (!t.TryConsumeTo(spellId))
216 return false;
217 val.Spell = sSpellMgr->GetSpellInfo(spellId);
219 t.TryConsumeTo(val.MaxValue) && t.TryConsumeTo(val.Owner) && t.TryConsumeTo(val.KnownRecipes) && t.IsEmpty());
220}
#define MAX_TALENT_RANK
Definition DBCEnums.h:432
DBCStorage< GlyphSlotEntry > sGlyphSlotStore(GlyphSlotfmt)
DBCStorage< ItemRandomSuffixEntry > sItemRandomSuffixStore(ItemRandomSuffixfmt)
DBCStorage< AchievementEntry > sAchievementStore(Achievementfmt)
DBCStorage< ItemRandomPropertiesEntry > sItemRandomPropertiesStore(ItemRandomPropertiesfmt)
DBCStorage< TalentEntry > sTalentStore(TalentEntryfmt)
DBCStorage< GlyphPropertiesEntry > sGlyphPropertiesStore(GlyphPropertiesfmt)
uint8_t uint8
Definition Define.h:135
int16_t int16
Definition Define.h:130
int8_t int8
Definition Define.h:131
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
static constexpr char HYPERLINK_DATA_DELIMITER
#define sObjectMgr
Definition ObjectMgr.h:1721
@ EFFECT_0
@ SPELL_EFFECT_TRADE_SKILL
@ SPELL_ATTR0_TRADESPELL
#define sSpellMgr
Definition SpellMgr.h:738
HyperlinkDataTokenizer(std::string_view str)
std::string_view _str
SpellEffects Effect
Definition SpellInfo.h:210
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:375
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:483
int32 RandomProperty
std::array< uint32, MAX_TALENT_RANK > SpellRank