diff options
author | Treeston <treeston.mmoc@gmail.com> | 2020-09-01 22:02:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-01 22:02:22 +0200 |
commit | d0b91f69279a823be159590c09945bc426f50d3e (patch) | |
tree | 1545fbeca0c4e86c3b3db22fe8a46f4b466afcde | |
parent | 3fbbe7cfbe1bc51db12bdc1ec7b21c16d1716366 (diff) |
Core/Misc: More DBC std::array refactors, stricter |Hitem checks, and more hyperlink unit tests
-rw-r--r-- | src/server/game/AuctionHouse/AuctionHouseMgr.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Chat/HyperlinkTags.cpp | 44 | ||||
-rw-r--r-- | src/server/game/Chat/Hyperlinks.cpp | 23 | ||||
-rw-r--r-- | src/server/game/Chat/Hyperlinks.h | 7 | ||||
-rw-r--r-- | src/server/shared/DataStores/DBCStructure.h | 28 | ||||
-rw-r--r-- | tests/DummyData.cpp | 76 | ||||
-rw-r--r-- | tests/game/Hyperlinks.cpp | 30 |
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]") |