aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2020-09-01 22:02:22 +0200
committerGitHub <noreply@github.com>2020-09-01 22:02:22 +0200
commitd0b91f69279a823be159590c09945bc426f50d3e (patch)
tree1545fbeca0c4e86c3b3db22fe8a46f4b466afcde
parent3fbbe7cfbe1bc51db12bdc1ec7b21c16d1716366 (diff)
Core/Misc: More DBC std::array refactors, stricter |Hitem checks, and more hyperlink unit tests
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp8
-rw-r--r--src/server/game/Chat/HyperlinkTags.cpp44
-rw-r--r--src/server/game/Chat/Hyperlinks.cpp23
-rw-r--r--src/server/game/Chat/Hyperlinks.h7
-rw-r--r--src/server/shared/DataStores/DBCStructure.h28
-rw-r--r--tests/DummyData.cpp76
-rw-r--r--tests/game/Hyperlinks.cpp30
7 files changed, 171 insertions, 45 deletions
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index 93fcedf17bb..86efd1a63a1 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -796,19 +796,19 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
// These are found in ItemRandomSuffix.dbc and ItemRandomProperties.dbc
// even though the DBC names seem misleading
- char const* const* suffix = nullptr;
+ std::array<char const*, 16> const* suffix = nullptr;
if (propRefID < 0)
{
ItemRandomSuffixEntry const* itemRandSuffix = sItemRandomSuffixStore.LookupEntry(-propRefID);
if (itemRandSuffix)
- suffix = itemRandSuffix->Name;
+ suffix = &itemRandSuffix->Name;
}
else
{
ItemRandomPropertiesEntry const* itemRandProp = sItemRandomPropertiesStore.LookupEntry(propRefID);
if (itemRandProp)
- suffix = itemRandProp->Name;
+ suffix = &itemRandProp->Name;
}
// dbc local name
@@ -817,7 +817,7 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player
// Append the suffix (ie: of the Monkey) to the name using localization
// or default enUS if localization is invalid
name += ' ';
- name += suffix[locdbc_idx >= 0 ? locdbc_idx : LOCALE_enUS];
+ name += (*suffix)[locdbc_idx >= 0 ? locdbc_idx : LOCALE_enUS];
}
}
diff --git a/src/server/game/Chat/HyperlinkTags.cpp b/src/server/game/Chat/HyperlinkTags.cpp
index d511265c537..35c47c04c0d 100644
--- a/src/server/game/Chat/HyperlinkTags.cpp
+++ b/src/server/game/Chat/HyperlinkTags.cpp
@@ -113,9 +113,47 @@ bool Trinity::Hyperlinks::LinkTags::item::StoreTo(ItemLinkData& val, std::string
if (!t.TryConsumeTo(itemId))
return false;
val.Item = sObjectMgr->GetItemTemplate(itemId);
- return val.Item && t.TryConsumeTo(val.EnchantId) && t.TryConsumeTo(val.GemEnchantId[0]) && t.TryConsumeTo(val.GemEnchantId[1]) &&
- t.TryConsumeTo(val.GemEnchantId[2]) && t.TryConsumeTo(dummy) && t.TryConsumeTo(val.RandomPropertyId) && t.TryConsumeTo(val.RandomPropertySeed) &&
- t.TryConsumeTo(val.RenderLevel) && t.IsEmpty() && !dummy;
+
+ int randomPropertyId;
+ if (!(val.Item && t.TryConsumeTo(val.EnchantId) && t.TryConsumeTo(val.GemEnchantId[0]) && t.TryConsumeTo(val.GemEnchantId[1]) &&
+ t.TryConsumeTo(val.GemEnchantId[2]) && t.TryConsumeTo(dummy) && t.TryConsumeTo(randomPropertyId) && t.TryConsumeTo(val.RandomSuffixBaseAmount) &&
+ t.TryConsumeTo(val.RenderLevel) && t.IsEmpty() && !dummy))
+ return false;
+
+ if (randomPropertyId < 0)
+ {
+ if (!val.Item->RandomSuffix)
+ return false;
+ if (ItemRandomSuffixEntry const* suffixEntry = sItemRandomSuffixStore.LookupEntry(-randomPropertyId))
+ {
+ val.RandomSuffix = suffixEntry;
+ val.RandomProperty = nullptr;
+ }
+ else
+ return false;
+ }
+ else if (randomPropertyId > 0)
+ {
+ if (!val.Item->RandomProperty)
+ return false;
+ if (ItemRandomPropertiesEntry const* propEntry = sItemRandomPropertiesStore.LookupEntry(randomPropertyId))
+ {
+ val.RandomSuffix = nullptr;
+ val.RandomProperty = propEntry;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ val.RandomSuffix = nullptr;
+ val.RandomProperty = nullptr;
+ }
+
+ if ((val.RandomSuffix && !val.RandomSuffixBaseAmount) || (val.RandomSuffixBaseAmount && !val.RandomSuffix))
+ return false;
+
+ return true;
}
bool Trinity::Hyperlinks::LinkTags::quest::StoreTo(QuestLinkData& val, std::string_view text)
diff --git a/src/server/game/Chat/Hyperlinks.cpp b/src/server/game/Chat/Hyperlinks.cpp
index 308ec33d46d..8b82cb1e38c 100644
--- a/src/server/game/Chat/Hyperlinks.cpp
+++ b/src/server/game/Chat/Hyperlinks.cpp
@@ -132,21 +132,11 @@ struct LinkValidator<LinkTags::item>
{
ItemLocale const* locale = sObjectMgr->GetItemLocale(data.Item->ItemId);
- char const* const* randomSuffixes = nullptr; // this is a c-style array of c strings (and i don't want to touch DBCStructure.h right now)
- if (data.RandomPropertyId < 0)
- {
- if (ItemRandomSuffixEntry const* suffixEntry = sItemRandomSuffixStore.LookupEntry(-data.RandomPropertyId))
- randomSuffixes = suffixEntry->Name;
- else
- return false;
- }
- else if (data.RandomPropertyId > 0)
- {
- if (ItemRandomPropertiesEntry const* propEntry = sItemRandomPropertiesStore.LookupEntry(data.RandomPropertyId))
- randomSuffixes = propEntry->Name;
- else
- return false;
- }
+ std::array<char const*, 16> const* randomSuffixes = nullptr;
+ if (data.RandomProperty)
+ randomSuffixes = &data.RandomProperty->Name;
+ else if (data.RandomSuffix)
+ randomSuffixes = &data.RandomSuffix->Name;
for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
{
@@ -157,8 +147,9 @@ struct LinkValidator<LinkTags::item>
continue;
if (randomSuffixes)
{
- std::string_view randomSuffix(randomSuffixes[i]);
+ std::string_view randomSuffix((*randomSuffixes)[i]);
if (
+ (!randomSuffix.empty()) &&
(text.length() == (name.length() + 1 + randomSuffix.length())) &&
(text.substr(0, name.length()) == name) &&
(text[name.length()] == ' ') &&
diff --git a/src/server/game/Chat/Hyperlinks.h b/src/server/game/Chat/Hyperlinks.h
index 69bfdb28ff0..4a263df4a01 100644
--- a/src/server/game/Chat/Hyperlinks.h
+++ b/src/server/game/Chat/Hyperlinks.h
@@ -29,6 +29,8 @@
struct AchievementEntry;
struct GlyphPropertiesEntry;
struct GlyphSlotEntry;
+struct ItemRandomPropertiesEntry;
+struct ItemRandomSuffixEntry;
struct ItemTemplate;
class SpellInfo;
class Quest;
@@ -59,8 +61,9 @@ namespace Trinity::Hyperlinks
ItemTemplate const* Item;
uint32 EnchantId;
std::array<uint32, 3> GemEnchantId;
- int32 RandomPropertyId;
- int32 RandomPropertySeed;
+ ItemRandomPropertiesEntry const* RandomProperty;
+ ItemRandomSuffixEntry const* RandomSuffix;
+ uint32 RandomSuffixBaseAmount;
uint8 RenderLevel;
};
diff --git a/src/server/shared/DataStores/DBCStructure.h b/src/server/shared/DataStores/DBCStructure.h
index e3b67d43703..753067043b6 100644
--- a/src/server/shared/DataStores/DBCStructure.h
+++ b/src/server/shared/DataStores/DBCStructure.h
@@ -951,24 +951,24 @@ struct ItemLimitCategoryEntry
struct ItemRandomPropertiesEntry
{
- uint32 ID; // 0
- //char const* InternalName; // 1
- uint32 Enchantment[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 2-4
- //uint32 UnusedEnchantment[2]; // 5-6
- char const* Name[16]; // 7-22
- //uint32 Name_lang_mask; // 23
+ uint32 ID; // 0
+ //char const* InternalName; // 1
+ std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 2-4
+ //std::array<uint32, 2> UnusedEnchantment; // 5-6
+ std::array<char const*, 16> Name; // 7-22
+ //uint32 Name_lang_mask; // 23
};
struct ItemRandomSuffixEntry
{
- uint32 ID; // 0
- char const* Name[16]; // 1-16
- //uint32 Name_lang_mask; // 17
- //char const* InternalName; // 18
- uint32 Enchantment[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 19-21
- //uint32 UnusedEnchantment[2] // 22-23
- uint32 AllocationPct[MAX_ITEM_ENCHANTMENT_EFFECTS]; // 24-26
- //uint32 UnusedAllocationPct[2] // 27-28
+ uint32 ID; // 0
+ std::array<char const*, 16> Name; // 1-16
+ //uint32 Name_lang_mask; // 17
+ //char const* InternalName; // 18
+ std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> Enchantment; // 19-21
+ //std::array<uint32, 2> UnusedEnchantment; // 22-23
+ std::array<uint32, MAX_ITEM_ENCHANTMENT_EFFECTS> AllocationPct; // 24-26
+ //std::array<uint32, 2> UnusedAllocationPct; // 27-28
};
#define MAX_ITEM_SET_ITEMS 10
diff --git a/tests/DummyData.cpp b/tests/DummyData.cpp
index b6b70363bc7..f1f0f1cbb08 100644
--- a/tests/DummyData.cpp
+++ b/tests/DummyData.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -28,7 +28,7 @@
t.ItemId = itemId;
t.Class = ItemClass::ITEM_CLASS_MISC;
t.SubClass = 0;
- t.SoundOverrideSubclass = 0;
+ t.SoundOverrideSubclass = -1;
t.Name1 = name;
t.DisplayInfoID = 0;
t.Quality = ItemQualities::ITEM_QUALITY_ARTIFACT;
@@ -112,21 +112,88 @@
localeData.Name[i] = name;
}
+static UnitTestDataLoader::DBC<ItemRandomPropertiesEntry, &ItemRandomPropertiesEntry::ID> randomProperties(sItemRandomPropertiesStore);
+static UnitTestDataLoader::DBC<ItemRandomSuffixEntry, &ItemRandomSuffixEntry::ID> randomSuffixes(sItemRandomSuffixStore);
/*static*/ void UnitTestDataLoader::LoadItemTemplates()
{
if (!sObjectMgr->_itemTemplateStore.empty())
return;
ItemTemplate& hearthstone = GetItemTemplate(6948, "Hearthstone");
- hearthstone.SoundOverrideSubclass = -1;
hearthstone.DisplayInfoID = 6418;
hearthstone.Quality = ItemQualities::ITEM_QUALITY_NORMAL;
hearthstone.Flags = ItemFlags::ITEM_FLAG_PLAYERCAST;
hearthstone.MaxCount = 1;
hearthstone.Spells[0].SpellId = 8690;
hearthstone.Bonding = ItemBondingType::BIND_WHEN_PICKED_UP;
+ SetItemLocale(6948, LocaleConstant::LOCALE_esES, "Piedra de hogar");
- SetItemLocale(6948, LocaleConstant::LOCALE_esMX, "Piedra de hogar");
+ ItemTemplate& niceHat = GetItemTemplate(10250, "Master's Hat");
+ niceHat.Class = ItemClass::ITEM_CLASS_ARMOR;
+ niceHat.SubClass = ItemSubclassArmor::ITEM_SUBCLASS_ARMOR_CLOTH;
+ niceHat.DisplayInfoID = 27824;
+ niceHat.Quality = ItemQualities::ITEM_QUALITY_UNCOMMON;
+ niceHat.BuyCount = 1;
+ niceHat.BuyPrice = 66902;
+ niceHat.SellPrice = 13380;
+ niceHat.InventoryType = InventoryType::INVTYPE_HEAD;
+ niceHat.ItemLevel = 63;
+ niceHat.RequiredLevel = 58;
+ niceHat.Armor = 66;
+ niceHat.Bonding = ItemBondingType::BIND_WHEN_EQUIPED;
+ niceHat.Material = 7;
+ niceHat.RandomProperty = 639;
+ niceHat.MaxDurability = 45;
+ niceHat.RequiredDisenchantSkill = 225;
+ niceHat.DisenchantID = 11;
+ SetItemLocale(10250, LocaleConstant::LOCALE_esES, "Sombrero de maestro");
+
+ ItemTemplate& vikingShield = GetItemTemplate(36449, "Vrykul Shield");
+ vikingShield.Class = ItemClass::ITEM_CLASS_ARMOR;
+ vikingShield.SubClass = ItemSubclassArmor::ITEM_SUBCLASS_ARMOR_SHIELD;
+ vikingShield.DisplayInfoID = 52191;
+ vikingShield.Quality = ItemQualities::ITEM_QUALITY_UNCOMMON;
+ vikingShield.BuyCount = 1;
+ vikingShield.BuyPrice = 300510;
+ vikingShield.SellPrice = 60102;
+ vikingShield.InventoryType = InventoryType::INVTYPE_SHIELD;
+ vikingShield.ItemLevel = 146;
+ vikingShield.RequiredLevel = 71;
+ vikingShield.Armor = 4476;
+ vikingShield.Bonding = ItemBondingType::BIND_WHEN_EQUIPED;
+ vikingShield.Material = 1;
+ vikingShield.Sheath = 4;
+ vikingShield.RandomSuffix = 82;
+ vikingShield.Block = 138;
+ vikingShield.MaxDurability = 85;
+ vikingShield.RequiredDisenchantSkill = 325;
+ vikingShield.DisenchantID = 34;
+ SetItemLocale(36449, LOCALE_esES, "Escudo vrykul");
+
+ for (auto& [id, data] : sObjectMgr->_itemTemplateStore)
+ data.InitializeQueryData();
+
+ auto propLoader = randomProperties.Loader();
+ ItemRandomPropertiesEntry& fieryWrath = propLoader.Add();
+ fieryWrath.ID = 1902;
+ fieryWrath.Enchantment = {};
+ fieryWrath.Enchantment[0] = 2182;
+ fieryWrath.Name.fill("");
+ fieryWrath.Name[LOCALE_enUS] = "of Fiery Wrath";
+ fieryWrath.Name[LOCALE_esES] = "de c\xc3\xb3lera \xc3\xadgnea";
+
+ auto suffixLoader = randomSuffixes.Loader();
+ ItemRandomSuffixEntry& champion = suffixLoader.Add();
+ champion.ID = 45;
+ champion.Name.fill("");
+ champion.Name[LOCALE_enUS] = "of the Champion";
+ champion.Name[LOCALE_esES] = "del Campe\xc3\xb3n";
+ champion.Enchantment[0] = 2805;
+ champion.Enchantment[1] = 2803;
+ champion.Enchantment[2] = 2813;
+ champion.AllocationPct[0] = 5259;
+ champion.AllocationPct[1] = 7889;
+ champion.AllocationPct[2] = 5259;
}
static UnitTestDataLoader::DBC<AchievementEntry, &AchievementEntry::ID> achievements(sAchievementStore);
@@ -141,7 +208,6 @@ static UnitTestDataLoader::DBC<AchievementEntry, &AchievementEntry::ID> achievem
toc5.Title.fill("");
toc5.Title[LOCALE_enUS] = "Heroic: Trial of the Champion";
toc5.Title[LOCALE_esES] = "Heroico: Prueba del Campe\xc3\xb3n";
- toc5.Title[LOCALE_esMX] = "Heroico: Prueba del Campe\xc3\xb3n";
toc5.Category = 14921;
toc5.Points = 10;
toc5.Flags = 0;
diff --git a/tests/game/Hyperlinks.cpp b/tests/game/Hyperlinks.cpp
index 4648d295328..3ab3f2bb1f0 100644
--- a/tests/game/Hyperlinks.cpp
+++ b/tests/game/Hyperlinks.cpp
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -71,6 +71,34 @@ TEST_CASE("|Hitem validation", "[Hyperlinks]")
REQUIRE(false == CheckAllLinks("This is a mis-colored |cffa335ee|Hitem:6948:0:0:0:0:0:0:0:80|h[Hearthstone]|h|r."));
REQUIRE(false == CheckAllLinks("This is a |cffffffff|Hitem:6948:-1:0:0:0:0:0:0:-1|h[Hearthstone]|h|r that is quite negative."));
}
+
+ SECTION("Item link with random property")
+ {
+ REQUIRE(true == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1902:0:60|h[Master's Hat of Fiery Wrath]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1902:0:60|h[Master's Hat]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1:0:60|h[Master's Hat]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:-1902:0:60|h[Master's Hat of Fiery Wrath]|h|r"));
+ REQUIRE(true == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1902:0:60|h[Sombrero de maestro de c\xc3\xb3lera \xc3\xadgnea]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1902:0:60|h[Sombrero de maestro of Fiery Wrath]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1902:0:60|h[Master's Hat de c\xc3\xb3lera \xc3\xadgnea]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1902:1:60|h[Master's Hat of Fiery Wrath]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:10250:0:0:0:0:0:1902:-1:60|h[Master's Hat of Fiery Wrath]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cffffffff|Hitem:6948:0:0:0:0:0:1902:0:80|h[Hearthstone of Fiery Wrath]|h|r"));
+ }
+
+ SECTION("Item link with random suffix")
+ {
+ REQUIRE(true == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-45:43:80|h[Vrykul Shield of the Champion]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-45:43:80|h[Vrykul Shield]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-1:43:80|h[Vrykul Shield]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:45:43:80|h[Vrykul Shield of the Champion]|h|r"));
+ REQUIRE(true == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-45:43:80|h[Escudo vrykul del Campe\xc3\xb3n]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-45:43:80|h[Escudo vrykul of the Champion]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-45:43:80|h[Vrykul Shield del Campe\xc3\xb3n]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-45:0:80|h[Escudo vrykul del Campe\xc3\xb3n]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cff1eff00|Hitem:36449:0:0:0:0:0:-45:-1:80|h[Vrykul Shield of the Champion]|h|r"));
+ REQUIRE(false == CheckAllLinks("|cffffffff|Hitem:6948:0:0:0:0:0:-45:43:80|h[Hearthstone of the Champion]|h|r"));
+ }
}
TEST_CASE("|Hachievement validation", "[Hyperlinks]")