Core/Items: Item bonus generation improvements

* Pass ItemContext to item creation wherever possible
* Support scaling item levels with m+ keystone levels (not used currently)
* Fixed item link validation when client sends it as default uninitialized bonus list with context only
* Support scaling items depending on current active season (seasons not implemented)
* Implemented content tuning redirection
Port From (https://github.com/TrinityCore/TrinityCore/commit/0fb8765a6638fd947b59fce44d5c31251d0cdadd)
This commit is contained in:
hondacrx
2023-06-21 09:19:40 -04:00
parent 378b0ffccd
commit 49a07ebcce
30 changed files with 796 additions and 336 deletions
+16
View File
@@ -87,6 +87,7 @@ namespace Game.DataStorage
BroadcastTextStorage = ReadDB2<BroadcastTextRecord>("BroadcastText.db2", HotfixStatements.SEL_BROADCAST_TEXT, HotfixStatements.SEL_BROADCAST_TEXT_LOCALE);
BroadcastTextDurationStorage = ReadDB2<BroadcastTextDurationRecord>("BroadcastTextDuration.db2", HotfixStatements.SEL_BROADCAST_TEXT_DURATION);
CfgRegionsStorage = ReadDB2<Cfg_RegionsRecord>("Cfg_Regions.db2", HotfixStatements.SEL_CFG_REGIONS);
ChallengeModeItemBonusOverrideStorage = ReadDB2<ChallengeModeItemBonusOverrideRecord>("ChallengeModeItemBonusOverride.db2", HotfixStatements.SEL_CHALLENGE_MODE_ITEM_BONUS_OVERRIDE);
CharTitlesStorage = ReadDB2<CharTitlesRecord>("CharTitles.db2", HotfixStatements.SEL_CHAR_TITLES, HotfixStatements.SEL_CHAR_TITLES_LOCALE);
CharacterLoadoutStorage = ReadDB2<CharacterLoadoutRecord>("CharacterLoadout.db2", HotfixStatements.SEL_CHARACTER_LOADOUT);
CharacterLoadoutItemStorage = ReadDB2<CharacterLoadoutItemRecord>("CharacterLoadoutItem.db2", HotfixStatements.SEL_CHARACTER_LOADOUT_ITEM);
@@ -106,8 +107,10 @@ namespace Game.DataStorage
ChrSpecializationStorage = ReadDB2<ChrSpecializationRecord>("ChrSpecialization.db2", HotfixStatements.SEL_CHR_SPECIALIZATION, HotfixStatements.SEL_CHR_SPECIALIZATION_LOCALE);
CinematicCameraStorage = ReadDB2<CinematicCameraRecord>("CinematicCamera.db2", HotfixStatements.SEL_CINEMATIC_CAMERA);
CinematicSequencesStorage = ReadDB2<CinematicSequencesRecord>("CinematicSequences.db2", HotfixStatements.SEL_CINEMATIC_SEQUENCES);
ConditionalContentTuningStorage = ReadDB2<ConditionalContentTuningRecord>("ConditionalContentTuning.db2", HotfixStatements.SEL_CONDITIONAL_CONTENT_TUNING);
ContentTuningStorage = ReadDB2<ContentTuningRecord>("ContentTuning.db2", HotfixStatements.SEL_CONTENT_TUNING);
ContentTuningXExpectedStorage = ReadDB2<ContentTuningXExpectedRecord>("ContentTuningXExpected.db2", HotfixStatements.SEL_CONTENT_TUNING_X_EXPECTED);
ContentTuningXLabelStorage = ReadDB2<ContentTuningXLabelRecord>("ContentTuningXLabel.db2", HotfixStatements.SEL_CONTENT_TUNING_X_LABEL);
ConversationLineStorage = ReadDB2<ConversationLineRecord>("ConversationLine.db2", HotfixStatements.SEL_CONVERSATION_LINE);
CorruptionEffectsStorage = ReadDB2<CorruptionEffectsRecord>("CorruptionEffects.db2", HotfixStatements.SEL_CORRUPTION_EFFECTS);
CreatureDisplayInfoStorage = ReadDB2<CreatureDisplayInfoRecord>("CreatureDisplayInfo.db2", HotfixStatements.SEL_CREATURE_DISPLAY_INFO);
@@ -173,10 +176,13 @@ namespace Game.DataStorage
ItemArmorTotalStorage = ReadDB2<ItemArmorTotalRecord>("ItemArmorTotal.db2", HotfixStatements.SEL_ITEM_ARMOR_TOTAL);
//ItemBagFamilyStorage = ReadDB2<ItemBagFamilyRecord>("ItemBagFamily.db2", HotfixStatements.SEL_ITEM_BAG_FAMILY, HotfixStatements.SEL_ITEM_BAG_FAMILY_LOCALE);
ItemBonusStorage = ReadDB2<ItemBonusRecord>("ItemBonus.db2", HotfixStatements.SEL_ITEM_BONUS);
ItemBonusListGroupEntryStorage = ReadDB2<ItemBonusListGroupEntryRecord>("ItemBonusListGroupEntry.db2", HotfixStatements.SEL_ITEM_BONUS_LIST_GROUP_ENTRY);
ItemBonusListLevelDeltaStorage = ReadDB2<ItemBonusListLevelDeltaRecord>("ItemBonusListLevelDelta.db2", HotfixStatements.SEL_ITEM_BONUS_LIST_LEVEL_DELTA);
ItemBonusTreeStorage = ReadDB2<ItemBonusTreeRecord>("ItemBonusTree.db2", HotfixStatements.SEL_ITEM_BONUS_TREE);
ItemBonusTreeNodeStorage = ReadDB2<ItemBonusTreeNodeRecord>("ItemBonusTreeNode.db2", HotfixStatements.SEL_ITEM_BONUS_TREE_NODE);
ItemChildEquipmentStorage = ReadDB2<ItemChildEquipmentRecord>("ItemChildEquipment.db2", HotfixStatements.SEL_ITEM_CHILD_EQUIPMENT);
ItemClassStorage = ReadDB2<ItemClassRecord>("ItemClass.db2", HotfixStatements.SEL_ITEM_CLASS, HotfixStatements.SEL_ITEM_CLASS_LOCALE);
ItemContextPickerEntryStorage = ReadDB2<ItemContextPickerEntryRecord>("ItemContextPickerEntry.db2", HotfixStatements.SEL_ITEM_CONTEXT_PICKER_ENTRY);
ItemCurrencyCostStorage = ReadDB2<ItemCurrencyCostRecord>("ItemCurrencyCost.db2", HotfixStatements.SEL_ITEM_CURRENCY_COST);
ItemDamageAmmoStorage = ReadDB2<ItemDamageRecord>("ItemDamageAmmo.db2", HotfixStatements.SEL_ITEM_DAMAGE_AMMO);
ItemDamageOneHandStorage = ReadDB2<ItemDamageRecord>("ItemDamageOneHand.db2", HotfixStatements.SEL_ITEM_DAMAGE_ONE_HAND);
@@ -228,6 +234,7 @@ namespace Game.DataStorage
MountTypeXCapabilityStorage = ReadDB2<MountTypeXCapabilityRecord>("MountTypeXCapability.db2", HotfixStatements.SEL_MOUNT_TYPE_X_CAPABILITY);
MountXDisplayStorage = ReadDB2<MountXDisplayRecord>("MountXDisplay.db2", HotfixStatements.SEL_MOUNT_X_DISPLAY);
MovieStorage = ReadDB2<MovieRecord>("Movie.db2", HotfixStatements.SEL_MOVIE);
MythicPlusSeasonStorage = ReadDB2<MythicPlusSeasonRecord>("MythicPlusSeason.db2", HotfixStatements.SEL_MYTHIC_PLUS_SEASON);
NameGenStorage = ReadDB2<NameGenRecord>("NameGen.db2", HotfixStatements.SEL_NAME_GEN);
NamesProfanityStorage = ReadDB2<NamesProfanityRecord>("NamesProfanity.db2", HotfixStatements.SEL_NAMES_PROFANITY);
NamesReservedStorage = ReadDB2<NamesReservedRecord>("NamesReserved.db2", HotfixStatements.SEL_NAMES_RESERVED, HotfixStatements.SEL_NAMES_RESERVED_LOCALE);
@@ -243,6 +250,7 @@ namespace Game.DataStorage
PrestigeLevelInfoStorage = ReadDB2<PrestigeLevelInfoRecord>("PrestigeLevelInfo.db2", HotfixStatements.SEL_PRESTIGE_LEVEL_INFO, HotfixStatements.SEL_PRESTIGE_LEVEL_INFO_LOCALE);
PvpDifficultyStorage = ReadDB2<PvpDifficultyRecord>("PVPDifficulty.db2", HotfixStatements.SEL_PVP_DIFFICULTY);
PvpItemStorage = ReadDB2<PvpItemRecord>("PVPItem.db2", HotfixStatements.SEL_PVP_ITEM);
PvpSeasonStorage = ReadDB2<PvpSeasonRecord>("PvpSeason.db2", HotfixStatements.SEL_PVP_SEASON);
PvpTalentStorage = ReadDB2<PvpTalentRecord>("PvpTalent.db2", HotfixStatements.SEL_PVP_TALENT, HotfixStatements.SEL_PVP_TALENT_LOCALE);
PvpTalentCategoryStorage = ReadDB2<PvpTalentCategoryRecord>("PvpTalentCategory.db2", HotfixStatements.SEL_PVP_TALENT_CATEGORY);
PvpTalentSlotUnlockStorage = ReadDB2<PvpTalentSlotUnlockRecord>("PvpTalentSlotUnlock.db2", HotfixStatements.SEL_PVP_TALENT_SLOT_UNLOCK);
@@ -511,6 +519,7 @@ namespace Game.DataStorage
public static DB6Storage<BroadcastTextRecord> BroadcastTextStorage;
public static DB6Storage<BroadcastTextDurationRecord> BroadcastTextDurationStorage;
public static DB6Storage<Cfg_RegionsRecord> CfgRegionsStorage;
public static DB6Storage<ChallengeModeItemBonusOverrideRecord> ChallengeModeItemBonusOverrideStorage;
public static DB6Storage<CharTitlesRecord> CharTitlesStorage;
public static DB6Storage<CharacterLoadoutRecord> CharacterLoadoutStorage;
public static DB6Storage<CharacterLoadoutItemRecord> CharacterLoadoutItemStorage;
@@ -530,8 +539,10 @@ namespace Game.DataStorage
public static DB6Storage<ChrSpecializationRecord> ChrSpecializationStorage;
public static DB6Storage<CinematicCameraRecord> CinematicCameraStorage;
public static DB6Storage<CinematicSequencesRecord> CinematicSequencesStorage;
public static DB6Storage<ConditionalContentTuningRecord> ConditionalContentTuningStorage;
public static DB6Storage<ContentTuningRecord> ContentTuningStorage;
public static DB6Storage<ContentTuningXExpectedRecord> ContentTuningXExpectedStorage;
public static DB6Storage<ContentTuningXLabelRecord> ContentTuningXLabelStorage;
public static DB6Storage<ConversationLineRecord> ConversationLineStorage;
public static DB6Storage<CorruptionEffectsRecord> CorruptionEffectsStorage;
public static DB6Storage<CreatureDisplayInfoRecord> CreatureDisplayInfoStorage;
@@ -597,8 +608,11 @@ namespace Game.DataStorage
public static DB6Storage<ItemArmorTotalRecord> ItemArmorTotalStorage;
//public static DB6Storage<ItemBagFamilyRecord> ItemBagFamilyStorage;
public static DB6Storage<ItemBonusRecord> ItemBonusStorage;
public static DB6Storage<ItemBonusListGroupEntryRecord> ItemBonusListGroupEntryStorage;
public static DB6Storage<ItemBonusListLevelDeltaRecord> ItemBonusListLevelDeltaStorage;
public static DB6Storage<ItemBonusTreeRecord> ItemBonusTreeStorage;
public static DB6Storage<ItemBonusTreeNodeRecord> ItemBonusTreeNodeStorage;
public static DB6Storage<ItemContextPickerEntryRecord> ItemContextPickerEntryStorage;
public static DB6Storage<ItemClassRecord> ItemClassStorage;
public static DB6Storage<ItemChildEquipmentRecord> ItemChildEquipmentStorage;
public static DB6Storage<ItemCurrencyCostRecord> ItemCurrencyCostStorage;
@@ -652,6 +666,7 @@ namespace Game.DataStorage
public static DB6Storage<MountTypeXCapabilityRecord> MountTypeXCapabilityStorage;
public static DB6Storage<MountXDisplayRecord> MountXDisplayStorage;
public static DB6Storage<MovieRecord> MovieStorage;
public static DB6Storage<MythicPlusSeasonRecord> MythicPlusSeasonStorage;
public static DB6Storage<NameGenRecord> NameGenStorage;
public static DB6Storage<NamesProfanityRecord> NamesProfanityStorage;
public static DB6Storage<NamesReservedRecord> NamesReservedStorage;
@@ -667,6 +682,7 @@ namespace Game.DataStorage
public static DB6Storage<PrestigeLevelInfoRecord> PrestigeLevelInfoStorage;
public static DB6Storage<PvpDifficultyRecord> PvpDifficultyStorage;
public static DB6Storage<PvpItemRecord> PvpItemStorage;
public static DB6Storage<PvpSeasonRecord> PvpSeasonStorage;
public static DB6Storage<PvpTalentRecord> PvpTalentStorage;
public static DB6Storage<PvpTalentCategoryRecord> PvpTalentCategoryStorage;
public static DB6Storage<PvpTalentSlotUnlockRecord> PvpTalentSlotUnlockStorage;
+49 -214
View File
@@ -90,10 +90,6 @@ namespace Game.DataStorage
_azeriteTierUnlockLevels[key][azeriteTierUnlock.Tier] = azeriteTierUnlock.AzeriteLevel;
}
MultiMap<uint, AzeriteUnlockMappingRecord> azeriteUnlockMappings = new();
foreach (AzeriteUnlockMappingRecord azeriteUnlockMapping in AzeriteUnlockMappingStorage.Values)
azeriteUnlockMappings.Add(azeriteUnlockMapping.AzeriteUnlockMappingSetID, azeriteUnlockMapping);
foreach (BattlemasterListRecord battlemaster in BattlemasterListStorage.Values)
{
if (battlemaster.MaxLevel < battlemaster.MinLevel)
@@ -230,12 +226,18 @@ namespace Game.DataStorage
_chrSpecializationsByIndex[storageIndex][chrSpec.OrderIndex] = chrSpec;
}
foreach (ConditionalContentTuningRecord conditionalContentTuning in ConditionalContentTuningStorage.Values)
_conditionalContentTuning.Add(conditionalContentTuning.ParentContentTuningID, conditionalContentTuning);
foreach (ContentTuningXExpectedRecord contentTuningXExpectedStat in ContentTuningXExpectedStorage.Values)
{
if (ExpectedStatModStorage.ContainsKey(contentTuningXExpectedStat.ExpectedStatModID))
_expectedStatModsByContentTuning.Add(contentTuningXExpectedStat.ContentTuningID, contentTuningXExpectedStat);
}
foreach (ContentTuningXLabelRecord contentTuningXLabel in ContentTuningXLabelStorage.Values)
_contentTuningLabels.Add((contentTuningXLabel.ContentTuningID, contentTuningXLabel.LabelID));
foreach (CurrencyContainerRecord currencyContainer in CurrencyContainerStorage.Values)
_currencyContainers.Add(currencyContainer.CurrencyTypesID, currencyContainer);
@@ -283,15 +285,6 @@ namespace Game.DataStorage
foreach (GlyphRequiredSpecRecord glyphRequiredSpec in GlyphRequiredSpecStorage.Values)
_glyphRequiredSpecs.Add(glyphRequiredSpec.GlyphPropertiesID, glyphRequiredSpec.ChrSpecializationID);
foreach (var bonus in ItemBonusStorage.Values)
_itemBonusLists.Add(bonus.ParentItemBonusListID, bonus);
foreach (ItemBonusListLevelDeltaRecord itemBonusListLevelDelta in ItemBonusListLevelDeltaStorage.Values)
_itemLevelDeltaToBonusListContainer[itemBonusListLevelDelta.ItemLevelDelta] = itemBonusListLevelDelta.Id;
foreach (var bonusTreeNode in ItemBonusTreeNodeStorage.Values)
_itemBonusTrees.Add(bonusTreeNode.ParentItemBonusTreeID, bonusTreeNode);
foreach (ItemChildEquipmentRecord itemChildEquipment in ItemChildEquipmentStorage.Values)
{
//ASSERT(_itemChildEquipment.find(itemChildEquipment.ParentItemID) == _itemChildEquipment.end(), "Item must have max 1 child item.");
@@ -311,9 +304,6 @@ namespace Game.DataStorage
foreach (ItemLimitCategoryConditionRecord condition in ItemLimitCategoryConditionStorage.Values)
_itemCategoryConditions.Add(condition.ParentItemLimitCategoryID, condition);
foreach (ItemLevelSelectorQualityRecord itemLevelSelectorQuality in ItemLevelSelectorQualityStorage.Values)
_itemLevelQualitySelectorQualities.Add(itemLevelSelectorQuality.ParentILSQualitySetID, itemLevelSelectorQuality);
foreach (var appearanceMod in ItemModifiedAppearanceStorage.Values)
{
//ASSERT(appearanceMod.ItemID <= 0xFFFFFF);
@@ -326,12 +316,6 @@ namespace Game.DataStorage
foreach (var itemSpecOverride in ItemSpecOverrideStorage.Values)
_itemSpecOverrides.Add(itemSpecOverride.ItemID, itemSpecOverride);
foreach (var itemBonusTreeAssignment in ItemXBonusTreeStorage.Values)
_itemToBonusTree.Add(itemBonusTreeAssignment.ItemID, itemBonusTreeAssignment.ItemBonusTreeID);
foreach (var pair in _azeriteEmpoweredItems)
LoadAzeriteEmpoweredItemUnlockMappings(azeriteUnlockMappings, pair.Key);
foreach (JournalTierRecord journalTier in JournalTierStorage.Values)
_journalTiersByIndex.Add(journalTier);
@@ -1038,9 +1022,18 @@ namespace Game.DataStorage
return GetChrSpecializationByIndex(class_, PlayerConst.InitialSpecializationIndex);
}
public ContentTuningLevels? GetContentTuningData(uint contentTuningId, uint replacementConditionMask, bool forItem = false)
public uint GetRedirectedContentTuningId(uint contentTuningId, uint redirectFlag)
{
ContentTuningRecord contentTuning = ContentTuningStorage.LookupByKey(contentTuningId);
foreach (var conditionalContentTuning in _conditionalContentTuning.LookupByKey(contentTuningId))
if ((conditionalContentTuning.RedirectFlag & redirectFlag) != 0)
return (uint)conditionalContentTuning.RedirectContentTuningID;
return contentTuningId;
}
public ContentTuningLevels? GetContentTuningData(uint contentTuningId, uint redirectFlag, bool forItem = false)
{
ContentTuningRecord contentTuning = ContentTuningStorage.LookupByKey(GetRedirectedContentTuningId(contentTuningId, redirectFlag));
if (contentTuning == null)
return null;
@@ -1077,6 +1070,11 @@ namespace Game.DataStorage
return levels;
}
public bool HasContentTuningLabel(uint contentTuningId, int label)
{
return _contentTuningLabels.Contains((contentTuningId, label));
}
public string GetCreatureFamilyPetName(CreatureFamily petfamily, Locale locale)
{
if (petfamily == CreatureFamily.None)
@@ -1261,20 +1259,26 @@ namespace Game.DataStorage
return null;
}
float ExpectedStatModReducer(float mod, ContentTuningXExpectedRecord contentTuningXExpected, ExpectedStatType stat)
float ExpectedStatModReducer(float mod, ContentTuningXExpectedRecord contentTuningXExpected, ExpectedStatType stat, int ActiveMilestoneSeason)
{
if (contentTuningXExpected == null)
return mod;
//if (contentTuningXExpected->MinMythicPlusSeasonID)
// if (MythicPlusSeasonEntry const* mythicPlusSeason = sMythicPlusSeasonStore.LookupEntry(contentTuningXExpected->MinMythicPlusSeasonID))
// if (MythicPlusSubSeason < mythicPlusSeason->SubSeason)
// return mod;
if (contentTuningXExpected.MinMythicPlusSeasonID != 0)
{
var mythicPlusSeason = MythicPlusSeasonStorage.LookupByKey(contentTuningXExpected.MinMythicPlusSeasonID);
if (mythicPlusSeason != null)
if (ActiveMilestoneSeason < mythicPlusSeason.MilestoneSeason)
return mod;
}
//if (contentTuningXExpected->MaxMythicPlusSeasonID)
// if (MythicPlusSeasonEntry const* mythicPlusSeason = sMythicPlusSeasonStore.LookupEntry(contentTuningXExpected->MaxMythicPlusSeasonID))
// if (MythicPlusSubSeason >= mythicPlusSeason->SubSeason)
// return mod;
if (contentTuningXExpected.MaxMythicPlusSeasonID != 0)
{
var mythicPlusSeason = MythicPlusSeasonStorage.LookupByKey(contentTuningXExpected.MaxMythicPlusSeasonID);
if (mythicPlusSeason != null)
if (ActiveMilestoneSeason >= mythicPlusSeason.MilestoneSeason)
return mod;
}
var expectedStatMod = ExpectedStatModStorage.LookupByKey(contentTuningXExpected.ExpectedStatModID);
switch (stat)
@@ -1300,11 +1304,9 @@ namespace Game.DataStorage
}
return mod;
// int32 MythicPlusSubSeason = 0;
}
public float EvaluateExpectedStat(ExpectedStatType stat, uint level, int expansion, uint contentTuningId, Class unitClass)
public float EvaluateExpectedStat(ExpectedStatType stat, uint level, int expansion, uint contentTuningId, Class unitClass, int mythicPlusMilestoneSeason)
{
var expectedStatRecord = _expectedStatsByLevel.LookupByKey(Tuple.Create(level, expansion));
if (expectedStatRecord == null)
@@ -1338,56 +1340,56 @@ namespace Game.DataStorage
case ExpectedStatType.CreatureHealth:
value = expectedStatRecord.CreatureHealth;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.CreatureHealthMod;
break;
case ExpectedStatType.PlayerHealth:
value = expectedStatRecord.PlayerHealth;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.PlayerHealthMod;
break;
case ExpectedStatType.CreatureAutoAttackDps:
value = expectedStatRecord.CreatureAutoAttackDps;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.CreatureAutoAttackDPSMod;
break;
case ExpectedStatType.CreatureArmor:
value = expectedStatRecord.CreatureArmor;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.CreatureArmorMod;
break;
case ExpectedStatType.PlayerMana:
value = expectedStatRecord.PlayerMana;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.PlayerManaMod;
break;
case ExpectedStatType.PlayerPrimaryStat:
value = expectedStatRecord.PlayerPrimaryStat;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.PlayerPrimaryStatMod;
break;
case ExpectedStatType.PlayerSecondaryStat:
value = expectedStatRecord.PlayerSecondaryStat;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.PlayerSecondaryStatMod;
break;
case ExpectedStatType.ArmorConstant:
value = expectedStatRecord.ArmorConstant;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.ArmorConstantMod;
break;
@@ -1396,7 +1398,7 @@ namespace Game.DataStorage
case ExpectedStatType.CreatureSpellDamage:
value = expectedStatRecord.CreatureSpellDamage;
if (!contentTuningMods.Empty())
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat));
value *= contentTuningMods.Sum(expectedStatMod => ExpectedStatModReducer(1.0f, expectedStatMod, stat, mythicPlusMilestoneSeason));
if (classMod != null)
value *= classMod.CreatureSpellDamageMod;
break;
@@ -1440,169 +1442,6 @@ namespace Game.DataStorage
return _heirlooms.LookupByKey(itemId);
}
public List<ItemBonusRecord> GetItemBonusList(uint bonusListId)
{
return _itemBonusLists.LookupByKey(bonusListId);
}
public uint GetItemBonusListForItemLevelDelta(short delta)
{
return _itemLevelDeltaToBonusListContainer.LookupByKey(delta);
}
void VisitItemBonusTree(uint itemBonusTreeId, bool visitChildren, Action<ItemBonusTreeNodeRecord> visitor)
{
var bonusTreeNodeList = _itemBonusTrees.LookupByKey(itemBonusTreeId);
if (bonusTreeNodeList.Empty())
return;
foreach (var bonusTreeNode in bonusTreeNodeList)
{
visitor(bonusTreeNode);
if (visitChildren && bonusTreeNode.ChildItemBonusTreeID != 0)
VisitItemBonusTree(bonusTreeNode.ChildItemBonusTreeID, true, visitor);
}
}
public List<uint> GetDefaultItemBonusTree(uint itemId, ItemContext itemContext)
{
List<uint> bonusListIDs = new();
ItemSparseRecord proto = ItemSparseStorage.LookupByKey(itemId);
if (proto == null)
return bonusListIDs;
var itemIdRange = _itemToBonusTree.LookupByKey(itemId);
if (itemIdRange == null)
return bonusListIDs;
ushort itemLevelSelectorId = 0;
foreach (var itemBonusTreeId in itemIdRange)
{
uint matchingNodes = 0;
VisitItemBonusTree(itemBonusTreeId, false, bonusTreeNode =>
{
if ((ItemContext)bonusTreeNode.ItemContext == ItemContext.None || itemContext == (ItemContext)bonusTreeNode.ItemContext)
++matchingNodes;
});
if (matchingNodes != 1)
continue;
VisitItemBonusTree(itemBonusTreeId, true, bonusTreeNode =>
{
ItemContext requiredContext = (ItemContext)bonusTreeNode.ItemContext != ItemContext.ForceToNone ? (ItemContext)bonusTreeNode.ItemContext : ItemContext.None;
if ((ItemContext)bonusTreeNode.ItemContext != ItemContext.None && itemContext != requiredContext)
return;
if (bonusTreeNode.ChildItemBonusListID != 0)
{
bonusListIDs.Add(bonusTreeNode.ChildItemBonusListID);
}
else if (bonusTreeNode.ChildItemLevelSelectorID != 0)
{
itemLevelSelectorId = bonusTreeNode.ChildItemLevelSelectorID;
}
});
}
ItemLevelSelectorRecord selector = ItemLevelSelectorStorage.LookupByKey(itemLevelSelectorId);
if (selector != null)
{
short delta = (short)(selector.MinItemLevel - proto.ItemLevel);
uint bonus = GetItemBonusListForItemLevelDelta(delta);
if (bonus != 0)
bonusListIDs.Add(bonus);
ItemLevelSelectorQualitySetRecord selectorQualitySet = ItemLevelSelectorQualitySetStorage.LookupByKey(selector.ItemLevelSelectorQualitySetID);
if (selectorQualitySet != null)
{
var itemSelectorQualities = _itemLevelQualitySelectorQualities.LookupByKey(selector.ItemLevelSelectorQualitySetID);
if (itemSelectorQualities != null)
{
ItemQuality quality = ItemQuality.Uncommon;
if (selector.MinItemLevel >= selectorQualitySet.IlvlEpic)
quality = ItemQuality.Epic;
else if (selector.MinItemLevel >= selectorQualitySet.IlvlRare)
quality = ItemQuality.Rare;
var itemSelectorQuality = itemSelectorQualities.Find(p => p.Quality < (sbyte)quality);
if (itemSelectorQuality != null)
bonusListIDs.Add(itemSelectorQuality.QualityItemBonusListID);
}
}
AzeriteUnlockMappingRecord azeriteUnlockMapping = _azeriteUnlockMappings.LookupByKey((proto.Id, itemContext));
if (azeriteUnlockMapping != null)
{
switch (proto.inventoryType)
{
case InventoryType.Head:
bonusListIDs.Add(azeriteUnlockMapping.ItemBonusListHead);
break;
case InventoryType.Shoulders:
bonusListIDs.Add(azeriteUnlockMapping.ItemBonusListShoulders);
break;
case InventoryType.Chest:
case InventoryType.Robe:
bonusListIDs.Add(azeriteUnlockMapping.ItemBonusListChest);
break;
}
}
}
return bonusListIDs;
}
public List<uint> GetAllItemBonusTreeBonuses(uint itemBonusTreeId)
{
List<uint> bonusListIDs = new();
VisitItemBonusTree(itemBonusTreeId, true, bonusTreeNode =>
{
if (bonusTreeNode.ChildItemBonusListID != 0)
bonusListIDs.Add(bonusTreeNode.ChildItemBonusListID);
});
return bonusListIDs;
}
void LoadAzeriteEmpoweredItemUnlockMappings(MultiMap<uint, AzeriteUnlockMappingRecord> azeriteUnlockMappingsBySet, uint itemId)
{
var itemIdRange = _itemToBonusTree.LookupByKey(itemId);
if (itemIdRange == null)
return;
foreach (var itemTreeItr in itemIdRange)
{
VisitItemBonusTree(itemTreeItr, true, bonusTreeNode =>
{
if (bonusTreeNode.ChildItemBonusListID == 0 && bonusTreeNode.ChildItemLevelSelectorID != 0)
{
ItemLevelSelectorRecord selector = ItemLevelSelectorStorage.LookupByKey(bonusTreeNode.ChildItemLevelSelectorID);
if (selector == null)
return;
var azeriteUnlockMappings = azeriteUnlockMappingsBySet.LookupByKey(selector.AzeriteUnlockMappingSet);
if (azeriteUnlockMappings != null)
{
AzeriteUnlockMappingRecord selectedAzeriteUnlockMapping = null;
foreach (AzeriteUnlockMappingRecord azeriteUnlockMapping in azeriteUnlockMappings)
{
if (azeriteUnlockMapping.ItemLevel > selector.MinItemLevel ||
(selectedAzeriteUnlockMapping != null && selectedAzeriteUnlockMapping.ItemLevel > azeriteUnlockMapping.ItemLevel))
continue;
selectedAzeriteUnlockMapping = azeriteUnlockMapping;
}
if (selectedAzeriteUnlockMapping != null)
_azeriteUnlockMappings[(itemId, (ItemContext)bonusTreeNode.ItemContext)] = selectedAzeriteUnlockMapping;
}
}
});
}
}
public ItemChildEquipmentRecord GetItemChildEquipment(uint itemId)
{
return _itemChildEquipment.LookupByKey(itemId);
@@ -2383,7 +2222,6 @@ namespace Game.DataStorage
AzeriteItemMilestonePowerRecord[] _azeriteItemMilestonePowerByEssenceSlot = new AzeriteItemMilestonePowerRecord[SharedConst.MaxAzeriteEssenceSlot];
MultiMap<uint, AzeritePowerSetMemberRecord> _azeritePowers = new();
Dictionary<(uint azeriteUnlockSetId, ItemContext itemContext), byte[]> _azeriteTierUnlockLevels = new();
Dictionary<(uint itemId, ItemContext itemContext), AzeriteUnlockMappingRecord> _azeriteUnlockMappings = new();
Dictionary<(int broadcastTextId, CascLocaleBit cascLocaleBit), int> _broadcastTextDurations = new();
ChrClassUIDisplayRecord[] _uiDisplayByClass = new ChrClassUIDisplayRecord[(int)Class.Max];
uint[][] _powersByClass = new uint[(int)Class.Max][];
@@ -2393,6 +2231,8 @@ namespace Game.DataStorage
MultiMap<Tuple<byte, byte>, ChrCustomizationOptionRecord> _chrCustomizationOptionsByRaceAndGender = new();
Dictionary<uint, MultiMap<uint, uint>> _chrCustomizationRequiredChoices = new();
ChrSpecializationRecord[][] _chrSpecializationsByIndex = new ChrSpecializationRecord[(int)Class.Max + 1][];
MultiMap<uint, ConditionalContentTuningRecord> _conditionalContentTuning = new();
List<(uint, int)> _contentTuningLabels = new();
MultiMap<uint, CurrencyContainerRecord> _currencyContainers = new();
MultiMap<uint, CurvePointRecord> _curvePoints = new();
Dictionary<Tuple<uint, byte, byte, byte>, EmotesTextSoundRecord> _emoteTextSounds = new();
@@ -2403,16 +2243,11 @@ namespace Game.DataStorage
Dictionary<uint, HeirloomRecord> _heirlooms = new();
MultiMap<uint, uint> _glyphBindableSpells = new();
MultiMap<uint, uint> _glyphRequiredSpecs = new();
MultiMap<uint, ItemBonusRecord> _itemBonusLists = new();
Dictionary<short, uint> _itemLevelDeltaToBonusListContainer = new();
MultiMap<uint, ItemBonusTreeNodeRecord> _itemBonusTrees = new();
Dictionary<uint, ItemChildEquipmentRecord> _itemChildEquipment = new();
ItemClassRecord[] _itemClassByOldEnum = new ItemClassRecord[20];
List<uint> _itemsWithCurrencyCost = new();
MultiMap<uint, ItemLimitCategoryConditionRecord> _itemCategoryConditions = new();
MultiMap<uint, ItemLevelSelectorQualityRecord> _itemLevelQualitySelectorQualities = new();
Dictionary<uint, ItemModifiedAppearanceRecord> _itemModifiedAppearancesByItem = new();
MultiMap<uint, uint> _itemToBonusTree = new();
MultiMap<uint, ItemSetSpellRecord> _itemSetSpells = new();
MultiMap<uint, ItemSpecOverrideRecord> _itemSpecOverrides = new();
List<JournalTierRecord> _journalTiersByIndex = new();
@@ -16,6 +16,18 @@ namespace Game.DataStorage
public uint ChallengeOrigin;
}
public sealed class ChallengeModeItemBonusOverrideRecord
{
public uint Id;
public int ItemBonusTreeGroupID;
public int DstItemBonusTreeID;
public sbyte Type;
public int Value;
public int MythicPlusSeasonID;
public int PvPSeasonID;
public uint SrcItemBonusTreeID;
}
public sealed class CharTitlesRecord
{
public uint Id;
@@ -317,6 +329,15 @@ namespace Game.DataStorage
public ushort[] Camera = new ushort[8];
}
public sealed class ConditionalContentTuningRecord
{
public uint Id;
public int OrderIndex;
public int RedirectContentTuningID;
public int RedirectFlag;
public uint ParentContentTuningID;
}
public sealed class ContentTuningRecord
{
public uint Id;
@@ -357,6 +378,13 @@ namespace Game.DataStorage
public uint ContentTuningID;
}
public sealed class ContentTuningXLabelRecord
{
public uint Id;
public int LabelID;
public uint ContentTuningID;
}
public sealed class ConversationLineRecord
{
public uint Id;
+32 -5
View File
@@ -2,6 +2,7 @@
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
using Framework.Constants;
using System;
namespace Game.DataStorage
{
@@ -99,12 +100,14 @@ namespace Game.DataStorage
public sealed class ItemBonusListGroupEntryRecord
{
public uint Id;
public uint ItemBonusListGroupID;
public int ItemBonusListGroupID;
public int ItemBonusListID;
public int ItemLevelSelectorID;
public int OrderIndex;
public int SequenceValue;
public int ItemExtendedCostID;
public int PlayerConditionID;
public int Flags;
public int ItemLogicalCostGroupID;
}
public sealed class ItemBonusListLevelDeltaRecord
@@ -120,6 +123,13 @@ namespace Game.DataStorage
public int ItemID;
}
public sealed class ItemBonusTreeRecord
{
public uint Id;
public int Flags;
public int InventoryTypeSlotMask;
}
public sealed class ItemBonusTreeNodeRecord
{
public uint Id;
@@ -129,8 +139,8 @@ namespace Game.DataStorage
public ushort ChildItemLevelSelectorID;
public uint ChildItemBonusListGroupID;
public uint IblGroupPointsModSetID;
public int Unknown1010_1;
public int Unknown1010_2;
public int MinMythicPlusLevel;
public int MaxMythicPlusLevel;
public uint ParentItemBonusTreeID;
}
@@ -151,11 +161,24 @@ namespace Game.DataStorage
public byte Flags;
}
public sealed class ItemContextPickerEntryRecord
{
public uint Id;
public byte ItemCreationContext;
public byte OrderIndex;
public int PVal;
public int LabelID;
public uint Flags;
public uint PlayerConditionID;
public uint ItemContextPickerID;
}
public sealed class ItemCurrencyCostRecord
{
public uint Id;
public uint ItemID;
}
// common struct for:
// ItemDamageAmmo.dbc
// ItemDamageOneHand.dbc
@@ -220,12 +243,16 @@ namespace Game.DataStorage
public ushort AzeriteUnlockMappingSet;
}
public sealed class ItemLevelSelectorQualityRecord
public sealed class ItemLevelSelectorQualityRecord : IEquatable<ItemLevelSelectorQualityRecord>, IEquatable<ItemQuality>
{
public uint Id;
public uint QualityItemBonusListID;
public sbyte Quality;
public uint ParentILSQualitySetID;
public bool Equals(ItemLevelSelectorQualityRecord other) { return Quality < other.Quality; }
public bool Equals(ItemQuality quality) { return Quality < (sbyte)quality; }
}
public sealed class ItemLevelSelectorQualitySetRecord
@@ -229,4 +229,12 @@ namespace Game.DataStorage
public uint SubtitleFileDataID;
public int SubtitleFileFormat;
}
public sealed class MythicPlusSeasonRecord
{
public uint Id;
public int MilestoneSeason;
public int ExpansionLevel;
public int HeroicLFGDungeonMinGear;
}
}
@@ -178,6 +178,14 @@ namespace Game.DataStorage
public byte ItemLevelDelta;
}
public sealed class PvpSeasonRecord
{
public uint Id;
public int MilestoneSeason;
public int AllianceAchievementID;
public int HordeAchievementID;
}
public sealed class PvpTalentRecord
{
public string Description;