diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 3f0f6f44b..edb29c486 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -2213,6 +2213,23 @@ namespace Framework.Constants SharedActionBars = 0x4 } + [Flags] + public enum TraitCondFlags + { + None = 0x0, + IsGate = 0x1, + IsAlwaysMet = 0x2, + IsSufficient = 0x4, + } + + public enum TraitConditionType + { + Available = 0, + Visible = 1, + Granted = 2, + Increased = 3 + } + public enum TraitConfigType { Invalid = 0, @@ -2221,6 +2238,66 @@ namespace Framework.Constants Generic = 3 } + public enum TraitCurrencyType + { + Gold = 0, + CurrencyTypesBased = 1, + TraitSourced = 2 + } + + public enum TraitEdgeType + { + VisualOnly = 0, + DeprecatedRankConnection = 1, + SufficientForAvailability = 2, + RequiredForAvailability = 3, + MutuallyExclusive = 4, + DeprecatedSelectionOption = 5 + } + + public enum TraitNodeEntryType + { + SpendHex = 0, + SpendSquare = 1, + SpendCircle = 2, + SpendSmallCircle = 3, + DeprecatedSelect = 4, + DragAndDrop = 5, + SpendDiamond = 6, + ProfPath = 7, + ProfPerk = 8, + ProfPathUnlock = 9 + } + + [Flags] + public enum TraitNodeGroupFlag + { + None = 0x0, + AvailableByDefault = 0x1 + } + + public enum TraitNodeType + { + Single = 0, + Tiered = 1, + Selection = 2 + } + + public enum TraitPointsOperationType + { + None = -1, + Set = 0, + Multiply = 1 + } + + [Flags] + public enum TraitTreeFlag + { + None = 0x0, + CannotRefund = 0x1, + HideSingleRankNumbers = 0x2 + } + public enum UiMapFlag { None = 0x00, diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index f6491d9d9..27407aa8b 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -116,7 +116,6 @@ namespace Framework.Database PrepareStatement(CharStatements.SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_INVENTORY, "SELECT " + SelectItemInstanceContent + ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE ci.guid = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC"); - PrepareStatement(CharStatements.SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button"); PrepareStatement(CharStatements.SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_SOCIALLIST, "SELECT cs.friend, c.account, cs.flags, cs.note FROM character_social cs JOIN characters c ON c.guid = cs.friend WHERE cs.guid = ? AND c.deleteinfos_name IS NULL LIMIT 255"); PrepareStatement(CharStatements.SEL_CHARACTER_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ, orientation FROM character_homebind WHERE guid = ?"); @@ -148,7 +147,7 @@ namespace Framework.Database PrepareStatement(CharStatements.DEL_CHARACTER_FAVORITE_AUCTIONS_BY_CHAR, "DELETE FROM character_favorite_auctions WHERE guid = ?"); PrepareStatement(CharStatements.SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?"); - PrepareStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button"); + PrepareStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? AND traitConfigId = ? ORDER BY button"); PrepareStatement(CharStatements.SEL_MAILITEMS, "SELECT " + SelectItemInstanceContent + ", ii.owner_guid, m.id FROM mail_items mi INNER JOIN mail m ON mi.mail_id = m.id LEFT JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE m.receiver = ?"); PrepareStatement(CharStatements.SEL_MAILITEMS_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN mail_items mi ON a.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); PrepareStatement(CharStatements.SEL_MAILITEMS_AZERITE, "SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel, " + @@ -605,9 +604,10 @@ namespace Framework.Database PrepareStatement(CharStatements.DEL_CHAR_PVP_TALENT, "DELETE FROM character_pvp_talent WHERE guid = ?"); PrepareStatement(CharStatements.DEL_CHAR_SKILLS, "DELETE FROM character_skills WHERE guid = ?"); PrepareStatement(CharStatements.UPD_CHAR_MONEY, "UPDATE characters SET money = ? WHERE guid = ?"); - PrepareStatement(CharStatements.INS_CHAR_ACTION, "INSERT INTO character_action (guid, spec, button, action, type) VALUES (?, ?, ?, ?, ?)"); - PrepareStatement(CharStatements.UPD_CHAR_ACTION, "UPDATE character_action SET action = ?, type = ? WHERE guid = ? AND button = ? AND spec = ?"); - PrepareStatement(CharStatements.DEL_CHAR_ACTION_BY_BUTTON_SPEC, "DELETE FROM character_action WHERE guid = ? and button = ? and spec = ?"); + PrepareStatement(CharStatements.INS_CHAR_ACTION, "INSERT INTO character_action (guid, spec, traitConfigId, button, action, type) VALUES (?, ?, ?, ?, ?, ?)"); + PrepareStatement(CharStatements.UPD_CHAR_ACTION, "UPDATE character_action SET action = ?, type = ? WHERE guid = ? AND button = ? AND spec = ? AND traitConfigId = ?"); + PrepareStatement(CharStatements.DEL_CHAR_ACTION_BY_BUTTON_SPEC, "DELETE FROM character_action WHERE guid = ? and button = ? and spec = ? AND traitConfigId = ?"); + PrepareStatement(CharStatements.DEL_CHAR_ACTION_BY_TRAIT_CONFIG, "DELETE FROM character_action WHERE guid = ? AND traitConfigId = ?"); PrepareStatement(CharStatements.DEL_CHAR_INVENTORY_BY_ITEM, "DELETE FROM character_inventory WHERE item = ?"); PrepareStatement(CharStatements.DEL_CHAR_INVENTORY_BY_BAG_SLOT, "DELETE FROM character_inventory WHERE bag = ? AND slot = ? AND guid = ?"); PrepareStatement(CharStatements.UPD_MAIL, "UPDATE mail SET has_items = ?, expire_time = ?, deliver_time = ?, money = ?, cod = ?, checked = ? WHERE id = ?"); @@ -639,6 +639,14 @@ namespace Framework.Database PrepareStatement(CharStatements.UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?"); PrepareStatement(CharStatements.INS_CHAR_FISHINGSTEPS, "INSERT INTO character_fishingsteps (guid, fishingSteps) VALUES (?, ?)"); PrepareStatement(CharStatements.DEL_CHAR_FISHINGSTEPS, "DELETE FROM character_fishingsteps WHERE guid = ?"); + PrepareStatement(CharStatements.SEL_CHAR_TRAIT_ENTRIES, "SELECT traitConfigId, traitNodeId, traitNodeEntryId, `rank`, grantedRanks FROM character_trait_entry WHERE guid = ?"); + PrepareStatement(CharStatements.INS_CHAR_TRAIT_ENTRIES, "INSERT INTO character_trait_entry (guid, traitConfigId, traitNodeId, traitNodeEntryId, `rank`, grantedRanks) VALUES (?, ?, ?, ?, ?, ?)"); + PrepareStatement(CharStatements.DEL_CHAR_TRAIT_ENTRIES, "DELETE FROM character_trait_entry WHERE guid = ? AND traitConfigId = ?"); + PrepareStatement(CharStatements.DEL_CHAR_TRAIT_ENTRIES_BY_CHAR, "DELETE FROM character_trait_entry WHERE guid = ?"); + PrepareStatement(CharStatements.SEL_CHAR_TRAIT_CONFIGS, "SELECT traitConfigId, type, chrSpecializationId, combatConfigFlags, localIdentifier, skillLineId, traitSystemId, `name` FROM character_trait_config WHERE guid = ?"); + PrepareStatement(CharStatements.INS_CHAR_TRAIT_CONFIGS, "INSERT INTO character_trait_config (guid, traitConfigId, type, chrSpecializationId, combatConfigFlags, localIdentifier, skillLineId, traitSystemId, `name`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(CharStatements.DEL_CHAR_TRAIT_CONFIGS, "DELETE FROM character_trait_config WHERE guid = ? AND traitConfigId = ?"); + PrepareStatement(CharStatements.DEL_CHAR_TRAIT_CONFIGS_BY_CHAR, "DELETE FROM character_trait_config WHERE guid = ?"); // Void Storage PrepareStatement(CharStatements.SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, randomBonusListId, fixedScalingLevel, artifactKnowledgeLevel, context, bonusListIDs FROM character_void_storage WHERE playerGuid = ?"); @@ -821,7 +829,6 @@ namespace Framework.Database SEL_CHARACTER_REPUTATION, SEL_CHARACTER_INVENTORY, - SEL_CHARACTER_ACTIONS, SEL_CHARACTER_ACTIONS_SPEC, SEL_MAIL_COUNT, SEL_CHARACTER_SOCIALLIST, @@ -1233,6 +1240,7 @@ namespace Framework.Database INS_CHAR_ACTION, UPD_CHAR_ACTION, DEL_CHAR_ACTION_BY_BUTTON_SPEC, + DEL_CHAR_ACTION_BY_TRAIT_CONFIG, DEL_CHAR_INVENTORY_BY_ITEM, DEL_CHAR_INVENTORY_BY_BAG_SLOT, UPD_MAIL, @@ -1262,6 +1270,14 @@ namespace Framework.Database UPD_CHAR_LIST_SLOT, INS_CHAR_FISHINGSTEPS, DEL_CHAR_FISHINGSTEPS, + SEL_CHAR_TRAIT_ENTRIES, + INS_CHAR_TRAIT_ENTRIES, + DEL_CHAR_TRAIT_ENTRIES, + DEL_CHAR_TRAIT_ENTRIES_BY_CHAR, + SEL_CHAR_TRAIT_CONFIGS, + INS_CHAR_TRAIT_CONFIGS, + DEL_CHAR_TRAIT_CONFIGS, + DEL_CHAR_TRAIT_CONFIGS_BY_CHAR, SEL_CHAR_VOID_STORAGE, REP_CHAR_VOID_STORAGE_ITEM, diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index 5a2bd1dec..374146b8f 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -23,196 +23,231 @@ namespace Framework.Database { // Achievement.db2 PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT, "SELECT Description, Title, Reward, ID, InstanceID, Faction, Supercedes, Category, MinimumCriteria, " + - "Points, Flags, UiOrder, IconFileID, RewardItemID, CriteriaTree, SharesCriteria, CovenantID FROM achievement"); - PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT_LOCALE, "SELECT ID, Description_lang, Title_lang, Reward_lang FROM achievement_locale WHERE locale = ?"); + "Points, Flags, UiOrder, IconFileID, RewardItemID, CriteriaTree, SharesCriteria, CovenantID FROM achievement WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT_LOCALE, "SELECT ID, Description_lang, Title_lang, Reward_lang FROM achievement_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // AchievementCategory.db2 - PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT_CATEGORY, "SELECT Name, ID, Parent, UiOrder FROM achievement_category"); - PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM achievement_category_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT_CATEGORY, "SELECT Name, ID, Parent, UiOrder FROM achievement_category WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ACHIEVEMENT_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM achievement_category_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // AdventureJournal.db2 PrepareStatement(HotfixStatements.SEL_ADVENTURE_JOURNAL, "SELECT ID, Name, Description, ButtonText, RewardDescription, ContinueDescription, Type, " + "PlayerConditionID, Flags, ButtonActionType, TextureFileDataID, LfgDungeonID, QuestID, BattleMasterListID, PriorityMin, PriorityMax, ItemID, " + - "ItemQuantity, CurrencyType, CurrencyQuantity, UiMapID, BonusPlayerConditionID1, BonusPlayerConditionID2, BonusValue1, BonusValue2 FROM adventure_journal"); + "ItemQuantity, CurrencyType, CurrencyQuantity, UiMapID, BonusPlayerConditionID1, BonusPlayerConditionID2, BonusValue1, BonusValue2" + + " FROM adventure_journal WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_ADVENTURE_JOURNAL_LOCALE, "SELECT ID, Name_lang, Description_lang, ButtonText_lang, RewardDescription_lang, " + - "ContinueDescription_lang FROM adventure_journal_locale WHERE locale = ?"); + "ContinueDescription_lang FROM adventure_journal_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // AdventureMapPoi.db2 PrepareStatement(HotfixStatements.SEL_ADVENTURE_MAP_POI, "SELECT ID, Title, Description, WorldPositionX, WorldPositionY, Type, PlayerConditionID, QuestID, " + - "LfgDungeonID, RewardItemID, UiTextureAtlasMemberID, UiTextureKitID, MapID, AreaTableID FROM adventure_map_poi"); - PrepareStatement(HotfixStatements.SEL_ADVENTURE_MAP_POI_LOCALE, "SELECT ID, Title_lang, Description_lang FROM adventure_map_poi_locale WHERE locale = ?"); + "LfgDungeonID, RewardItemID, UiTextureAtlasMemberID, UiTextureKitID, MapID, AreaTableID FROM adventure_map_poi WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ADVENTURE_MAP_POI_LOCALE, "SELECT ID, Title_lang, Description_lang FROM adventure_map_poi_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // AnimationData.db2 - PrepareStatement(HotfixStatements.SEL_ANIMATION_DATA, "SELECT ID, Fallback, BehaviorTier, BehaviorID, Flags1, Flags2 FROM animation_data"); + PrepareStatement(HotfixStatements.SEL_ANIMATION_DATA, "SELECT ID, Fallback, BehaviorTier, BehaviorID, Flags1, Flags2 FROM animation_data" + + " WHERE (`VerifiedBuild` > 0) = ?"); // AnimKit.db2 - PrepareStatement(HotfixStatements.SEL_ANIM_KIT, "SELECT ID, OneShotDuration, OneShotStopAnimKitID, LowDefAnimKitID FROM anim_kit"); + PrepareStatement(HotfixStatements.SEL_ANIM_KIT, "SELECT ID, OneShotDuration, OneShotStopAnimKitID, LowDefAnimKitID FROM anim_kit" + + " WHERE (`VerifiedBuild` > 0) = ?"); // AreaGroupMember.db2 - PrepareStatement(HotfixStatements.SEL_AREA_GROUP_MEMBER, "SELECT ID, AreaID, AreaGroupID FROM area_group_member"); + PrepareStatement(HotfixStatements.SEL_AREA_GROUP_MEMBER, "SELECT ID, AreaID, AreaGroupID FROM area_group_member WHERE (`VerifiedBuild` > 0) = ?"); // AreaTable.db2 PrepareStatement(HotfixStatements.SEL_AREA_TABLE, "SELECT ID, ZoneName, AreaName, ContinentID, ParentAreaID, AreaBit, SoundProviderPref, " + "SoundProviderPrefUnderwater, AmbienceID, UwAmbience, ZoneMusic, UwZoneMusic, IntroSound, UwIntroSound, FactionGroupMask, AmbientMultiplier, " + "MountFlags, PvpCombatWorldStateID, WildBattlePetLevelMin, WildBattlePetLevelMax, WindSettingsID, ContentTuningID, Flags1, Flags2, " + - "LiquidTypeID1, LiquidTypeID2, LiquidTypeID3, LiquidTypeID4 FROM area_table"); - PrepareStatement(HotfixStatements.SEL_AREA_TABLE_LOCALE, "SELECT ID, AreaName_lang FROM area_table_locale WHERE locale = ?"); + "LiquidTypeID1, LiquidTypeID2, LiquidTypeID3, LiquidTypeID4 FROM area_table WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_AREA_TABLE_LOCALE, "SELECT ID, AreaName_lang FROM area_table_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // AreaTrigger.db2 PrepareStatement(HotfixStatements.SEL_AREA_TRIGGER, "SELECT PosX, PosY, PosZ, ID, ContinentID, PhaseUseFlags, PhaseID, PhaseGroupID, Radius, BoxLength, " + - "BoxWidth, BoxHeight, BoxYaw, ShapeType, ShapeID, AreaTriggerActionSetID, Flags FROM area_trigger"); + "BoxWidth, BoxHeight, BoxYaw, ShapeType, ShapeID, AreaTriggerActionSetID, Flags FROM area_trigger WHERE (`VerifiedBuild` > 0) = ?"); // ArmorLocation.db2 - PrepareStatement(HotfixStatements.SEL_ARMOR_LOCATION, "SELECT ID, Clothmodifier, Leathermodifier, Chainmodifier, Platemodifier, Modifier FROM armor_location"); + PrepareStatement(HotfixStatements.SEL_ARMOR_LOCATION, "SELECT ID, Clothmodifier, Leathermodifier, Chainmodifier, Platemodifier, Modifier FROM armor_location" + + " WHERE (`VerifiedBuild` > 0) = ?"); // Artifact.db2 PrepareStatement(HotfixStatements.SEL_ARTIFACT, "SELECT Name, ID, UiTextureKitID, UiNameColor, UiBarOverlayColor, UiBarBackgroundColor, " + - "ChrSpecializationID, Flags, ArtifactCategoryID, UiModelSceneID, SpellVisualKitID FROM artifact"); - PrepareStatement(HotfixStatements.SEL_ARTIFACT_LOCALE, "SELECT ID, Name_lang FROM artifact_locale WHERE locale = ?"); + "ChrSpecializationID, Flags, ArtifactCategoryID, UiModelSceneID, SpellVisualKitID FROM artifact WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ARTIFACT_LOCALE, "SELECT ID, Name_lang FROM artifact_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ArtifactAppearance.db2 PrepareStatement(HotfixStatements.SEL_ARTIFACT_APPEARANCE, "SELECT Name, ID, ArtifactAppearanceSetID, DisplayIndex, UnlockPlayerConditionID, " + "ItemAppearanceModifierID, UiSwatchColor, UiModelSaturation, UiModelOpacity, OverrideShapeshiftFormID, OverrideShapeshiftDisplayID, " + - "UiItemAppearanceID, UiAltItemAppearanceID, Flags, UiCameraID, UsablePlayerConditionID FROM artifact_appearance"); - PrepareStatement(HotfixStatements.SEL_ARTIFACT_APPEARANCE_LOCALE, "SELECT ID, Name_lang FROM artifact_appearance_locale WHERE locale = ?"); + "UiItemAppearanceID, UiAltItemAppearanceID, Flags, UiCameraID, UsablePlayerConditionID FROM artifact_appearance" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ARTIFACT_APPEARANCE_LOCALE, "SELECT ID, Name_lang FROM artifact_appearance_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // ArtifactAppearanceSet.db2 PrepareStatement(HotfixStatements.SEL_ARTIFACT_APPEARANCE_SET, "SELECT Name, Description, ID, DisplayIndex, UiCameraID, AltHandUICameraID, " + - "ForgeAttachmentOverride, Flags, ArtifactID FROM artifact_appearance_set"); + "ForgeAttachmentOverride, Flags, ArtifactID FROM artifact_appearance_set WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_ARTIFACT_APPEARANCE_SET_LOCALE, "SELECT ID, Name_lang, Description_lang FROM artifact_appearance_set_locale" + - " WHERE locale = ?"); + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ArtifactCategory.db2 - PrepareStatement(HotfixStatements.SEL_ARTIFACT_CATEGORY, "SELECT ID, XpMultCurrencyID, XpMultCurveID FROM artifact_category"); + PrepareStatement(HotfixStatements.SEL_ARTIFACT_CATEGORY, "SELECT ID, XpMultCurrencyID, XpMultCurveID FROM artifact_category WHERE (`VerifiedBuild` > 0) = ?"); // ArtifactPower.db2 PrepareStatement(HotfixStatements.SEL_ARTIFACT_POWER, "SELECT DisplayPosX, DisplayPosY, ID, ArtifactID, MaxPurchasableRank, Label, Flags, Tier" + - " FROM artifact_power"); + " FROM artifact_power WHERE (`VerifiedBuild` > 0) = ?"); // ArtifactPowerLink.db2 - PrepareStatement(HotfixStatements.SEL_ARTIFACT_POWER_LINK, "SELECT ID, PowerA, PowerB FROM artifact_power_link"); + PrepareStatement(HotfixStatements.SEL_ARTIFACT_POWER_LINK, "SELECT ID, PowerA, PowerB FROM artifact_power_link WHERE (`VerifiedBuild` > 0) = ?"); // ArtifactPowerPicker.db2 - PrepareStatement(HotfixStatements.SEL_ARTIFACT_POWER_PICKER, "SELECT ID, PlayerConditionID FROM artifact_power_picker"); + PrepareStatement(HotfixStatements.SEL_ARTIFACT_POWER_PICKER, "SELECT ID, PlayerConditionID FROM artifact_power_picker WHERE (`VerifiedBuild` > 0) = ?"); // ArtifactPowerRank.db2 PrepareStatement(HotfixStatements.SEL_ARTIFACT_POWER_RANK, "SELECT ID, RankIndex, SpellID, ItemBonusListID, AuraPointsOverride, ArtifactPowerID" + - " FROM artifact_power_rank"); + " FROM artifact_power_rank WHERE (`VerifiedBuild` > 0) = ?"); // ArtifactQuestXp.db2 PrepareStatement(HotfixStatements.SEL_ARTIFACT_QUEST_XP, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, " + - "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM artifact_quest_xp"); + "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM artifact_quest_xp WHERE (`VerifiedBuild` > 0) = ?"); // ArtifactTier.db2 PrepareStatement(HotfixStatements.SEL_ARTIFACT_TIER, "SELECT ID, ArtifactTier, MaxNumTraits, MaxArtifactKnowledge, KnowledgePlayerCondition, " + - "MinimumEmpowerKnowledge FROM artifact_tier"); + "MinimumEmpowerKnowledge FROM artifact_tier WHERE (`VerifiedBuild` > 0) = ?"); // ArtifactUnlock.db2 - PrepareStatement(HotfixStatements.SEL_ARTIFACT_UNLOCK, "SELECT ID, PowerID, PowerRank, ItemBonusListID, PlayerConditionID, ArtifactID FROM artifact_unlock"); + PrepareStatement(HotfixStatements.SEL_ARTIFACT_UNLOCK, "SELECT ID, PowerID, PowerRank, ItemBonusListID, PlayerConditionID, ArtifactID FROM artifact_unlock" + + " WHERE (`VerifiedBuild` > 0) = ?"); // AuctionHouse.db2 - PrepareStatement(HotfixStatements.SEL_AUCTION_HOUSE, "SELECT ID, Name, FactionID, DepositRate, ConsignmentRate FROM auction_house"); - PrepareStatement(HotfixStatements.SEL_AUCTION_HOUSE_LOCALE, "SELECT ID, Name_lang FROM auction_house_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_AUCTION_HOUSE, "SELECT ID, Name, FactionID, DepositRate, ConsignmentRate FROM auction_house" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_AUCTION_HOUSE_LOCALE, "SELECT ID, Name_lang FROM auction_house_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // AzeriteEmpoweredItem.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_EMPOWERED_ITEM, "SELECT ID, ItemID, AzeriteTierUnlockSetID, AzeritePowerSetID FROM azerite_empowered_item"); + PrepareStatement(HotfixStatements.SEL_AZERITE_EMPOWERED_ITEM, "SELECT ID, ItemID, AzeriteTierUnlockSetID, AzeritePowerSetID FROM azerite_empowered_item" + + " WHERE (`VerifiedBuild` > 0) = ?"); // AzeriteEssence.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE, "SELECT ID, Name, Description, SpecSetID FROM azerite_essence"); - PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_LOCALE, "SELECT ID, Name_lang, Description_lang FROM azerite_essence_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE, "SELECT ID, Name, Description, SpecSetID FROM azerite_essence WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_LOCALE, "SELECT ID, Name_lang, Description_lang FROM azerite_essence_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // AzeriteEssencePower.db2 PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_POWER, "SELECT ID, SourceAlliance, SourceHorde, AzeriteEssenceID, Tier, MajorPowerDescription, " + - "MinorPowerDescription, MajorPowerActual, MinorPowerActual FROM azerite_essence_power"); - PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_POWER_LOCALE, "SELECT ID, SourceAlliance_lang, SourceHorde_lang FROM azerite_essence_power_locale WHERE locale = ?"); + "MinorPowerDescription, MajorPowerActual, MinorPowerActual FROM azerite_essence_power WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_POWER_LOCALE, "SELECT ID, SourceAlliance_lang, SourceHorde_lang FROM azerite_essence_power_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // AzeriteItem.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_ITEM, "SELECT ID, ItemID FROM azerite_item"); + PrepareStatement(HotfixStatements.SEL_AZERITE_ITEM, "SELECT ID, ItemID FROM azerite_item WHERE (`VerifiedBuild` > 0) = ?"); // AzeriteItemMilestonePower.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_ITEM_MILESTONE_POWER, "SELECT ID, RequiredLevel, AzeritePowerID, Type, AutoUnlock FROM azerite_item_milestone_power"); + PrepareStatement(HotfixStatements.SEL_AZERITE_ITEM_MILESTONE_POWER, "SELECT ID, RequiredLevel, AzeritePowerID, Type, AutoUnlock" + + " FROM azerite_item_milestone_power WHERE (`VerifiedBuild` > 0) = ?"); // AzeriteKnowledgeMultiplier.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_KNOWLEDGE_MULTIPLIER, "SELECT ID, Multiplier FROM azerite_knowledge_multiplier"); + PrepareStatement(HotfixStatements.SEL_AZERITE_KNOWLEDGE_MULTIPLIER, "SELECT ID, Multiplier FROM azerite_knowledge_multiplier WHERE (`VerifiedBuild` > 0) = ?"); // AzeriteLevelInfo.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_LEVEL_INFO, "SELECT ID, BaseExperienceToNextLevel, MinimumExperienceToNextLevel, ItemLevel FROM azerite_level_info"); + PrepareStatement(HotfixStatements.SEL_AZERITE_LEVEL_INFO, "SELECT ID, BaseExperienceToNextLevel, MinimumExperienceToNextLevel, ItemLevel" + + " FROM azerite_level_info WHERE (`VerifiedBuild` > 0) = ?"); // AzeritePower.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_POWER, "SELECT ID, SpellID, ItemBonusListID, SpecSetID, Flags FROM azerite_power"); + PrepareStatement(HotfixStatements.SEL_AZERITE_POWER, "SELECT ID, SpellID, ItemBonusListID, SpecSetID, Flags FROM azerite_power" + + " WHERE (`VerifiedBuild` > 0) = ?"); // AzeritePowerSetMember.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_POWER_SET_MEMBER, "SELECT ID, AzeritePowerSetID, AzeritePowerID, Class, Tier, OrderIndex FROM azerite_power_set_member"); + PrepareStatement(HotfixStatements.SEL_AZERITE_POWER_SET_MEMBER, "SELECT ID, AzeritePowerSetID, AzeritePowerID, Class, Tier, OrderIndex" + + " FROM azerite_power_set_member WHERE (`VerifiedBuild` > 0) = ?"); // AzeriteTierUnlock.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_TIER_UNLOCK, "SELECT ID, ItemCreationContext, Tier, AzeriteLevel, AzeriteTierUnlockSetID FROM azerite_tier_unlock"); + PrepareStatement(HotfixStatements.SEL_AZERITE_TIER_UNLOCK, "SELECT ID, ItemCreationContext, Tier, AzeriteLevel, AzeriteTierUnlockSetID" + + " FROM azerite_tier_unlock WHERE (`VerifiedBuild` > 0) = ?"); // AzeriteTierUnlockSet.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_TIER_UNLOCK_SET, "SELECT ID, Flags FROM azerite_tier_unlock_set"); + PrepareStatement(HotfixStatements.SEL_AZERITE_TIER_UNLOCK_SET, "SELECT ID, Flags FROM azerite_tier_unlock_set WHERE (`VerifiedBuild` > 0) = ?"); // AzeriteUnlockMapping.db2 PrepareStatement(HotfixStatements.SEL_AZERITE_UNLOCK_MAPPING, "SELECT ID, ItemLevel, ItemBonusListHead, ItemBonusListShoulders, ItemBonusListChest, " + - "AzeriteUnlockMappingSetID FROM azerite_unlock_mapping"); + "AzeriteUnlockMappingSetID FROM azerite_unlock_mapping WHERE (`VerifiedBuild` > 0) = ?"); // BankBagSlotPrices.db2 - PrepareStatement(HotfixStatements.SEL_BANK_BAG_SLOT_PRICES, "SELECT ID, Cost FROM bank_bag_slot_prices"); + PrepareStatement(HotfixStatements.SEL_BANK_BAG_SLOT_PRICES, "SELECT ID, Cost FROM bank_bag_slot_prices WHERE (`VerifiedBuild` > 0) = ?"); // BannedAddons.db2 - PrepareStatement(HotfixStatements.SEL_BANNED_ADDONS, "SELECT ID, Name, Version, Flags FROM banned_addons"); + PrepareStatement(HotfixStatements.SEL_BANNED_ADDONS, "SELECT ID, Name, Version, Flags FROM banned_addons WHERE (`VerifiedBuild` > 0) = ?"); // BarberShopStyle.db2 - PrepareStatement(HotfixStatements.SEL_BARBER_SHOP_STYLE, "SELECT ID, DisplayName, Description, Type, CostModifier, Race, Sex, Data FROM barber_shop_style"); - PrepareStatement(HotfixStatements.SEL_BARBER_SHOP_STYLE_LOCALE, "SELECT ID, DisplayName_lang, Description_lang FROM barber_shop_style_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_BARBER_SHOP_STYLE, "SELECT ID, DisplayName, Description, Type, CostModifier, Race, Sex, Data FROM barber_shop_style" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_BARBER_SHOP_STYLE_LOCALE, "SELECT ID, DisplayName_lang, Description_lang FROM barber_shop_style_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // BattlePetBreedQuality.db2 - PrepareStatement(HotfixStatements.SEL_BATTLE_PET_BREED_QUALITY, "SELECT ID, MaxQualityRoll, StateMultiplier, QualityEnum FROM battle_pet_breed_quality"); + PrepareStatement(HotfixStatements.SEL_BATTLE_PET_BREED_QUALITY, "SELECT ID, MaxQualityRoll, StateMultiplier, QualityEnum FROM battle_pet_breed_quality" + + " WHERE (`VerifiedBuild` > 0) = ?"); // BattlePetBreedState.db2 - PrepareStatement(HotfixStatements.SEL_BATTLE_PET_BREED_STATE, "SELECT ID, BattlePetStateID, Value, BattlePetBreedID FROM battle_pet_breed_state"); + PrepareStatement(HotfixStatements.SEL_BATTLE_PET_BREED_STATE, "SELECT ID, BattlePetStateID, Value, BattlePetBreedID FROM battle_pet_breed_state" + + " WHERE (`VerifiedBuild` > 0) = ?"); // BattlePetSpecies.db2 PrepareStatement(HotfixStatements.SEL_BATTLE_PET_SPECIES, "SELECT Description, SourceText, ID, CreatureID, SummonSpellID, IconFileDataID, PetTypeEnum, " + - "Flags, SourceTypeEnum, CardUIModelSceneID, LoadoutUIModelSceneID, CovenantID FROM battle_pet_species"); - PrepareStatement(HotfixStatements.SEL_BATTLE_PET_SPECIES_LOCALE, "SELECT ID, Description_lang, SourceText_lang FROM battle_pet_species_locale WHERE locale = ?"); + "Flags, SourceTypeEnum, CardUIModelSceneID, LoadoutUIModelSceneID, CovenantID FROM battle_pet_species WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_BATTLE_PET_SPECIES_LOCALE, "SELECT ID, Description_lang, SourceText_lang FROM battle_pet_species_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // BattlePetSpeciesState.db2 - PrepareStatement(HotfixStatements.SEL_BATTLE_PET_SPECIES_STATE, "SELECT ID, BattlePetStateID, Value, BattlePetSpeciesID FROM battle_pet_species_state"); + PrepareStatement(HotfixStatements.SEL_BATTLE_PET_SPECIES_STATE, "SELECT ID, BattlePetStateID, Value, BattlePetSpeciesID FROM battle_pet_species_state" + + " WHERE (`VerifiedBuild` > 0) = ?"); // BattlemasterList.db2 PrepareStatement(HotfixStatements.SEL_BATTLEMASTER_LIST, "SELECT ID, Name, GameType, ShortDescription, LongDescription, InstanceType, MinLevel, MaxLevel, " + "RatedPlayers, MinPlayers, MaxPlayers, GroupsAllowed, MaxGroupSize, HolidayWorldState, Flags, IconFileDataID, RequiredPlayerConditionID, " + "MapID1, MapID2, MapID3, MapID4, MapID5, MapID6, MapID7, MapID8, MapID9, MapID10, MapID11, MapID12, MapID13, MapID14, MapID15, MapID16" + - " FROM battlemaster_list"); + " FROM battlemaster_list WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_BATTLEMASTER_LIST_LOCALE, "SELECT ID, Name_lang, GameType_lang, ShortDescription_lang, LongDescription_lang" + - " FROM battlemaster_list_locale WHERE locale = ?"); + " FROM battlemaster_list_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // BroadcastText.db2 PrepareStatement(HotfixStatements.SEL_BROADCAST_TEXT, "SELECT `Text`, Text1, ID, LanguageID, ConditionID, EmotesID, Flags, ChatBubbleDurationMs, " + - "VoiceOverPriorityID, SoundKitID1, SoundKitID2, EmoteID1, EmoteID2, EmoteID3, EmoteDelay1, EmoteDelay2, EmoteDelay3 FROM broadcast_text"); - PrepareStatement(HotfixStatements.SEL_BROADCAST_TEXT_LOCALE, "SELECT ID, Text_lang, Text1_lang FROM broadcast_text_locale WHERE locale = ?"); + "VoiceOverPriorityID, SoundKitID1, SoundKitID2, EmoteID1, EmoteID2, EmoteID3, EmoteDelay1, EmoteDelay2, EmoteDelay3 FROM broadcast_text" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_BROADCAST_TEXT_LOCALE, "SELECT ID, Text_lang, Text1_lang FROM broadcast_text_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // BroadcastTextDuration.db2 - PrepareStatement(HotfixStatements.SEL_BROADCAST_TEXT_DURATION, "SELECT ID, BroadcastTextID, Locale, Duration FROM broadcast_text_duration"); + PrepareStatement(HotfixStatements.SEL_BROADCAST_TEXT_DURATION, "SELECT ID, BroadcastTextID, Locale, Duration FROM broadcast_text_duration" + + " WHERE (`VerifiedBuild` > 0) = ?"); // CfgRegions.db2 - PrepareStatement(HotfixStatements.SEL_CFG_REGIONS, "SELECT ID, Tag, RegionID, Raidorigin, RegionGroupMask, ChallengeOrigin FROM cfg_regions"); + PrepareStatement(HotfixStatements.SEL_CFG_REGIONS, "SELECT ID, Tag, RegionID, Raidorigin, RegionGroupMask, ChallengeOrigin FROM cfg_regions" + + " WHERE (`VerifiedBuild` > 0) = ?"); // CharTitles.db2 - PrepareStatement(HotfixStatements.SEL_CHAR_TITLES, "SELECT ID, Name, Name1, MaskID, Flags FROM char_titles"); - PrepareStatement(HotfixStatements.SEL_CHAR_TITLES_LOCALE, "SELECT ID, Name_lang, Name1_lang FROM char_titles_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_CHAR_TITLES, "SELECT ID, Name, Name1, MaskID, Flags FROM char_titles WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CHAR_TITLES_LOCALE, "SELECT ID, Name_lang, Name1_lang FROM char_titles_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // CharacterLoadout.db2 - PrepareStatement(HotfixStatements.SEL_CHARACTER_LOADOUT, "SELECT ID, RaceMask, ChrClassID, Purpose, ItemContext FROM character_loadout"); + PrepareStatement(HotfixStatements.SEL_CHARACTER_LOADOUT, "SELECT ID, RaceMask, ChrClassID, Purpose, ItemContext FROM character_loadout" + + " WHERE (`VerifiedBuild` > 0) = ?"); // CharacterLoadoutItem.db2 - PrepareStatement(HotfixStatements.SEL_CHARACTER_LOADOUT_ITEM, "SELECT ID, CharacterLoadoutID, ItemID FROM character_loadout_item"); + PrepareStatement(HotfixStatements.SEL_CHARACTER_LOADOUT_ITEM, "SELECT ID, CharacterLoadoutID, ItemID FROM character_loadout_item" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ChatChannels.db2 - PrepareStatement(HotfixStatements.SEL_CHAT_CHANNELS, "SELECT ID, Name, Shortcut, Flags, FactionGroup, Ruleset FROM chat_channels"); - PrepareStatement(HotfixStatements.SEL_CHAT_CHANNELS_LOCALE, "SELECT ID, Name_lang, Shortcut_lang FROM chat_channels_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_CHAT_CHANNELS, "SELECT ID, Name, Shortcut, Flags, FactionGroup, Ruleset FROM chat_channels" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CHAT_CHANNELS_LOCALE, "SELECT ID, Name_lang, Shortcut_lang FROM chat_channels_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // ChrClassUiDisplay.db2 - PrepareStatement(HotfixStatements.SEL_CHR_CLASS_UI_DISPLAY, "SELECT ID, ChrClassesID, AdvGuidePlayerConditionID, SplashPlayerConditionID FROM chr_class_ui_display"); + PrepareStatement(HotfixStatements.SEL_CHR_CLASS_UI_DISPLAY, "SELECT ID, ChrClassesID, AdvGuidePlayerConditionID, SplashPlayerConditionID" + + " FROM chr_class_ui_display WHERE (`VerifiedBuild` > 0) = ?"); // ChrClasses.db2 PrepareStatement(HotfixStatements.SEL_CHR_CLASSES, "SELECT Name, Filename, NameMale, NameFemale, PetNameToken, Description, RoleInfoString, DisabledString, " + @@ -221,47 +256,59 @@ namespace Framework.Database "MaleCharacterCreationIdleVisualFallback, FemaleCharacterCreationVisualFallback, FemaleCharacterCreationIdleVisualFallback, " + "CharacterCreationIdleGroundVisualFallback, CharacterCreationGroundVisualFallback, AlteredFormCharacterCreationIdleVisualFallback, " + "CharacterCreationAnimLoopWaitTimeMsFallback, CinematicSequenceID, DefaultSpec, PrimaryStatPriority, DisplayPower, " + - "RangedAttackPowerPerAgility, AttackPowerPerAgility, AttackPowerPerStrength, SpellClassSet, ClassColorR, ClassColorG, ClassColorB FROM chr_classes"); + "RangedAttackPowerPerAgility, AttackPowerPerAgility, AttackPowerPerStrength, SpellClassSet, ClassColorR, ClassColorG, ClassColorB" + + " FROM chr_classes WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_CHR_CLASSES_LOCALE, "SELECT ID, Name_lang, NameMale_lang, NameFemale_lang, Description_lang, RoleInfoString_lang, " + - "DisabledString_lang, HyphenatedNameMale_lang, HyphenatedNameFemale_lang FROM chr_classes_locale WHERE locale = ?"); + "DisabledString_lang, HyphenatedNameMale_lang, HyphenatedNameFemale_lang FROM chr_classes_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // ChrClassesXPowerTypes.db2 - PrepareStatement(HotfixStatements.SEL_CHR_CLASSES_X_POWER_TYPES, "SELECT ID, PowerType, ClassID FROM chr_classes_x_power_types"); + PrepareStatement(HotfixStatements.SEL_CHR_CLASSES_X_POWER_TYPES, "SELECT ID, PowerType, ClassID FROM chr_classes_x_power_types" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ChrCustomizationChoice.db2 PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_CHOICE, "SELECT Name, ID, ChrCustomizationOptionID, ChrCustomizationReqID, " + - "ChrCustomizationVisReqID, SortOrder, UiOrderIndex, Flags, AddedInPatch, SwatchColor1, SwatchColor2 FROM chr_customization_choice"); - PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_CHOICE_LOCALE, "SELECT ID, Name_lang FROM chr_customization_choice_locale WHERE locale = ?"); + "ChrCustomizationVisReqID, SortOrder, UiOrderIndex, Flags, AddedInPatch, SwatchColor1, SwatchColor2 FROM chr_customization_choice" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_CHOICE_LOCALE, "SELECT ID, Name_lang FROM chr_customization_choice_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ChrCustomizationDisplayInfo.db2 PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_DISPLAY_INFO, "SELECT ID, ShapeshiftFormID, DisplayID, BarberShopMinCameraDistance, " + - "BarberShopHeightOffset FROM chr_customization_display_info"); + "BarberShopHeightOffset FROM chr_customization_display_info WHERE (`VerifiedBuild` > 0) = ?"); // ChrCustomizationElement.db2 PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_ELEMENT, "SELECT ID, ChrCustomizationChoiceID, RelatedChrCustomizationChoiceID, " + "ChrCustomizationGeosetID, ChrCustomizationSkinnedModelID, ChrCustomizationMaterialID, ChrCustomizationBoneSetID, " + - "ChrCustomizationCondModelID, ChrCustomizationDisplayInfoID, ChrCustItemGeoModifyID, ChrCustomizationVoiceID FROM chr_customization_element"); + "ChrCustomizationCondModelID, ChrCustomizationDisplayInfoID, ChrCustItemGeoModifyID, ChrCustomizationVoiceID FROM chr_customization_element" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ChrCustomizationOption.db2 PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_OPTION, "SELECT Name, ID, SecondaryID, Flags, ChrModelID, SortIndex, ChrCustomizationCategoryID, " + - "OptionType, BarberShopCostModifier, ChrCustomizationID, ChrCustomizationReqID, UiOrderIndex, AddedInPatch FROM chr_customization_option"); - PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_OPTION_LOCALE, "SELECT ID, Name_lang FROM chr_customization_option_locale WHERE locale = ?"); + "OptionType, BarberShopCostModifier, ChrCustomizationID, ChrCustomizationReqID, UiOrderIndex, AddedInPatch FROM chr_customization_option" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_OPTION_LOCALE, "SELECT ID, Name_lang FROM chr_customization_option_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ChrCustomizationReq.db2 - PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_REQ, "SELECT ID, ReqSource, Flags, ClassMask, AchievementID, QuestID, OverrideArchive, ItemModifiedAppearanceID FROM chr_customization_req"); - PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_REQ_LOCALE, "SELECT ID, ReqSource_lang FROM chr_customization_req_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_REQ, "SELECT ID, ReqSource, Flags, ClassMask, AchievementID, QuestID, OverrideArchive, " + + "ItemModifiedAppearanceID FROM chr_customization_req WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_REQ_LOCALE, "SELECT ID, ReqSource_lang FROM chr_customization_req_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // ChrCustomizationReqChoice.db2 - PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_REQ_CHOICE, "SELECT ID, ChrCustomizationChoiceID, ChrCustomizationReqID FROM chr_customization_req_choice"); + PrepareStatement(HotfixStatements.SEL_CHR_CUSTOMIZATION_REQ_CHOICE, "SELECT ID, ChrCustomizationChoiceID, ChrCustomizationReqID" + + " FROM chr_customization_req_choice WHERE (`VerifiedBuild` > 0) = ?"); // ChrModel.db2 PrepareStatement(HotfixStatements.SEL_CHR_MODEL, "SELECT FaceCustomizationOffset1, FaceCustomizationOffset2, FaceCustomizationOffset3, CustomizeOffset1, " + "CustomizeOffset2, CustomizeOffset3, ID, Sex, DisplayID, CharComponentTextureLayoutID, Flags, SkeletonFileDataID, ModelFallbackChrModelID, " + "TextureFallbackChrModelID, HelmVisFallbackChrModelID, CustomizeScale, CustomizeFacing, CameraDistanceOffset, BarberShopCameraOffsetScale, " + - "BarberShopCameraHeightOffsetScale, BarberShopCameraRotationOffset FROM chr_model"); + "BarberShopCameraHeightOffsetScale, BarberShopCameraRotationOffset FROM chr_model WHERE (`VerifiedBuild` > 0) = ?"); // ChrRaceXChrModel.db2 - PrepareStatement(HotfixStatements.SEL_CHR_RACE_X_CHR_MODEL, "SELECT ID, ChrRacesID, ChrModelID, Sex, AllowedTransmogSlots FROM chr_race_x_chr_model"); + PrepareStatement(HotfixStatements.SEL_CHR_RACE_X_CHR_MODEL, "SELECT ID, ChrRacesID, ChrModelID, Sex, AllowedTransmogSlots FROM chr_race_x_chr_model" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ChrRaces.db2 PrepareStatement(HotfixStatements.SEL_CHR_RACES, "SELECT ID, ClientPrefix, ClientFileString, Name, NameFemale, NameLowercase, NameFemaleLowercase, " + @@ -274,53 +321,57 @@ namespace Framework.Database "HelmetAnimScalingRaceID, TransmogrifyDisabledSlotMask, UnalteredVisualCustomizationRaceID, AlteredFormCustomizeOffsetFallback1, " + "AlteredFormCustomizeOffsetFallback2, AlteredFormCustomizeOffsetFallback3, AlteredFormCustomizeRotationFallback, Unknown910_11, " + "Unknown910_12, Unknown910_13, Unknown910_21, Unknown910_22, Unknown910_23, Unknown1000, BaseLanguage, CreatureType, MaleModelFallbackSex, " + - "FemaleModelFallbackSex, MaleTextureFallbackSex, FemaleTextureFallbackSex FROM chr_races"); + "FemaleModelFallbackSex, MaleTextureFallbackSex, FemaleTextureFallbackSex FROM chr_races WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_CHR_RACES_LOCALE, "SELECT ID, Name_lang, NameFemale_lang, NameLowercase_lang, NameFemaleLowercase_lang, LoreName_lang, " + "LoreNameFemale_lang, LoreNameLower_lang, LoreNameLowerFemale_lang, LoreDescription_lang, ShortName_lang, ShortNameFemale_lang, " + - "ShortNameLower_lang, ShortNameLowerFemale_lang FROM chr_races_locale WHERE locale = ?"); + "ShortNameLower_lang, ShortNameLowerFemale_lang FROM chr_races_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ChrSpecialization.db2 PrepareStatement(HotfixStatements.SEL_CHR_SPECIALIZATION, "SELECT Name, FemaleName, Description, ID, ClassID, OrderIndex, PetTalentType, Role, Flags, " + - "SpellIconFileID, PrimaryStatPriority, AnimReplacements, MasterySpellID1, MasterySpellID2 FROM chr_specialization"); + "SpellIconFileID, PrimaryStatPriority, AnimReplacements, MasterySpellID1, MasterySpellID2 FROM chr_specialization" + + " WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_CHR_SPECIALIZATION_LOCALE, "SELECT ID, Name_lang, FemaleName_lang, Description_lang FROM chr_specialization_locale" + - " WHERE locale = ?"); + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // CinematicCamera.db2 - PrepareStatement(HotfixStatements.SEL_CINEMATIC_CAMERA, "SELECT ID, OriginX, OriginY, OriginZ, SoundID, OriginFacing, FileDataID, ConversationID FROM cinematic_camera"); + PrepareStatement(HotfixStatements.SEL_CINEMATIC_CAMERA, "SELECT ID, OriginX, OriginY, OriginZ, SoundID, OriginFacing, FileDataID, ConversationID" + + " FROM cinematic_camera WHERE (`VerifiedBuild` > 0) = ?"); // CinematicSequences.db2 - PrepareStatement(HotfixStatements.SEL_CINEMATIC_SEQUENCES, "SELECT ID, SoundID, Camera1, Camera2, Camera3, Camera4, Camera5, Camera6, Camera7, Camera8 FROM cinematic_sequences"); + PrepareStatement(HotfixStatements.SEL_CINEMATIC_SEQUENCES, "SELECT ID, SoundID, Camera1, Camera2, Camera3, Camera4, Camera5, Camera6, Camera7, Camera8" + + " FROM cinematic_sequences WHERE (`VerifiedBuild` > 0) = ?"); // ContentTuning.db2 PrepareStatement(HotfixStatements.SEL_CONTENT_TUNING, "SELECT ID, Flags, ExpansionID, MinLevel, MaxLevel, MinLevelType, MaxLevelType, TargetLevelDelta, " + - "TargetLevelMaxDelta, TargetLevelMin, TargetLevelMax, MinItemLevel FROM content_tuning"); + "TargetLevelMaxDelta, TargetLevelMin, TargetLevelMax, MinItemLevel FROM content_tuning WHERE (`VerifiedBuild` > 0) = ?"); // ContentTuningXExpected.db2 PrepareStatement(HotfixStatements.SEL_CONTENT_TUNING_X_EXPECTED, "SELECT ID, ExpectedStatModID, MinMythicPlusSeasonID, MaxMythicPlusSeasonID, " + - "ContentTuningID FROM content_tuning_x_expected"); + "ContentTuningID FROM content_tuning_x_expected WHERE (`VerifiedBuild` > 0) = ?"); // ConversationLine.db2 PrepareStatement(HotfixStatements.SEL_CONVERSATION_LINE, "SELECT ID, BroadcastTextID, SpellVisualKitID, AdditionalDuration, NextConversationLineID, " + - "AnimKitID, SpeechType, StartAnimation, EndAnimation FROM conversation_line"); + "AnimKitID, SpeechType, StartAnimation, EndAnimation FROM conversation_line WHERE (`VerifiedBuild` > 0) = ?"); // CorruptionEffects.db2 - PrepareStatement(HotfixStatements.SEL_CORRUPTION_EFFECTS, "SELECT ID, MinCorruption, Aura, PlayerConditionID, Flags FROM corruption_effects"); + PrepareStatement(HotfixStatements.SEL_CORRUPTION_EFFECTS, "SELECT ID, MinCorruption, Aura, PlayerConditionID, Flags FROM corruption_effects" + + " WHERE (`VerifiedBuild` > 0) = ?"); // CreatureDisplayInfo.db2 PrepareStatement(HotfixStatements.SEL_CREATURE_DISPLAY_INFO, "SELECT ID, ModelID, SoundID, SizeClass, CreatureModelScale, CreatureModelAlpha, BloodID, " + "ExtendedDisplayInfoID, NPCSoundID, ParticleColorID, PortraitCreatureDisplayInfoID, PortraitTextureFileDataID, ObjectEffectPackageID, " + "AnimReplacementSetID, Flags, StateSpellVisualKitID, PlayerOverrideScale, PetInstanceScale, UnarmedWeaponType, MountPoofSpellVisualKitID, " + "DissolveEffectID, Gender, DissolveOutEffectID, CreatureModelMinLod, TextureVariationFileDataID1, TextureVariationFileDataID2, " + - "TextureVariationFileDataID3, TextureVariationFileDataID4 FROM creature_display_info"); + "TextureVariationFileDataID3, TextureVariationFileDataID4 FROM creature_display_info WHERE (`VerifiedBuild` > 0) = ?"); // CreatureDisplayInfoExtra.db2 PrepareStatement(HotfixStatements.SEL_CREATURE_DISPLAY_INFO_EXTRA, "SELECT ID, DisplayRaceID, DisplaySexID, DisplayClassID, Flags, BakeMaterialResourcesID, " + - "HDBakeMaterialResourcesID FROM creature_display_info_extra"); + "HDBakeMaterialResourcesID FROM creature_display_info_extra WHERE (`VerifiedBuild` > 0) = ?"); // CreatureFamily.db2 PrepareStatement(HotfixStatements.SEL_CREATURE_FAMILY, "SELECT ID, Name, MinScale, MinScaleLevel, MaxScale, MaxScaleLevel, PetFoodMask, PetTalentType, " + - "IconFileID, SkillLine1, SkillLine2 FROM creature_family"); - PrepareStatement(HotfixStatements.SEL_CREATURE_FAMILY_LOCALE, "SELECT ID, Name_lang FROM creature_family_locale WHERE locale = ?"); + "IconFileID, SkillLine1, SkillLine2 FROM creature_family WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CREATURE_FAMILY_LOCALE, "SELECT ID, Name_lang FROM creature_family_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // CreatureModelData.db2 PrepareStatement(HotfixStatements.SEL_CREATURE_MODEL_DATA, "SELECT ID, GeoBox1, GeoBox2, GeoBox3, GeoBox4, GeoBox5, GeoBox6, Flags, FileDataID, BloodID, " + @@ -328,52 +379,60 @@ namespace Framework.Database "DeathThudCameraEffectID, SoundID, SizeClass, CollisionWidth, CollisionHeight, WorldEffectScale, CreatureGeosetDataID, HoverHeight, " + "AttachedEffectScale, ModelScale, MissileCollisionRadius, MissileCollisionPush, MissileCollisionRaise, MountHeight, OverrideLootEffectScale, " + "OverrideNameScale, OverrideSelectionRadius, TamedPetBaseScale, Unknown820_1, Unknown820_2, Unknown820_31, Unknown820_32" + - " FROM creature_model_data"); + " FROM creature_model_data WHERE (`VerifiedBuild` > 0) = ?"); // CreatureType.db2 - PrepareStatement(HotfixStatements.SEL_CREATURE_TYPE, "SELECT ID, Name, Flags FROM creature_type"); - PrepareStatement(HotfixStatements.SEL_CREATURE_TYPE_LOCALE, "SELECT ID, Name_lang FROM creature_type_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_CREATURE_TYPE, "SELECT ID, Name, Flags FROM creature_type WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CREATURE_TYPE_LOCALE, "SELECT ID, Name_lang FROM creature_type_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // Criteria.db2 PrepareStatement(HotfixStatements.SEL_CRITERIA, "SELECT ID, Type, Asset, ModifierTreeId, StartEvent, StartAsset, StartTimer, FailEvent, FailAsset, Flags, " + - "EligibilityWorldStateID, EligibilityWorldStateValue FROM criteria"); + "EligibilityWorldStateID, EligibilityWorldStateValue FROM criteria WHERE (`VerifiedBuild` > 0) = ?"); // CriteriaTree.db2 - PrepareStatement(HotfixStatements.SEL_CRITERIA_TREE, "SELECT ID, Description, Parent, Amount, Operator, CriteriaID, OrderIndex, Flags FROM criteria_tree"); - PrepareStatement(HotfixStatements.SEL_CRITERIA_TREE_LOCALE, "SELECT ID, Description_lang FROM criteria_tree_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_CRITERIA_TREE, "SELECT ID, Description, Parent, Amount, Operator, CriteriaID, OrderIndex, Flags FROM criteria_tree" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CRITERIA_TREE_LOCALE, "SELECT ID, Description_lang FROM criteria_tree_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // CurrencyContainer.db2 PrepareStatement(HotfixStatements.SEL_CURRENCY_CONTAINER, "SELECT ID, ContainerName, ContainerDescription, MinAmount, MaxAmount, ContainerIconID, " + - "ContainerQuality, OnLootSpellVisualKitID, CurrencyTypesID FROM currency_container"); - PrepareStatement(HotfixStatements.SEL_CURRENCY_CONTAINER_LOCALE, "SELECT ID, ContainerName_lang, ContainerDescription_lang FROM currency_container_locale WHERE locale = ?"); + "ContainerQuality, OnLootSpellVisualKitID, CurrencyTypesID FROM currency_container WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CURRENCY_CONTAINER_LOCALE, "SELECT ID, ContainerName_lang, ContainerDescription_lang FROM currency_container_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // CurrencyTypes.db2 PrepareStatement(HotfixStatements.SEL_CURRENCY_TYPES, "SELECT ID, Name, Description, CategoryID, InventoryIconFileID, SpellWeight, SpellCategory, MaxQty, " + "MaxEarnablePerWeek, Quality, FactionID, ItemGroupSoundsID, XpQuestDifficulty, AwardConditionID, MaxQtyWorldStateID, " + - "RechargingAmountPerCycle, RechargingCycleDurationMS, Flags1, Flags2 FROM currency_types"); - PrepareStatement(HotfixStatements.SEL_CURRENCY_TYPES_LOCALE, "SELECT ID, Name_lang, Description_lang FROM currency_types_locale WHERE locale = ?"); + "RechargingAmountPerCycle, RechargingCycleDurationMS, Flags1, Flags2 FROM currency_types WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_CURRENCY_TYPES_LOCALE, "SELECT ID, Name_lang, Description_lang FROM currency_types_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // Curve.db2 - PrepareStatement(HotfixStatements.SEL_CURVE, "SELECT ID, Type, Flags FROM curve"); + PrepareStatement(HotfixStatements.SEL_CURVE, "SELECT ID, Type, Flags FROM curve WHERE (`VerifiedBuild` > 0) = ?"); // CurvePoint.db2 - PrepareStatement(HotfixStatements.SEL_CURVE_POINT, "SELECT PosX, PosY, PreSLSquishPosX, PreSLSquishPosY, ID, CurveID, OrderIndex FROM curve_point"); + PrepareStatement(HotfixStatements.SEL_CURVE_POINT, "SELECT PosX, PosY, PreSLSquishPosX, PreSLSquishPosY, ID, CurveID, OrderIndex FROM curve_point" + + " WHERE (`VerifiedBuild` > 0) = ?"); // DestructibleModelData.db2 PrepareStatement(HotfixStatements.SEL_DESTRUCTIBLE_MODEL_DATA, "SELECT ID, State0ImpactEffectDoodadSet, State0AmbientDoodadSet, State1Wmo, " + "State1DestructionDoodadSet, State1ImpactEffectDoodadSet, State1AmbientDoodadSet, State2Wmo, State2DestructionDoodadSet, " + "State2ImpactEffectDoodadSet, State2AmbientDoodadSet, State3Wmo, State3InitDoodadSet, State3AmbientDoodadSet, EjectDirection, DoNotHighlight, " + - "State0Wmo, HealEffect, HealEffectSpeed, State0NameSet, State1NameSet, State2NameSet, State3NameSet FROM destructible_model_data"); + "State0Wmo, HealEffect, HealEffectSpeed, State0NameSet, State1NameSet, State2NameSet, State3NameSet FROM destructible_model_data" + + " WHERE (`VerifiedBuild` > 0) = ?"); // Difficulty.db2 PrepareStatement(HotfixStatements.SEL_DIFFICULTY, "SELECT ID, Name, InstanceType, OrderIndex, OldEnumValue, FallbackDifficultyID, MinPlayers, MaxPlayers, " + - "Flags, ItemContext, ToggleDifficultyID, GroupSizeHealthCurveID, GroupSizeDmgCurveID, GroupSizeSpellPointsCurveID FROM difficulty"); - PrepareStatement(HotfixStatements.SEL_DIFFICULTY_LOCALE, "SELECT ID, Name_lang FROM difficulty_locale WHERE locale = ?"); + "Flags, ItemContext, ToggleDifficultyID, GroupSizeHealthCurveID, GroupSizeDmgCurveID, GroupSizeSpellPointsCurveID FROM difficulty" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_DIFFICULTY_LOCALE, "SELECT ID, Name_lang FROM difficulty_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // DungeonEncounter.db2 PrepareStatement(HotfixStatements.SEL_DUNGEON_ENCOUNTER, "SELECT Name, ID, MapID, DifficultyID, OrderIndex, CompleteWorldStateID, Bit, Flags, " + - "SpellIconFileID, Faction FROM dungeon_encounter"); - PrepareStatement(HotfixStatements.SEL_DUNGEON_ENCOUNTER_LOCALE, "SELECT ID, Name_lang FROM dungeon_encounter_locale WHERE locale = ?"); + "SpellIconFileID, Faction FROM dungeon_encounter WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_DUNGEON_ENCOUNTER_LOCALE, "SELECT ID, Name_lang FROM dungeon_encounter_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // DurabilityCosts.db2 PrepareStatement(HotfixStatements.SEL_DURABILITY_COSTS, "SELECT ID, WeaponSubClassCost1, WeaponSubClassCost2, WeaponSubClassCost3, WeaponSubClassCost4, " + @@ -381,309 +440,339 @@ namespace Framework.Database "WeaponSubClassCost11, WeaponSubClassCost12, WeaponSubClassCost13, WeaponSubClassCost14, WeaponSubClassCost15, WeaponSubClassCost16, " + "WeaponSubClassCost17, WeaponSubClassCost18, WeaponSubClassCost19, WeaponSubClassCost20, WeaponSubClassCost21, ArmorSubClassCost1, " + "ArmorSubClassCost2, ArmorSubClassCost3, ArmorSubClassCost4, ArmorSubClassCost5, ArmorSubClassCost6, ArmorSubClassCost7, ArmorSubClassCost8" + - " FROM durability_costs"); + " FROM durability_costs WHERE (`VerifiedBuild` > 0) = ?"); // DurabilityQuality.db2 - PrepareStatement(HotfixStatements.SEL_DURABILITY_QUALITY, "SELECT ID, Data FROM durability_quality"); + PrepareStatement(HotfixStatements.SEL_DURABILITY_QUALITY, "SELECT ID, Data FROM durability_quality WHERE (`VerifiedBuild` > 0) = ?"); // Emotes.db2 PrepareStatement(HotfixStatements.SEL_EMOTES, "SELECT ID, RaceMask, EmoteSlashCommand, AnimID, EmoteFlags, EmoteSpecProc, EmoteSpecProcParam, EventSoundID, " + - "SpellVisualKitID, ClassMask FROM emotes"); + "SpellVisualKitID, ClassMask FROM emotes WHERE (`VerifiedBuild` > 0) = ?"); // EmotesText.db2 - PrepareStatement(HotfixStatements.SEL_EMOTES_TEXT, "SELECT ID, Name, EmoteID FROM emotes_text"); + PrepareStatement(HotfixStatements.SEL_EMOTES_TEXT, "SELECT ID, Name, EmoteID FROM emotes_text WHERE (`VerifiedBuild` > 0) = ?"); // EmotesTextSound.db2 - PrepareStatement(HotfixStatements.SEL_EMOTES_TEXT_SOUND, "SELECT ID, RaceID, ClassID, SexID, SoundID, EmotesTextID FROM emotes_text_sound"); + PrepareStatement(HotfixStatements.SEL_EMOTES_TEXT_SOUND, "SELECT ID, RaceID, ClassID, SexID, SoundID, EmotesTextID FROM emotes_text_sound" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ExpectedStat.db2 PrepareStatement(HotfixStatements.SEL_EXPECTED_STAT, "SELECT ID, ExpansionID, CreatureHealth, PlayerHealth, CreatureAutoAttackDps, CreatureArmor, " + - "PlayerMana, PlayerPrimaryStat, PlayerSecondaryStat, ArmorConstant, CreatureSpellDamage, Lvl FROM expected_stat"); + "PlayerMana, PlayerPrimaryStat, PlayerSecondaryStat, ArmorConstant, CreatureSpellDamage, Lvl FROM expected_stat" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ExpectedStatMod.db2 PrepareStatement(HotfixStatements.SEL_EXPECTED_STAT_MOD, "SELECT ID, CreatureHealthMod, PlayerHealthMod, CreatureAutoAttackDPSMod, CreatureArmorMod, " + - "PlayerManaMod, PlayerPrimaryStatMod, PlayerSecondaryStatMod, ArmorConstantMod, CreatureSpellDamageMod FROM expected_stat_mod"); + "PlayerManaMod, PlayerPrimaryStatMod, PlayerSecondaryStatMod, ArmorConstantMod, CreatureSpellDamageMod FROM expected_stat_mod" + + " WHERE (`VerifiedBuild` > 0) = ?"); // Faction.db2 PrepareStatement(HotfixStatements.SEL_FACTION, "SELECT ID, ReputationRaceMask1, ReputationRaceMask2, ReputationRaceMask3, ReputationRaceMask4, Name, " + "Description, ReputationIndex, ParentFactionID, Expansion, FriendshipRepID, Flags, ParagonFactionID, RenownFactionID, RenownCurrencyID, " + "ReputationClassMask1, ReputationClassMask2, ReputationClassMask3, ReputationClassMask4, ReputationFlags1, ReputationFlags2, " + "ReputationFlags3, ReputationFlags4, ReputationBase1, ReputationBase2, ReputationBase3, ReputationBase4, ReputationMax1, ReputationMax2, " + - "ReputationMax3, ReputationMax4, ParentFactionMod1, ParentFactionMod2, ParentFactionCap1, ParentFactionCap2 FROM faction"); - PrepareStatement(HotfixStatements.SEL_FACTION_LOCALE, "SELECT ID, Name_lang, Description_lang FROM faction_locale WHERE locale = ?"); + "ReputationMax3, ReputationMax4, ParentFactionMod1, ParentFactionMod2, ParentFactionCap1, ParentFactionCap2 FROM faction" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_FACTION_LOCALE, "SELECT ID, Name_lang, Description_lang FROM faction_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // FactionTemplate.db2 PrepareStatement(HotfixStatements.SEL_FACTION_TEMPLATE, "SELECT ID, Faction, Flags, FactionGroup, FriendGroup, EnemyGroup, Enemies1, Enemies2, Enemies3, " + - "Enemies4, Enemies5, Enemies6, Enemies7, Enemies8, Friend1, Friend2, Friend3, Friend4, Friend5, Friend6, Friend7, Friend8 FROM faction_template"); + "Enemies4, Enemies5, Enemies6, Enemies7, Enemies8, Friend1, Friend2, Friend3, Friend4, Friend5, Friend6, Friend7, Friend8" + + " FROM faction_template WHERE (`VerifiedBuild` > 0) = ?"); // FriendshipRepReaction.db2 - PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REP_REACTION, "SELECT ID, Reaction, FriendshipRepID, ReactionThreshold, OverrideColor FROM friendship_rep_reaction"); - PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REP_REACTION_LOCALE, "SELECT ID, Reaction_lang FROM friendship_rep_reaction_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REP_REACTION, "SELECT ID, Reaction, FriendshipRepID, ReactionThreshold, OverrideColor" + + " FROM friendship_rep_reaction WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REP_REACTION_LOCALE, "SELECT ID, Reaction_lang FROM friendship_rep_reaction_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // FriendshipReputation.db2 - PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REPUTATION, "SELECT Description, StandingModified, StandingChanged, ID, FactionID, TextureFileID, Flags FROM friendship_reputation"); - PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REPUTATION_LOCALE, "SELECT ID, Description_lang, StandingModified_lang, StandingChanged_lang FROM friendship_reputation_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REPUTATION, "SELECT Description, StandingModified, StandingChanged, ID, FactionID, TextureFileID, Flags" + + " FROM friendship_reputation WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_FRIENDSHIP_REPUTATION_LOCALE, "SELECT ID, Description_lang, StandingModified_lang, StandingChanged_lang" + + " FROM friendship_reputation_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // GameobjectArtKit.db2 - PrepareStatement(HotfixStatements.SEL_GAMEOBJECT_ART_KIT, "SELECT ID, AttachModelFileID, TextureVariationFileID1, TextureVariationFileID2, TextureVariationFileID3 FROM gameobject_art_kit"); + PrepareStatement(HotfixStatements.SEL_GAMEOBJECT_ART_KIT, "SELECT ID, AttachModelFileID, TextureVariationFileID1, TextureVariationFileID2, " + + "TextureVariationFileID3 FROM gameobject_art_kit WHERE (`VerifiedBuild` > 0) = ?"); // GameobjectDisplayInfo.db2 PrepareStatement(HotfixStatements.SEL_GAMEOBJECT_DISPLAY_INFO, "SELECT ID, GeoBoxMinX, GeoBoxMinY, GeoBoxMinZ, GeoBoxMaxX, GeoBoxMaxY, GeoBoxMaxZ, " + - "FileDataID, ObjectEffectPackageID, OverrideLootEffectScale, OverrideNameScale FROM gameobject_display_info"); + "FileDataID, ObjectEffectPackageID, OverrideLootEffectScale, OverrideNameScale FROM gameobject_display_info WHERE (`VerifiedBuild` > 0) = ?"); // Gameobjects.db2 PrepareStatement(HotfixStatements.SEL_GAMEOBJECTS, "SELECT Name, PosX, PosY, PosZ, Rot1, Rot2, Rot3, Rot4, ID, OwnerID, DisplayID, Scale, TypeID, " + "PhaseUseFlags, PhaseID, PhaseGroupID, PropValue1, PropValue2, PropValue3, PropValue4, PropValue5, PropValue6, PropValue7, PropValue8" + - " FROM gameobjects"); - PrepareStatement(HotfixStatements.SEL_GAMEOBJECTS_LOCALE, "SELECT ID, Name_lang FROM gameobjects_locale WHERE locale = ?"); + " FROM gameobjects WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_GAMEOBJECTS_LOCALE, "SELECT ID, Name_lang FROM gameobjects_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // GarrAbility.db2 PrepareStatement(HotfixStatements.SEL_GARR_ABILITY, "SELECT ID, Name, Description, GarrAbilityCategoryID, GarrFollowerTypeID, IconFileDataID, " + - "FactionChangeGarrAbilityID, Flags FROM garr_ability"); - PrepareStatement(HotfixStatements.SEL_GARR_ABILITY_LOCALE, "SELECT ID, Name_lang, Description_lang FROM garr_ability_locale WHERE locale = ?"); + "FactionChangeGarrAbilityID, Flags FROM garr_ability WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_GARR_ABILITY_LOCALE, "SELECT ID, Name_lang, Description_lang FROM garr_ability_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // GarrBuilding.db2 PrepareStatement(HotfixStatements.SEL_GARR_BUILDING, "SELECT ID, HordeName, AllianceName, Description, Tooltip, GarrTypeID, BuildingType, " + "HordeGameObjectID, AllianceGameObjectID, GarrSiteID, UpgradeLevel, BuildSeconds, CurrencyTypeID, CurrencyQty, HordeUiTextureKitID, " + "AllianceUiTextureKitID, IconFileDataID, AllianceSceneScriptPackageID, HordeSceneScriptPackageID, MaxAssignments, ShipmentCapacity, " + - "GarrAbilityID, BonusGarrAbilityID, GoldCost, Flags FROM garr_building"); + "GarrAbilityID, BonusGarrAbilityID, GoldCost, Flags FROM garr_building WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_GARR_BUILDING_LOCALE, "SELECT ID, HordeName_lang, AllianceName_lang, Description_lang, Tooltip_lang" + - " FROM garr_building_locale WHERE locale = ?"); + " FROM garr_building_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // GarrBuildingPlotInst.db2 PrepareStatement(HotfixStatements.SEL_GARR_BUILDING_PLOT_INST, "SELECT MapOffsetX, MapOffsetY, ID, GarrBuildingID, GarrSiteLevelPlotInstID, " + - "UiTextureAtlasMemberID FROM garr_building_plot_inst"); + "UiTextureAtlasMemberID FROM garr_building_plot_inst WHERE (`VerifiedBuild` > 0) = ?"); // GarrClassSpec.db2 PrepareStatement(HotfixStatements.SEL_GARR_CLASS_SPEC, "SELECT ID, ClassSpec, ClassSpecMale, ClassSpecFemale, UiTextureAtlasMemberID, GarrFollItemSetID, " + - "FollowerClassLimit, Flags FROM garr_class_spec"); + "FollowerClassLimit, Flags FROM garr_class_spec WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_GARR_CLASS_SPEC_LOCALE, "SELECT ID, ClassSpec_lang, ClassSpecMale_lang, ClassSpecFemale_lang FROM garr_class_spec_locale" + - " WHERE locale = ?"); + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // GarrFollower.db2 PrepareStatement(HotfixStatements.SEL_GARR_FOLLOWER, "SELECT ID, HordeSourceText, AllianceSourceText, TitleName, GarrTypeID, GarrFollowerTypeID, " + "HordeCreatureID, AllianceCreatureID, HordeGarrFollRaceID, AllianceGarrFollRaceID, HordeGarrClassSpecID, AllianceGarrClassSpecID, Quality, " + "FollowerLevel, ItemLevelWeapon, ItemLevelArmor, HordeSourceTypeEnum, AllianceSourceTypeEnum, HordeIconFileDataID, AllianceIconFileDataID, " + "HordeGarrFollItemSetID, AllianceGarrFollItemSetID, HordeUITextureKitID, AllianceUITextureKitID, Vitality, HordeFlavorGarrStringID, " + - "AllianceFlavorGarrStringID, HordeSlottingBroadcastTextID, AllySlottingBroadcastTextID, ChrClassID, Flags, Gender, AutoCombatantID, CovenantID FROM garr_follower"); + "AllianceFlavorGarrStringID, HordeSlottingBroadcastTextID, AllySlottingBroadcastTextID, ChrClassID, Flags, Gender, AutoCombatantID, " + + "CovenantID FROM garr_follower WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_GARR_FOLLOWER_LOCALE, "SELECT ID, HordeSourceText_lang, AllianceSourceText_lang, TitleName_lang FROM garr_follower_locale" + - " WHERE locale = ?"); + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // GarrFollowerXAbility.db2 PrepareStatement(HotfixStatements.SEL_GARR_FOLLOWER_X_ABILITY, "SELECT ID, OrderIndex, FactionIndex, GarrAbilityID, GarrFollowerID" + - " FROM garr_follower_x_ability"); + " FROM garr_follower_x_ability WHERE (`VerifiedBuild` > 0) = ?"); // GarrMission.db2 PrepareStatement(HotfixStatements.SEL_GARR_MISSION, "SELECT ID, Name, Location, Description, MapPosX, MapPosY, WorldPosX, WorldPosY, GarrTypeID, " + "GarrMissionTypeID, GarrFollowerTypeID, MaxFollowers, MissionCost, MissionCostCurrencyTypesID, OfferedGarrMissionTextureID, UiTextureKitID, " + "EnvGarrMechanicID, EnvGarrMechanicTypeID, PlayerConditionID, GarrMissionSetID, TargetLevel, TargetItemLevel, MissionDuration, " + "TravelDuration, OfferDuration, BaseCompletionChance, BaseFollowerXP, OvermaxRewardPackID, FollowerDeathChance, AreaID, Flags, " + - "AutoMissionScalar, AutoMissionScalarCurveID, AutoCombatantEnvCasterID FROM garr_mission"); - PrepareStatement(HotfixStatements.SEL_GARR_MISSION_LOCALE, "SELECT ID, Name_lang, Location_lang, Description_lang FROM garr_mission_locale WHERE locale = ?"); + "AutoMissionScalar, AutoMissionScalarCurveID, AutoCombatantEnvCasterID FROM garr_mission WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_GARR_MISSION_LOCALE, "SELECT ID, Name_lang, Location_lang, Description_lang FROM garr_mission_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // GarrPlot.db2 PrepareStatement(HotfixStatements.SEL_GARR_PLOT, "SELECT ID, Name, PlotType, HordeConstructObjID, AllianceConstructObjID, Flags, UiCategoryID, " + - "UpgradeRequirement1, UpgradeRequirement2 FROM garr_plot"); + "UpgradeRequirement1, UpgradeRequirement2 FROM garr_plot WHERE (`VerifiedBuild` > 0) = ?"); // GarrPlotBuilding.db2 - PrepareStatement(HotfixStatements.SEL_GARR_PLOT_BUILDING, "SELECT ID, GarrPlotID, GarrBuildingID FROM garr_plot_building"); + PrepareStatement(HotfixStatements.SEL_GARR_PLOT_BUILDING, "SELECT ID, GarrPlotID, GarrBuildingID FROM garr_plot_building WHERE (`VerifiedBuild` > 0) = ?"); // GarrPlotInstance.db2 - PrepareStatement(HotfixStatements.SEL_GARR_PLOT_INSTANCE, "SELECT ID, Name, GarrPlotID FROM garr_plot_instance"); + PrepareStatement(HotfixStatements.SEL_GARR_PLOT_INSTANCE, "SELECT ID, Name, GarrPlotID FROM garr_plot_instance WHERE (`VerifiedBuild` > 0) = ?"); // GarrSiteLevel.db2 PrepareStatement(HotfixStatements.SEL_GARR_SITE_LEVEL, "SELECT ID, TownHallUiPosX, TownHallUiPosY, GarrSiteID, GarrLevel, MapID, UpgradeMovieID, " + - "UiTextureKitID, MaxBuildingLevel, UpgradeCost, UpgradeGoldCost FROM garr_site_level"); + "UiTextureKitID, MaxBuildingLevel, UpgradeCost, UpgradeGoldCost FROM garr_site_level WHERE (`VerifiedBuild` > 0) = ?"); // GarrSiteLevelPlotInst.db2 PrepareStatement(HotfixStatements.SEL_GARR_SITE_LEVEL_PLOT_INST, "SELECT ID, UiMarkerPosX, UiMarkerPosY, GarrSiteLevelID, GarrPlotInstanceID, UiMarkerSize" + - " FROM garr_site_level_plot_inst"); + " FROM garr_site_level_plot_inst WHERE (`VerifiedBuild` > 0) = ?"); // GarrTalentTree.db2 PrepareStatement(HotfixStatements.SEL_GARR_TALENT_TREE, "SELECT ID, Name, GarrTypeID, ClassID, MaxTiers, UiOrder, Flags, UiTextureKitID, " + - "GarrTalentTreeType, PlayerConditionID, FeatureTypeIndex, FeatureSubtypeIndex, CurrencyID FROM garr_talent_tree"); - PrepareStatement(HotfixStatements.SEL_GARR_TALENT_TREE_LOCALE, "SELECT ID, Name_lang FROM garr_talent_tree_locale WHERE locale = ?"); + "GarrTalentTreeType, PlayerConditionID, FeatureTypeIndex, FeatureSubtypeIndex, CurrencyID FROM garr_talent_tree" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_GARR_TALENT_TREE_LOCALE, "SELECT ID, Name_lang FROM garr_talent_tree_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // GemProperties.db2 - PrepareStatement(HotfixStatements.SEL_GEM_PROPERTIES, "SELECT ID, EnchantId, Type FROM gem_properties"); + PrepareStatement(HotfixStatements.SEL_GEM_PROPERTIES, "SELECT ID, EnchantId, Type FROM gem_properties WHERE (`VerifiedBuild` > 0) = ?"); // GlobalCurve.db2 - PrepareStatement(HotfixStatements.SEL_GLOBAL_CURVE, "SELECT ID, CurveID, Type FROM global_curve"); + PrepareStatement(HotfixStatements.SEL_GLOBAL_CURVE, "SELECT ID, CurveID, Type FROM global_curve WHERE (`VerifiedBuild` > 0) = ?"); // GlyphBindableSpell.db2 - PrepareStatement(HotfixStatements.SEL_GLYPH_BINDABLE_SPELL, "SELECT ID, SpellID, GlyphPropertiesID FROM glyph_bindable_spell"); + PrepareStatement(HotfixStatements.SEL_GLYPH_BINDABLE_SPELL, "SELECT ID, SpellID, GlyphPropertiesID FROM glyph_bindable_spell WHERE (`VerifiedBuild` > 0) = ?"); // GlyphProperties.db2 - PrepareStatement(HotfixStatements.SEL_GLYPH_PROPERTIES, "SELECT ID, SpellID, GlyphType, GlyphExclusiveCategoryID, SpellIconFileDataID FROM glyph_properties"); + PrepareStatement(HotfixStatements.SEL_GLYPH_PROPERTIES, "SELECT ID, SpellID, GlyphType, GlyphExclusiveCategoryID, SpellIconFileDataID FROM glyph_properties" + + " WHERE (`VerifiedBuild` > 0) = ?"); // GlyphRequiredSpec.db2 - PrepareStatement(HotfixStatements.SEL_GLYPH_REQUIRED_SPEC, "SELECT ID, ChrSpecializationID, GlyphPropertiesID FROM glyph_required_spec"); + PrepareStatement(HotfixStatements.SEL_GLYPH_REQUIRED_SPEC, "SELECT ID, ChrSpecializationID, GlyphPropertiesID FROM glyph_required_spec" + + " WHERE (`VerifiedBuild` > 0) = ?"); // GossipNpcOption.db2 PrepareStatement(HotfixStatements.SEL_GOSSIP_NPC_OPTION, "SELECT ID, GossipNpcOption, LFGDungeonsID, TrainerID, GarrFollowerTypeID, CharShipmentID, " + "GarrTalentTreeID, UiMapID, UiItemInteractionID, Unknown_1000_8, Unknown_1000_9, CovenantID, GossipOptionID, TraitTreeID, ProfessionID, " + - "Unknown_1002_14 FROM gossip_npc_option"); + "Unknown_1002_14 FROM gossip_npc_option WHERE (`VerifiedBuild` > 0) = ?"); // GuildColorBackground.db2 - PrepareStatement(HotfixStatements.SEL_GUILD_COLOR_BACKGROUND, "SELECT ID, Red, Blue, Green FROM guild_color_background"); + PrepareStatement(HotfixStatements.SEL_GUILD_COLOR_BACKGROUND, "SELECT ID, Red, Blue, Green FROM guild_color_background WHERE (`VerifiedBuild` > 0) = ?"); // GuildColorBorder.db2 - PrepareStatement(HotfixStatements.SEL_GUILD_COLOR_BORDER, "SELECT ID, Red, Blue, Green FROM guild_color_border"); + PrepareStatement(HotfixStatements.SEL_GUILD_COLOR_BORDER, "SELECT ID, Red, Blue, Green FROM guild_color_border WHERE (`VerifiedBuild` > 0) = ?"); // GuildColorEmblem.db2 - PrepareStatement(HotfixStatements.SEL_GUILD_COLOR_EMBLEM, "SELECT ID, Red, Blue, Green FROM guild_color_emblem"); + PrepareStatement(HotfixStatements.SEL_GUILD_COLOR_EMBLEM, "SELECT ID, Red, Blue, Green FROM guild_color_emblem WHERE (`VerifiedBuild` > 0) = ?"); // GuildPerkSpells.db2 - PrepareStatement(HotfixStatements.SEL_GUILD_PERK_SPELLS, "SELECT ID, SpellID FROM guild_perk_spells"); + PrepareStatement(HotfixStatements.SEL_GUILD_PERK_SPELLS, "SELECT ID, SpellID FROM guild_perk_spells WHERE (`VerifiedBuild` > 0) = ?"); // Heirloom.db2 PrepareStatement(HotfixStatements.SEL_HEIRLOOM, "SELECT SourceText, ID, ItemID, LegacyUpgradedItemID, StaticUpgradedItemID, SourceTypeEnum, Flags, " + "LegacyItemID, UpgradeItemID1, UpgradeItemID2, UpgradeItemID3, UpgradeItemID4, UpgradeItemID5, UpgradeItemID6, UpgradeItemBonusListID1, " + - "UpgradeItemBonusListID2, UpgradeItemBonusListID3, UpgradeItemBonusListID4, UpgradeItemBonusListID5, UpgradeItemBonusListID6 FROM heirloom"); - PrepareStatement(HotfixStatements.SEL_HEIRLOOM_LOCALE, "SELECT ID, SourceText_lang FROM heirloom_locale WHERE locale = ?"); + "UpgradeItemBonusListID2, UpgradeItemBonusListID3, UpgradeItemBonusListID4, UpgradeItemBonusListID5, UpgradeItemBonusListID6 FROM heirloom" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_HEIRLOOM_LOCALE, "SELECT ID, SourceText_lang FROM heirloom_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // Holidays.db2 PrepareStatement(HotfixStatements.SEL_HOLIDAYS, "SELECT ID, Region, Looping, HolidayNameID, HolidayDescriptionID, Priority, CalendarFilterType, Flags, " + "Duration1, Duration2, Duration3, Duration4, Duration5, Duration6, Duration7, Duration8, Duration9, Duration10, Date1, Date2, Date3, Date4, " + "Date5, Date6, Date7, Date8, Date9, Date10, Date11, Date12, Date13, Date14, Date15, Date16, Date17, Date18, Date19, Date20, Date21, Date22, " + "Date23, Date24, Date25, Date26, CalendarFlags1, CalendarFlags2, CalendarFlags3, CalendarFlags4, CalendarFlags5, CalendarFlags6, " + - "CalendarFlags7, CalendarFlags8, CalendarFlags9, CalendarFlags10, TextureFileDataID1, TextureFileDataID2, TextureFileDataID3 FROM holidays"); + "CalendarFlags7, CalendarFlags8, CalendarFlags9, CalendarFlags10, TextureFileDataID1, TextureFileDataID2, TextureFileDataID3 FROM holidays" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ImportPriceArmor.db2 - PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_ARMOR, "SELECT ID, ClothModifier, LeatherModifier, ChainModifier, PlateModifier FROM import_price_armor"); + PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_ARMOR, "SELECT ID, ClothModifier, LeatherModifier, ChainModifier, PlateModifier FROM import_price_armor" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ImportPriceQuality.db2 - PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_QUALITY, "SELECT ID, Data FROM import_price_quality"); + PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_QUALITY, "SELECT ID, Data FROM import_price_quality WHERE (`VerifiedBuild` > 0) = ?"); // ImportPriceShield.db2 - PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_SHIELD, "SELECT ID, Data FROM import_price_shield"); + PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_SHIELD, "SELECT ID, Data FROM import_price_shield WHERE (`VerifiedBuild` > 0) = ?"); // ImportPriceWeapon.db2 - PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_WEAPON, "SELECT ID, Data FROM import_price_weapon"); + PrepareStatement(HotfixStatements.SEL_IMPORT_PRICE_WEAPON, "SELECT ID, Data FROM import_price_weapon WHERE (`VerifiedBuild` > 0) = ?"); // Item.db2 PrepareStatement(HotfixStatements.SEL_ITEM, "SELECT ID, ClassID, SubclassID, Material, InventoryType, SheatheType, SoundOverrideSubclassID, IconFileDataID, " + - "ItemGroupSoundsID, ContentTuningID, ModifiedCraftingReagentItemID, CraftingQualityID FROM item"); + "ItemGroupSoundsID, ContentTuningID, ModifiedCraftingReagentItemID, CraftingQualityID FROM item WHERE (`VerifiedBuild` > 0) = ?"); // ItemAppearance.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_APPEARANCE, "SELECT ID, DisplayType, ItemDisplayInfoID, DefaultIconFileDataID, UiOrder, PlayerConditionID FROM item_appearance"); + PrepareStatement(HotfixStatements.SEL_ITEM_APPEARANCE, "SELECT ID, DisplayType, ItemDisplayInfoID, DefaultIconFileDataID, UiOrder, PlayerConditionID" + + " FROM item_appearance WHERE (`VerifiedBuild` > 0) = ?"); // ItemArmorQuality.db2 PrepareStatement(HotfixStatements.SEL_ITEM_ARMOR_QUALITY, "SELECT ID, Qualitymod1, Qualitymod2, Qualitymod3, Qualitymod4, Qualitymod5, Qualitymod6, " + - "Qualitymod7 FROM item_armor_quality"); + "Qualitymod7 FROM item_armor_quality WHERE (`VerifiedBuild` > 0) = ?"); // ItemArmorShield.db2 PrepareStatement(HotfixStatements.SEL_ITEM_ARMOR_SHIELD, "SELECT ID, Quality1, Quality2, Quality3, Quality4, Quality5, Quality6, Quality7, ItemLevel" + - " FROM item_armor_shield"); + " FROM item_armor_shield WHERE (`VerifiedBuild` > 0) = ?"); // ItemArmorTotal.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_ARMOR_TOTAL, "SELECT ID, ItemLevel, Cloth, Leather, Mail, Plate FROM item_armor_total"); + PrepareStatement(HotfixStatements.SEL_ITEM_ARMOR_TOTAL, "SELECT ID, ItemLevel, Cloth, Leather, Mail, Plate FROM item_armor_total" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ItemBagFamily.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_BAG_FAMILY, "SELECT ID, Name FROM item_bag_family"); - PrepareStatement(HotfixStatements.SEL_ITEM_BAG_FAMILY_LOCALE, "SELECT ID, Name_lang FROM item_bag_family_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_BAG_FAMILY, "SELECT ID, Name FROM item_bag_family WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_BAG_FAMILY_LOCALE, "SELECT ID, Name_lang FROM item_bag_family_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ItemBonus.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_BONUS, "SELECT ID, Value1, Value2, Value3, Value4, ParentItemBonusListID, Type, OrderIndex FROM item_bonus"); + PrepareStatement(HotfixStatements.SEL_ITEM_BONUS, "SELECT ID, Value1, Value2, Value3, Value4, ParentItemBonusListID, Type, OrderIndex FROM item_bonus" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ItemBonusListLevelDelta.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_BONUS_LIST_LEVEL_DELTA, "SELECT ItemLevelDelta, ID FROM item_bonus_list_level_delta"); + PrepareStatement(HotfixStatements.SEL_ITEM_BONUS_LIST_LEVEL_DELTA, "SELECT ItemLevelDelta, ID FROM item_bonus_list_level_delta" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ItemBonusTreeNode.db2 PrepareStatement(HotfixStatements.SEL_ITEM_BONUS_TREE_NODE, "SELECT ID, ItemContext, ChildItemBonusTreeID, ChildItemBonusListID, ChildItemLevelSelectorID, " + - "ChildItemBonusListGroupID, IblGroupPointsModSetID, ParentItemBonusTreeID FROM item_bonus_tree_node"); + "ChildItemBonusListGroupID, IblGroupPointsModSetID, ParentItemBonusTreeID FROM item_bonus_tree_node WHERE (`VerifiedBuild` > 0) = ?"); // ItemChildEquipment.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_CHILD_EQUIPMENT, "SELECT ID, ParentItemID, ChildItemID, ChildItemEquipSlot FROM item_child_equipment"); + PrepareStatement(HotfixStatements.SEL_ITEM_CHILD_EQUIPMENT, "SELECT ID, ParentItemID, ChildItemID, ChildItemEquipSlot FROM item_child_equipment" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ItemClass.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_CLASS, "SELECT ID, ClassName, ClassID, PriceModifier, Flags FROM item_class"); - PrepareStatement(HotfixStatements.SEL_ITEM_CLASS_LOCALE, "SELECT ID, ClassName_lang FROM item_class_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_CLASS, "SELECT ID, ClassName, ClassID, PriceModifier, Flags FROM item_class WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_CLASS_LOCALE, "SELECT ID, ClassName_lang FROM item_class_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ItemCurrencyCost.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_CURRENCY_COST, "SELECT ID, ItemID FROM item_currency_cost"); + PrepareStatement(HotfixStatements.SEL_ITEM_CURRENCY_COST, "SELECT ID, ItemID FROM item_currency_cost WHERE (`VerifiedBuild` > 0) = ?"); // ItemDamageAmmo.db2 PrepareStatement(HotfixStatements.SEL_ITEM_DAMAGE_AMMO, "SELECT ID, ItemLevel, Quality1, Quality2, Quality3, Quality4, Quality5, Quality6, Quality7" + - " FROM item_damage_ammo"); + " FROM item_damage_ammo WHERE (`VerifiedBuild` > 0) = ?"); // ItemDamageOneHand.db2 PrepareStatement(HotfixStatements.SEL_ITEM_DAMAGE_ONE_HAND, "SELECT ID, ItemLevel, Quality1, Quality2, Quality3, Quality4, Quality5, Quality6, Quality7" + - " FROM item_damage_one_hand"); + " FROM item_damage_one_hand WHERE (`VerifiedBuild` > 0) = ?"); // ItemDamageOneHandCaster.db2 PrepareStatement(HotfixStatements.SEL_ITEM_DAMAGE_ONE_HAND_CASTER, "SELECT ID, ItemLevel, Quality1, Quality2, Quality3, Quality4, Quality5, Quality6, " + - "Quality7 FROM item_damage_one_hand_caster"); + "Quality7 FROM item_damage_one_hand_caster WHERE (`VerifiedBuild` > 0) = ?"); // ItemDamageTwoHand.db2 PrepareStatement(HotfixStatements.SEL_ITEM_DAMAGE_TWO_HAND, "SELECT ID, ItemLevel, Quality1, Quality2, Quality3, Quality4, Quality5, Quality6, Quality7" + - " FROM item_damage_two_hand"); + " FROM item_damage_two_hand WHERE (`VerifiedBuild` > 0) = ?"); // ItemDamageTwoHandCaster.db2 PrepareStatement(HotfixStatements.SEL_ITEM_DAMAGE_TWO_HAND_CASTER, "SELECT ID, ItemLevel, Quality1, Quality2, Quality3, Quality4, Quality5, Quality6, " + - "Quality7 FROM item_damage_two_hand_caster"); + "Quality7 FROM item_damage_two_hand_caster WHERE (`VerifiedBuild` > 0) = ?"); // ItemDisenchantLoot.db2 PrepareStatement(HotfixStatements.SEL_ITEM_DISENCHANT_LOOT, "SELECT ID, Subclass, Quality, MinLevel, MaxLevel, SkillRequired, ExpansionID, Class" + - " FROM item_disenchant_loot"); + " FROM item_disenchant_loot WHERE (`VerifiedBuild` > 0) = ?"); // ItemEffect.db2 PrepareStatement(HotfixStatements.SEL_ITEM_EFFECT, "SELECT ID, LegacySlotIndex, TriggerType, Charges, CoolDownMSec, CategoryCoolDownMSec, SpellCategoryID, " + - "SpellID, ChrSpecializationID FROM item_effect"); + "SpellID, ChrSpecializationID FROM item_effect WHERE (`VerifiedBuild` > 0) = ?"); // ItemExtendedCost.db2 PrepareStatement(HotfixStatements.SEL_ITEM_EXTENDED_COST, "SELECT ID, RequiredArenaRating, ArenaBracket, Flags, MinFactionID, MinReputation, " + "RequiredAchievement, ItemID1, ItemID2, ItemID3, ItemID4, ItemID5, ItemCount1, ItemCount2, ItemCount3, ItemCount4, ItemCount5, CurrencyID1, " + "CurrencyID2, CurrencyID3, CurrencyID4, CurrencyID5, CurrencyCount1, CurrencyCount2, CurrencyCount3, CurrencyCount4, CurrencyCount5" + - " FROM item_extended_cost"); + " FROM item_extended_cost WHERE (`VerifiedBuild` > 0) = ?"); // ItemLevelSelector.db2 PrepareStatement(HotfixStatements.SEL_ITEM_LEVEL_SELECTOR, "SELECT ID, MinItemLevel, ItemLevelSelectorQualitySetID, AzeriteUnlockMappingSet" + - " FROM item_level_selector"); + " FROM item_level_selector WHERE (`VerifiedBuild` > 0) = ?"); // ItemLevelSelectorQuality.db2 PrepareStatement(HotfixStatements.SEL_ITEM_LEVEL_SELECTOR_QUALITY, "SELECT ID, QualityItemBonusListID, Quality, ParentILSQualitySetID" + - " FROM item_level_selector_quality"); + " FROM item_level_selector_quality WHERE (`VerifiedBuild` > 0) = ?"); // ItemLevelSelectorQualitySet.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_LEVEL_SELECTOR_QUALITY_SET, "SELECT ID, IlvlRare, IlvlEpic FROM item_level_selector_quality_set"); + PrepareStatement(HotfixStatements.SEL_ITEM_LEVEL_SELECTOR_QUALITY_SET, "SELECT ID, IlvlRare, IlvlEpic FROM item_level_selector_quality_set" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ItemLimitCategory.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_LIMIT_CATEGORY, "SELECT ID, Name, Quantity, Flags FROM item_limit_category"); - PrepareStatement(HotfixStatements.SEL_ITEM_LIMIT_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM item_limit_category_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_LIMIT_CATEGORY, "SELECT ID, Name, Quantity, Flags FROM item_limit_category WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_LIMIT_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM item_limit_category_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // ItemLimitCategoryCondition.db2 PrepareStatement(HotfixStatements.SEL_ITEM_LIMIT_CATEGORY_CONDITION, "SELECT ID, AddQuantity, PlayerConditionID, ParentItemLimitCategoryID" + - " FROM item_limit_category_condition"); + " FROM item_limit_category_condition WHERE (`VerifiedBuild` > 0) = ?"); // ItemModifiedAppearance.db2 PrepareStatement(HotfixStatements.SEL_ITEM_MODIFIED_APPEARANCE, "SELECT ID, ItemID, ItemAppearanceModifierID, ItemAppearanceID, OrderIndex, " + - "TransmogSourceTypeEnum FROM item_modified_appearance"); + "TransmogSourceTypeEnum FROM item_modified_appearance WHERE (`VerifiedBuild` > 0) = ?"); // ItemModifiedAppearanceExtra.db2 PrepareStatement(HotfixStatements.SEL_ITEM_MODIFIED_APPEARANCE_EXTRA, "SELECT ID, IconFileDataID, UnequippedIconFileDataID, SheatheType, " + - "DisplayWeaponSubclassID, DisplayInventoryType FROM item_modified_appearance_extra"); + "DisplayWeaponSubclassID, DisplayInventoryType FROM item_modified_appearance_extra WHERE (`VerifiedBuild` > 0) = ?"); // ItemNameDescription.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_NAME_DESCRIPTION, "SELECT ID, Description, Color FROM item_name_description"); - PrepareStatement(HotfixStatements.SEL_ITEM_NAME_DESCRIPTION_LOCALE, "SELECT ID, Description_lang FROM item_name_description_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_NAME_DESCRIPTION, "SELECT ID, Description, Color FROM item_name_description WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_NAME_DESCRIPTION_LOCALE, "SELECT ID, Description_lang FROM item_name_description_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ItemPriceBase.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_PRICE_BASE, "SELECT ID, ItemLevel, Armor, Weapon FROM item_price_base"); + PrepareStatement(HotfixStatements.SEL_ITEM_PRICE_BASE, "SELECT ID, ItemLevel, Armor, Weapon FROM item_price_base WHERE (`VerifiedBuild` > 0) = ?"); // ItemSearchName.db2 PrepareStatement(HotfixStatements.SEL_ITEM_SEARCH_NAME, "SELECT ID, AllowableRace, Display, OverallQualityID, ExpansionID, MinFactionID, MinReputation, " + "AllowableClass, RequiredLevel, RequiredSkill, RequiredSkillRank, RequiredAbility, ItemLevel, Flags1, Flags2, Flags3, Flags4" + - " FROM item_search_name"); - PrepareStatement(HotfixStatements.SEL_ITEM_SEARCH_NAME_LOCALE, "SELECT ID, Display_lang FROM item_search_name_locale WHERE locale = ?"); + " FROM item_search_name WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_SEARCH_NAME_LOCALE, "SELECT ID, Display_lang FROM item_search_name_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // ItemSet.db2 PrepareStatement(HotfixStatements.SEL_ITEM_SET, "SELECT ID, Name, SetFlags, RequiredSkill, RequiredSkillRank, ItemID1, ItemID2, ItemID3, ItemID4, ItemID5, " + - "ItemID6, ItemID7, ItemID8, ItemID9, ItemID10, ItemID11, ItemID12, ItemID13, ItemID14, ItemID15, ItemID16, ItemID17 FROM item_set"); - PrepareStatement(HotfixStatements.SEL_ITEM_SET_LOCALE, "SELECT ID, Name_lang FROM item_set_locale WHERE locale = ?"); + "ItemID6, ItemID7, ItemID8, ItemID9, ItemID10, ItemID11, ItemID12, ItemID13, ItemID14, ItemID15, ItemID16, ItemID17 FROM item_set" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_SET_LOCALE, "SELECT ID, Name_lang FROM item_set_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ItemSetSpell.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_SET_SPELL, "SELECT ID, ChrSpecID, SpellID, Threshold, ItemSetID FROM item_set_spell"); + PrepareStatement(HotfixStatements.SEL_ITEM_SET_SPELL, "SELECT ID, ChrSpecID, SpellID, Threshold, ItemSetID FROM item_set_spell" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ItemSparse.db2 PrepareStatement(HotfixStatements.SEL_ITEM_SPARSE, "SELECT ID, AllowableRace, Description, Display3, Display2, Display1, Display, ExpansionID, DmgVariance, " + @@ -698,68 +787,77 @@ namespace Framework.Database "ItemLevel, AllowableClass, ArtifactID, SpellWeight, SpellWeightCategory, SocketType1, SocketType2, SocketType3, SheatheType, Material, " + "PageMaterialID, Bonding, DamageDamageType, StatModifierBonusStat1, StatModifierBonusStat2, StatModifierBonusStat3, StatModifierBonusStat4, " + "StatModifierBonusStat5, StatModifierBonusStat6, StatModifierBonusStat7, StatModifierBonusStat8, StatModifierBonusStat9, " + - "StatModifierBonusStat10, ContainerSlots, RequiredPVPMedal, RequiredPVPRank, RequiredLevel, InventoryType, OverallQualityID FROM item_sparse"); - PrepareStatement(HotfixStatements.SEL_ITEM_SPARSE_LOCALE, "SELECT ID, Description_lang, Display3_lang, Display2_lang, Display1_lang, Display_lang" + - " FROM item_sparse_locale WHERE locale = ?"); + "StatModifierBonusStat10, ContainerSlots, RequiredPVPMedal, RequiredPVPRank, RequiredLevel, InventoryType, OverallQualityID FROM item_sparse" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_ITEM_SPARSE_LOCALE, "SELECT ID, Description_lang, Display3_lang, Display2_lang, Display1_lang, Display_lang" + + " FROM item_sparse_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ItemSpec.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_SPEC, "SELECT ID, MinLevel, MaxLevel, ItemType, PrimaryStat, SecondaryStat, SpecializationID FROM item_spec"); + PrepareStatement(HotfixStatements.SEL_ITEM_SPEC, "SELECT ID, MinLevel, MaxLevel, ItemType, PrimaryStat, SecondaryStat, SpecializationID FROM item_spec" + + " WHERE (`VerifiedBuild` > 0) = ?"); // ItemSpecOverride.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_SPEC_OVERRIDE, "SELECT ID, SpecID, ItemID FROM item_spec_override"); + PrepareStatement(HotfixStatements.SEL_ITEM_SPEC_OVERRIDE, "SELECT ID, SpecID, ItemID FROM item_spec_override WHERE (`VerifiedBuild` > 0) = ?"); // ItemXBonusTree.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_X_BONUS_TREE, "SELECT ID, ItemBonusTreeID, ItemID FROM item_x_bonus_tree"); + PrepareStatement(HotfixStatements.SEL_ITEM_X_BONUS_TREE, "SELECT ID, ItemBonusTreeID, ItemID FROM item_x_bonus_tree WHERE (`VerifiedBuild` > 0) = ?"); // ItemXItemEffect.db2 - PrepareStatement(HotfixStatements.SEL_ITEM_X_ITEM_EFFECT, "SELECT ID, ItemEffectID, ItemID FROM item_x_item_effect"); + PrepareStatement(HotfixStatements.SEL_ITEM_X_ITEM_EFFECT, "SELECT ID, ItemEffectID, ItemID FROM item_x_item_effect WHERE (`VerifiedBuild` > 0) = ?"); // JournalEncounter.db2 PrepareStatement(HotfixStatements.SEL_JOURNAL_ENCOUNTER, "SELECT Name, Description, MapX, MapY, ID, JournalInstanceID, DungeonEncounterID, OrderIndex, " + - "FirstSectionID, UiMapID, MapDisplayConditionID, Flags, DifficultyMask FROM journal_encounter"); - PrepareStatement(HotfixStatements.SEL_JOURNAL_ENCOUNTER_LOCALE, "SELECT ID, Name_lang, Description_lang FROM journal_encounter_locale WHERE locale = ?"); + "FirstSectionID, UiMapID, MapDisplayConditionID, Flags, DifficultyMask FROM journal_encounter WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_JOURNAL_ENCOUNTER_LOCALE, "SELECT ID, Name_lang, Description_lang FROM journal_encounter_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // JournalEncounterSection.db2 PrepareStatement(HotfixStatements.SEL_JOURNAL_ENCOUNTER_SECTION, "SELECT ID, Title, BodyText, JournalEncounterID, OrderIndex, ParentSectionID, " + "FirstChildSectionID, NextSiblingSectionID, Type, IconCreatureDisplayInfoID, UiModelSceneID, SpellID, IconFileDataID, Flags, IconFlags, " + - "DifficultyMask FROM journal_encounter_section"); - PrepareStatement(HotfixStatements.SEL_JOURNAL_ENCOUNTER_SECTION_LOCALE, "SELECT ID, Title_lang, BodyText_lang FROM journal_encounter_section_locale WHERE locale = ?"); + "DifficultyMask FROM journal_encounter_section WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_JOURNAL_ENCOUNTER_SECTION_LOCALE, "SELECT ID, Title_lang, BodyText_lang FROM journal_encounter_section_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // JournalInstance.db2 PrepareStatement(HotfixStatements.SEL_JOURNAL_INSTANCE, "SELECT ID, Name, Description, MapID, BackgroundFileDataID, ButtonFileDataID, " + - "ButtonSmallFileDataID, LoreFileDataID, Flags, AreaID FROM journal_instance"); - PrepareStatement(HotfixStatements.SEL_JOURNAL_INSTANCE_LOCALE, "SELECT ID, Name_lang, Description_lang FROM journal_instance_locale WHERE locale = ?"); + "ButtonSmallFileDataID, LoreFileDataID, Flags, AreaID FROM journal_instance WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_JOURNAL_INSTANCE_LOCALE, "SELECT ID, Name_lang, Description_lang FROM journal_instance_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // JournalTier.db2 - PrepareStatement(HotfixStatements.SEL_JOURNAL_TIER, "SELECT ID, Name, PlayerConditionID FROM journal_tier"); - PrepareStatement(HotfixStatements.SEL_JOURNAL_TIER_LOCALE, "SELECT ID, Name_lang FROM journal_tier_locale WHERE locale = ?"); - + PrepareStatement(HotfixStatements.SEL_JOURNAL_TIER, "SELECT ID, Name, PlayerConditionID FROM journal_tier WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_JOURNAL_TIER_LOCALE, "SELECT ID, Name_lang FROM journal_tier_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // Keychain.db2 PrepareStatement(HotfixStatements.SEL_KEYCHAIN, "SELECT ID, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key10, Key11, Key12, Key13, Key14, Key15, " + - "Key16, Key17, Key18, Key19, Key20, Key21, Key22, Key23, Key24, Key25, Key26, Key27, Key28, Key29, Key30, Key31, Key32 FROM keychain"); + "Key16, Key17, Key18, Key19, Key20, Key21, Key22, Key23, Key24, Key25, Key26, Key27, Key28, Key29, Key30, Key31, Key32 FROM keychain" + + " WHERE (`VerifiedBuild` > 0) = ?"); // KeystoneAffix.db2 - PrepareStatement(HotfixStatements.SEL_KEYSTONE_AFFIX, "SELECT Name, Description, ID, FiledataID FROM keystone_affix"); - PrepareStatement(HotfixStatements.SEL_KEYSTONE_AFFIX_LOCALE, "SELECT ID, Name_lang, Description_lang FROM keystone_affix_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_KEYSTONE_AFFIX, "SELECT Name, Description, ID, FiledataID FROM keystone_affix WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_KEYSTONE_AFFIX_LOCALE, "SELECT ID, Name_lang, Description_lang FROM keystone_affix_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // LanguageWords.db2 - PrepareStatement(HotfixStatements.SEL_LANGUAGE_WORDS, "SELECT ID, Word, LanguageID FROM language_words"); + PrepareStatement(HotfixStatements.SEL_LANGUAGE_WORDS, "SELECT ID, Word, LanguageID FROM language_words WHERE (`VerifiedBuild` > 0) = ?"); // Languages.db2 - PrepareStatement(HotfixStatements.SEL_LANGUAGES, "SELECT ID, Name, Flags, UiTextureKitID, UiTextureKitElementCount FROM languages"); - PrepareStatement(HotfixStatements.SEL_LANGUAGES_LOCALE, "SELECT ID, Name_lang FROM languages_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_LANGUAGES, "SELECT ID, Name, Flags, UiTextureKitID, UiTextureKitElementCount FROM languages" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_LANGUAGES_LOCALE, "SELECT ID, Name_lang FROM languages_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // LfgDungeons.db2 PrepareStatement(HotfixStatements.SEL_LFG_DUNGEONS, "SELECT ID, Name, Description, TypeID, Subtype, Faction, IconTextureFileID, RewardsBgTextureFileID, " + "PopupBgTextureFileID, ExpansionLevel, MapID, DifficultyID, MinGear, GroupID, OrderIndex, RequiredPlayerConditionId, RandomID, ScenarioID, " + "FinalEncounterID, CountTank, CountHealer, CountDamage, MinCountTank, MinCountHealer, MinCountDamage, BonusReputationAmount, MentorItemLevel, " + - "MentorCharLevel, ContentTuningID, Flags1, Flags2 FROM lfg_dungeons"); - PrepareStatement(HotfixStatements.SEL_LFG_DUNGEONS_LOCALE, "SELECT ID, Name_lang, Description_lang FROM lfg_dungeons_locale WHERE locale = ?"); + "MentorCharLevel, ContentTuningID, Flags1, Flags2 FROM lfg_dungeons WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_LFG_DUNGEONS_LOCALE, "SELECT ID, Name_lang, Description_lang FROM lfg_dungeons_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // Light.db2 PrepareStatement(HotfixStatements.SEL_LIGHT, "SELECT ID, GameCoordsX, GameCoordsY, GameCoordsZ, GameFalloffStart, GameFalloffEnd, ContinentID, " + - "LightParamsID1, LightParamsID2, LightParamsID3, LightParamsID4, LightParamsID5, LightParamsID6, LightParamsID7, LightParamsID8 FROM light"); + "LightParamsID1, LightParamsID2, LightParamsID3, LightParamsID4, LightParamsID5, LightParamsID6, LightParamsID7, LightParamsID8 FROM light" + + " WHERE (`VerifiedBuild` > 0) = ?"); // LiquidType.db2 PrepareStatement(HotfixStatements.SEL_LIQUID_TYPE, "SELECT ID, Name, Texture1, Texture2, Texture3, Texture4, Texture5, Texture6, Flags, SoundBank, SoundID, " + @@ -767,89 +865,100 @@ namespace Framework.Database "ParticleTexSlots, MaterialID, MinimapStaticCol, FrameCountTexture1, FrameCountTexture2, FrameCountTexture3, FrameCountTexture4, " + "FrameCountTexture5, FrameCountTexture6, Color1, Color2, Float1, Float2, Float3, `Float4`, Float5, Float6, Float7, `Float8`, Float9, Float10, " + "Float11, Float12, Float13, Float14, Float15, Float16, Float17, Float18, `Int1`, `Int2`, `Int3`, `Int4`, Coefficient1, Coefficient2, " + - "Coefficient3, Coefficient4 FROM liquid_type"); + "Coefficient3, Coefficient4 FROM liquid_type WHERE (`VerifiedBuild` > 0) = ?"); // Lock.db2 - PrepareStatement(HotfixStatements.SEL_LOCK, "SELECT ID, Flags, Index1, Index2, Index3, Index4, Index5, Index6, Index7, Index8, Skill1, Skill2, Skill3, Skill4, " + - "Skill5, Skill6, Skill7, Skill8, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Action1, Action2, Action3, Action4, Action5, " + - "Action6, Action7, Action8 FROM `lock`"); + PrepareStatement(HotfixStatements.SEL_LOCK, "SELECT ID, Flags, Index1, Index2, Index3, Index4, Index5, Index6, Index7, Index8, Skill1, Skill2, Skill3, " + + "Skill4, Skill5, Skill6, Skill7, Skill8, Type1, Type2, Type3, Type4, Type5, Type6, Type7, Type8, Action1, Action2, Action3, Action4, Action5, " + + "Action6, Action7, Action8 FROM `lock` WHERE (`VerifiedBuild` > 0) = ?"); // MailTemplate.db2 - PrepareStatement(HotfixStatements.SEL_MAIL_TEMPLATE, "SELECT ID, Body FROM mail_template"); - PrepareStatement(HotfixStatements.SEL_MAIL_TEMPLATE_LOCALE, "SELECT ID, Body_lang FROM mail_template_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_MAIL_TEMPLATE, "SELECT ID, Body FROM mail_template WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_MAIL_TEMPLATE_LOCALE, "SELECT ID, Body_lang FROM mail_template_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // Map.db2 PrepareStatement(HotfixStatements.SEL_MAP, "SELECT ID, Directory, MapName, MapDescription0, MapDescription1, PvpShortDescription, PvpLongDescription, " + "CorpseX, CorpseY, MapType, InstanceType, ExpansionID, AreaTableID, LoadingScreenID, TimeOfDayOverride, ParentMapID, CosmeticParentMapID, " + - "TimeOffset, MinimapIconScale, CorpseMapID, MaxPlayers, WindSettingsID, ZmpFileDataID, WdtFileDataID, NavigationMaxDistance, Flags1, Flags2, Flags3 FROM map"); + "TimeOffset, MinimapIconScale, CorpseMapID, MaxPlayers, WindSettingsID, ZmpFileDataID, WdtFileDataID, NavigationMaxDistance, Flags1, Flags2, " + + "Flags3 FROM map WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_MAP_LOCALE, "SELECT ID, MapName_lang, MapDescription0_lang, MapDescription1_lang, PvpShortDescription_lang, " + - "PvpLongDescription_lang FROM map_locale WHERE locale = ?"); + "PvpLongDescription_lang FROM map_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // MapChallengeMode.db2 - PrepareStatement(HotfixStatements.SEL_MAP_CHALLENGE_MODE, "SELECT Name, ID, MapID, Flags, ExpansionLevel, RequiredWorldStateID, CriteriaCount1, CriteriaCount2, CriteriaCount3 FROM map_challenge_mode"); - PrepareStatement(HotfixStatements.SEL_MAP_CHALLENGE_MODE_LOCALE, "SELECT ID, Name_lang FROM map_challenge_mode_locale WHERe locale = ?"); + PrepareStatement(HotfixStatements.SEL_MAP_CHALLENGE_MODE, "SELECT Name, ID, MapID, Flags, ExpansionLevel, RequiredWorldStateID, CriteriaCount1, " + + "CriteriaCount2, CriteriaCount3 FROM map_challenge_mode WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_MAP_CHALLENGE_MODE_LOCALE, "SELECT ID, Name_lang FROM map_challenge_mode_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // MapDifficulty.db2 PrepareStatement(HotfixStatements.SEL_MAP_DIFFICULTY, "SELECT ID, Message, DifficultyID, LockID, ResetInterval, MaxPlayers, ItemContext, " + - "ItemContextPickerID, Flags, ContentTuningID, MapID FROM map_difficulty"); - PrepareStatement(HotfixStatements.SEL_MAP_DIFFICULTY_LOCALE, "SELECT ID, Message_lang FROM map_difficulty_locale WHERE locale = ?"); + "ItemContextPickerID, Flags, ContentTuningID, MapID FROM map_difficulty WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_MAP_DIFFICULTY_LOCALE, "SELECT ID, Message_lang FROM map_difficulty_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // MapDifficultyXCondition.db2 PrepareStatement(HotfixStatements.SEL_MAP_DIFFICULTY_X_CONDITION, "SELECT ID, FailureDescription, PlayerConditionID, OrderIndex, MapDifficultyID" + - " FROM map_difficulty_x_condition"); - PrepareStatement(HotfixStatements.SEL_MAP_DIFFICULTY_X_CONDITION_LOCALE, "SELECT ID, FailureDescription_lang FROM map_difficulty_x_condition_locale WHERE locale = ?"); + " FROM map_difficulty_x_condition WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_MAP_DIFFICULTY_X_CONDITION_LOCALE, "SELECT ID, FailureDescription_lang FROM map_difficulty_x_condition_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // MawPower.db2 - PrepareStatement(HotfixStatements.SEL_MAW_POWER, "SELECT ID, SpellID, MawPowerRarityID FROM maw_power"); + PrepareStatement(HotfixStatements.SEL_MAW_POWER, "SELECT ID, SpellID, MawPowerRarityID FROM maw_power WHERE (`VerifiedBuild` > 0) = ?"); // ModifierTree.db2 - PrepareStatement(HotfixStatements.SEL_MODIFIER_TREE, "SELECT ID, Parent, Operator, Amount, Type, Asset, SecondaryAsset, TertiaryAsset FROM modifier_tree"); + PrepareStatement(HotfixStatements.SEL_MODIFIER_TREE, "SELECT ID, Parent, Operator, Amount, Type, Asset, SecondaryAsset, TertiaryAsset FROM modifier_tree" + + " WHERE (`VerifiedBuild` > 0) = ?"); // Mount.db2 PrepareStatement(HotfixStatements.SEL_MOUNT, "SELECT Name, SourceText, Description, ID, MountTypeID, Flags, SourceTypeEnum, SourceSpellID, " + - "PlayerConditionID, MountFlyRideHeight, UiModelSceneID, MountSpecialRiderAnimKitID, MountSpecialSpellVisualKitID FROM mount"); - PrepareStatement(HotfixStatements.SEL_MOUNT_LOCALE, "SELECT ID, Name_lang, SourceText_lang, Description_lang FROM mount_locale WHERE locale = ?"); + "PlayerConditionID, MountFlyRideHeight, UiModelSceneID, MountSpecialRiderAnimKitID, MountSpecialSpellVisualKitID FROM mount" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_MOUNT_LOCALE, "SELECT ID, Name_lang, SourceText_lang, Description_lang FROM mount_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // MountCapability.db2 PrepareStatement(HotfixStatements.SEL_MOUNT_CAPABILITY, "SELECT ID, Flags, ReqRidingSkill, ReqAreaID, ReqSpellAuraID, ReqSpellKnownID, ModSpellAuraID, " + - "ReqMapID, PlayerConditionID, FlightCapabilityID FROM mount_capability"); + "ReqMapID, PlayerConditionID, FlightCapabilityID FROM mount_capability WHERE (`VerifiedBuild` > 0) = ?"); // MountTypeXCapability.db2 - PrepareStatement(HotfixStatements.SEL_MOUNT_TYPE_X_CAPABILITY, "SELECT ID, MountTypeID, MountCapabilityID, OrderIndex FROM mount_type_x_capability"); + PrepareStatement(HotfixStatements.SEL_MOUNT_TYPE_X_CAPABILITY, "SELECT ID, MountTypeID, MountCapabilityID, OrderIndex FROM mount_type_x_capability" + + " WHERE (`VerifiedBuild` > 0) = ?"); // MountXDisplay.db2 - PrepareStatement(HotfixStatements.SEL_MOUNT_X_DISPLAY, "SELECT ID, CreatureDisplayInfoID, PlayerConditionID, MountID FROM mount_x_display"); + PrepareStatement(HotfixStatements.SEL_MOUNT_X_DISPLAY, "SELECT ID, CreatureDisplayInfoID, PlayerConditionID, MountID FROM mount_x_display" + + " WHERE (`VerifiedBuild` > 0) = ?"); // Movie.db2 - PrepareStatement(HotfixStatements.SEL_MOVIE, "SELECT ID, Volume, KeyID, AudioFileDataID, SubtitleFileDataID FROM movie"); + PrepareStatement(HotfixStatements.SEL_MOVIE, "SELECT ID, Volume, KeyID, AudioFileDataID, SubtitleFileDataID FROM movie WHERE (`VerifiedBuild` > 0) = ?"); // NameGen.db2 - PrepareStatement(HotfixStatements.SEL_NAME_GEN, "SELECT ID, Name, RaceID, Sex FROM name_gen"); + PrepareStatement(HotfixStatements.SEL_NAME_GEN, "SELECT ID, Name, RaceID, Sex FROM name_gen WHERE (`VerifiedBuild` > 0) = ?"); // NamesProfanity.db2 - PrepareStatement(HotfixStatements.SEL_NAMES_PROFANITY, "SELECT ID, Name, Language FROM names_profanity"); + PrepareStatement(HotfixStatements.SEL_NAMES_PROFANITY, "SELECT ID, Name, Language FROM names_profanity WHERE (`VerifiedBuild` > 0) = ?"); // NamesReserved.db2 - PrepareStatement(HotfixStatements.SEL_NAMES_RESERVED, "SELECT ID, Name FROM names_reserved"); + PrepareStatement(HotfixStatements.SEL_NAMES_RESERVED, "SELECT ID, Name FROM names_reserved WHERE (`VerifiedBuild` > 0) = ?"); // NamesReservedLocale.db2 - PrepareStatement(HotfixStatements.SEL_NAMES_RESERVED_LOCALE, "SELECT ID, Name, LocaleMask FROM names_reserved_locale"); + PrepareStatement(HotfixStatements.SEL_NAMES_RESERVED_LOCALE, "SELECT ID, Name, LocaleMask FROM names_reserved_locale WHERE (`VerifiedBuild` > 0) = ?"); // NumTalentsAtLevel.db2 - PrepareStatement(HotfixStatements.SEL_NUM_TALENTS_AT_LEVEL, "SELECT ID, NumTalents, NumTalentsDeathKnight, NumTalentsDemonHunter FROM num_talents_at_level"); + PrepareStatement(HotfixStatements.SEL_NUM_TALENTS_AT_LEVEL, "SELECT ID, NumTalents, NumTalentsDeathKnight, NumTalentsDemonHunter FROM num_talents_at_level" + + " WHERE (`VerifiedBuild` > 0) = ?"); // OverrideSpellData.db2 PrepareStatement(HotfixStatements.SEL_OVERRIDE_SPELL_DATA, "SELECT ID, Spells1, Spells2, Spells3, Spells4, Spells5, Spells6, Spells7, Spells8, Spells9, " + - "Spells10, PlayerActionBarFileDataID, Flags FROM override_spell_data"); + "Spells10, PlayerActionBarFileDataID, Flags FROM override_spell_data WHERE (`VerifiedBuild` > 0) = ?"); // ParagonReputation.db2 - PrepareStatement(HotfixStatements.SEL_PARAGON_REPUTATION, "SELECT ID, FactionID, LevelThreshold, QuestID FROM paragon_reputation"); + PrepareStatement(HotfixStatements.SEL_PARAGON_REPUTATION, "SELECT ID, FactionID, LevelThreshold, QuestID FROM paragon_reputation" + + " WHERE (`VerifiedBuild` > 0) = ?"); // Phase.db2 - PrepareStatement(HotfixStatements.SEL_PHASE, "SELECT ID, Flags FROM phase"); + PrepareStatement(HotfixStatements.SEL_PHASE, "SELECT ID, Flags FROM phase WHERE (`VerifiedBuild` > 0) = ?"); // PhaseXPhaseGroup.db2 - PrepareStatement(HotfixStatements.SEL_PHASE_X_PHASE_GROUP, "SELECT ID, PhaseID, PhaseGroupID FROM phase_x_phase_group"); + PrepareStatement(HotfixStatements.SEL_PHASE_X_PHASE_GROUP, "SELECT ID, PhaseID, PhaseGroupID FROM phase_x_phase_group WHERE (`VerifiedBuild` > 0) = ?"); // PlayerCondition.db2 PrepareStatement(HotfixStatements.SEL_PLAYER_CONDITION, "SELECT ID, RaceMask, FailureDescription, ClassMask, SkillLogic, LanguageID, MinLanguage, " + @@ -870,176 +979,194 @@ namespace Framework.Database "QuestKillMonster1, QuestKillMonster2, QuestKillMonster3, QuestKillMonster4, QuestKillMonster5, QuestKillMonster6, MovementFlags1, " + "MovementFlags2, TraitNodeEntryID1, TraitNodeEntryID2, TraitNodeEntryID3, TraitNodeEntryID4, TraitNodeEntryMinRank1, TraitNodeEntryMinRank2, " + "TraitNodeEntryMinRank3, TraitNodeEntryMinRank4, TraitNodeEntryMaxRank1, TraitNodeEntryMaxRank2, TraitNodeEntryMaxRank3, " + - "TraitNodeEntryMaxRank4 FROM player_condition"); - PrepareStatement(HotfixStatements.SEL_PLAYER_CONDITION_LOCALE, "SELECT ID, FailureDescription_lang FROM player_condition_locale WHERE locale = ?"); + "TraitNodeEntryMaxRank4 FROM player_condition WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_PLAYER_CONDITION_LOCALE, "SELECT ID, FailureDescription_lang FROM player_condition_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // PowerDisplay.db2 - PrepareStatement(HotfixStatements.SEL_POWER_DISPLAY, "SELECT ID, GlobalStringBaseTag, ActualType, Red, Green, Blue FROM power_display"); + PrepareStatement(HotfixStatements.SEL_POWER_DISPLAY, "SELECT ID, GlobalStringBaseTag, ActualType, Red, Green, Blue FROM power_display" + + " WHERE (`VerifiedBuild` > 0) = ?"); // PowerType.db2 PrepareStatement(HotfixStatements.SEL_POWER_TYPE, "SELECT NameGlobalStringTag, CostGlobalStringTag, ID, PowerTypeEnum, MinPower, MaxBasePower, CenterPower, " + - "DefaultPower, DisplayModifier, RegenInterruptTimeMS, RegenPeace, RegenCombat, Flags FROM power_type"); + "DefaultPower, DisplayModifier, RegenInterruptTimeMS, RegenPeace, RegenCombat, Flags FROM power_type WHERE (`VerifiedBuild` > 0) = ?"); // PrestigeLevelInfo.db2 PrepareStatement(HotfixStatements.SEL_PRESTIGE_LEVEL_INFO, "SELECT ID, Name, PrestigeLevel, BadgeTextureFileDataID, Flags, AwardedAchievementID" + - " FROM prestige_level_info"); - PrepareStatement(HotfixStatements.SEL_PRESTIGE_LEVEL_INFO_LOCALE, "SELECT ID, Name_lang FROM prestige_level_info_locale WHERE locale = ?"); + " FROM prestige_level_info WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_PRESTIGE_LEVEL_INFO_LOCALE, "SELECT ID, Name_lang FROM prestige_level_info_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // PvpDifficulty.db2 - PrepareStatement(HotfixStatements.SEL_PVP_DIFFICULTY, "SELECT ID, RangeIndex, MinLevel, MaxLevel, MapID FROM pvp_difficulty"); + PrepareStatement(HotfixStatements.SEL_PVP_DIFFICULTY, "SELECT ID, RangeIndex, MinLevel, MaxLevel, MapID FROM pvp_difficulty WHERE (`VerifiedBuild` > 0) = ?"); // PvpItem.db2 - PrepareStatement(HotfixStatements.SEL_PVP_ITEM, "SELECT ID, ItemID, ItemLevelDelta FROM pvp_item"); + PrepareStatement(HotfixStatements.SEL_PVP_ITEM, "SELECT ID, ItemID, ItemLevelDelta FROM pvp_item WHERE (`VerifiedBuild` > 0) = ?"); // PvpTalent.db2 PrepareStatement(HotfixStatements.SEL_PVP_TALENT, "SELECT Description, ID, SpecID, SpellID, OverridesSpellID, Flags, ActionBarSpellID, PvpTalentCategoryID, " + - "LevelRequired, PlayerConditionID FROM pvp_talent"); - PrepareStatement(HotfixStatements.SEL_PVP_TALENT_LOCALE, "SELECT ID, Description_lang FROM pvp_talent_locale WHERE locale = ?"); + "LevelRequired, PlayerConditionID FROM pvp_talent WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_PVP_TALENT_LOCALE, "SELECT ID, Description_lang FROM pvp_talent_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // PvpTalentCategory.db2 - PrepareStatement(HotfixStatements.SEL_PVP_TALENT_CATEGORY, "SELECT ID, TalentSlotMask FROM pvp_talent_category"); + PrepareStatement(HotfixStatements.SEL_PVP_TALENT_CATEGORY, "SELECT ID, TalentSlotMask FROM pvp_talent_category WHERE (`VerifiedBuild` > 0) = ?"); // PvpTalentSlotUnlock.db2 PrepareStatement(HotfixStatements.SEL_PVP_TALENT_SLOT_UNLOCK, "SELECT ID, Slot, LevelRequired, DeathKnightLevelRequired, DemonHunterLevelRequired" + - " FROM pvp_talent_slot_unlock"); + " FROM pvp_talent_slot_unlock WHERE (`VerifiedBuild` > 0) = ?"); // PvpTier.db2 - PrepareStatement(HotfixStatements.SEL_PVP_TIER, "SELECT Name, ID, MinRating, MaxRating, PrevTier, NextTier, BracketID, `Rank`, RankIconFileDataID FROM pvp_tier"); - PrepareStatement(HotfixStatements.SEL_PVP_TIER_LOCALE, "SELECT ID, Name_lang FROM pvp_tier_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_PVP_TIER, "SELECT Name, ID, MinRating, MaxRating, PrevTier, NextTier, BracketID, `Rank`, RankIconFileDataID" + + " FROM pvp_tier WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_PVP_TIER_LOCALE, "SELECT ID, Name_lang FROM pvp_tier_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // QuestFactionReward.db2 PrepareStatement(HotfixStatements.SEL_QUEST_FACTION_REWARD, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, " + - "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_faction_reward"); + "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_faction_reward WHERE (`VerifiedBuild` > 0) = ?"); // QuestInfo.db2 - PrepareStatement(HotfixStatements.SEL_QUEST_INFO, "SELECT ID, InfoName, Type, Modifiers, Profession FROM quest_info"); - PrepareStatement(HotfixStatements.SEL_QUEST_INFO_LOCALE, "SELECT ID, InfoName_lang FROM quest_info_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_QUEST_INFO, "SELECT ID, InfoName, Type, Modifiers, Profession FROM quest_info WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_QUEST_INFO_LOCALE, "SELECT ID, InfoName_lang FROM quest_info_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // QuestLineXQuest.db2 - PrepareStatement(HotfixStatements.SEL_QUEST_LINE_X_QUEST, "SELECT ID, QuestLineID, QuestID, OrderIndex, Flags FROM quest_line_x_quest"); + PrepareStatement(HotfixStatements.SEL_QUEST_LINE_X_QUEST, "SELECT ID, QuestLineID, QuestID, OrderIndex, Flags FROM quest_line_x_quest" + + " WHERE (`VerifiedBuild` > 0) = ?"); // QuestMoneyReward.db2 PrepareStatement(HotfixStatements.SEL_QUEST_MONEY_REWARD, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, " + - "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_money_reward"); + "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM quest_money_reward WHERE (`VerifiedBuild` > 0) = ?"); // QuestPackageItem.db2 - PrepareStatement(HotfixStatements.SEL_QUEST_PACKAGE_ITEM, "SELECT ID, PackageID, ItemID, ItemQuantity, DisplayType FROM quest_package_item"); + PrepareStatement(HotfixStatements.SEL_QUEST_PACKAGE_ITEM, "SELECT ID, PackageID, ItemID, ItemQuantity, DisplayType FROM quest_package_item" + + " WHERE (`VerifiedBuild` > 0) = ?"); // QuestSort.db2 - PrepareStatement(HotfixStatements.SEL_QUEST_SORT, "SELECT ID, SortName, UiOrderIndex FROM quest_sort"); - PrepareStatement(HotfixStatements.SEL_QUEST_SORT_LOCALE, "SELECT ID, SortName_lang FROM quest_sort_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_QUEST_SORT, "SELECT ID, SortName, UiOrderIndex FROM quest_sort WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_QUEST_SORT_LOCALE, "SELECT ID, SortName_lang FROM quest_sort_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // QuestV2.db2 - PrepareStatement(HotfixStatements.SEL_QUEST_V2, "SELECT ID, UniqueBitFlag, UiQuestDetailsTheme FROM quest_v2"); + PrepareStatement(HotfixStatements.SEL_QUEST_V2, "SELECT ID, UniqueBitFlag, UiQuestDetailsTheme FROM quest_v2 WHERE (`VerifiedBuild` > 0) = ?"); // QuestXp.db2 PrepareStatement(HotfixStatements.SEL_QUEST_XP, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, Difficulty7, " + - "Difficulty8, Difficulty9, Difficulty10 FROM quest_xp"); + "Difficulty8, Difficulty9, Difficulty10 FROM quest_xp WHERE (`VerifiedBuild` > 0) = ?"); // RandPropPoints.db2 PrepareStatement(HotfixStatements.SEL_RAND_PROP_POINTS, "SELECT ID, DamageReplaceStatF, DamageSecondaryF, DamageReplaceStat, DamageSecondary, EpicF1, " + "EpicF2, EpicF3, EpicF4, EpicF5, SuperiorF1, SuperiorF2, SuperiorF3, SuperiorF4, SuperiorF5, GoodF1, GoodF2, GoodF3, GoodF4, GoodF5, Epic1, " + - "Epic2, Epic3, Epic4, Epic5, Superior1, Superior2, Superior3, Superior4, Superior5, Good1, Good2, Good3, Good4, Good5 FROM rand_prop_points"); + "Epic2, Epic3, Epic4, Epic5, Superior1, Superior2, Superior3, Superior4, Superior5, Good1, Good2, Good3, Good4, Good5 FROM rand_prop_points" + + " WHERE (`VerifiedBuild` > 0) = ?"); // RewardPack.db2 PrepareStatement(HotfixStatements.SEL_REWARD_PACK, "SELECT ID, CharTitleID, Money, ArtifactXPDifficulty, ArtifactXPMultiplier, ArtifactXPCategoryID, " + - "TreasurePickerID FROM reward_pack"); + "TreasurePickerID FROM reward_pack WHERE (`VerifiedBuild` > 0) = ?"); // RewardPackXCurrencyType.db2 - PrepareStatement(HotfixStatements.SEL_REWARD_PACK_X_CURRENCY_TYPE, "SELECT ID, CurrencyTypeID, Quantity, RewardPackID FROM reward_pack_x_currency_type"); + PrepareStatement(HotfixStatements.SEL_REWARD_PACK_X_CURRENCY_TYPE, "SELECT ID, CurrencyTypeID, Quantity, RewardPackID FROM reward_pack_x_currency_type" + + " WHERE (`VerifiedBuild` > 0) = ?"); // RewardPackXItem.db2 - PrepareStatement(HotfixStatements.SEL_REWARD_PACK_X_ITEM, "SELECT ID, ItemID, ItemQuantity, RewardPackID FROM reward_pack_x_item"); + PrepareStatement(HotfixStatements.SEL_REWARD_PACK_X_ITEM, "SELECT ID, ItemID, ItemQuantity, RewardPackID FROM reward_pack_x_item" + + " WHERE (`VerifiedBuild` > 0) = ?"); // Scenario.db2 - PrepareStatement(HotfixStatements.SEL_SCENARIO, "SELECT ID, Name, AreaTableID, Type, Flags, UiTextureKitID FROM scenario"); - PrepareStatement(HotfixStatements.SEL_SCENARIO_LOCALE, "SELECT ID, Name_lang FROM scenario_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_SCENARIO, "SELECT ID, Name, AreaTableID, Type, Flags, UiTextureKitID FROM scenario WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SCENARIO_LOCALE, "SELECT ID, Name_lang FROM scenario_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // ScenarioStep.db2 PrepareStatement(HotfixStatements.SEL_SCENARIO_STEP, "SELECT ID, Description, Title, ScenarioID, Criteriatreeid, RewardQuestID, RelatedStep, Supersedes, " + - "OrderIndex, Flags, VisibilityPlayerConditionID, WidgetSetID FROM scenario_step"); - PrepareStatement(HotfixStatements.SEL_SCENARIO_STEP_LOCALE, "SELECT ID, Description_lang, Title_lang FROM scenario_step_locale WHERE locale = ?"); + "OrderIndex, Flags, VisibilityPlayerConditionID, WidgetSetID FROM scenario_step WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SCENARIO_STEP_LOCALE, "SELECT ID, Description_lang, Title_lang FROM scenario_step_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // SceneScript.db2 - PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT, "SELECT ID, FirstSceneScriptID, NextSceneScriptID, Unknown915 FROM scene_script"); + PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT, "SELECT ID, FirstSceneScriptID, NextSceneScriptID, Unknown915 FROM scene_script" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SceneScriptGlobalText.db2 - PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT_GLOBAL_TEXT, "SELECT ID, Name, Script FROM scene_script_global_text"); + PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT_GLOBAL_TEXT, "SELECT ID, Name, Script FROM scene_script_global_text WHERE (`VerifiedBuild` > 0) = ?"); // SceneScriptPackage.db2 - PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT_PACKAGE, "SELECT ID, Name, Unknown915 FROM scene_script_package"); + PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT_PACKAGE, "SELECT ID, Name, Unknown915 FROM scene_script_package WHERE (`VerifiedBuild` > 0) = ?"); // SceneScriptText.db2 - PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT_TEXT, "SELECT ID, Name, Script FROM scene_script_text"); + PrepareStatement(HotfixStatements.SEL_SCENE_SCRIPT_TEXT, "SELECT ID, Name, Script FROM scene_script_text WHERE (`VerifiedBuild` > 0) = ?"); // SkillLine.db2 PrepareStatement(HotfixStatements.SEL_SKILL_LINE, "SELECT DisplayName, AlternateVerb, Description, HordeDisplayName, OverrideSourceInfoDisplayName, ID, " + "CategoryID, SpellIconFileID, CanLink, ParentSkillLineID, ParentTierIndex, Flags, SpellBookSpellID, ExpansionNameSharedStringID, " + - "HordeExpansionNameSharedStringID FROM skill_line"); + "HordeExpansionNameSharedStringID FROM skill_line WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_SKILL_LINE_LOCALE, "SELECT ID, DisplayName_lang, AlternateVerb_lang, Description_lang, HordeDisplayName_lang" + - " FROM skill_line_locale WHERE locale = ?"); + " FROM skill_line_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // SkillLineAbility.db2 PrepareStatement(HotfixStatements.SEL_SKILL_LINE_ABILITY, "SELECT RaceMask, AbilityVerb, AbilityAllVerb, ID, SkillLine, Spell, MinSkillLineRank, ClassMask, " + "SupercedesSpell, AcquireMethod, TrivialSkillLineRankHigh, TrivialSkillLineRankLow, Flags, NumSkillUps, UniqueBit, TradeSkillCategoryID, " + - "SkillupSkillLineID FROM skill_line_ability"); + "SkillupSkillLineID FROM skill_line_ability WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_SKILL_LINE_ABILITY_LOCALE, "SELECT ID, AbilityVerb_lang, AbilityAllVerb_lang FROM skill_line_ability_locale" + - " WHERE locale = ?"); + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); + + // SkillLineXTraitTree.db2 + PrepareStatement(HotfixStatements.SEL_SKILL_LINE_X_TRAIT_TREE, "SELECT ID, SkillLineID, TraitTreeID, OrderIndex FROM skill_line_x_trait_tree" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SkillRaceClassInfo.db2 PrepareStatement(HotfixStatements.SEL_SKILL_RACE_CLASS_INFO, "SELECT ID, RaceMask, SkillID, ClassMask, Flags, Availability, MinLevel, SkillTierID" + - " FROM skill_race_class_info"); + " FROM skill_race_class_info WHERE (`VerifiedBuild` > 0) = ?"); // SoulbindConduitRank.db2 - PrepareStatement(HotfixStatements.SEL_SOULBIND_CONDUIT_RANK, "SELECT ID, RankIndex, SpellID, AuraPointsOverride, SoulbindConduitID FROM soulbind_conduit_rank"); + PrepareStatement(HotfixStatements.SEL_SOULBIND_CONDUIT_RANK, "SELECT ID, RankIndex, SpellID, AuraPointsOverride, SoulbindConduitID" + + " FROM soulbind_conduit_rank WHERE (`VerifiedBuild` > 0) = ?"); // SoundKit.db2 PrepareStatement(HotfixStatements.SEL_SOUND_KIT, "SELECT ID, SoundType, VolumeFloat, Flags, MinDistance, DistanceCutoff, EAXDef, SoundKitAdvancedID, " + "VolumeVariationPlus, VolumeVariationMinus, PitchVariationPlus, PitchVariationMinus, DialogType, PitchAdjust, BusOverwriteID, MaxInstances, " + - "SoundMixGroupID FROM sound_kit"); + "SoundMixGroupID FROM sound_kit WHERE (`VerifiedBuild` > 0) = ?"); // SpecializationSpells.db2 PrepareStatement(HotfixStatements.SEL_SPECIALIZATION_SPELLS, "SELECT Description, ID, SpecID, SpellID, OverridesSpellID, DisplayOrder" + - " FROM specialization_spells"); - PrepareStatement(HotfixStatements.SEL_SPECIALIZATION_SPELLS_LOCALE, "SELECT ID, Description_lang FROM specialization_spells_locale WHERE locale = ?"); + " FROM specialization_spells WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SPECIALIZATION_SPELLS_LOCALE, "SELECT ID, Description_lang FROM specialization_spells_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // SpecSetMember.db2 - PrepareStatement(HotfixStatements.SEL_SPEC_SET_MEMBER, "SELECT ID, ChrSpecializationID, SpecSetID FROM spec_set_member"); + PrepareStatement(HotfixStatements.SEL_SPEC_SET_MEMBER, "SELECT ID, ChrSpecializationID, SpecSetID FROM spec_set_member WHERE (`VerifiedBuild` > 0) = ?"); // SpellAuraOptions.db2 PrepareStatement(HotfixStatements.SEL_SPELL_AURA_OPTIONS, "SELECT ID, DifficultyID, CumulativeAura, ProcCategoryRecovery, ProcChance, ProcCharges, " + - "SpellProcsPerMinuteID, ProcTypeMask1, ProcTypeMask2, SpellID FROM spell_aura_options"); + "SpellProcsPerMinuteID, ProcTypeMask1, ProcTypeMask2, SpellID FROM spell_aura_options WHERE (`VerifiedBuild` > 0) = ?"); // SpellAuraRestrictions.db2 PrepareStatement(HotfixStatements.SEL_SPELL_AURA_RESTRICTIONS, "SELECT ID, DifficultyID, CasterAuraState, TargetAuraState, ExcludeCasterAuraState, " + "ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CasterAuraType, TargetAuraType, " + - "ExcludeCasterAuraType, ExcludeTargetAuraType, SpellID FROM spell_aura_restrictions"); + "ExcludeCasterAuraType, ExcludeTargetAuraType, SpellID FROM spell_aura_restrictions WHERE (`VerifiedBuild` > 0) = ?"); // SpellCastTimes.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_CAST_TIMES, "SELECT ID, Base, Minimum FROM spell_cast_times"); + PrepareStatement(HotfixStatements.SEL_SPELL_CAST_TIMES, "SELECT ID, Base, Minimum FROM spell_cast_times WHERE (`VerifiedBuild` > 0) = ?"); // SpellCastingRequirements.db2 PrepareStatement(HotfixStatements.SEL_SPELL_CASTING_REQUIREMENTS, "SELECT ID, SpellID, FacingCasterFlags, MinFactionID, MinReputation, RequiredAreasID, " + - "RequiredAuraVision, RequiresSpellFocus FROM spell_casting_requirements"); + "RequiredAuraVision, RequiresSpellFocus FROM spell_casting_requirements WHERE (`VerifiedBuild` > 0) = ?"); // SpellCategories.db2 PrepareStatement(HotfixStatements.SEL_SPELL_CATEGORIES, "SELECT ID, DifficultyID, Category, DefenseType, DispelType, Mechanic, PreventionType, " + - "StartRecoveryCategory, ChargeCategory, SpellID FROM spell_categories"); + "StartRecoveryCategory, ChargeCategory, SpellID FROM spell_categories WHERE (`VerifiedBuild` > 0) = ?"); // SpellCategory.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_CATEGORY, "SELECT ID, Name, Flags, UsesPerWeek, MaxCharges, ChargeRecoveryTime, TypeMask FROM spell_category"); - PrepareStatement(HotfixStatements.SEL_SPELL_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM spell_category_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_CATEGORY, "SELECT ID, Name, Flags, UsesPerWeek, MaxCharges, ChargeRecoveryTime, TypeMask FROM spell_category" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM spell_category_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // SpellClassOptions.db2 PrepareStatement(HotfixStatements.SEL_SPELL_CLASS_OPTIONS, "SELECT ID, SpellID, ModalNextSpell, SpellClassSet, SpellClassMask1, SpellClassMask2, " + - "SpellClassMask3, SpellClassMask4 FROM spell_class_options"); + "SpellClassMask3, SpellClassMask4 FROM spell_class_options WHERE (`VerifiedBuild` > 0) = ?"); // SpellCooldowns.db2 PrepareStatement(HotfixStatements.SEL_SPELL_COOLDOWNS, "SELECT ID, DifficultyID, CategoryRecoveryTime, RecoveryTime, StartRecoveryTime, AuraSpellID, " + - "SpellID FROM spell_cooldowns"); + "SpellID FROM spell_cooldowns WHERE (`VerifiedBuild` > 0) = ?"); // SpellDuration.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_DURATION, "SELECT ID, Duration, MaxDuration FROM spell_duration"); + PrepareStatement(HotfixStatements.SEL_SPELL_DURATION, "SELECT ID, Duration, MaxDuration FROM spell_duration WHERE (`VerifiedBuild` > 0) = ?"); // SpellEffect.db2 PrepareStatement(HotfixStatements.SEL_SPELL_EFFECT, "SELECT ID, EffectAura, DifficultyID, EffectIndex, Effect, EffectAmplitude, EffectAttributes, " + @@ -1047,224 +1174,344 @@ namespace Framework.Database "EffectPosFacing, EffectRealPointsPerLevel, EffectTriggerSpell, BonusCoefficientFromAP, PvpMultiplier, Coefficient, Variance, " + "ResourceCoefficient, GroupSizeBasePointsCoefficient, EffectBasePoints, ScalingClass, EffectMiscValue1, EffectMiscValue2, EffectRadiusIndex1, " + "EffectRadiusIndex2, EffectSpellClassMask1, EffectSpellClassMask2, EffectSpellClassMask3, EffectSpellClassMask4, ImplicitTarget1, " + - "ImplicitTarget2, SpellID FROM spell_effect"); + "ImplicitTarget2, SpellID FROM spell_effect WHERE (`VerifiedBuild` > 0) = ?"); // SpellEquippedItems.db2 PrepareStatement(HotfixStatements.SEL_SPELL_EQUIPPED_ITEMS, "SELECT ID, SpellID, EquippedItemClass, EquippedItemInvTypes, EquippedItemSubclass" + - " FROM spell_equipped_items"); + " FROM spell_equipped_items WHERE (`VerifiedBuild` > 0) = ?"); // SpellFocusObject.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_FOCUS_OBJECT, "SELECT ID, Name FROM spell_focus_object"); - PrepareStatement(HotfixStatements.SEL_SPELL_FOCUS_OBJECT_LOCALE, "SELECT ID, Name_lang FROM spell_focus_object_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_FOCUS_OBJECT, "SELECT ID, Name FROM spell_focus_object WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_FOCUS_OBJECT_LOCALE, "SELECT ID, Name_lang FROM spell_focus_object_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // SpellInterrupts.db2 PrepareStatement(HotfixStatements.SEL_SPELL_INTERRUPTS, "SELECT ID, DifficultyID, InterruptFlags, AuraInterruptFlags1, AuraInterruptFlags2, " + - "ChannelInterruptFlags1, ChannelInterruptFlags2, SpellID FROM spell_interrupts"); + "ChannelInterruptFlags1, ChannelInterruptFlags2, SpellID FROM spell_interrupts WHERE (`VerifiedBuild` > 0) = ?"); // SpellItemEnchantment.db2 PrepareStatement(HotfixStatements.SEL_SPELL_ITEM_ENCHANTMENT, "SELECT ID, Name, HordeName, Duration, EffectArg1, EffectArg2, EffectArg3, " + "EffectScalingPoints1, EffectScalingPoints2, EffectScalingPoints3, IconFileDataID, MinItemLevel, MaxItemLevel, TransmogUseConditionID, " + "TransmogCost, EffectPointsMin1, EffectPointsMin2, EffectPointsMin3, ItemVisual, Flags, RequiredSkillID, RequiredSkillRank, ItemLevel, " + - "Charges, Effect1, Effect2, Effect3, ScalingClass, ScalingClassRestricted, ConditionID, MinLevel, MaxLevel FROM spell_item_enchantment"); - PrepareStatement(HotfixStatements.SEL_SPELL_ITEM_ENCHANTMENT_LOCALE, "SELECT ID, Name_lang, HordeName_lang FROM spell_item_enchantment_locale WHERE locale = ?"); + "Charges, Effect1, Effect2, Effect3, ScalingClass, ScalingClassRestricted, ConditionID, MinLevel, MaxLevel FROM spell_item_enchantment" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_ITEM_ENCHANTMENT_LOCALE, "SELECT ID, Name_lang, HordeName_lang FROM spell_item_enchantment_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // SpellItemEnchantmentCondition.db2 PrepareStatement(HotfixStatements.SEL_SPELL_ITEM_ENCHANTMENT_CONDITION, "SELECT ID, LtOperandType1, LtOperandType2, LtOperandType3, LtOperandType4, " + "LtOperandType5, LtOperand1, LtOperand2, LtOperand3, LtOperand4, LtOperand5, Operator1, Operator2, Operator3, Operator4, Operator5, " + "RtOperandType1, RtOperandType2, RtOperandType3, RtOperandType4, RtOperandType5, RtOperand1, RtOperand2, RtOperand3, RtOperand4, RtOperand5, " + - "Logic1, Logic2, Logic3, Logic4, Logic5 FROM spell_item_enchantment_condition"); + "Logic1, Logic2, Logic3, Logic4, Logic5 FROM spell_item_enchantment_condition WHERE (`VerifiedBuild` > 0) = ?"); // SpellLabel.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_LABEL, "SELECT ID, LabelID, SpellID FROM spell_label"); + PrepareStatement(HotfixStatements.SEL_SPELL_LABEL, "SELECT ID, LabelID, SpellID FROM spell_label WHERE (`VerifiedBuild` > 0) = ?"); // SpellLearnSpell.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_LEARN_SPELL, "SELECT ID, SpellID, LearnSpellID, OverridesSpellID FROM spell_learn_spell"); + PrepareStatement(HotfixStatements.SEL_SPELL_LEARN_SPELL, "SELECT ID, SpellID, LearnSpellID, OverridesSpellID FROM spell_learn_spell" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellLevels.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_LEVELS, "SELECT ID, DifficultyID, MaxLevel, MaxPassiveAuraLevel, BaseLevel, SpellLevel, SpellID FROM spell_levels"); + PrepareStatement(HotfixStatements.SEL_SPELL_LEVELS, "SELECT ID, DifficultyID, MaxLevel, MaxPassiveAuraLevel, BaseLevel, SpellLevel, SpellID" + + " FROM spell_levels WHERE (`VerifiedBuild` > 0) = ?"); // SpellMisc.db2 PrepareStatement(HotfixStatements.SEL_SPELL_MISC, "SELECT ID, Attributes1, Attributes2, Attributes3, Attributes4, Attributes5, Attributes6, Attributes7, " + "Attributes8, Attributes9, Attributes10, Attributes11, Attributes12, Attributes13, Attributes14, Attributes15, DifficultyID, " + "CastingTimeIndex, DurationIndex, RangeIndex, SchoolMask, Speed, LaunchDelay, MinDuration, SpellIconFileDataID, ActiveIconFileDataID, " + - "ContentTuningID, ShowFutureSpellPlayerConditionID, SpellVisualScript, ActiveSpellVisualScript, SpellID FROM spell_misc"); + "ContentTuningID, ShowFutureSpellPlayerConditionID, SpellVisualScript, ActiveSpellVisualScript, SpellID FROM spell_misc" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellName.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_NAME, "SELECT ID, Name FROM spell_name"); - PrepareStatement(HotfixStatements.SEL_SPELL_NAME_LOCALE, "SELECT ID, Name_lang FROM spell_name_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_NAME, "SELECT ID, Name FROM spell_name WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_NAME_LOCALE, "SELECT ID, Name_lang FROM spell_name_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // SpellPower.db2 PrepareStatement(HotfixStatements.SEL_SPELL_POWER, "SELECT ID, OrderIndex, ManaCost, ManaCostPerLevel, ManaPerSecond, PowerDisplayID, AltPowerBarID, " + - "PowerCostPct, PowerCostMaxPct, OptionalCostPct, PowerPctPerSecond, PowerType, RequiredAuraSpellID, OptionalCost, SpellID FROM spell_power"); + "PowerCostPct, PowerCostMaxPct, OptionalCostPct, PowerPctPerSecond, PowerType, RequiredAuraSpellID, OptionalCost, SpellID FROM spell_power" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellPowerDifficulty.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_POWER_DIFFICULTY, "SELECT ID, DifficultyID, OrderIndex FROM spell_power_difficulty"); + PrepareStatement(HotfixStatements.SEL_SPELL_POWER_DIFFICULTY, "SELECT ID, DifficultyID, OrderIndex FROM spell_power_difficulty" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellProcsPerMinute.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_PROCS_PER_MINUTE, "SELECT ID, BaseProcRate, Flags FROM spell_procs_per_minute"); + PrepareStatement(HotfixStatements.SEL_SPELL_PROCS_PER_MINUTE, "SELECT ID, BaseProcRate, Flags FROM spell_procs_per_minute WHERE (`VerifiedBuild` > 0) = ?"); // SpellProcsPerMinuteMod.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_PROCS_PER_MINUTE_MOD, "SELECT ID, Type, Param, Coeff, SpellProcsPerMinuteID FROM spell_procs_per_minute_mod"); + PrepareStatement(HotfixStatements.SEL_SPELL_PROCS_PER_MINUTE_MOD, "SELECT ID, Type, Param, Coeff, SpellProcsPerMinuteID FROM spell_procs_per_minute_mod" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellRadius.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_RADIUS, "SELECT ID, Radius, RadiusPerLevel, RadiusMin, RadiusMax FROM spell_radius"); + PrepareStatement(HotfixStatements.SEL_SPELL_RADIUS, "SELECT ID, Radius, RadiusPerLevel, RadiusMin, RadiusMax FROM spell_radius" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellRange.db2 PrepareStatement(HotfixStatements.SEL_SPELL_RANGE, "SELECT ID, DisplayName, DisplayNameShort, Flags, RangeMin1, RangeMin2, RangeMax1, RangeMax2" + - " FROM spell_range"); - PrepareStatement(HotfixStatements.SEL_SPELL_RANGE_LOCALE, "SELECT ID, DisplayName_lang, DisplayNameShort_lang FROM spell_range_locale WHERE locale = ?"); + " FROM spell_range WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_RANGE_LOCALE, "SELECT ID, DisplayName_lang, DisplayNameShort_lang FROM spell_range_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // SpellReagents.db2 PrepareStatement(HotfixStatements.SEL_SPELL_REAGENTS, "SELECT ID, SpellID, Reagent1, Reagent2, Reagent3, Reagent4, Reagent5, Reagent6, Reagent7, Reagent8, " + "ReagentCount1, ReagentCount2, ReagentCount3, ReagentCount4, ReagentCount5, ReagentCount6, ReagentCount7, ReagentCount8, " + "ReagentRecraftCount1, ReagentRecraftCount2, ReagentRecraftCount3, ReagentRecraftCount4, ReagentRecraftCount5, ReagentRecraftCount6, " + "ReagentRecraftCount7, ReagentRecraftCount8, ReagentSource1, ReagentSource2, ReagentSource3, ReagentSource4, ReagentSource5, ReagentSource6, " + - "ReagentSource7, ReagentSource8 FROM spell_reagents"); + "ReagentSource7, ReagentSource8 FROM spell_reagents WHERE (`VerifiedBuild` > 0) = ?"); // SpellReagentsCurrency.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_REAGENTS_CURRENCY, "SELECT ID, SpellID, CurrencyTypesID, CurrencyCount FROM spell_reagents_currency"); + PrepareStatement(HotfixStatements.SEL_SPELL_REAGENTS_CURRENCY, "SELECT ID, SpellID, CurrencyTypesID, CurrencyCount FROM spell_reagents_currency" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellScaling.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_SCALING, "SELECT ID, SpellID, MinScalingLevel, MaxScalingLevel, ScalesFromItemLevel FROM spell_scaling"); + PrepareStatement(HotfixStatements.SEL_SPELL_SCALING, "SELECT ID, SpellID, MinScalingLevel, MaxScalingLevel, ScalesFromItemLevel FROM spell_scaling" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellShapeshift.db2 PrepareStatement(HotfixStatements.SEL_SPELL_SHAPESHIFT, "SELECT ID, SpellID, StanceBarOrder, ShapeshiftExclude1, ShapeshiftExclude2, ShapeshiftMask1, " + - "ShapeshiftMask2 FROM spell_shapeshift"); + "ShapeshiftMask2 FROM spell_shapeshift WHERE (`VerifiedBuild` > 0) = ?"); // SpellShapeshiftForm.db2 PrepareStatement(HotfixStatements.SEL_SPELL_SHAPESHIFT_FORM, "SELECT ID, Name, CreatureType, Flags, AttackIconFileID, BonusActionBar, CombatRoundTime, " + "DamageVariance, MountTypeID, CreatureDisplayID1, CreatureDisplayID2, CreatureDisplayID3, CreatureDisplayID4, PresetSpellID1, PresetSpellID2, " + - "PresetSpellID3, PresetSpellID4, PresetSpellID5, PresetSpellID6, PresetSpellID7, PresetSpellID8 FROM spell_shapeshift_form"); - PrepareStatement(HotfixStatements.SEL_SPELL_SHAPESHIFT_FORM_LOCALE, "SELECT ID, Name_lang FROM spell_shapeshift_form_locale WHERE locale = ?"); + "PresetSpellID3, PresetSpellID4, PresetSpellID5, PresetSpellID6, PresetSpellID7, PresetSpellID8 FROM spell_shapeshift_form" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_SPELL_SHAPESHIFT_FORM_LOCALE, "SELECT ID, Name_lang FROM spell_shapeshift_form_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // SpellTargetRestrictions.db2 PrepareStatement(HotfixStatements.SEL_SPELL_TARGET_RESTRICTIONS, "SELECT ID, DifficultyID, ConeDegrees, MaxTargets, MaxTargetLevel, TargetCreatureType, " + - "Targets, Width, SpellID FROM spell_target_restrictions"); + "Targets, Width, SpellID FROM spell_target_restrictions WHERE (`VerifiedBuild` > 0) = ?"); // SpellTotems.db2 - PrepareStatement(HotfixStatements.SEL_SPELL_TOTEMS, "SELECT ID, SpellID, RequiredTotemCategoryID1, RequiredTotemCategoryID2, Totem1, Totem2 FROM spell_totems"); + PrepareStatement(HotfixStatements.SEL_SPELL_TOTEMS, "SELECT ID, SpellID, RequiredTotemCategoryID1, RequiredTotemCategoryID2, Totem1, Totem2" + + " FROM spell_totems WHERE (`VerifiedBuild` > 0) = ?"); // SpellVisual.db2 PrepareStatement(HotfixStatements.SEL_SPELL_VISUAL, "SELECT ID, MissileCastOffset1, MissileCastOffset2, MissileCastOffset3, MissileImpactOffset1, " + "MissileImpactOffset2, MissileImpactOffset3, AnimEventSoundID, Flags, MissileAttachment, MissileDestinationAttachment, " + "MissileCastPositionerID, MissileImpactPositionerID, MissileTargetingKit, HostileSpellVisualID, CasterSpellVisualID, SpellVisualMissileSetID, " + - "DamageNumberDelay, LowViolenceSpellVisualID, RaidSpellVisualMissileSetID, ReducedUnexpectedCameraMovementSpellVisualID FROM spell_visual"); + "DamageNumberDelay, LowViolenceSpellVisualID, RaidSpellVisualMissileSetID, ReducedUnexpectedCameraMovementSpellVisualID FROM spell_visual" + + " WHERE (`VerifiedBuild` > 0) = ?"); // SpellVisualEffectName.db2 PrepareStatement(HotfixStatements.SEL_SPELL_VISUAL_EFFECT_NAME, "SELECT ID, ModelFileDataID, BaseMissileSpeed, Scale, MinAllowedScale, MaxAllowedScale, " + - "Alpha, Flags, TextureFileDataID, EffectRadius, Type, GenericID, RibbonQualityID, DissolveEffectID, ModelPosition, Unknown901 FROM spell_visual_effect_name"); + "Alpha, Flags, TextureFileDataID, EffectRadius, Type, GenericID, RibbonQualityID, DissolveEffectID, ModelPosition, Unknown901" + + " FROM spell_visual_effect_name WHERE (`VerifiedBuild` > 0) = ?"); // SpellVisualMissile.db2 PrepareStatement(HotfixStatements.SEL_SPELL_VISUAL_MISSILE, "SELECT CastOffset1, CastOffset2, CastOffset3, ImpactOffset1, ImpactOffset2, ImpactOffset3, ID, " + "SpellVisualEffectNameID, SoundEntriesID, Attachment, DestinationAttachment, CastPositionerID, ImpactPositionerID, FollowGroundHeight, " + "FollowGroundDropSpeed, FollowGroundApproach, Flags, SpellMissileMotionID, AnimKitID, ClutterLevel, DecayTimeAfterImpact, " + - "SpellVisualMissileSetID FROM spell_visual_missile"); + "SpellVisualMissileSetID FROM spell_visual_missile WHERE (`VerifiedBuild` > 0) = ?"); // SpellVisualKit.db2 PrepareStatement(HotfixStatements.SEL_SPELL_VISUAL_KIT, "SELECT ID, FallbackPriority, FallbackSpellVisualKitId, DelayMin, DelayMax, Flags1, Flags2" + - " FROM spell_visual_kit"); + " FROM spell_visual_kit WHERE (`VerifiedBuild` > 0) = ?"); // SpellXSpellVisual.db2 PrepareStatement(HotfixStatements.SEL_SPELL_X_SPELL_VISUAL, "SELECT ID, DifficultyID, SpellVisualID, Probability, Flags, Priority, SpellIconFileID, " + "ActiveIconFileID, ViewerUnitConditionID, ViewerPlayerConditionID, CasterUnitConditionID, CasterPlayerConditionID, SpellID" + - " FROM spell_x_spell_visual"); + " FROM spell_x_spell_visual WHERE (`VerifiedBuild` > 0) = ?"); // SummonProperties.db2 - PrepareStatement(HotfixStatements.SEL_SUMMON_PROPERTIES, "SELECT ID, Control, Faction, Title, Slot, Flags1, Flags2 FROM summon_properties"); + PrepareStatement(HotfixStatements.SEL_SUMMON_PROPERTIES, "SELECT ID, Control, Faction, Title, Slot, Flags1, Flags2 FROM summon_properties" + + " WHERE (`VerifiedBuild` > 0) = ?"); // TactKey.db2 PrepareStatement(HotfixStatements.SEL_TACT_KEY, "SELECT ID, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9, Key10, Key11, Key12, Key13, Key14, Key15, " + - "Key16 FROM tact_key"); + "Key16 FROM tact_key WHERE (`VerifiedBuild` > 0) = ?"); // Talent.db2 PrepareStatement(HotfixStatements.SEL_TALENT, "SELECT ID, Description, TierID, Flags, ColumnIndex, ClassID, SpecID, SpellID, OverridesSpellID, " + - "CategoryMask1, CategoryMask2 FROM talent"); - PrepareStatement(HotfixStatements.SEL_TALENT_LOCALE, "SELECT ID, Description_lang FROM talent_locale WHERE locale = ?"); + "CategoryMask1, CategoryMask2 FROM talent WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TALENT_LOCALE, "SELECT ID, Description_lang FROM talent_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // TaxiNodes.db2 PrepareStatement(HotfixStatements.SEL_TAXI_NODES, "SELECT Name, PosX, PosY, PosZ, MapOffsetX, MapOffsetY, FlightMapOffsetX, FlightMapOffsetY, ID, " + "ContinentID, ConditionID, CharacterBitNumber, Flags, UiTextureKitID, MinimapAtlasMemberID, Facing, SpecialIconConditionID, " + - "VisibilityConditionID, MountCreatureID1, MountCreatureID2 FROM taxi_nodes"); - PrepareStatement(HotfixStatements.SEL_TAXI_NODES_LOCALE, "SELECT ID, Name_lang FROM taxi_nodes_locale WHERE locale = ?"); + "VisibilityConditionID, MountCreatureID1, MountCreatureID2 FROM taxi_nodes WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TAXI_NODES_LOCALE, "SELECT ID, Name_lang FROM taxi_nodes_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // TaxiPath.db2 - PrepareStatement(HotfixStatements.SEL_TAXI_PATH, "SELECT ID, FromTaxiNode, ToTaxiNode, Cost FROM taxi_path"); + PrepareStatement(HotfixStatements.SEL_TAXI_PATH, "SELECT ID, FromTaxiNode, ToTaxiNode, Cost FROM taxi_path WHERE (`VerifiedBuild` > 0) = ?"); // TaxiPathNode.db2 PrepareStatement(HotfixStatements.SEL_TAXI_PATH_NODE, "SELECT LocX, LocY, LocZ, ID, PathID, NodeIndex, ContinentID, Flags, Delay, ArrivalEventID, " + - "DepartureEventID FROM taxi_path_node"); + "DepartureEventID FROM taxi_path_node WHERE (`VerifiedBuild` > 0) = ?"); // TotemCategory.db2 - PrepareStatement(HotfixStatements.SEL_TOTEM_CATEGORY, "SELECT ID, Name, TotemCategoryType, TotemCategoryMask FROM totem_category"); - PrepareStatement(HotfixStatements.SEL_TOTEM_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM totem_category_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_TOTEM_CATEGORY, "SELECT ID, Name, TotemCategoryType, TotemCategoryMask FROM totem_category" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TOTEM_CATEGORY_LOCALE, "SELECT ID, Name_lang FROM totem_category_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // Toy.db2 - PrepareStatement(HotfixStatements.SEL_TOY, "SELECT SourceText, ID, ItemID, Flags, SourceTypeEnum FROM toy"); - PrepareStatement(HotfixStatements.SEL_TOY_LOCALE, "SELECT ID, SourceText_lang FROM toy_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_TOY, "SELECT SourceText, ID, ItemID, Flags, SourceTypeEnum FROM toy WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TOY_LOCALE, "SELECT ID, SourceText_lang FROM toy_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // TransmogHoliday.db2 - PrepareStatement(HotfixStatements.SEL_TRANSMOG_HOLIDAY, "SELECT ID, RequiredTransmogHoliday FROM transmog_holiday"); + PrepareStatement(HotfixStatements.SEL_TRANSMOG_HOLIDAY, "SELECT ID, RequiredTransmogHoliday FROM transmog_holiday WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitCond.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_COND, "SELECT ID, CondType, TraitTreeID, GrantedRanks, QuestID, AchievementID, SpecSetID, TraitNodeGroupID, " + + "TraitNodeID, TraitCurrencyID, SpentAmountRequired, Flags, RequiredLevel, FreeSharedStringID, SpendMoreSharedStringID FROM trait_cond" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitCost.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_COST, "SELECT InternalName, ID, Amount, TraitCurrencyID FROM trait_cost WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitCurrency.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_CURRENCY, "SELECT ID, Type, CurrencyTypesID, Flags, Icon FROM trait_currency WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitCurrencySource.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_CURRENCY_SOURCE, "SELECT Requirement, ID, TraitCurrencyID, Amount, QuestID, AchievementID, PlayerLevel, " + + "TraitNodeEntryID, OrderIndex FROM trait_currency_source WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TRAIT_CURRENCY_SOURCE_LOCALE, "SELECT ID, Requirement_lang FROM trait_currency_source_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); + + // TraitDefinition.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_DEFINITION, "SELECT OverrideName, OverrideSubtext, OverrideDescription, ID, SpellID, OverrideIcon, " + + "OverridesSpellID, VisibleSpellID FROM trait_definition WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TRAIT_DEFINITION_LOCALE, "SELECT ID, OverrideName_lang, OverrideSubtext_lang, OverrideDescription_lang" + + " FROM trait_definition_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); + + // TraitDefinitionEffectPoints.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_DEFINITION_EFFECT_POINTS, "SELECT ID, TraitDefinitionID, EffectIndex, OperationType, CurveID" + + " FROM trait_definition_effect_points WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitEdge.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_EDGE, "SELECT ID, VisualStyle, LeftTraitNodeID, RightTraitNodeID, Type FROM trait_edge" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNode.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE, "SELECT ID, TraitTreeID, PosX, PosY, Type, Flags FROM trait_node WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeEntry.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_ENTRY, "SELECT ID, TraitDefinitionID, MaxRanks, NodeEntryType FROM trait_node_entry" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeEntryXTraitCond.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_ENTRY_X_TRAIT_COND, "SELECT ID, TraitCondID, TraitNodeEntryID FROM trait_node_entry_x_trait_cond" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeEntryXTraitCost.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_ENTRY_X_TRAIT_COST, "SELECT ID, TraitNodeEntryID, TraitCostID FROM trait_node_entry_x_trait_cost" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeGroup.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_GROUP, "SELECT ID, TraitTreeID, Flags FROM trait_node_group WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeGroupXTraitCond.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_GROUP_X_TRAIT_COND, "SELECT ID, TraitCondID, TraitNodeGroupID FROM trait_node_group_x_trait_cond" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeGroupXTraitCost.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_GROUP_X_TRAIT_COST, "SELECT ID, TraitNodeGroupID, TraitCostID FROM trait_node_group_x_trait_cost" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeGroupXTraitNode.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_GROUP_X_TRAIT_NODE, "SELECT ID, TraitNodeGroupID, TraitNodeID, `Index` FROM trait_node_group_x_trait_node" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeXTraitCond.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_X_TRAIT_COND, "SELECT ID, TraitCondID, TraitNodeID FROM trait_node_x_trait_cond" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeXTraitCost.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_X_TRAIT_COST, "SELECT ID, TraitNodeID, TraitCostID FROM trait_node_x_trait_cost" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitNodeXTraitNodeEntry.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_NODE_X_TRAIT_NODE_ENTRY, "SELECT ID, TraitNodeID, TraitNodeEntryID, `Index` FROM trait_node_x_trait_node_entry" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitTree.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_TREE, "SELECT ID, TraitSystemID, Unused1000_1, FirstTraitNodeID, PlayerConditionID, Flags, Unused1000_2, " + + "Unused1000_3 FROM trait_tree WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitTreeLoadout.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_TREE_LOADOUT, "SELECT ID, TraitTreeID, ChrSpecializationID FROM trait_tree_loadout" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitTreeLoadoutEntry.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_TREE_LOADOUT_ENTRY, "SELECT ID, TraitTreeLoadoutID, SelectedTraitNodeID, SelectedTraitNodeEntryID, NumPoints, " + + "OrderIndex FROM trait_tree_loadout_entry WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitTreeXTraitCost.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_TREE_X_TRAIT_COST, "SELECT ID, TraitTreeID, TraitCostID FROM trait_tree_x_trait_cost" + + " WHERE (`VerifiedBuild` > 0) = ?"); + + // TraitTreeXTraitCurrency.db2 + PrepareStatement(HotfixStatements.SEL_TRAIT_TREE_X_TRAIT_CURRENCY, "SELECT ID, `Index`, TraitTreeID, TraitCurrencyID FROM trait_tree_x_trait_currency" + + " WHERE (`VerifiedBuild` > 0) = ?"); // TransmogIllusion.db2 - PrepareStatement(HotfixStatements.SEL_TRANSMOG_ILLUSION, "SELECT ID, UnlockConditionID, TransmogCost, SpellItemEnchantmentID, Flags FROM transmog_illusion"); + PrepareStatement(HotfixStatements.SEL_TRANSMOG_ILLUSION, "SELECT ID, UnlockConditionID, TransmogCost, SpellItemEnchantmentID, Flags FROM transmog_illusion" + + " WHERE (`VerifiedBuild` > 0) = ?"); // TransmogSet.db2 PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET, "SELECT Name, ID, ClassMask, TrackingQuestID, Flags, TransmogSetGroupID, ItemNameDescriptionID, " + - "ParentTransmogSetID, Unknown810, ExpansionID, PatchID, UiOrder, PlayerConditionID FROM transmog_set"); - PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_LOCALE, "SELECT ID, Name_lang FROM transmog_set_locale WHERE locale = ?"); + "ParentTransmogSetID, Unknown810, ExpansionID, PatchID, UiOrder, PlayerConditionID FROM transmog_set WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_LOCALE, "SELECT ID, Name_lang FROM transmog_set_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // TransmogSetGroup.db2 - PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_GROUP, "SELECT ID, Name FROM transmog_set_group"); - PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_GROUP_LOCALE, "SELECT ID, Name_lang FROM transmog_set_group_locale WHERE locale = ?"); + PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_GROUP, "SELECT ID, Name FROM transmog_set_group WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_GROUP_LOCALE, "SELECT ID, Name_lang FROM transmog_set_group_locale WHERE (`VerifiedBuild` > 0) = ?" + + " AND locale = ?"); // TransmogSetItem.db2 - PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_ITEM, "SELECT ID, TransmogSetID, ItemModifiedAppearanceID, Flags FROM transmog_set_item"); + PrepareStatement(HotfixStatements.SEL_TRANSMOG_SET_ITEM, "SELECT ID, TransmogSetID, ItemModifiedAppearanceID, Flags FROM transmog_set_item" + + " WHERE (`VerifiedBuild` > 0) = ?"); // TransportAnimation.db2 - PrepareStatement(HotfixStatements.SEL_TRANSPORT_ANIMATION, "SELECT ID, PosX, PosY, PosZ, SequenceID, TimeIndex, TransportID FROM transport_animation"); + PrepareStatement(HotfixStatements.SEL_TRANSPORT_ANIMATION, "SELECT ID, PosX, PosY, PosZ, SequenceID, TimeIndex, TransportID FROM transport_animation" + + " WHERE (`VerifiedBuild` > 0) = ?"); // TransportRotation.db2 - PrepareStatement(HotfixStatements.SEL_TRANSPORT_ROTATION, "SELECT ID, Rot1, Rot2, Rot3, Rot4, TimeIndex, GameObjectsID FROM transport_rotation"); + PrepareStatement(HotfixStatements.SEL_TRANSPORT_ROTATION, "SELECT ID, Rot1, Rot2, Rot3, Rot4, TimeIndex, GameObjectsID FROM transport_rotation" + + " WHERE (`VerifiedBuild` > 0) = ?"); // UiMap.db2 PrepareStatement(HotfixStatements.SEL_UI_MAP, "SELECT Name, ID, ParentUiMapID, Flags, `System`, Type, BountySetID, BountyDisplayLocation, " + - "VisibilityPlayerConditionID, HelpTextPosition, BkgAtlasID, AlternateUiMapGroup, ContentTuningID FROM ui_map"); - PrepareStatement(HotfixStatements.SEL_UI_MAP_LOCALE, "SELECT ID, Name_lang FROM ui_map_locale WHERE locale = ?"); + "VisibilityPlayerConditionID, HelpTextPosition, BkgAtlasID, AlternateUiMapGroup, ContentTuningID FROM ui_map WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_UI_MAP_LOCALE, "SELECT ID, Name_lang FROM ui_map_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // UiMapAssignment.db2 PrepareStatement(HotfixStatements.SEL_UI_MAP_ASSIGNMENT, "SELECT UiMinX, UiMinY, UiMaxX, UiMaxY, Region1X, Region1Y, Region1Z, Region2X, Region2Y, " + - "Region2Z, ID, UiMapID, OrderIndex, MapID, AreaID, WmoDoodadPlacementID, WmoGroupID FROM ui_map_assignment"); + "Region2Z, ID, UiMapID, OrderIndex, MapID, AreaID, WmoDoodadPlacementID, WmoGroupID FROM ui_map_assignment WHERE (`VerifiedBuild` > 0) = ?"); // UiMapLink.db2 PrepareStatement(HotfixStatements.SEL_UI_MAP_LINK, "SELECT UiMinX, UiMinY, UiMaxX, UiMaxY, ID, ParentUiMapID, OrderIndex, ChildUiMapID, PlayerConditionID, " + - "OverrideHighlightFileDataID, OverrideHighlightAtlasID, Flags FROM ui_map_link"); + "OverrideHighlightFileDataID, OverrideHighlightAtlasID, Flags FROM ui_map_link WHERE (`VerifiedBuild` > 0) = ?"); // UiMapXMapArt.db2 - PrepareStatement(HotfixStatements.SEL_UI_MAP_X_MAP_ART, "SELECT ID, PhaseID, UiMapArtID, UiMapID FROM ui_map_x_map_art"); + PrepareStatement(HotfixStatements.SEL_UI_MAP_X_MAP_ART, "SELECT ID, PhaseID, UiMapArtID, UiMapID FROM ui_map_x_map_art WHERE (`VerifiedBuild` > 0) = ?"); // UiSplashScreen.db2 PrepareStatement(HotfixStatements.SEL_UI_SPLASH_SCREEN, "SELECT ID, Header, TopLeftFeatureTitle, TopLeftFeatureDesc, BottomLeftFeatureTitle, " + "BottomLeftFeatureDesc, RightFeatureTitle, RightFeatureDesc, AllianceQuestID, HordeQuestID, ScreenType, TextureKitID, SoundKitID, " + - "PlayerConditionID, CharLevelConditionID, RequiredTimeEventPassed FROM ui_splash_screen"); + "PlayerConditionID, CharLevelConditionID, RequiredTimeEventPassed FROM ui_splash_screen WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_UI_SPLASH_SCREEN_LOCALE, "SELECT ID, Header_lang, TopLeftFeatureTitle_lang, TopLeftFeatureDesc_lang, " + - "BottomLeftFeatureTitle_lang, BottomLeftFeatureDesc_lang, RightFeatureTitle_lang, RightFeatureDesc_lang FROM ui_splash_screen_locale WHERE locale = ?"); + "BottomLeftFeatureTitle_lang, BottomLeftFeatureDesc_lang, RightFeatureTitle_lang, RightFeatureDesc_lang FROM ui_splash_screen_locale" + + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // UnitCondition.db2 PrepareStatement(HotfixStatements.SEL_UNIT_CONDITION, "SELECT ID, Flags, Variable1, Variable2, Variable3, Variable4, Variable5, Variable6, Variable7, " + - "Variable8, Op1, Op2, Op3, Op4, Op5, Op6, Op7, Op8, Value1, Value2, Value3, Value4, Value5, Value6, Value7, Value8 FROM unit_condition"); + "Variable8, Op1, Op2, Op3, Op4, Op5, Op6, Op7, Op8, Value1, Value2, Value3, Value4, Value5, Value6, Value7, Value8 FROM unit_condition" + + " WHERE (`VerifiedBuild` > 0) = ?"); // UnitPowerBar.db2 PrepareStatement(HotfixStatements.SEL_UNIT_POWER_BAR, "SELECT ID, Name, Cost, OutOfError, ToolTip, MinPower, MaxPower, StartPower, CenterPower, " + "RegenerationPeace, RegenerationCombat, BarType, Flags, StartInset, EndInset, FileDataID1, FileDataID2, FileDataID3, FileDataID4, " + - "FileDataID5, FileDataID6, Color1, Color2, Color3, Color4, Color5, Color6 FROM unit_power_bar"); + "FileDataID5, FileDataID6, Color1, Color2, Color3, Color4, Color5, Color6 FROM unit_power_bar WHERE (`VerifiedBuild` > 0) = ?"); PrepareStatement(HotfixStatements.SEL_UNIT_POWER_BAR_LOCALE, "SELECT ID, Name_lang, Cost_lang, OutOfError_lang, ToolTip_lang FROM unit_power_bar_locale" + - " WHERE locale = ?"); + " WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // Vehicle.db2 PrepareStatement(HotfixStatements.SEL_VEHICLE, "SELECT ID, Flags, FlagsB, TurnSpeed, PitchSpeed, PitchMin, PitchMax, MouseLookOffsetPitch, " + "CameraFadeDistScalarMin, CameraFadeDistScalarMax, CameraPitchOffset, FacingLimitRight, FacingLimitLeft, CameraYawOffset, " + "VehicleUIIndicatorID, MissileTargetingID, VehiclePOITypeID, SeatID1, SeatID2, SeatID3, SeatID4, SeatID5, SeatID6, SeatID7, SeatID8, " + - "PowerDisplayID1, PowerDisplayID2, PowerDisplayID3 FROM vehicle"); + "PowerDisplayID1, PowerDisplayID2, PowerDisplayID3 FROM vehicle WHERE (`VerifiedBuild` > 0) = ?"); // VehicleSeat.db2 PrepareStatement(HotfixStatements.SEL_VEHICLE_SEAT, "SELECT ID, AttachmentOffsetX, AttachmentOffsetY, AttachmentOffsetZ, CameraOffsetX, CameraOffsetY, " + @@ -1275,23 +1522,26 @@ namespace Framework.Database "PassengerAttachmentID, PassengerYaw, PassengerPitch, PassengerRoll, VehicleEnterAnimDelay, VehicleExitAnimDelay, VehicleAbilityDisplay, " + "EnterUISoundID, ExitUISoundID, UiSkinFileDataID, CameraEnteringDelay, CameraEnteringDuration, CameraExitingDelay, CameraExitingDuration, " + "CameraPosChaseRate, CameraFacingChaseRate, CameraEnteringZoom, CameraSeatZoomMin, CameraSeatZoomMax, EnterAnimKitID, RideAnimKitID, " + - "ExitAnimKitID, VehicleEnterAnimKitID, VehicleRideAnimKitID, VehicleExitAnimKitID, CameraModeID FROM vehicle_seat"); + "ExitAnimKitID, VehicleEnterAnimKitID, VehicleRideAnimKitID, VehicleExitAnimKitID, CameraModeID FROM vehicle_seat" + + " WHERE (`VerifiedBuild` > 0) = ?"); // WmoAreaTable.db2 PrepareStatement(HotfixStatements.SEL_WMO_AREA_TABLE, "SELECT AreaName, ID, WmoID, NameSetID, WmoGroupID, SoundProviderPref, SoundProviderPrefUnderwater, " + - "AmbienceID, UwAmbience, ZoneMusic, UwZoneMusic, IntroSound, UwIntroSound, AreaTableID, Flags FROM wmo_area_table"); - PrepareStatement(HotfixStatements.SEL_WMO_AREA_TABLE_LOCALE, "SELECT ID, AreaName_lang FROM wmo_area_table_locale WHERE locale = ?"); + "AmbienceID, UwAmbience, ZoneMusic, UwZoneMusic, IntroSound, UwIntroSound, AreaTableID, Flags FROM wmo_area_table" + + " WHERE (`VerifiedBuild` > 0) = ?"); + PrepareStatement(HotfixStatements.SEL_WMO_AREA_TABLE_LOCALE, "SELECT ID, AreaName_lang FROM wmo_area_table_locale WHERE (`VerifiedBuild` > 0) = ? AND locale = ?"); // WorldEffect.db2 PrepareStatement(HotfixStatements.SEL_WORLD_EFFECT, "SELECT ID, QuestFeedbackEffectID, WhenToDisplay, TargetType, TargetAsset, PlayerConditionID, " + - "CombatConditionID FROM world_effect"); + "CombatConditionID FROM world_effect WHERE (`VerifiedBuild` > 0) = ?"); // WorldMapOverlay.db2 PrepareStatement(HotfixStatements.SEL_WORLD_MAP_OVERLAY, "SELECT ID, UiMapArtID, TextureWidth, TextureHeight, OffsetX, OffsetY, HitRectTop, HitRectBottom, " + - "HitRectLeft, HitRectRight, PlayerConditionID, Flags, AreaID1, AreaID2, AreaID3, AreaID4 FROM world_map_overlay"); + "HitRectLeft, HitRectRight, PlayerConditionID, Flags, AreaID1, AreaID2, AreaID3, AreaID4 FROM world_map_overlay" + + " WHERE (`VerifiedBuild` > 0) = ?"); // WorldStateExpression.db2 - PrepareStatement(HotfixStatements.SEL_WORLD_STATE_EXPRESSION, "SELECT ID, Expression FROM world_state_expression"); + PrepareStatement(HotfixStatements.SEL_WORLD_STATE_EXPRESSION, "SELECT ID, Expression FROM world_state_expression WHERE (`VerifiedBuild` > 0) = ?"); } } @@ -1820,6 +2070,8 @@ namespace Framework.Database SEL_SKILL_LINE_ABILITY, SEL_SKILL_LINE_ABILITY_LOCALE, + SEL_SKILL_LINE_X_TRAIT_TREE, + SEL_SKILL_RACE_CLASS_INFO, SEL_SOULBIND_CONDUIT_RANK, @@ -1935,6 +2187,54 @@ namespace Framework.Database SEL_TRANSMOG_HOLIDAY, + SEL_TRAIT_COND, + + SEL_TRAIT_COST, + + SEL_TRAIT_CURRENCY, + + SEL_TRAIT_CURRENCY_SOURCE, + SEL_TRAIT_CURRENCY_SOURCE_LOCALE, + + SEL_TRAIT_DEFINITION, + SEL_TRAIT_DEFINITION_LOCALE, + + SEL_TRAIT_DEFINITION_EFFECT_POINTS, + + SEL_TRAIT_EDGE, + + SEL_TRAIT_NODE, + + SEL_TRAIT_NODE_ENTRY, + + SEL_TRAIT_NODE_ENTRY_X_TRAIT_COND, + + SEL_TRAIT_NODE_ENTRY_X_TRAIT_COST, + + SEL_TRAIT_NODE_GROUP, + + SEL_TRAIT_NODE_GROUP_X_TRAIT_COND, + + SEL_TRAIT_NODE_GROUP_X_TRAIT_COST, + + SEL_TRAIT_NODE_GROUP_X_TRAIT_NODE, + + SEL_TRAIT_NODE_X_TRAIT_COND, + + SEL_TRAIT_NODE_X_TRAIT_COST, + + SEL_TRAIT_NODE_X_TRAIT_NODE_ENTRY, + + SEL_TRAIT_TREE, + + SEL_TRAIT_TREE_LOADOUT, + + SEL_TRAIT_TREE_LOADOUT_ENTRY, + + SEL_TRAIT_TREE_X_TRAIT_COST, + + SEL_TRAIT_TREE_X_TRAIT_CURRENCY, + SEL_TRANSMOG_ILLUSION, SEL_TRANSMOG_SET, diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 439e446de..2c0161744 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -2724,13 +2724,13 @@ namespace Game case UnitConditionVariable.IsEnemy: return (otherUnit && unit.GetReactionTo(otherUnit) <= ReputationRank.Hostile) ? 1 : 0; case UnitConditionVariable.IsSpecMelee: - return (unit.IsPlayer() && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Flags.HasFlag(ChrSpecializationFlag.Melee)) ? 1 : 0; + return (unit.IsPlayer() && unit.ToPlayer().GetPrimarySpecialization() != 0 && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Flags.HasFlag(ChrSpecializationFlag.Melee)) ? 1 : 0; case UnitConditionVariable.IsSpecTank: - return (unit.IsPlayer() && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Role == 0) ? 1 : 0; + return (unit.IsPlayer() && unit.ToPlayer().GetPrimarySpecialization() != 0 && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Role == 0) ? 1 : 0; case UnitConditionVariable.IsSpecRanged: - return (unit.IsPlayer() && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Flags.HasFlag(ChrSpecializationFlag.Ranged)) ? 1 : 0; + return (unit.IsPlayer() && unit.ToPlayer().GetPrimarySpecialization() != 0 && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Flags.HasFlag(ChrSpecializationFlag.Ranged)) ? 1 : 0; case UnitConditionVariable.IsSpecHealer: - return (unit.IsPlayer() && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Role == 1) ? 1 : 0; + return (unit.IsPlayer() && unit.ToPlayer().GetPrimarySpecialization() != 0 && CliDB.ChrSpecializationStorage.LookupByKey(unit.ToPlayer().GetPrimarySpecialization()).Role == 1) ? 1 : 0; case UnitConditionVariable.IsPlayerControlledNPC: return unit.IsCreature() && unit.HasUnitFlag(UnitFlags.PlayerControlled) ? 1 : 0; case UnitConditionVariable.IsDying: diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index 8db748a0a..902c7f1ba 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -275,6 +275,7 @@ namespace Game.DataStorage SceneScriptTextStorage = ReadDB2("SceneScriptText.db2", HotfixStatements.SEL_SCENE_SCRIPT_TEXT); SkillLineStorage = ReadDB2("SkillLine.db2", HotfixStatements.SEL_SKILL_LINE, HotfixStatements.SEL_SKILL_LINE_LOCALE); SkillLineAbilityStorage = ReadDB2("SkillLineAbility.db2", HotfixStatements.SEL_SKILL_LINE_ABILITY); + SkillLineXTraitTreeStorage = ReadDB2("SkillLineXTraitTree.db2", HotfixStatements.SEL_SKILL_LINE_X_TRAIT_TREE); SkillRaceClassInfoStorage = ReadDB2("SkillRaceClassInfo.db2", HotfixStatements.SEL_SKILL_RACE_CLASS_INFO); SoulbindConduitRankStorage = ReadDB2("SoulbindConduitRank.db2", HotfixStatements.SEL_SOULBIND_CONDUIT_RANK); SoundKitStorage = ReadDB2("SoundKit.db2", HotfixStatements.SEL_SOUND_KIT); @@ -326,6 +327,29 @@ namespace Game.DataStorage TaxiPathNodeStorage = ReadDB2("TaxiPathNode.db2", HotfixStatements.SEL_TAXI_PATH_NODE); TotemCategoryStorage = ReadDB2("TotemCategory.db2", HotfixStatements.SEL_TOTEM_CATEGORY, HotfixStatements.SEL_TOTEM_CATEGORY_LOCALE); ToyStorage = ReadDB2("Toy.db2", HotfixStatements.SEL_TOY, HotfixStatements.SEL_TOY_LOCALE); + TraitCondStorage = ReadDB2("TraitCond.db2", HotfixStatements.SEL_TRAIT_COND); + TraitCostStorage = ReadDB2("TraitCost.db2", HotfixStatements.SEL_TRAIT_COST); + TraitCurrencyStorage = ReadDB2("TraitCurrency.db2", HotfixStatements.SEL_TRAIT_CURRENCY); + TraitCurrencySourceStorage = ReadDB2("TraitCurrencySource.db2", HotfixStatements.SEL_TRAIT_CURRENCY_SOURCE, HotfixStatements.SEL_TRAIT_CURRENCY_SOURCE_LOCALE); + TraitDefinitionStorage = ReadDB2("TraitDefinition.db2", HotfixStatements.SEL_TRAIT_DEFINITION, HotfixStatements.SEL_TRAIT_DEFINITION_LOCALE); + TraitDefinitionEffectPointsStorage = ReadDB2("TraitDefinitionEffectPoints.db2", HotfixStatements.SEL_TRAIT_DEFINITION_EFFECT_POINTS); + TraitEdgeStorage = ReadDB2("TraitEdge.db2", HotfixStatements.SEL_TRAIT_EDGE); + TraitNodeStorage = ReadDB2("TraitNode.db2", HotfixStatements.SEL_TRAIT_NODE); + TraitNodeEntryStorage = ReadDB2("TraitNodeEntry.db2", HotfixStatements.SEL_TRAIT_NODE_ENTRY); + TraitNodeEntryXTraitCondStorage = ReadDB2("TraitNodeEntryXTraitCond.db2", HotfixStatements.SEL_TRAIT_NODE_ENTRY_X_TRAIT_COND); + TraitNodeEntryXTraitCostStorage = ReadDB2("TraitNodeEntryXTraitCost.db2", HotfixStatements.SEL_TRAIT_NODE_ENTRY_X_TRAIT_COST); + TraitNodeGroupStorage = ReadDB2("TraitNodeGroup.db2", HotfixStatements.SEL_TRAIT_NODE_GROUP); + TraitNodeGroupXTraitCondStorage = ReadDB2("TraitNodeGroupXTraitCond.db2", HotfixStatements.SEL_TRAIT_NODE_GROUP_X_TRAIT_COND); + TraitNodeGroupXTraitCostStorage = ReadDB2("TraitNodeGroupXTraitCost.db2", HotfixStatements.SEL_TRAIT_NODE_GROUP_X_TRAIT_COST); + TraitNodeGroupXTraitNodeStorage = ReadDB2("TraitNodeGroupXTraitNode.db2", HotfixStatements.SEL_TRAIT_NODE_GROUP_X_TRAIT_NODE); + TraitNodeXTraitCondStorage = ReadDB2("TraitNodeXTraitCond.db2", HotfixStatements.SEL_TRAIT_NODE_X_TRAIT_COND); + TraitNodeXTraitCostStorage = ReadDB2("TraitNodeXTraitCost.db2", HotfixStatements.SEL_TRAIT_NODE_X_TRAIT_COST); + TraitNodeXTraitNodeEntryStorage = ReadDB2("TraitNodeXTraitNodeEntry.db2", HotfixStatements.SEL_TRAIT_NODE_X_TRAIT_NODE_ENTRY); + TraitTreeStorage = ReadDB2("TraitTree.db2", HotfixStatements.SEL_TRAIT_TREE); + TraitTreeLoadoutStorage = ReadDB2("TraitTreeLoadout.db2", HotfixStatements.SEL_TRAIT_TREE_LOADOUT); + TraitTreeLoadoutEntryStorage = ReadDB2("TraitTreeLoadoutEntry.db2", HotfixStatements.SEL_TRAIT_TREE_LOADOUT_ENTRY); + TraitTreeXTraitCostStorage = ReadDB2("TraitTreeXTraitCost.db2", HotfixStatements.SEL_TRAIT_TREE_X_TRAIT_COST); + TraitTreeXTraitCurrencyStorage = ReadDB2("TraitTreeXTraitCurrency.db2", HotfixStatements.SEL_TRAIT_TREE_X_TRAIT_CURRENCY); TransmogHolidayStorage = ReadDB2("TransmogHoliday.db2", HotfixStatements.SEL_TRANSMOG_HOLIDAY); TransmogIllusionStorage = ReadDB2("TransmogIllusion.db2", HotfixStatements.SEL_TRANSMOG_ILLUSION); TransmogSetStorage = ReadDB2("TransmogSet.db2", HotfixStatements.SEL_TRANSMOG_SET, HotfixStatements.SEL_TRANSMOG_SET_LOCALE); @@ -674,6 +698,7 @@ namespace Game.DataStorage public static DB6Storage SceneScriptTextStorage; public static DB6Storage SkillLineStorage; public static DB6Storage SkillLineAbilityStorage; + public static DB6Storage SkillLineXTraitTreeStorage; public static DB6Storage SkillRaceClassInfoStorage; public static DB6Storage SoulbindConduitRankStorage; public static DB6Storage SoundKitStorage; @@ -725,6 +750,29 @@ namespace Game.DataStorage public static DB6Storage TaxiPathNodeStorage; public static DB6Storage TotemCategoryStorage; public static DB6Storage ToyStorage; + public static DB6Storage TraitCondStorage; + public static DB6Storage TraitCostStorage; + public static DB6Storage TraitCurrencyStorage; + public static DB6Storage TraitCurrencySourceStorage; + public static DB6Storage TraitDefinitionStorage; + public static DB6Storage TraitDefinitionEffectPointsStorage; + public static DB6Storage TraitEdgeStorage; + public static DB6Storage TraitNodeStorage; + public static DB6Storage TraitNodeEntryStorage; + public static DB6Storage TraitNodeEntryXTraitCondStorage; + public static DB6Storage TraitNodeEntryXTraitCostStorage; + public static DB6Storage TraitNodeGroupStorage; + public static DB6Storage TraitNodeGroupXTraitCondStorage; + public static DB6Storage TraitNodeGroupXTraitCostStorage; + public static DB6Storage TraitNodeGroupXTraitNodeStorage; + public static DB6Storage TraitNodeXTraitCondStorage; + public static DB6Storage TraitNodeXTraitCostStorage; + public static DB6Storage TraitNodeXTraitNodeEntryStorage; + public static DB6Storage TraitTreeStorage; + public static DB6Storage TraitTreeLoadoutStorage; + public static DB6Storage TraitTreeLoadoutEntryStorage; + public static DB6Storage TraitTreeXTraitCostStorage; + public static DB6Storage TraitTreeXTraitCurrencyStorage; public static DB6Storage TransmogHolidayStorage; public static DB6Storage TransmogIllusionStorage; public static DB6Storage TransmogSetStorage; @@ -874,7 +922,7 @@ namespace Game.DataStorage { return row.Wins * row.Xp; } - + public static float GetIlvlStatMultiplier(GtGenericMultByILvlRecord row, InventoryType invType) { switch (invType) diff --git a/Source/Game/DataStorage/DB2Manager.cs b/Source/Game/DataStorage/DB2Manager.cs index dc051ae24..ddee1e3e4 100644 --- a/Source/Game/DataStorage/DB2Manager.cs +++ b/Source/Game/DataStorage/DB2Manager.cs @@ -1985,19 +1985,24 @@ namespace Game.DataStorage public SkillRaceClassInfoRecord GetSkillRaceClassInfo(uint skill, Race race, Class class_) { var bounds = _skillRaceClassInfoBySkill.LookupByKey(skill); - foreach (var record in bounds) + foreach (var skllRaceClassInfo in bounds) { - if (record.RaceMask != 0 && !Convert.ToBoolean(record.RaceMask & SharedConst.GetMaskForRace(race))) + if (skllRaceClassInfo.RaceMask != 0 && !Convert.ToBoolean(skllRaceClassInfo.RaceMask & SharedConst.GetMaskForRace(race))) continue; - if (record.ClassMask != 0 && !Convert.ToBoolean(record.ClassMask & (1 << ((byte)class_ - 1)))) + if (skllRaceClassInfo.ClassMask != 0 && !Convert.ToBoolean(skllRaceClassInfo.ClassMask & (1 << ((byte)class_ - 1)))) continue; - return record; + return skllRaceClassInfo; } return null; } + public List GetSkillRaceClassInfo(uint skill) + { + return _skillRaceClassInfoBySkill.LookupByKey(skill); + } + public SoulbindConduitRankRecord GetSoulbindConduitRank(int soulbindConduitId, int rank) { return _soulbindConduitRanks.LookupByKey(Tuple.Create(soulbindConduitId, rank)); diff --git a/Source/Game/DataStorage/Structs/C_Records.cs b/Source/Game/DataStorage/Structs/C_Records.cs index 20632cd9b..bcc6e90ee 100644 --- a/Source/Game/DataStorage/Structs/C_Records.cs +++ b/Source/Game/DataStorage/Structs/C_Records.cs @@ -292,7 +292,7 @@ namespace Game.DataStorage public sealed class ChrSpecializationRecord { - public string Name; + public LocalizedString Name; public string FemaleName; public string Description; public uint Id; diff --git a/Source/Game/DataStorage/Structs/S_Records.cs b/Source/Game/DataStorage/Structs/S_Records.cs index d9435b5a7..80c29546f 100644 --- a/Source/Game/DataStorage/Structs/S_Records.cs +++ b/Source/Game/DataStorage/Structs/S_Records.cs @@ -124,6 +124,14 @@ namespace Game.DataStorage public ushort SkillupSkillLineID; } + public sealed class SkillLineXTraitTreeRecord + { + public uint Id; + public int SkillLineID; + public int TraitTreeID; + public int OrderIndex; + } + public sealed class SkillRaceClassInfoRecord { public uint Id; diff --git a/Source/Game/DataStorage/Structs/T_Records.cs b/Source/Game/DataStorage/Structs/T_Records.cs index 3cfe6e96c..45dc7fbcd 100644 --- a/Source/Game/DataStorage/Structs/T_Records.cs +++ b/Source/Game/DataStorage/Structs/T_Records.cs @@ -103,6 +103,222 @@ namespace Game.DataStorage public int RequiredTransmogHoliday; } + public sealed class TraitCondRecord + { + public uint Id; + public int CondType; + public int TraitTreeID; + public int GrantedRanks; + public uint QuestID; + public uint AchievementID; + public int SpecSetID; + public int TraitNodeGroupID; + public int TraitNodeID; + public int TraitCurrencyID; + public int SpentAmountRequired; + public int Flags; + public int RequiredLevel; + public int FreeSharedStringID; + public int SpendMoreSharedStringID; + + public TraitConditionType GetCondType() { return (TraitConditionType)CondType; } + } + + public sealed class TraitCostRecord + { + public string InternalName; + public uint Id; + public int Amount; + public int TraitCurrencyID; + } + + public sealed class TraitCurrencyRecord + { + public uint Id; + public int Type; + public int CurrencyTypesID; + public int Flags; + public int Icon; + + public TraitCurrencyType GetCurrencyType() { return (TraitCurrencyType)Type; } + } + + public sealed class TraitCurrencySourceRecord + { + public LocalizedString Requirement; + public uint Id; + public int TraitCurrencyID; + public int Amount; + public uint QuestID; + public uint AchievementID; + public uint PlayerLevel; + public int TraitNodeEntryID; + public int OrderIndex; + } + + public sealed class TraitDefinitionRecord + { + public LocalizedString OverrideName; + public LocalizedString OverrideSubtext; + public LocalizedString OverrideDescription; + public uint Id; + public uint SpellID; + public int OverrideIcon; + public uint OverridesSpellID; + public uint VisibleSpellID; + } + + public sealed class TraitDefinitionEffectPointsRecord + { + public uint Id; + public int TraitDefinitionID; + public int EffectIndex; + public int OperationType; + public int CurveID; + + public TraitPointsOperationType GetOperationType() { return (TraitPointsOperationType)OperationType; } + } + + public sealed class TraitEdgeRecord + { + public uint Id; + public int VisualStyle; + public int LeftTraitNodeID; + public int RightTraitNodeID; + public int Type; + } + + public sealed class TraitNodeRecord + { + public uint Id; + public int TraitTreeID; + public int PosX; + public int PosY; + public sbyte Type; + public int Flags; + + public TraitNodeType GetNodeType() { return (TraitNodeType)Type; } + } + + public sealed class TraitNodeEntryRecord + { + public uint Id; + public int TraitDefinitionID; + public int MaxRanks; + public byte NodeRecordType; + } + + public sealed class TraitNodeEntryXTraitCondRecord + { + public uint Id; + public int TraitCondID; + public uint TraitNodeEntryID; + } + + public sealed class TraitNodeEntryXTraitCostRecord + { + public uint Id; + public int TraitNodeEntryID; + public int TraitCostID; + } + + public sealed class TraitNodeGroupRecord + { + public uint Id; + public int TraitTreeID; + public int Flags; + } + + public sealed class TraitNodeGroupXTraitCondRecord + { + public uint Id; + public int TraitCondID; + public int TraitNodeGroupID; + } + + public sealed class TraitNodeGroupXTraitCostRecord + { + public uint Id; + public int TraitNodeGroupID; + public int TraitCostID; + } + + public sealed class TraitNodeGroupXTraitNodeRecord + { + public uint Id; + public int TraitNodeGroupID; + public int TraitNodeID; + public int Index; + } + + public sealed class TraitNodeXTraitCondRecord + { + public uint Id; + public int TraitCondID; + public int TraitNodeID; + } + + public sealed class TraitNodeXTraitCostRecord + { + public uint Id; + public uint TraitNodeID; + public int TraitCostID; + } + + public sealed class TraitNodeXTraitNodeEntryRecord + { + public uint Id; + public int TraitNodeID; + public int TraitNodeEntryID; + public int Index; + } + + public sealed class TraitTreeRecord + { + public uint Id; + public int TraitSystemID; + public int Unused1000_1; + public int FirstTraitNodeID; + public int PlayerConditionID; + public int Flags; + public float Unused1000_2; + public float Unused1000_3; + + public TraitTreeFlag GetFlags() { return (TraitTreeFlag)Flags; } + } + + public sealed class TraitTreeLoadoutRecord + { + public uint Id; + public int TraitTreeID; + public int ChrSpecializationID; + } + + public sealed class TraitTreeLoadoutEntryRecord + { + public uint Id; + public int TraitTreeLoadoutID; + public int SelectedTraitNodeID; + public int SelectedTraitNodeEntryID; + public int NumPoints; + public int OrderIndex; + } + + public sealed class TraitTreeXTraitCostRecord + { + public uint Id; + public uint TraitTreeID; + public int TraitCostID; + } + + public sealed class TraitTreeXTraitCurrencyRecord + { + public uint Id; + public int Index; + public int TraitTreeID; + public int TraitCurrencyID; + } + public sealed class TransmogIllusionRecord { public uint Id; @@ -161,5 +377,4 @@ namespace Game.DataStorage public uint TimeIndex; public uint GameObjectsID; } - -} +} \ No newline at end of file diff --git a/Source/Game/Entities/Object/Update/UpdateField.cs b/Source/Game/Entities/Object/Update/UpdateField.cs index 7f7eacef3..87bdfde0d 100644 --- a/Source/Game/Entities/Object/Update/UpdateField.cs +++ b/Source/Game/Entities/Object/Update/UpdateField.cs @@ -141,7 +141,7 @@ namespace Game.Entities public bool HasValue() { return _hasValue; } } - + public class UpdateFieldArray where T : new() { public T[] _values; @@ -437,6 +437,12 @@ namespace Game.Entities return updateField; } + public UpdateFieldString ModifyValue(UpdateFieldString updateField) + { + MarkChanged(updateField); + return updateField; + } + public ref U ModifyValue(UpdateFieldArray updateField, int index) where U : new() { MarkChanged(updateField, index); @@ -472,6 +478,12 @@ namespace Game.Entities _changesMask.Set(updateField.Bit); } + public void MarkChanged(UpdateFieldString updateField) + { + _changesMask.Set(updateField.BlockBit); + _changesMask.Set(updateField.Bit); + } + public void MarkChanged(UpdateFieldArray updateField, int index) where U : new() { _changesMask.Set(updateField.Bit); diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index c9c45d5d0..ba91dc0b0 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -824,7 +824,7 @@ namespace Game.Entities public abstract void BuildValuesCreate(WorldPacket data, Player target); public abstract void BuildValuesUpdate(WorldPacket data, Player target); - public void SetUpdateFieldValue(IUpdateField updateField, T newValue) where T : new() + public void SetUpdateFieldValue(IUpdateField updateField, T newValue) { if (!newValue.Equals(updateField.GetValue())) { @@ -863,7 +863,7 @@ namespace Game.Entities SetUpdateFieldValue(ref value, (T)(value | (dynamic)flag)); } - public void RemoveUpdateFieldFlagValue(IUpdateField updateField, T flag) where T : new() + public void RemoveUpdateFieldFlagValue(IUpdateField updateField, T flag) { //static_assert(std::is_integral < T >::value, "SetUpdateFieldFlagValue must be used with integral types"); SetUpdateFieldValue(updateField, (T)(updateField.GetValue() & ~(dynamic)flag)); diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 8443c2d25..d0483b623 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -1010,6 +1010,146 @@ namespace Game.Entities while (result.NextRow()); } } + + void _LoadTraits(SQLResult configsResult, SQLResult entriesResult) + { + MultiMap traitEntriesByConfig = new(); + if (!entriesResult.IsEmpty()) + { + // 0 1, 2 3 4 + // SELECT traitConfigId, traitNodeId, traitNodeEntryId, rank, grantedRanks FROM character_trait_entry WHERE guid = ? + do + { + TraitEntryPacket traitEntry = new(); + traitEntry.TraitNodeID = entriesResult.Read(1); + traitEntry.TraitNodeEntryID = entriesResult.Read(2); + traitEntry.Rank = entriesResult.Read(3); + traitEntry.GrantedRanks = entriesResult.Read(4); + + if (!TraitMgr.IsValidEntry(traitEntry)) + continue; + + traitEntriesByConfig.Add(entriesResult.Read(0), traitEntry); + + } while (entriesResult.NextRow()); + } + + if (!configsResult.IsEmpty()) + { + // 0 1 2 3 4 5 6 7 + // SELECT traitConfigId, type, chrSpecializationId, combatConfigFlags, localIdentifier, skillLineId, traitSystemId, `name` FROM character_trait_config WHERE guid = ? + do + { + TraitConfigPacket traitConfig = new(); + traitConfig.ID = configsResult.Read(0); + traitConfig.Type = (TraitConfigType)configsResult.Read(1); + switch (traitConfig.Type) + { + case TraitConfigType.Combat: + traitConfig.ChrSpecializationID = configsResult.Read(2); + traitConfig.CombatConfigFlags = (TraitCombatConfigFlags)configsResult.Read(3); + traitConfig.LocalIdentifier = configsResult.Read(4); + break; + case TraitConfigType.Profession: + traitConfig.SkillLineID = configsResult.Read(5); + break; + case TraitConfigType.Generic: + traitConfig.TraitSystemID = configsResult.Read(6); + break; + default: + break; + } + + traitConfig.Name = configsResult.Read(7); + + foreach (var traitEntry in traitEntriesByConfig.LookupByKey(traitConfig.ID)) + traitConfig.Entries.Add(traitEntry); + + if (TraitMgr.ValidateConfig(traitConfig, this) != TalentLearnResult.LearnOk) + { + traitConfig.Entries.Clear(); + foreach (TraitEntry grantedEntry in TraitMgr.GetGrantedTraitEntriesForConfig(traitConfig, this)) + traitConfig.Entries.Add(new TraitEntryPacket(grantedEntry)); + } + + AddTraitConfig(traitConfig); + + } while (configsResult.NextRow()); + } + + bool hasConfigForSpec(int specId) + { + return m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return traitConfig.Type == (int)TraitConfigType.Combat + && traitConfig.ChrSpecializationID == specId + && (traitConfig.CombatConfigFlags & (int)TraitCombatConfigFlags.ActiveForSpec) != 0; + }) >= 0; + } + + int findFreeLocalIdentifier(int specId) + { + int index = 1; + while (m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return traitConfig.Type == (int)TraitConfigType.Combat + && traitConfig.ChrSpecializationID == specId + && traitConfig.LocalIdentifier == index; + }) >= 0) + ++index; + + return index; + } + + for (uint i = 0; i < PlayerConst.MaxSpecializations - 1 /*initial spec doesnt get a config*/; ++i) + { + var spec = Global.DB2Mgr.GetChrSpecializationByIndex(GetClass(), i); + if (spec != null) + { + if (hasConfigForSpec((int)spec.Id)) + continue; + + TraitConfigPacket traitConfig = new(); + traitConfig.Type = TraitConfigType.Combat; + traitConfig.ChrSpecializationID = (int)spec.Id; + traitConfig.CombatConfigFlags = TraitCombatConfigFlags.ActiveForSpec; + traitConfig.LocalIdentifier = findFreeLocalIdentifier((int)spec.Id); + traitConfig.Name = spec.Name[GetSession().GetSessionDbcLocale()]; + + CreateTraitConfig(traitConfig); + } + } + + int activeConfig = m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return traitConfig.Type == (int)TraitConfigType.Combat + && traitConfig.ChrSpecializationID == GetPrimarySpecialization() + && (traitConfig.CombatConfigFlags & (int)TraitCombatConfigFlags.ActiveForSpec) != 0; + }); + + if (activeConfig >= 0) + SetActiveCombatTraitConfigID(m_activePlayerData.TraitConfigs[activeConfig].ID); + + foreach (TraitConfig traitConfig in m_activePlayerData.TraitConfigs) + { + switch ((TraitConfigType)(int)traitConfig.Type) + { + case TraitConfigType.Combat: + if (traitConfig.ID != m_activePlayerData.ActiveCombatTraitConfigID) + continue; + break; + case TraitConfigType.Profession: + if (!HasSkill((uint)(int)traitConfig.SkillLineID)) + continue; + break; + default: + break; + } + + ApplyTraitConfig(traitConfig.ID, true); + } + } + void _LoadGlyphs(SQLResult result) { // SELECT talentGroup, glyphId from character_glyphs WHERE guid = ? @@ -1863,6 +2003,23 @@ namespace Game.Entities void _SaveActions(SQLTransaction trans) { + int traitConfigId = 0; + + TraitConfig traitConfig = GetTraitConfig((int)(uint)m_activePlayerData.ActiveCombatTraitConfigID); + if (traitConfig != null) + { + int usedSavedTraitConfigIndex = m_activePlayerData.TraitConfigs.FindIndexIf(savedConfig => + { + return (TraitConfigType)(int)savedConfig.Type == TraitConfigType.Combat + && ((TraitCombatConfigFlags)(int)savedConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) == TraitCombatConfigFlags.None + && ((TraitCombatConfigFlags)(int)savedConfig.CombatConfigFlags & TraitCombatConfigFlags.SharedActionBars) == TraitCombatConfigFlags.None + && savedConfig.LocalIdentifier == traitConfig.LocalIdentifier; + }); + + if (usedSavedTraitConfigIndex >= 0) + traitConfigId = m_activePlayerData.TraitConfigs[usedSavedTraitConfigIndex].ID; + } + PreparedStatement stmt; foreach (var pair in m_actionButtons.ToList()) @@ -1873,9 +2030,10 @@ namespace Game.Entities stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHAR_ACTION); stmt.AddValue(0, GetGUID().GetCounter()); stmt.AddValue(1, GetActiveTalentGroup()); - stmt.AddValue(2, pair.Key); - stmt.AddValue(3, pair.Value.GetAction()); - stmt.AddValue(4, (byte)pair.Value.GetButtonType()); + stmt.AddValue(2, traitConfigId); + stmt.AddValue(3, pair.Key); + stmt.AddValue(4, pair.Value.GetAction()); + stmt.AddValue(5, (byte)pair.Value.GetButtonType()); trans.Append(stmt); pair.Value.uState = ActionButtonUpdateState.UnChanged; @@ -1887,6 +2045,7 @@ namespace Game.Entities stmt.AddValue(2, GetGUID().GetCounter()); stmt.AddValue(3, pair.Key); stmt.AddValue(4, GetActiveTalentGroup()); + stmt.AddValue(5, traitConfigId); trans.Append(stmt); pair.Value.uState = ActionButtonUpdateState.UnChanged; @@ -1896,6 +2055,7 @@ namespace Game.Entities stmt.AddValue(0, GetGUID().GetCounter()); stmt.AddValue(1, pair.Key); stmt.AddValue(2, GetActiveTalentGroup()); + stmt.AddValue(3, traitConfigId); trans.Append(stmt); m_actionButtons.Remove(pair.Key); @@ -2135,6 +2295,99 @@ namespace Game.Entities trans.Append(stmt); } } + + void _SaveTraits(SQLTransaction trans) + { + PreparedStatement stmt = null; + foreach (var (traitConfigId, state) in m_traitConfigStates) + { + switch (state) + { + case PlayerSpellState.Changed: + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_TRAIT_ENTRIES); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfigId); + trans.Append(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_TRAIT_CONFIGS); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfigId); + trans.Append(stmt); + + TraitConfig traitConfig = GetTraitConfig(traitConfigId); + if (traitConfig != null) + { + stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHAR_TRAIT_CONFIGS); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfig.ID); + stmt.AddValue(2, traitConfig.Type); + switch ((TraitConfigType)(int)traitConfig.Type) + { + case TraitConfigType.Combat: + stmt.AddValue(3, traitConfig.ChrSpecializationID); + stmt.AddValue(4, traitConfig.CombatConfigFlags); + stmt.AddValue(5, traitConfig.LocalIdentifier); + stmt.AddNull(6); + stmt.AddNull(7); + break; + case TraitConfigType.Profession: + stmt.AddNull(3); + stmt.AddNull(4); + stmt.AddNull(5); + stmt.AddValue(6, traitConfig.SkillLineID); + stmt.AddNull(7); + break; + case TraitConfigType.Generic: + stmt.AddNull(3); + stmt.AddNull(4); + stmt.AddNull(5); + stmt.AddNull(6); + stmt.AddValue(7, traitConfig.TraitSystemID); + break; + default: + break; + } + + stmt.AddValue(8, traitConfig.Name); + trans.Append(stmt); + + foreach (var traitEntry in traitConfig.Entries) + { + stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_CHAR_TRAIT_ENTRIES); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfig.ID); + stmt.AddValue(2, traitEntry.TraitNodeID); + stmt.AddValue(3, traitEntry.TraitNodeEntryID); + stmt.AddValue(4, traitEntry.Rank); + stmt.AddValue(5, traitEntry.GrantedRanks); + trans.Append(stmt); + } + } + break; + case PlayerSpellState.Removed: + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_TRAIT_ENTRIES); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfigId); + trans.Append(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_TRAIT_CONFIGS); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfigId); + trans.Append(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_ACTION_BY_TRAIT_CONFIG); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfigId); + trans.Append(stmt); + break; + default: + break; + } + } + + m_traitConfigStates.Clear(); + } + public void _SaveMail(SQLTransaction trans) { PreparedStatement stmt; @@ -3074,6 +3327,8 @@ namespace Game.Entities LearnDefaultSkills(); LearnCustomSpells(); + _LoadTraits(holder.GetResult(PlayerLoginQueryLoad.TraitConfigs), holder.GetResult(PlayerLoginQueryLoad.TraitEntries)); // must be after loading spells + // must be before inventory (some items required reputation check) reputationMgr.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Reputation)); @@ -3086,7 +3341,7 @@ namespace Game.Entities // update items with duration and realtime UpdateItemDuration(time_diff, true); - _LoadActions(holder.GetResult(PlayerLoginQueryLoad.Actions)); + StartLoadingActionButtons(); // unread mails and next delivery time, actual mails not loaded _LoadMail(holder.GetResult(PlayerLoginQueryLoad.Mails), @@ -3633,6 +3888,7 @@ namespace Game.Entities _SaveMonthlyQuestStatus(characterTransaction); _SaveGlyphs(characterTransaction); _SaveTalents(characterTransaction); + _SaveTraits(characterTransaction); _SaveSpells(characterTransaction); GetSpellHistory().SaveToDB(characterTransaction); _SaveActions(characterTransaction); @@ -4183,6 +4439,14 @@ namespace Game.Entities Garrison.DeleteFromDB(guid, trans); + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_TRAIT_ENTRIES_BY_CHAR); + stmt.AddValue(0, guid); + trans.Append(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_TRAIT_CONFIGS_BY_CHAR); + stmt.AddValue(0, guid); + trans.Append(stmt); + Global.CharacterCacheStorage.DeleteCharacterCacheEntry(playerGuid, name); break; } diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index 60bb98d37..56c27339a 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -257,6 +257,8 @@ namespace Game.Entities uint m_PlayedTimeTotal; uint m_PlayedTimeLevel; + Dictionary m_traitConfigStates = new(); + Dictionary m_actionButtons = new(); ObjectGuid m_playerSharingQuest; uint m_sharedQuestId; diff --git a/Source/Game/Entities/Player/Player.Spells.cs b/Source/Game/Entities/Player/Player.Spells.cs index 049f1fcbe..326ef0369 100644 --- a/Source/Game/Entities/Player/Player.Spells.cs +++ b/Source/Game/Entities/Player/Player.Spells.cs @@ -1024,13 +1024,17 @@ namespace Game.Entities } public bool HasSkill(SkillType skill) + { + return HasSkill((uint)skill); + } + public bool HasSkill(uint skill) { if (skill == 0) return false; SkillInfo skillInfoField = m_activePlayerData.Skill; - var skillStatusData = mSkillStatus.LookupByKey((uint)skill); + var skillStatusData = mSkillStatus.LookupByKey(skill); return skillStatusData != null && skillStatusData.State != SkillState.Deleted && skillInfoField.SkillRank[skillStatusData.Pos] != 0; } public void SetSkill(SkillType skill, uint step, uint newVal, uint maxVal) @@ -2046,14 +2050,14 @@ namespace Game.Entities SendPacket(new SendUnlearnSpells()); } - public void LearnSpell(uint spellId, bool dependent, uint fromSkill = 0, bool suppressMessaging = false) + public void LearnSpell(uint spellId, bool dependent, uint fromSkill = 0, bool suppressMessaging = false, int? traitDefinitionId = null) { PlayerSpell spell = m_spells.LookupByKey(spellId); bool disabled = (spell != null) && spell.Disabled; bool active = !disabled || spell.Active; - bool learning = AddSpell(spellId, active, true, dependent, false, false, fromSkill); + bool learning = AddSpell(spellId, active, true, dependent, false, false, fromSkill, traitDefinitionId); // prevent duplicated entires in spell book, also not send if not in world (loading) if (learning && IsInWorld) @@ -2061,6 +2065,7 @@ namespace Game.Entities LearnedSpells learnedSpells = new(); LearnedSpellInfo learnedSpellInfo = new(); learnedSpellInfo.SpellID = spellId; + learnedSpellInfo.TraitDefinitionID = traitDefinitionId; learnedSpells.SuppressMessaging = suppressMessaging; learnedSpells.ClientLearnedSpellData.Add(learnedSpellInfo); SendPacket(learnedSpells); @@ -2315,7 +2320,7 @@ namespace Game.Entities return null; } - bool AddSpell(uint spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint fromSkill = 0) + bool AddSpell(uint spellId, bool active, bool learning, bool dependent, bool disabled, bool loading = false, uint fromSkill = 0, int? traitDefinitionId = null) { SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None); if (spellInfo == null) @@ -2394,6 +2399,18 @@ namespace Game.Entities dependent_set = true; } + if (spell.TraitDefinitionId != traitDefinitionId) + { + if (spell.TraitDefinitionId.HasValue) + { + TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(spell.TraitDefinitionId.Value); + if (traitDefinition != null) + RemoveOverrideSpell((uint)traitDefinition.OverridesSpellID, spellId); + } + + spell.TraitDefinitionId = traitDefinitionId; + } + // update active state for known spell if (spell.Active != active && spell.State != PlayerSpellState.Removed && !spell.Disabled) { @@ -2475,6 +2492,8 @@ namespace Game.Entities newspell.Active = active; newspell.Dependent = dependent; newspell.Disabled = disabled; + if (traitDefinitionId.HasValue) + newspell.TraitDefinitionId = traitDefinitionId.Value; // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible if (newspell.Active && !newspell.Disabled && spellInfo.IsRanked()) @@ -2524,26 +2543,73 @@ namespace Game.Entities return false; } + bool castSpell = false; + // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned) // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive if (!loading && spellInfo.HasAttribute(SpellCustomAttributes.IsTalent) && spellInfo.HasEffect(SpellEffectName.LearnSpell)) { // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show) - CastSpell(this, spellId, true); + castSpell = true; } // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks else if (spellInfo.IsPassive()) - { - if (HandlePassiveSpellLearn(spellInfo)) - CastSpell(this, spellId, true); - } + castSpell = HandlePassiveSpellLearn(spellInfo); else if (spellInfo.HasEffect(SpellEffectName.SkillStep)) - { - CastSpell(this, spellId, true); - return false; - } + castSpell = true; else if (spellInfo.HasAttribute(SpellAttr1.CastWhenLearned)) - CastSpell(this, spellId, true); + castSpell = true; + + if (castSpell) + { + CastSpellExtraArgs args = new(TriggerCastFlags.FullMask); + + if (traitDefinitionId.HasValue) + { + TraitConfig traitConfig = GetTraitConfig((int)(uint)m_activePlayerData.ActiveCombatTraitConfigID); + if (traitConfig != null) + { + int traitEntryIndex = traitConfig.Entries.FindIndexIf(traitEntry => + { + return CliDB.TraitNodeEntryStorage.LookupByKey(traitEntry.TraitNodeEntryID)?.TraitDefinitionID == traitDefinitionId; + }); + + int rank = 0; + if (traitEntryIndex >= 0) + rank = traitConfig.Entries[traitEntryIndex].Rank + traitConfig.Entries[traitEntryIndex].GrantedRanks; + + if (rank > 0) + { + var traitDefinitionEffectPoints = TraitMgr.GetTraitDefinitionEffectPointModifiers(traitDefinitionId.Value); + if (traitDefinitionEffectPoints != null) + { + foreach (TraitDefinitionEffectPointsRecord traitDefinitionEffectPoint in traitDefinitionEffectPoints) + { + if (traitDefinitionEffectPoint.EffectIndex >= spellInfo.GetEffects().Count) + continue; + + float basePoints = Global.DB2Mgr.GetCurveValueAt((uint)traitDefinitionEffectPoint.CurveID, rank); + if (traitDefinitionEffectPoint.GetOperationType() == TraitPointsOperationType.Multiply) + basePoints *= spellInfo.GetEffect((uint)traitDefinitionEffectPoint.EffectIndex).CalcBaseValue(this, null, 0, -1); + + args.AddSpellMod(SpellValueMod.BasePoint0 + traitDefinitionEffectPoint.EffectIndex, (int)basePoints); + } + } + } + } + } + + CastSpell(this, spellId, args); + if (spellInfo.HasEffect(SpellEffectName.SkillStep)) + return false; + } + + if (traitDefinitionId.HasValue) + { + TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(traitDefinitionId.Value); + if (traitDefinition != null) + AddOverrideSpell(traitDefinition.OverridesSpellID, spellId); + } // update free primary prof.points (if any, can be none in case GM .learn prof. learning) uint freeProfs = GetFreePrimaryProfessionPoints(); @@ -3525,5 +3591,6 @@ namespace Game.Entities public bool Active; public bool Dependent; public bool Disabled; + public int? TraitDefinitionId; } } diff --git a/Source/Game/Entities/Player/Player.Talents.cs b/Source/Game/Entities/Player/Player.Talents.cs index 2f5af1574..8d07b73dd 100644 --- a/Source/Game/Entities/Player/Player.Talents.cs +++ b/Source/Game/Entities/Player/Player.Talents.cs @@ -349,6 +349,8 @@ namespace Game.Entities RemoveOverrideSpell(talentInfo.OverridesSpellID, talentInfo.SpellID); } + ApplyTraitConfig((int)(uint)m_activePlayerData.ActiveCombatTraitConfigID, false); + // Remove spec specific spells RemoveSpecializationSpells(); @@ -357,6 +359,16 @@ namespace Game.Entities SetActiveTalentGroup(spec.OrderIndex); SetPrimarySpecialization(spec.Id); + int specTraitConfigIndex = m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && traitConfig.ChrSpecializationID == spec.Id + && ((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) != TraitCombatConfigFlags.None; + }); + if (specTraitConfigIndex >= 0) + SetActiveCombatTraitConfigID(m_activePlayerData.TraitConfigs[specTraitConfigIndex].ID); + else + SetActiveCombatTraitConfigID(0); foreach (var talentInfo in CliDB.TalentStorage.Values) { @@ -399,20 +411,11 @@ namespace Game.Entities } } + ApplyTraitConfig((int)(uint)m_activePlayerData.ActiveCombatTraitConfigID, true); + InitTalentForLevel(); - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC); - stmt.AddValue(0, GetGUID().GetCounter()); - stmt.AddValue(1, GetActiveTalentGroup()); - - WorldSession mySess = GetSession(); - mySess.GetQueryProcessor().AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(result => - { - // in case player logs out before db response (player would be deleted in that case) - Player thisPlayer = mySess.GetPlayer(); - if (thisPlayer != null) - thisPlayer.LoadActions(result); - })); + StartLoadingActionButtons(); UpdateDisplayPower(); PowerType pw = GetPowerType(); @@ -477,6 +480,48 @@ namespace Game.Entities } } + void StartLoadingActionButtons(Action callback = null) + { + uint traitConfigId = 0; + + TraitConfig traitConfig = GetTraitConfig((int)(uint)m_activePlayerData.ActiveCombatTraitConfigID); + if (traitConfig != null) + { + int usedSavedTraitConfigIndex = m_activePlayerData.TraitConfigs.FindIndexIf(savedConfig => + { + return (TraitConfigType)(int)savedConfig.Type == TraitConfigType.Combat + && ((TraitCombatConfigFlags)(int)savedConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) == TraitCombatConfigFlags.None + && ((TraitCombatConfigFlags)(int)savedConfig.CombatConfigFlags & TraitCombatConfigFlags.SharedActionBars) == TraitCombatConfigFlags.None + && savedConfig.LocalIdentifier == traitConfig.LocalIdentifier; + }); + + if (usedSavedTraitConfigIndex >= 0) + traitConfigId = (uint)(int)m_activePlayerData.TraitConfigs[usedSavedTraitConfigIndex].ID; + } + + // load them asynchronously + PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, GetActiveTalentGroup()); + stmt.AddValue(2, traitConfigId); + + var myGuid = GetGUID(); + + WorldSession mySess = GetSession(); + mySess.GetQueryProcessor().AddCallback(DB.Characters.AsyncQuery(stmt) + .WithCallback(result => + { + // safe callback, we can't pass this pointer directly + // in case player logs out before db response (player would be deleted in that case) + Player thisPlayer = mySess.GetPlayer(); + if (thisPlayer != null && thisPlayer.GetGUID() == myGuid) + thisPlayer.LoadActions(result); + + if (callback != null) + callback(); + })); + } + public Dictionary GetTalentMap(uint spec) { return _specializationInfo.Talents[spec]; } public List GetGlyphs(byte spec) { return _specializationInfo.Glyphs[spec]; } @@ -803,5 +848,357 @@ namespace Game.Entities { return GetPvpTalentMap(activeTalentGroup).Contains(talentID); } + + //Traits + public void CreateTraitConfig(TraitConfigPacket traitConfig) + { + int configId = TraitMgr.GenerateNewTraitConfigId(); + bool hasConfigId(int id) + { + return m_activePlayerData.TraitConfigs.FindIndexIf(config => config.ID == id) >= 0; + } + + while (hasConfigId(configId)) + configId = TraitMgr.GenerateNewTraitConfigId(); + + traitConfig.ID = configId; + + int traitConfigIndex = m_activePlayerData.TraitConfigs.Size(); + AddTraitConfig(traitConfig); + + foreach (TraitEntry grantedEntry in TraitMgr.GetGrantedTraitEntriesForConfig(traitConfig, this)) + { + var entryIndex = traitConfig.Entries.Find(entry => entry.TraitNodeID == grantedEntry.TraitNodeID && entry.TraitNodeEntryID == grantedEntry.TraitNodeEntryID); + if (entryIndex == null) + { + TraitConfig value = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, traitConfigIndex); + AddDynamicUpdateFieldValue(value.ModifyValue(value.Entries), grantedEntry); + } + } + + m_traitConfigStates[(int)configId] = PlayerSpellState.Changed; + } + + void AddTraitConfig(TraitConfigPacket traitConfig) + { + var setter = new TraitConfig(); + setter.ModifyValue(setter.ID).SetValue(traitConfig.ID); + setter.ModifyValue(setter.Name).SetValue(traitConfig.Name); + setter.ModifyValue(setter.Type).SetValue((int)traitConfig.Type); + setter.ModifyValue(setter.SkillLineID).SetValue((int)traitConfig.SkillLineID); + setter.ModifyValue(setter.ChrSpecializationID).SetValue(traitConfig.ChrSpecializationID); + setter.ModifyValue(setter.CombatConfigFlags).SetValue((int)traitConfig.CombatConfigFlags); + setter.ModifyValue(setter.LocalIdentifier).SetValue(traitConfig.LocalIdentifier); + setter.ModifyValue(setter.TraitSystemID).SetValue(traitConfig.TraitSystemID); + + AddDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs), setter); + + foreach (TraitEntryPacket traitEntry in traitConfig.Entries) + { + TraitEntry newEntry = new(); + newEntry.TraitNodeID = traitEntry.TraitNodeID; + newEntry.TraitNodeEntryID = traitEntry.TraitNodeEntryID; + newEntry.Rank = traitEntry.Rank; + newEntry.GrantedRanks = traitEntry.GrantedRanks; + AddDynamicUpdateFieldValue(setter.ModifyValue(setter.Entries), newEntry); + } + } + + public TraitConfig GetTraitConfig(int configId) + { + int index = m_activePlayerData.TraitConfigs.FindIndexIf(config => config.ID == configId); + if (index < 0) + return null; + + return m_activePlayerData.TraitConfigs[index]; + } + + public void UpdateTraitConfig(TraitConfigPacket newConfig, int savedConfigId, bool withCastTime) + { + int index = m_activePlayerData.TraitConfigs.FindIndexIf(config => config.ID == newConfig.ID); + if (index < 0) + return; + + if (withCastTime) + { + CastSpell(this, TraitMgr.COMMIT_COMBAT_TRAIT_CONFIG_CHANGES_SPELL_ID, new CastSpellExtraArgs(SpellValueMod.BasePoint0, savedConfigId).SetCustomArg(newConfig)); + return; + } + + bool isActiveConfig = true; + bool loadActionButtons = false; + switch ((TraitConfigType)(int)m_activePlayerData.TraitConfigs[index].Type) + { + case TraitConfigType.Combat: + isActiveConfig = newConfig.ID == m_activePlayerData.ActiveCombatTraitConfigID; + loadActionButtons = m_activePlayerData.TraitConfigs[index].LocalIdentifier != newConfig.LocalIdentifier; + break; + case TraitConfigType.Profession: + isActiveConfig = HasSkill((uint)(int)m_activePlayerData.TraitConfigs[index].SkillLineID); + break; + default: + break; + } + + Action finalizeTraitConfigUpdate = () => + { + TraitConfig newTraitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, index); + SetUpdateFieldValue(newTraitConfig.ModifyValue(newTraitConfig.LocalIdentifier), newConfig.LocalIdentifier); + + ApplyTraitEntryChanges(newConfig.ID, newConfig, isActiveConfig, true); + + if (savedConfigId != 0) + ApplyTraitEntryChanges(savedConfigId, newConfig, false, false); + + if (((TraitCombatConfigFlags)(int)newConfig.CombatConfigFlags).HasFlag(TraitCombatConfigFlags.StarterBuild)) + SetTraitConfigUseStarterBuild(newConfig.ID, true); + }; + + if (loadActionButtons) + { + SQLTransaction trans = new SQLTransaction(); + _SaveActions(trans); + DB.Characters.CommitTransaction(trans); + + StartLoadingActionButtons(finalizeTraitConfigUpdate); + } + else + finalizeTraitConfigUpdate(); + } + + void ApplyTraitEntryChanges(int editedConfigId, TraitConfigPacket newConfig, bool applyTraits, bool consumeCurrencies) + { + int editedIndex = m_activePlayerData.TraitConfigs.FindIndexIf(config => config.ID == editedConfigId); + if (editedIndex < 0) + return; + + TraitConfig editedConfig = m_activePlayerData.TraitConfigs[editedIndex]; + + // remove traits not found in new config + List entryIndicesToRemove = new(); + for (int i = 0; i < editedConfig.Entries.Size(); ++i) + { + TraitEntry oldEntry = editedConfig.Entries[i]; + var entryItr = newConfig.Entries.Find(ufEntry => ufEntry.TraitNodeID == oldEntry.TraitNodeID && ufEntry.TraitNodeEntryID == oldEntry.TraitNodeEntryID); + if (entryItr != null) + continue; + + if (applyTraits) + ApplyTraitEntry(oldEntry.TraitNodeEntryID, 0, 0, false); + + entryIndicesToRemove.Add(i); + } + + foreach (int indexToRemove in entryIndicesToRemove) + { + TraitConfig traitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, editedIndex); + RemoveDynamicUpdateFieldValue(traitConfig.ModifyValue(traitConfig.Entries), indexToRemove); + } + + List costEntries = new(); + + // apply new traits + for (var i = 0; i < newConfig.Entries.Count; ++i) + { + TraitEntryPacket newEntry = newConfig.Entries[i]; + int oldEntryIndex = editedConfig.Entries.FindIndexIf(ufEntry => ufEntry.TraitNodeID == newEntry.TraitNodeID && ufEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID); + if (oldEntryIndex < 0) + { + if (consumeCurrencies) + costEntries.Add(newEntry); + + TraitConfig newTraitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, editedIndex); + TraitEntry newUfEntry = new(); + newUfEntry.TraitNodeID = newEntry.TraitNodeID; + newUfEntry.TraitNodeEntryID = newEntry.TraitNodeEntryID; + newUfEntry.Rank = newEntry.Rank; + newUfEntry.GrantedRanks = newEntry.GrantedRanks; + + AddDynamicUpdateFieldValue(newTraitConfig.ModifyValue(newTraitConfig.Entries), newUfEntry); + + if (applyTraits) + ApplyTraitEntry(newUfEntry.TraitNodeEntryID, newUfEntry.Rank, 0, true); + } + else if (newEntry.Rank != editedConfig.Entries[oldEntryIndex].Rank || newEntry.GrantedRanks != editedConfig.Entries[oldEntryIndex].GrantedRanks) + { + if (consumeCurrencies && newEntry.Rank > editedConfig.Entries[oldEntryIndex].Rank) + { + TraitEntryPacket costEntry = new(); + costEntry.Rank -= editedConfig.Entries[oldEntryIndex].Rank; + costEntries.Add(newEntry); + } + + TraitConfig traitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, editedIndex); + TraitEntry traitEntry = traitConfig.ModifyValue(traitConfig.Entries, oldEntryIndex); + traitEntry.Rank = newEntry.Rank; + traitEntry.GrantedRanks = newEntry.GrantedRanks; + SetUpdateFieldValue(traitConfig.Entries, oldEntryIndex, traitEntry); + + if (applyTraits) + ApplyTraitEntry(newEntry.TraitNodeEntryID, newEntry.Rank, newEntry.GrantedRanks, true); + } + } + + if (consumeCurrencies) + { + Dictionary currencies = new(); + foreach (TraitEntryPacket costEntry in costEntries) + TraitMgr.FillSpentCurrenciesMap(costEntry, currencies); + + foreach (var (traitCurrencyId, amount) in currencies) + { + TraitCurrencyRecord traitCurrency = CliDB.TraitCurrencyStorage.LookupByKey(traitCurrencyId); + if (traitCurrency == null) + continue; + + switch (traitCurrency.GetCurrencyType()) + { + case TraitCurrencyType.Gold: + ModifyMoney(-amount); + break; + case TraitCurrencyType.CurrencyTypesBased: + ModifyCurrency((CurrencyTypes)traitCurrency.CurrencyTypesID, -amount); + break; + default: + break; + } + } + } + + m_traitConfigStates[(int)editedConfigId] = PlayerSpellState.Changed; + } + + public void RenameTraitConfig(int editedConfigId, string newName) + { + int editedIndex = m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return traitConfig.ID == editedConfigId + && (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && ((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) == TraitCombatConfigFlags.None; + }); + if (editedIndex < 0) + return; + + TraitConfig traitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, editedIndex); + SetUpdateFieldValue(traitConfig.ModifyValue(traitConfig.Name), newName); + + m_traitConfigStates[editedConfigId] = PlayerSpellState.Changed; + } + + public void DeleteTraitConfig(int deletedConfigId) + { + int deletedIndex = m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return traitConfig.ID == deletedConfigId + && (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && ((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) == TraitCombatConfigFlags.None; + }); + if (deletedIndex < 0) + return; + + RemoveDynamicUpdateFieldValue(m_values.ModifyValue(m_activePlayerData) + .ModifyValue(m_activePlayerData.TraitConfigs), deletedIndex); + + m_traitConfigStates[deletedConfigId] = PlayerSpellState.Removed; + } + + void ApplyTraitConfig(int configId, bool apply) + { + TraitConfig traitConfig = GetTraitConfig(configId); + if (traitConfig == null) + return; + + foreach (TraitEntry traitEntry in traitConfig.Entries) + ApplyTraitEntry(traitEntry.TraitNodeEntryID, traitEntry.Rank, traitEntry.GrantedRanks, apply); + } + + void ApplyTraitEntry(int traitNodeEntryId, int rank, int grantedRanks, bool apply) + { + TraitNodeEntryRecord traitNodeEntry = CliDB.TraitNodeEntryStorage.LookupByKey(traitNodeEntryId); + if (traitNodeEntry == null) + return; + + TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(traitNodeEntry.TraitDefinitionID); + if (traitDefinition == null) + return; + + if (traitDefinition.SpellID != 0) + { + if (apply) + LearnSpell(traitDefinition.SpellID, true, 0, false, traitNodeEntry.TraitDefinitionID); + else + RemoveSpell(traitDefinition.SpellID); + } + } + + public void SetTraitConfigUseStarterBuild(int traitConfigId, bool useStarterBuild) + { + int configIndex = m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return traitConfig.ID == traitConfigId + && (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && ((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) != TraitCombatConfigFlags.None; + }); + if (configIndex < 0) + return; + + bool currentlyUsesStarterBuild = ((TraitCombatConfigFlags)(int)m_activePlayerData.TraitConfigs[configIndex].CombatConfigFlags).HasFlag(TraitCombatConfigFlags.StarterBuild); + if (currentlyUsesStarterBuild == useStarterBuild) + return; + + if (useStarterBuild) + { + TraitConfig traitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, configIndex); + SetUpdateFieldFlagValue(traitConfig.ModifyValue(traitConfig.CombatConfigFlags), (int)TraitCombatConfigFlags.StarterBuild); + } + else + { + TraitConfig traitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, configIndex); + RemoveUpdateFieldFlagValue(traitConfig.ModifyValue(traitConfig.CombatConfigFlags), (int)TraitCombatConfigFlags.StarterBuild); + } + + m_traitConfigStates[(int)traitConfigId] = PlayerSpellState.Changed; + } + + public void SetTraitConfigUseSharedActionBars(int traitConfigId, bool usesSharedActionBars, bool isLastSelectedSavedConfig) + { + int configIndex = m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return traitConfig.ID == traitConfigId + && (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && ((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) == TraitCombatConfigFlags.None; + }); + if (configIndex < 0) + return; + + bool currentlyUsesSharedActionBars = ((TraitCombatConfigFlags)(int)m_activePlayerData.TraitConfigs[configIndex].CombatConfigFlags).HasFlag(TraitCombatConfigFlags.SharedActionBars); + if (currentlyUsesSharedActionBars == usesSharedActionBars) + return; + + TraitConfig traitConfig = m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.TraitConfigs, configIndex); + if (usesSharedActionBars) + { + SetUpdateFieldFlagValue(traitConfig.ModifyValue(traitConfig.CombatConfigFlags), (int)TraitCombatConfigFlags.SharedActionBars); + + PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_ACTION_BY_TRAIT_CONFIG); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, traitConfigId); + DB.Characters.Execute(stmt); + + if (isLastSelectedSavedConfig) + StartLoadingActionButtons(); // load action buttons that were saved in shared mode + } + else + { + RemoveUpdateFieldFlagValue(traitConfig.ModifyValue(traitConfig.CombatConfigFlags), (int)TraitCombatConfigFlags.SharedActionBars); + + // trigger a save with traitConfigId + foreach (var (_, button) in m_actionButtons) + if (button.uState != ActionButtonUpdateState.Deleted) + button.uState = ActionButtonUpdateState.New; + } + + m_traitConfigStates[traitConfigId] = PlayerSpellState.Changed; + } } } diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 7884608ab..229997a2e 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -6839,7 +6839,9 @@ namespace Game.Entities return false; } - //New shit + + void SetActiveCombatTraitConfigID(int traitConfigId) { SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ActiveCombatTraitConfigID), (uint)traitConfigId); } + void InitPrimaryProfessions() { SetFreePrimaryProfessions(WorldConfig.GetUIntValue(WorldCfg.MaxPrimaryTradeSkill)); diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 4ae08e62f..bc10f3d9a 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -2723,10 +2723,6 @@ namespace Game stmt.AddValue(0, lowGuid); SetQuery(PlayerLoginQueryLoad.VoidStorage, stmt); - stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_ACTIONS); - stmt.AddValue(0, lowGuid); - SetQuery(PlayerLoginQueryLoad.Actions, stmt); - stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAIL); stmt.AddValue(0, lowGuid); SetQuery(PlayerLoginQueryLoad.Mails, stmt); @@ -2877,6 +2873,14 @@ namespace Game stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GARRISON_FOLLOWER_ABILITIES); stmt.AddValue(0, lowGuid); SetQuery(PlayerLoginQueryLoad.GarrisonFollowerAbilities, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_TRAIT_ENTRIES); + stmt.AddValue(0, lowGuid); + SetQuery(PlayerLoginQueryLoad.TraitEntries, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_TRAIT_CONFIGS); + stmt.AddValue(0, lowGuid); + SetQuery(PlayerLoginQueryLoad.TraitConfigs, stmt); } public ObjectGuid GetGuid() { return m_guid; } @@ -2938,7 +2942,6 @@ namespace Game AzeriteMilestonePowers, AzeriteUnlockedEssences, AzeriteEmpowered, - Actions, Mails, MailItems, MailItemsArtifact, @@ -2980,6 +2983,8 @@ namespace Game GarrisonBuildings, GarrisonFollowers, GarrisonFollowerAbilities, + TraitEntries, + TraitConfigs, Max } diff --git a/Source/Game/Handlers/TraitHandler.cs b/Source/Game/Handlers/TraitHandler.cs new file mode 100644 index 000000000..c55e492f7 --- /dev/null +++ b/Source/Game/Handlers/TraitHandler.cs @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2012-2020 CypherCore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Framework.Constants; +using Game.DataStorage; +using Game.Entities; +using Game.Networking; +using Game.Networking.Packets; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Game +{ + public partial class WorldSession + { + [WorldPacketHandler(ClientOpcodes.TraitsCommitConfig)] + void HandleTraitsCommitConfig(TraitsCommitConfig traitsCommitConfig) + { + int configId = (int)(uint)traitsCommitConfig.Config.ID; + TraitConfig existingConfig = _player.GetTraitConfig(configId); + if (existingConfig == null) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown)); + return; + } + + if (_player.IsInCombat()) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedAffectingCombat)); + return; + } + + if (_player.GetBattleground() && _player.GetBattleground().GetStatus() == BattlegroundStatus.InProgress) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.InPvpMatch)); + return; + } + + bool hasRemovedEntries = false; + TraitConfigPacket newConfigState = new(existingConfig); + foreach (TraitEntryPacket newEntry in traitsCommitConfig.Config.Entries) + { + TraitEntryPacket traitEntry = newConfigState.Entries.Find(traitEntry => traitEntry.TraitNodeID == newEntry.TraitNodeID && traitEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID); + if (traitEntry != null && traitEntry.Rank > newEntry.Rank) + { + TraitNodeRecord traitNode = CliDB.TraitNodeStorage.LookupByKey(newEntry.TraitNodeID); + if (traitNode == null) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown)); + return; + } + + TraitTreeRecord traitTree = CliDB.TraitTreeStorage.LookupByKey(traitNode.TraitTreeID); + if (traitTree == null) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown)); + return; + } + + if (traitTree.GetFlags().HasFlag(TraitTreeFlag.CannotRefund)) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedCantRemoveTalent)); + return; + } + + TraitNodeEntryRecord traitNodeEntry = CliDB.TraitNodeEntryStorage.LookupByKey(newEntry.TraitNodeEntryID); + if (traitNodeEntry == null) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown)); + return; + } + + TraitDefinitionRecord traitDefinition = CliDB.TraitDefinitionStorage.LookupByKey(traitNodeEntry.TraitDefinitionID); + if (traitDefinition == null) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)TalentLearnResult.FailedUnknown)); + return; + } + + if (traitDefinition.SpellID != 0 && _player.GetSpellHistory().HasCooldown(traitDefinition.SpellID)) + { + SendPacket(new TraitConfigCommitFailed(configId, traitDefinition.SpellID, (int)TalentLearnResult.FailedCantRemoveTalent)); + return; + } + + if (traitDefinition.VisibleSpellID != 0 && _player.GetSpellHistory().HasCooldown((uint)traitDefinition.VisibleSpellID)) + { + SendPacket(new TraitConfigCommitFailed(configId, traitDefinition.VisibleSpellID, (int)TalentLearnResult.FailedCantRemoveTalent)); + return; + } + + hasRemovedEntries = true; + } + + if (traitEntry != null) + { + if (newEntry.Rank != 0) + traitEntry.Rank = newEntry.Rank; + else + newConfigState.Entries.RemoveAll(TraitEntrytraitEntry => traitEntry.TraitNodeID == newEntry.TraitNodeID && traitEntry.TraitNodeEntryID == newEntry.TraitNodeEntryID); + } + else + newConfigState.Entries.Add(newEntry); + } + + TalentLearnResult validationResult = TraitMgr.ValidateConfig(newConfigState, _player, true); + if (validationResult != TalentLearnResult.LearnOk) + { + SendPacket(new TraitConfigCommitFailed(configId, 0, (int)validationResult)); + return; + } + + bool needsCastTime = newConfigState.Type == TraitConfigType.Combat && hasRemovedEntries; + + if (traitsCommitConfig.SavedLocalIdentifier != 0) + newConfigState.LocalIdentifier = traitsCommitConfig.SavedLocalIdentifier; + else + { + TraitConfig savedConfig = _player.GetTraitConfig(traitsCommitConfig.SavedLocalIdentifier); + if (savedConfig != null) + newConfigState.LocalIdentifier = savedConfig.LocalIdentifier; + } + + _player.UpdateTraitConfig(newConfigState, traitsCommitConfig.SavedConfigID, needsCastTime); + } + + [WorldPacketHandler(ClientOpcodes.ClassTalentsRequestNewConfig)] + void HandleClassTalentsRequestNewConfig(ClassTalentsRequestNewConfig classTalentsRequestNewConfig) + { + if (classTalentsRequestNewConfig.Config.Type != TraitConfigType.Combat) + return; + + if ((classTalentsRequestNewConfig.Config.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) != (int)TraitCombatConfigFlags.None) + return; + + long configCount = _player.m_activePlayerData.TraitConfigs._values.Count(traitConfig => + { + return (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && ((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags & TraitCombatConfigFlags.ActiveForSpec) == TraitCombatConfigFlags.None; + }); + if (configCount >= TraitMgr.MAX_COMBAT_TRAIT_CONFIGS) + return; + + int findFreeLocalIdentifier() + { + int index = 1; + while (_player.m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && traitConfig.ChrSpecializationID == _player.GetPrimarySpecialization() + && traitConfig.LocalIdentifier == index; + }) >= 0) + ++index; + + return index; + } + + classTalentsRequestNewConfig.Config.ChrSpecializationID = (int)_player.GetPrimarySpecialization(); + classTalentsRequestNewConfig.Config.LocalIdentifier = findFreeLocalIdentifier(); + + foreach (TraitEntry grantedEntry in TraitMgr.GetGrantedTraitEntriesForConfig(classTalentsRequestNewConfig.Config, _player)) + { + var newEntry = classTalentsRequestNewConfig.Config.Entries.Find(entry => { return entry.TraitNodeID == grantedEntry.TraitNodeID && entry.TraitNodeEntryID == grantedEntry.TraitNodeEntryID; }); + if (newEntry == null) + { + newEntry = new(); + classTalentsRequestNewConfig.Config.Entries.Add(newEntry); + } + + newEntry.TraitNodeID = grantedEntry.TraitNodeID; + newEntry.TraitNodeEntryID = grantedEntry.TraitNodeEntryID; + newEntry.Rank = grantedEntry.Rank; + newEntry.GrantedRanks = grantedEntry.GrantedRanks; + + TraitNodeEntryRecord traitNodeEntry = CliDB.TraitNodeEntryStorage.LookupByKey(grantedEntry.TraitNodeEntryID); + if (traitNodeEntry != null) + if (newEntry.Rank + newEntry.GrantedRanks > traitNodeEntry.MaxRanks) + newEntry.Rank = Math.Max(0, traitNodeEntry.MaxRanks - newEntry.GrantedRanks); + } + + TalentLearnResult validationResult = TraitMgr.ValidateConfig(classTalentsRequestNewConfig.Config, _player); + if (validationResult != TalentLearnResult.LearnOk) + return; + + _player.CreateTraitConfig(classTalentsRequestNewConfig.Config); + } + + [WorldPacketHandler(ClientOpcodes.ClassTalentsRenameConfig)] + void HandleClassTalentsRenameConfig(ClassTalentsRenameConfig classTalentsRenameConfig) + { + _player.RenameTraitConfig(classTalentsRenameConfig.ConfigID, classTalentsRenameConfig.Name); + } + + [WorldPacketHandler(ClientOpcodes.ClassTalentsDeleteConfig)] + void HandleClassTalentsDeleteConfig(ClassTalentsDeleteConfig classTalentsDeleteConfig) + { + _player.DeleteTraitConfig(classTalentsDeleteConfig.ConfigID); + } + + [WorldPacketHandler(ClientOpcodes.ClassTalentsSetStarterBuildActive)] + void HandleClassTalentsSetStarterBuildActive(ClassTalentsSetStarterBuildActive classTalentsSetStarterBuildActive) + { + TraitConfig traitConfig = _player.GetTraitConfig(classTalentsSetStarterBuildActive.ConfigID); + if (traitConfig == null) + return; + + if ((TraitConfigType)(int)traitConfig.Type != TraitConfigType.Combat) + return; + + if (!((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags).HasFlag(TraitCombatConfigFlags.ActiveForSpec)) + return; + + if (classTalentsSetStarterBuildActive.Active) + { + TraitConfigPacket newConfigState = new(traitConfig); + + int freeLocalIdentifier = 1; + while (_player.m_activePlayerData.TraitConfigs.FindIndexIf(traitConfig => + { + return (TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat + && traitConfig.ChrSpecializationID == _player.GetPrimarySpecialization() + && traitConfig.LocalIdentifier == freeLocalIdentifier; + }) >= 0) + ++freeLocalIdentifier; + + TraitMgr.InitializeStarterBuildTraitConfig(newConfigState, _player); + newConfigState.CombatConfigFlags |= TraitCombatConfigFlags.StarterBuild; + newConfigState.LocalIdentifier = freeLocalIdentifier; + + _player.UpdateTraitConfig(newConfigState, 0, true); + } + else + _player.SetTraitConfigUseStarterBuild(classTalentsSetStarterBuildActive.ConfigID, false); + } + + [WorldPacketHandler(ClientOpcodes.ClassTalentsSetUsesSharedActionBars)] + void HandleClassTalentsSetUsesSharedActionBars(ClassTalentsSetUsesSharedActionBars classTalentsSetUsesSharedActionBars) + { + _player.SetTraitConfigUseSharedActionBars(classTalentsSetUsesSharedActionBars.ConfigID, classTalentsSetUsesSharedActionBars.UsesShared, + classTalentsSetUsesSharedActionBars.IsLastSelectedSavedConfig); + } + } +} diff --git a/Source/Game/Networking/Packets/InspectPackets.cs b/Source/Game/Networking/Packets/InspectPackets.cs index 2870298d2..45d0d6e92 100644 --- a/Source/Game/Networking/Packets/InspectPackets.cs +++ b/Source/Game/Networking/Packets/InspectPackets.cs @@ -339,12 +339,12 @@ namespace Game.Networking.Packets { public int Level; public int ChrSpecializationID; - public TraitConfig Config; + public TraitConfigPacket Config; public void Write(WorldPacket data) { - data . WriteInt32(Level); - data . WriteInt32(ChrSpecializationID); + data.WriteInt32(Level); + data.WriteInt32(ChrSpecializationID); Config.Write(data); } } diff --git a/Source/Game/Networking/Packets/TraitPackets.cs b/Source/Game/Networking/Packets/TraitPackets.cs new file mode 100644 index 000000000..ae3fc70ea --- /dev/null +++ b/Source/Game/Networking/Packets/TraitPackets.cs @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2012-2020 CypherCore + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +using Framework.Constants; +using Game.Entities; +using System; +using System.Collections.Generic; + +namespace Game.Networking.Packets +{ + class TraitsCommitConfig : ClientPacket + { + public TraitConfigPacket Config = new(); + public int SavedConfigID; + public int SavedLocalIdentifier; + + public TraitsCommitConfig(WorldPacket packet) : base(packet) { } + + public override void Read() + { + Config.Read(_worldPacket); + SavedConfigID = _worldPacket.ReadInt32(); + SavedLocalIdentifier = _worldPacket.ReadInt32(); + } + } + + class TraitConfigCommitFailed : ServerPacket + { + public int ConfigID; + public uint SpellID; + public int Reason; + + public TraitConfigCommitFailed(int configId = 0, uint spellId = 0, int reason = 0) : base(ServerOpcodes.TraitConfigCommitFailed) + { + ConfigID = configId; + SpellID = spellId; + Reason = reason; + } + + public override void Write() + { + _worldPacket.WriteInt32(ConfigID); + _worldPacket.WriteUInt32(SpellID); + _worldPacket.WriteBits(Reason, 4); + _worldPacket.FlushBits(); + } + } + + class ClassTalentsRequestNewConfig : ClientPacket + { + public TraitConfigPacket Config = new(); + + public ClassTalentsRequestNewConfig(WorldPacket packet) : base(packet) { } + + public override void Read() + { + Config.Read(_worldPacket); + } + } + + class ClassTalentsRenameConfig : ClientPacket + { + public int ConfigID; + public string Name; + + public ClassTalentsRenameConfig(WorldPacket packet) : base(packet) { } + + public override void Read() + { + ConfigID = _worldPacket.ReadInt32(); + uint nameLength = _worldPacket.ReadBits(9); + Name = _worldPacket.ReadString(nameLength); + } + } + + class ClassTalentsDeleteConfig : ClientPacket + { + public int ConfigID; + + public ClassTalentsDeleteConfig(WorldPacket packet) : base(packet) { } + + public override void Read() + { + ConfigID = _worldPacket.ReadInt32(); + } + } + + class ClassTalentsSetStarterBuildActive : ClientPacket + { + public int ConfigID; + public bool Active; + + public ClassTalentsSetStarterBuildActive(WorldPacket packet) : base(packet) { } + + public override void Read() + { + ConfigID = _worldPacket.ReadInt32(); + Active = _worldPacket.HasBit(); + } + } + + class ClassTalentsSetUsesSharedActionBars : ClientPacket + { + public int ConfigID; + public bool UsesShared; + public bool IsLastSelectedSavedConfig; + + public ClassTalentsSetUsesSharedActionBars(WorldPacket packet) : base(packet) { } + + public override void Read() + { + ConfigID = _worldPacket.ReadInt32(); + UsesShared = _worldPacket.HasBit(); + IsLastSelectedSavedConfig = _worldPacket.HasBit(); + } + } + + public class TraitEntryPacket + { + public int TraitNodeID; + public int TraitNodeEntryID; + public int Rank; + public int GrantedRanks; + + public TraitEntryPacket() { } + public TraitEntryPacket(TraitEntry ufEntry) + { + TraitNodeID = ufEntry.TraitNodeID; + TraitNodeEntryID = ufEntry.TraitNodeEntryID; + Rank = ufEntry.Rank; + GrantedRanks = ufEntry.GrantedRanks; + } + + public void Read(WorldPacket data) + { + TraitNodeID = data.ReadInt32(); + TraitNodeEntryID = data.ReadInt32(); + Rank = data.ReadInt32(); + GrantedRanks = data.ReadInt32(); + } + + public void Write(WorldPacket data) + { + data.WriteInt32(TraitNodeID); + data.WriteInt32(TraitNodeEntryID); + data.WriteInt32(Rank); + data.WriteInt32(GrantedRanks); + } + } + + public class TraitConfigPacket + { + public int ID; + public TraitConfigType Type; + public int ChrSpecializationID = 0; + public TraitCombatConfigFlags CombatConfigFlags; + public int LocalIdentifier; // Local to specialization + public uint SkillLineID; + public int TraitSystemID; + public List Entries = new(); + public string Name = ""; + + public TraitConfigPacket() { } + public TraitConfigPacket(TraitConfig ufConfig) + { + ID = ufConfig.ID; + Type = (TraitConfigType)(int)ufConfig.Type; + ChrSpecializationID = ufConfig.ChrSpecializationID; + CombatConfigFlags = (TraitCombatConfigFlags)(int)ufConfig.CombatConfigFlags; + LocalIdentifier = ufConfig.LocalIdentifier; + SkillLineID = (uint)(int)ufConfig.SkillLineID; + TraitSystemID = ufConfig.TraitSystemID; + foreach (TraitEntry ufEntry in ufConfig.Entries) + Entries.Add(new TraitEntryPacket(ufEntry)); + Name = ufConfig.Name; + } + + public void Read(WorldPacket data) + { + ID = data.ReadInt32(); + Type = (TraitConfigType)data.ReadInt32(); + var entriesCount = data.ReadInt32(); + switch (Type) + { + case TraitConfigType.Combat: + ChrSpecializationID = data.ReadInt32(); + CombatConfigFlags = (TraitCombatConfigFlags)data.ReadInt32(); + LocalIdentifier = data.ReadInt32(); + break; + case TraitConfigType.Profession: + SkillLineID = data.ReadUInt32(); + break; + case TraitConfigType.Generic: + TraitSystemID = data.ReadInt32(); + break; + default: + break; + } + + for (var i = 0; i < entriesCount; ++i) + { + TraitEntryPacket traitEntry = new(); + traitEntry.Read(data); + Entries.Add(traitEntry); + } + + uint nameLength = data.ReadBits(9); + Name = data.ReadString(nameLength); + } + + public void Write(WorldPacket data) + { + data.WriteInt32(ID); + data.WriteInt32((int)Type); + data.WriteInt32(Entries.Count); + switch (Type) + { + case TraitConfigType.Combat: + data.WriteInt32(ChrSpecializationID); + data.WriteInt32((int)CombatConfigFlags); + data.WriteInt32(LocalIdentifier); + break; + case TraitConfigType.Profession: + data.WriteUInt32(SkillLineID); + break; + case TraitConfigType.Generic: + data.WriteInt32(TraitSystemID); + break; + default: + break; + } + + foreach (TraitEntryPacket traitEntry in Entries) + traitEntry.Write(data); + + data.WriteBits(Name.GetByteCount(), 9); + data.FlushBits(); + + data.WriteString(Name); + } + } +} diff --git a/Source/Game/Networking/Packets/TraitPacketsCommon.cs b/Source/Game/Networking/Packets/TraitPacketsCommon.cs deleted file mode 100644 index 82dead96b..000000000 --- a/Source/Game/Networking/Packets/TraitPacketsCommon.cs +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012-2020 CypherCore - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -using Framework.Constants; -using Game.Entities; -using System.Collections.Generic; -using System; - -namespace Game.Networking.Packets -{ - public struct TraitEntry - { - public int TraitNodeID; - public int TraitNodeEntryID; - public int Rank; - public int GrantedRanks; - - public void Write(WorldPacket data) - { - data.WriteInt32(TraitNodeID); - data.WriteInt32(TraitNodeEntryID); - data.WriteInt32(Rank); - data.WriteInt32(GrantedRanks); - } - } - - public class TraitConfig - { - public int ID; - public TraitConfigType Type; - public int ChrSpecializationID = 0; - public TraitCombatConfigFlags CombatConfigFlags; - public int LocalIdentifier; // Local to specialization - public int SkillLineID; - public int TraitSystemID; - public List Entries = new(); - public string Name = ""; - - public void Write(WorldPacket data) - { - data.WriteInt32(ID); - data.WriteInt32((int)Type); - data.WriteInt32(Entries.Count); - switch (Type) - { - case TraitConfigType.Combat: - data.WriteInt32(ChrSpecializationID); - data.WriteInt32((int)CombatConfigFlags); - data.WriteInt32(LocalIdentifier); - break; - case TraitConfigType.Profession: - data.WriteInt32(SkillLineID); - break; - case TraitConfigType.Generic: - data.WriteInt32(TraitSystemID); - break; - default: - break; - } - - foreach (TraitEntry traitEntry in Entries) - traitEntry.Write(data); - - data.WriteBits(Name.GetByteCount(), 9); - data.FlushBits(); - - data.WriteString(Name); - } - } -} diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index bbb20d2b2..2f629a445 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -3394,7 +3394,14 @@ namespace Game.Spells Unit.ProcSkillsAndAuras(unitCaster, null, new ProcFlagsInit(ProcFlags.CastEnded), new ProcFlagsInit(), ProcFlagsSpellType.MaskAll, ProcFlagsSpellPhase.None, ProcFlagsHit.None, this, null, null); if (!ok) + { + // on failure (or manual cancel) send TraitConfigCommitFailed to revert talent UI saved config selection + if (m_caster.IsPlayer() && m_spellInfo.HasEffect(SpellEffectName.ChangeActiveCombatTraitConfig)) + if (m_customArg is TraitConfig) + m_caster.ToPlayer().SendPacket(new TraitConfigCommitFailed((m_customArg as TraitConfig).ID)); + return; + } if (unitCaster.IsTypeId(TypeId.Unit) && unitCaster.ToCreature().IsSummon()) { diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 722603c19..29dfbe969 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5676,6 +5676,41 @@ namespace Game.Spells for (int i = 0; i < damage; ++i) unitTarget.GetSpellHistory().RestoreCharge((uint)effectInfo.MiscValue); } + + [SpellEffectHandler(SpellEffectName.CreateTraitTreeConfig)] + void EffectCreateTraitTreeConfig() + { + if (effectHandleMode != SpellEffectHandleMode.HitTarget) + return; + + Player target = unitTarget?.ToPlayer(); + if (target == null) + return; + + TraitConfigPacket newConfig = new(); + newConfig.Type = TraitMgr.GetConfigTypeForTree(effectInfo.MiscValue); + if (newConfig.Type != TraitConfigType.Generic) + return; + + newConfig.TraitSystemID = CliDB.TraitTreeStorage.LookupByKey(effectInfo.MiscValue).TraitSystemID; + target.CreateTraitConfig(newConfig); + } + + [SpellEffectHandler(SpellEffectName.ChangeActiveCombatTraitConfig)] + void EffectChangeActiveCombatTraitConfig() + { + if (effectHandleMode != SpellEffectHandleMode.HitTarget) + return; + + Player target = unitTarget?.ToPlayer(); + if (target == null) + return; + + if (m_customArg is not TraitConfigPacket) + return; + + target.UpdateTraitConfig(m_customArg as TraitConfigPacket, damage, false); + } } public class DispelableAura diff --git a/Source/Game/Spells/TraitManager.cs b/Source/Game/Spells/TraitManager.cs new file mode 100644 index 000000000..16e3563df --- /dev/null +++ b/Source/Game/Spells/TraitManager.cs @@ -0,0 +1,746 @@ +using Framework.Constants; +using Game.DataStorage; +using Game.Entities; +using Game.Networking.Packets; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Game +{ + class TraitMgr + { + public static uint COMMIT_COMBAT_TRAIT_CONFIG_CHANGES_SPELL_ID = 384255u; + public static uint MAX_COMBAT_TRAIT_CONFIGS = 10u; + + static Dictionary _traitGroups = new(); + static Dictionary _traitNodes = new(); + static Dictionary _traitTrees = new(); + static int[] _skillLinesByClass = new int[(int)Class.Max]; + static MultiMap _traitTreesBySkillLine = new(); + static MultiMap _traitTreesByTraitSystem = new(); + static int _configIdGenerator; + static MultiMap _traitCurrencySourcesByCurrency = new(); + static MultiMap _traitDefinitionEffectPointModifiers = new(); + static MultiMap _traitTreeLoadoutsByChrSpecialization = new(); + + public static void Load() + { + _configIdGenerator = int.MaxValue; + + MultiMap nodeEntryConditions = new(); + foreach (TraitNodeEntryXTraitCondRecord traitNodeEntryXTraitCondEntry in CliDB.TraitNodeEntryXTraitCondStorage.Values) + { + TraitCondRecord traitCondEntry = CliDB.TraitCondStorage.LookupByKey(traitNodeEntryXTraitCondEntry.TraitCondID); + if (traitCondEntry != null) + nodeEntryConditions.Add((int)traitNodeEntryXTraitCondEntry.TraitNodeEntryID, traitCondEntry); + } + + MultiMap nodeEntryCosts = new(); + foreach (TraitNodeEntryXTraitCostRecord traitNodeEntryXTraitCostEntry in CliDB.TraitNodeEntryXTraitCostStorage.Values) + { + TraitCostRecord traitCostEntry = CliDB.TraitCostStorage.LookupByKey(traitNodeEntryXTraitCostEntry.TraitCostID); + if (traitCostEntry != null) + nodeEntryCosts.Add(traitNodeEntryXTraitCostEntry.TraitNodeEntryID, traitCostEntry); + } + + MultiMap nodeGroupConditions = new(); + foreach (TraitNodeGroupXTraitCondRecord traitNodeGroupXTraitCondEntry in CliDB.TraitNodeGroupXTraitCondStorage.Values) + { + TraitCondRecord traitCondEntry = CliDB.TraitCondStorage.LookupByKey(traitNodeGroupXTraitCondEntry.TraitCondID); + if (traitCondEntry != null) + nodeGroupConditions.Add(traitNodeGroupXTraitCondEntry.TraitNodeGroupID, traitCondEntry); + } + + MultiMap nodeGroupCosts = new(); + foreach (TraitNodeGroupXTraitCostRecord traitNodeGroupXTraitCostEntry in CliDB.TraitNodeGroupXTraitCostStorage.Values) + { + TraitCostRecord traitCondEntry = CliDB.TraitCostStorage.LookupByKey(traitNodeGroupXTraitCostEntry.TraitCostID); + if (traitCondEntry != null) + nodeGroupCosts.Add(traitNodeGroupXTraitCostEntry.TraitNodeGroupID, traitCondEntry); + } + + MultiMap nodeGroups = new(); + foreach (TraitNodeGroupXTraitNodeRecord traitNodeGroupXTraitNodeEntry in CliDB.TraitNodeGroupXTraitNodeStorage.Values) + nodeGroups.Add(traitNodeGroupXTraitNodeEntry.TraitNodeID, traitNodeGroupXTraitNodeEntry.TraitNodeGroupID); + + MultiMap nodeConditions = new(); + foreach (TraitNodeXTraitCondRecord traitNodeXTraitCondEntry in CliDB.TraitNodeXTraitCondStorage.Values) + { + TraitCondRecord traitCondEntry = CliDB.TraitCondStorage.LookupByKey(traitNodeXTraitCondEntry.TraitCondID); + if (traitCondEntry != null) + nodeConditions.Add(traitNodeXTraitCondEntry.TraitNodeID, traitCondEntry); + } + + MultiMap nodeCosts = new(); + foreach (TraitNodeXTraitCostRecord traitNodeXTraitCostEntry in CliDB.TraitNodeXTraitCostStorage.Values) + { + TraitCostRecord traitCostEntry = CliDB.TraitCostStorage.LookupByKey(traitNodeXTraitCostEntry.TraitCostID); + if (traitCostEntry != null) + nodeCosts.Add(traitNodeXTraitCostEntry.TraitNodeID, traitCostEntry); + } + + MultiMap nodeEntries = new(); + foreach (TraitNodeXTraitNodeEntryRecord traitNodeXTraitNodeEntryEntry in CliDB.TraitNodeXTraitNodeEntryStorage.Values) + { + TraitNodeEntryRecord traitNodeEntryEntry = CliDB.TraitNodeEntryStorage.LookupByKey(traitNodeXTraitNodeEntryEntry.TraitNodeEntryID); + if (traitNodeEntryEntry != null) + nodeEntries.Add(traitNodeXTraitNodeEntryEntry.TraitNodeID, traitNodeEntryEntry); + } + + MultiMap treeCosts = new(); + foreach (TraitTreeXTraitCostRecord traitTreeXTraitCostEntry in CliDB.TraitTreeXTraitCostStorage.Values) + { + TraitCostRecord traitCostEntry = CliDB.TraitCostStorage.LookupByKey(traitTreeXTraitCostEntry.TraitCostID); + if (traitCostEntry != null) + treeCosts.Add(traitTreeXTraitCostEntry.TraitTreeID, traitCostEntry); + } + + MultiMap treeCurrencies = new(); + foreach (TraitTreeXTraitCurrencyRecord traitTreeXTraitCurrencyEntry in CliDB.TraitTreeXTraitCurrencyStorage.Values) + { + TraitCurrencyRecord traitCurrencyEntry = CliDB.TraitCurrencyStorage.LookupByKey(traitTreeXTraitCurrencyEntry.TraitCurrencyID); + if (traitCurrencyEntry != null) + treeCurrencies.Add(traitTreeXTraitCurrencyEntry.TraitTreeID, traitCurrencyEntry); + } + + MultiMap traitTreesIdsByTraitSystem = new(); + foreach (TraitTreeRecord traitTree in CliDB.TraitTreeStorage.Values) + { + Tree tree = _traitTrees[(int)traitTree.Id]; + tree.Data = traitTree; + + var costs = treeCosts.LookupByKey(traitTree.Id); + if (costs != null) + tree.Costs = costs; + + var currencies = treeCurrencies.LookupByKey(traitTree.Id); + if (currencies != null) + tree.Currencies = currencies; + + if (traitTree.TraitSystemID != 0) + { + traitTreesIdsByTraitSystem.Add(traitTree.TraitSystemID, (int)traitTree.Id); + tree.ConfigType = TraitConfigType.Generic; + } + } + + foreach (TraitNodeGroupRecord traitNodeGroup in CliDB.TraitNodeGroupStorage.Values) + { + NodeGroup nodeGroup = _traitGroups[(int)traitNodeGroup.Id]; + nodeGroup.Data = traitNodeGroup; + + var conditions = nodeGroupConditions.LookupByKey(traitNodeGroup.Id); + if (conditions != null) + nodeGroup.Conditions = conditions; + + var costs = nodeGroupCosts.LookupByKey(traitNodeGroup.Id); + if (costs != null) + nodeGroup.Costs = costs; + } + + foreach (TraitNodeRecord traitNode in CliDB.TraitNodeStorage.Values) + { + Node node = _traitNodes[(int)traitNode.Id]; + node.Data = traitNode; + + Tree tree = _traitTrees.LookupByKey(traitNode.TraitTreeID); + if (tree != null) + tree.Nodes.Add(node); + + foreach (var traitNodeEntry in nodeEntries.LookupByKey(traitNode.Id)) + { + NodeEntry entry = new(); + entry.Data = traitNodeEntry; + + var conditions = nodeEntryConditions.LookupByKey(traitNodeEntry.Id); + if (conditions != null) + entry.Conditions = conditions; + + var costs = nodeEntryCosts.LookupByKey(traitNodeEntry.Id); + if (costs != null) + entry.Costs = costs; + + node.Entries.Add(entry); + } + + foreach (var nodeGroupId in nodeGroups.LookupByKey(traitNode.Id)) + { + NodeGroup nodeGroup = _traitGroups.LookupByKey(nodeGroupId); + if (nodeGroup == null) + continue; + + nodeGroup.Nodes.Add(node); + node.Groups.Add(nodeGroup); + } + + var conditions1 = nodeConditions.LookupByKey(traitNode.Id); + if (conditions1 != null) + node.Conditions = conditions1; + + var costs1 = nodeCosts.LookupByKey(traitNode.Id); + if (costs1 != null) + node.Costs = costs1; + } + + foreach (TraitEdgeRecord traitEdgeEntry in CliDB.TraitEdgeStorage.Values) + { + Node left = _traitNodes.LookupByKey(traitEdgeEntry.LeftTraitNodeID); + Node right = _traitNodes.LookupByKey(traitEdgeEntry.RightTraitNodeID); + if (left == null || right == null) + continue; + + right.ParentNodes.Add(Tuple.Create(left, (TraitEdgeType)traitEdgeEntry.Type)); + } + + foreach (SkillLineXTraitTreeRecord skillLineXTraitTreeEntry in CliDB.SkillLineXTraitTreeStorage.Values) + { + Tree tree = _traitTrees.LookupByKey(skillLineXTraitTreeEntry.TraitTreeID); + if (tree == null) + continue; + + SkillLineRecord skillLineEntry = CliDB.SkillLineStorage.LookupByKey(skillLineXTraitTreeEntry.SkillLineID); + if (skillLineEntry == null) + continue; + + _traitTreesBySkillLine[skillLineXTraitTreeEntry.SkillLineID].Add(tree); + if (skillLineEntry.CategoryID == SkillCategory.Class) + { + foreach (SkillRaceClassInfoRecord skillRaceClassInfo in Global.DB2Mgr.GetSkillRaceClassInfo(skillLineEntry.Id)) + for (int i = 1; i < (int)Class.Max; ++i) + if ((skillRaceClassInfo.ClassMask & (1 << (i - 1))) != 0) + _skillLinesByClass[i] = skillLineXTraitTreeEntry.SkillLineID; + + tree.ConfigType = TraitConfigType.Combat; + } + else + tree.ConfigType = TraitConfigType.Profession; + } + + foreach (var (traitSystemId, traitTreeId) in traitTreesIdsByTraitSystem) + { + Tree tree = _traitTrees.LookupByKey(traitTreeId); + if (tree != null) + _traitTreesByTraitSystem[traitSystemId].Add(tree); + } + + foreach (TraitCurrencySourceRecord traitCurrencySource in CliDB.TraitCurrencySourceStorage.Values) + _traitCurrencySourcesByCurrency[traitCurrencySource.TraitCurrencyID].Add(traitCurrencySource); + + foreach (TraitDefinitionEffectPointsRecord traitDefinitionEffectPoints in CliDB.TraitDefinitionEffectPointsStorage.Values) + _traitDefinitionEffectPointModifiers[traitDefinitionEffectPoints.TraitDefinitionID].Add(traitDefinitionEffectPoints); + + MultiMap traitTreeLoadoutEntries = new(); + foreach (TraitTreeLoadoutEntryRecord traitTreeLoadoutEntry in CliDB.TraitTreeLoadoutEntryStorage.Values) + traitTreeLoadoutEntries[traitTreeLoadoutEntry.TraitTreeLoadoutID].Add(traitTreeLoadoutEntry); + + foreach (TraitTreeLoadoutRecord traitTreeLoadout in CliDB.TraitTreeLoadoutStorage.Values) + { + var entries = traitTreeLoadoutEntries.LookupByKey(traitTreeLoadout.Id); + if (entries != null) + { + entries.Sort((left, right) => { return left.OrderIndex.CompareTo(right.OrderIndex); }); + // there should be only one loadout per spec, we take last one encountered + _traitTreeLoadoutsByChrSpecialization[traitTreeLoadout.ChrSpecializationID] = entries; + } + } + } + + /** + * Generates new TraitConfig identifier. + * Because this only needs to be unique for each character we let it overflow +*/ + public static int GenerateNewTraitConfigId() + { + if (_configIdGenerator == int.MaxValue) + _configIdGenerator = 0; + + return ++_configIdGenerator; + } + + public static TraitConfigType GetConfigTypeForTree(int traitTreeId) + { + Tree tree = _traitTrees.LookupByKey(traitTreeId); + if (tree == null) + return TraitConfigType.Invalid; + + return tree.ConfigType; + } + + /** + * @brief Finds relevant TraitTree identifiers + * @param traitConfig config data + * @return Trait tree data +*/ + public static List GetTreesForConfig(TraitConfigPacket traitConfig) + { + switch (traitConfig.Type) + { + case TraitConfigType.Combat: + ChrSpecializationRecord chrSpecializationEntry = CliDB.ChrSpecializationStorage.LookupByKey(traitConfig.ChrSpecializationID); + if (chrSpecializationEntry != null) + return _traitTreesBySkillLine.LookupByKey(_skillLinesByClass[chrSpecializationEntry.ClassID]); + break; + case TraitConfigType.Profession: + return _traitTreesBySkillLine.LookupByKey(traitConfig.SkillLineID); + case TraitConfigType.Generic: + return _traitTreesByTraitSystem.LookupByKey(traitConfig.TraitSystemID); + default: + break; + } + + return null; + } + + public static bool HasEnoughCurrency(TraitEntryPacket entry, Dictionary currencies) + { + int getCurrencyCount(int currencyId) + { + return currencies.LookupByKey(currencyId); + } + + Node node = _traitNodes.LookupByKey(entry.TraitNodeID); + foreach (NodeGroup group in node.Groups) + foreach (TraitCostRecord cost in group.Costs) + if (getCurrencyCount(cost.TraitCurrencyID) < cost.Amount * entry.Rank) + return false; + + var nodeEntryItr = node.Entries.Find(nodeEntry => nodeEntry.Data.Id == entry.TraitNodeEntryID); + if (nodeEntryItr != null) + foreach (TraitCostRecord cost in nodeEntryItr.Costs) + if (getCurrencyCount(cost.TraitCurrencyID) < cost.Amount * entry.Rank) + return false; + + foreach (TraitCostRecord cost in node.Costs) + if (getCurrencyCount(cost.TraitCurrencyID) < cost.Amount * entry.Rank) + return false; + + Tree tree = _traitTrees.LookupByKey(node.Data.TraitTreeID); + if (tree != null) + foreach (TraitCostRecord cost in tree.Costs) + if (getCurrencyCount(cost.TraitCurrencyID) < cost.Amount * entry.Rank) + return false; + + return true; + } + + public static void TakeCurrencyCost(TraitEntryPacket entry, Dictionary currencies) + { + Node node = _traitNodes.LookupByKey(entry.TraitNodeID); + foreach (NodeGroup group in node.Groups) + foreach (TraitCostRecord cost in group.Costs) + currencies[cost.TraitCurrencyID] -= cost.Amount * entry.Rank; + + var nodeEntryItr = node.Entries.Find(nodeEntry => nodeEntry.Data.Id == entry.TraitNodeEntryID); + if (nodeEntryItr != null) + foreach (TraitCostRecord cost in nodeEntryItr.Costs) + currencies[cost.TraitCurrencyID] -= cost.Amount * entry.Rank; + + foreach (TraitCostRecord cost in node.Costs) + currencies[cost.TraitCurrencyID] -= cost.Amount * entry.Rank; + + Tree tree = _traitTrees.LookupByKey(node.Data.TraitTreeID); + if (tree != null) + foreach (TraitCostRecord cost in tree.Costs) + currencies[cost.TraitCurrencyID] -= cost.Amount * entry.Rank; + } + + public static void FillOwnedCurrenciesMap(TraitConfigPacket traitConfig, Player player, Dictionary currencies) + { + List trees = GetTreesForConfig(traitConfig); + if (trees == null) + return; + + bool hasTraitNodeEntry(int traitNodeEntryId) + { + return traitConfig.Entries.Any(traitEntry => traitEntry.TraitNodeEntryID == traitNodeEntryId && (traitEntry.Rank > 0 || traitEntry.GrantedRanks > 0)); + } + + foreach (Tree tree in trees) + { + foreach (TraitCurrencyRecord currency in tree.Currencies) + { + switch (currency.GetCurrencyType()) + { + case TraitCurrencyType.Gold: + { + int amount = currencies[(int)currency.Id]; + if (player.GetMoney() > (ulong)(int.MaxValue - amount)) + amount = int.MaxValue; + else + amount += (int)player.GetMoney(); + break; + } + case TraitCurrencyType.CurrencyTypesBased: + currencies[(int)currency.Id] += (int)player.GetCurrency((uint)currency.CurrencyTypesID); + break; + case TraitCurrencyType.TraitSourced: + var currencySources = _traitCurrencySourcesByCurrency.LookupByKey(currency.Id); + if (currencySources != null) + { + foreach (TraitCurrencySourceRecord currencySource in currencySources) + { + if (currencySource.QuestID != 0 && !player.IsQuestRewarded(currencySource.QuestID)) + continue; + + if (currencySource.AchievementID != 0 && !player.HasAchieved(currencySource.AchievementID)) + continue; + + if (currencySource.PlayerLevel != 0 && player.GetLevel() < currencySource.PlayerLevel) + continue; + + if (currencySource.TraitNodeEntryID != 0 && !hasTraitNodeEntry(currencySource.TraitNodeEntryID)) + continue; + + currencies[currencySource.TraitCurrencyID] += currencySource.Amount; + } + } + break; + default: + break; + } + } + } + } + + public static void FillSpentCurrenciesMap(TraitEntryPacket entry, Dictionary cachedCurrencies) + { + Node node = _traitNodes.LookupByKey(entry.TraitNodeID); + foreach (NodeGroup group in node.Groups) + foreach (TraitCostRecord cost in group.Costs) + cachedCurrencies[cost.TraitCurrencyID] += cost.Amount * entry.Rank; + + var nodeEntryItr = node.Entries.Find(nodeEntry => nodeEntry.Data.Id == entry.TraitNodeEntryID); + if (nodeEntryItr != null) + foreach (TraitCostRecord cost in nodeEntryItr.Costs) + cachedCurrencies[cost.TraitCurrencyID] += cost.Amount * entry.Rank; + + foreach (TraitCostRecord cost in node.Costs) + cachedCurrencies[cost.TraitCurrencyID] += cost.Amount * entry.Rank; + + Tree tree = _traitTrees.LookupByKey(node.Data.TraitTreeID); + if (tree != null) + foreach (TraitCostRecord cost in tree.Costs) + cachedCurrencies[cost.TraitCurrencyID] += cost.Amount * entry.Rank; + } + + public static void FillSpentCurrenciesMap(TraitConfigPacket traitConfig, Dictionary cachedCurrencies) + { + foreach (TraitEntryPacket entry in traitConfig.Entries) + FillSpentCurrenciesMap(entry, cachedCurrencies); + } + + public static bool MeetsTraitCondition(TraitConfigPacket traitConfig, Player player, TraitCondRecord condition, ref Dictionary cachedCurrencies) + { + if (condition.QuestID != 0 && !player.IsQuestRewarded(condition.QuestID)) + return false; + + if (condition.AchievementID != 0 && !player.HasAchieved(condition.AchievementID)) + return false; + + if (condition.SpecSetID != 0 && !Global.DB2Mgr.IsSpecSetMember(condition.SpecSetID, player.GetPrimarySpecialization())) + return false; + + if (condition.TraitCurrencyID != 0 && condition.SpentAmountRequired != 0) + { + if (cachedCurrencies == null) + { + cachedCurrencies = new(); + FillSpentCurrenciesMap(traitConfig, cachedCurrencies); + } + + if (condition.TraitNodeGroupID != 0) + { + cachedCurrencies.TryAdd(condition.TraitCurrencyID, 0); + if (cachedCurrencies[condition.TraitCurrencyID] < condition.SpentAmountRequired) + return false; + } + else if (condition.TraitNodeID != 0) + { + cachedCurrencies.TryAdd(condition.TraitCurrencyID, 0); + if (cachedCurrencies[condition.TraitCurrencyID] < condition.SpentAmountRequired) + return false; + } + } + + if (condition.RequiredLevel != 0 && player.GetLevel() < condition.RequiredLevel) + return false; + + return true; + } + + public static List GetGrantedTraitEntriesForConfig(TraitConfigPacket traitConfig, Player player) + { + List entries = new(); + var trees = GetTreesForConfig(traitConfig); + if (trees == null) + return entries; + + TraitEntry getOrCreateEntry(uint nodeId, uint entryId) + { + TraitEntry foundTraitEntry = entries.Find(traitEntry => traitEntry.TraitNodeID == nodeId && traitEntry.TraitNodeEntryID == entryId); + if (foundTraitEntry == null) + { + foundTraitEntry = new(); + foundTraitEntry.TraitNodeID = (int)nodeId; + foundTraitEntry.TraitNodeEntryID = (int)entryId; + foundTraitEntry.Rank = 0; + foundTraitEntry.GrantedRanks = 0; + entries.Add(foundTraitEntry); + } + return foundTraitEntry; + } + + Dictionary cachedCurrencies = null; + + foreach (Tree tree in trees) + { + foreach (Node node in tree.Nodes) + { + foreach (NodeEntry entry in node.Entries) + foreach (TraitCondRecord condition in entry.Conditions) + if (condition.GetCondType() == TraitConditionType.Granted && MeetsTraitCondition(traitConfig, player, condition, ref cachedCurrencies)) + getOrCreateEntry(node.Data.Id, entry.Data.Id).GrantedRanks += condition.GrantedRanks; + + foreach (TraitCondRecord condition in node.Conditions) + if (condition.GetCondType() == TraitConditionType.Granted && MeetsTraitCondition(traitConfig, player, condition, ref cachedCurrencies)) + foreach (NodeEntry entry in node.Entries) + getOrCreateEntry(node.Data.Id, entry.Data.Id).GrantedRanks += condition.GrantedRanks; + + foreach (NodeGroup group in node.Groups) + foreach (TraitCondRecord condition in group.Conditions) + if (condition.GetCondType() == TraitConditionType.Granted && MeetsTraitCondition(traitConfig, player, condition, ref cachedCurrencies)) + foreach (NodeEntry entry in node.Entries) + getOrCreateEntry(node.Data.Id, entry.Data.Id).GrantedRanks += condition.GrantedRanks; + } + } + + return entries; + } + + public static bool IsValidEntry(TraitEntryPacket traitEntry) + { + Node node = _traitNodes.LookupByKey(traitEntry.TraitNodeID); + if (node == null) + return false; + + var entryItr = node.Entries.Find(entry => entry.Data.Id == traitEntry.TraitNodeEntryID); + if (entryItr == null) + return false; + + if (entryItr.Data.MaxRanks < traitEntry.Rank + traitEntry.GrantedRanks) + return false; + + return true; + } + + public static TalentLearnResult ValidateConfig(TraitConfigPacket traitConfig, Player player, bool requireSpendingAllCurrencies = false) + { + int getNodeEntryCount(int traitNodeId) + { + return traitConfig.Entries.Count(traitEntry => traitEntry.TraitNodeID == traitNodeId); + } + + TraitEntryPacket getNodeEntry(uint traitNodeId, uint traitNodeEntryId) + { + return traitConfig.Entries.Find(traitEntry => traitEntry.TraitNodeID == traitNodeId && traitEntry.TraitNodeEntryID == traitNodeEntryId); + } + + bool isNodeFullyFilled(Node node) + { + if (node.Data.GetNodeType() == TraitNodeType.Selection) + return node.Entries.Any(nodeEntry => + { + TraitEntryPacket traitEntry = getNodeEntry(node.Data.Id, nodeEntry.Data.Id); + return traitEntry != null && (traitEntry.Rank + traitEntry.GrantedRanks) == nodeEntry.Data.MaxRanks; + }); + + return node.Entries.All(nodeEntry => + { + TraitEntryPacket traitEntry = getNodeEntry(node.Data.Id, nodeEntry.Data.Id); + return traitEntry != null && (traitEntry.Rank + traitEntry.GrantedRanks) == nodeEntry.Data.MaxRanks; + }); + }; + + Dictionary spentCurrencies = new(); + FillSpentCurrenciesMap(traitConfig, spentCurrencies); + + foreach (TraitEntryPacket traitEntry in traitConfig.Entries) + { + if (!IsValidEntry(traitEntry)) + return TalentLearnResult.FailedUnknown; + + Node node = _traitNodes.LookupByKey(traitEntry.TraitNodeID); + if (node.Data.GetNodeType() == TraitNodeType.Selection) + if (getNodeEntryCount(traitEntry.TraitNodeID) != 1) + return TalentLearnResult.FailedUnknown; + + foreach (NodeEntry entry in node.Entries) + foreach (TraitCondRecord condition in entry.Conditions) + if ((condition.GetCondType() == TraitConditionType.Available || condition.GetCondType() == TraitConditionType.Visible) + && !MeetsTraitCondition(traitConfig, player, condition, ref spentCurrencies)) + return TalentLearnResult.FailedUnknown; + + foreach (TraitCondRecord condition in node.Conditions) + if ((condition.GetCondType() == TraitConditionType.Available || condition.GetCondType() == TraitConditionType.Visible) + && !MeetsTraitCondition(traitConfig, player, condition, ref spentCurrencies)) + return TalentLearnResult.FailedUnknown; + + foreach (NodeGroup group in node.Groups) + foreach (TraitCondRecord condition in group.Conditions) + if ((condition.GetCondType() == TraitConditionType.Available || condition.GetCondType() == TraitConditionType.Visible) + && !MeetsTraitCondition(traitConfig, player, condition, ref spentCurrencies)) + return TalentLearnResult.FailedUnknown; + + if (!node.ParentNodes.Empty()) + { + bool hasAnyParentTrait = false; + foreach (var (parentNode, edgeType) in node.ParentNodes) + { + if (!isNodeFullyFilled(parentNode)) + { + if (edgeType == TraitEdgeType.RequiredForAvailability) + return TalentLearnResult.FailedNotEnoughTalentsInPrimaryTree; + + continue; + } + + hasAnyParentTrait = true; + } + + if (!hasAnyParentTrait) + return TalentLearnResult.FailedNotEnoughTalentsInPrimaryTree; + } + } + + Dictionary grantedCurrencies = new(); + FillOwnedCurrenciesMap(traitConfig, player, grantedCurrencies); + + foreach (var (traitCurrencyId, spentAmount) in spentCurrencies) + { + if (CliDB.TraitCurrencyStorage.LookupByKey(traitCurrencyId).GetCurrencyType() != TraitCurrencyType.TraitSourced) + continue; + + if (spentAmount == 0) + continue; + + int grantedCount = grantedCurrencies.LookupByKey(traitCurrencyId); + if (grantedCount == 0 || grantedCount < spentAmount) + return TalentLearnResult.FailedNotEnoughTalentsInPrimaryTree; + + } + + if (requireSpendingAllCurrencies && traitConfig.Type == TraitConfigType.Combat) + { + foreach (var (traitCurrencyId, grantedAmount) in grantedCurrencies) + { + if (grantedAmount == 0) + continue; + + int spentAmount = spentCurrencies.LookupByKey(traitCurrencyId); + if (spentAmount == 0 || spentAmount != grantedAmount) + return TalentLearnResult.UnspentTalentPoints; + } + } + + return TalentLearnResult.LearnOk; + } + + public static List GetTraitDefinitionEffectPointModifiers(int traitDefinitionId) + { + return _traitDefinitionEffectPointModifiers.LookupByKey(traitDefinitionId); + } + + public static void InitializeStarterBuildTraitConfig(TraitConfigPacket traitConfig, Player player) + { + traitConfig.Entries.Clear(); + var trees = GetTreesForConfig(traitConfig); + if (trees == null) + return; + + foreach (TraitEntry grant in GetGrantedTraitEntriesForConfig(traitConfig, player)) + { + TraitEntryPacket newEntry = new(); + newEntry.TraitNodeID = grant.TraitNodeID; + newEntry.TraitNodeEntryID = grant.TraitNodeEntryID; + newEntry.GrantedRanks = grant.GrantedRanks; + traitConfig.Entries.Add(newEntry); + } + + Dictionary currencies = new(); + FillOwnedCurrenciesMap(traitConfig, player, currencies); + + var loadoutEntries = _traitTreeLoadoutsByChrSpecialization.LookupByKey(traitConfig.ChrSpecializationID); + if (loadoutEntries != null) + { + TraitEntryPacket findEntry(TraitConfigPacket config, int traitNodeId, int traitNodeEntryId) + { + return config.Entries.Find(traitEntry => traitEntry.TraitNodeID == traitNodeId && traitEntry.TraitNodeEntryID == traitNodeEntryId); + } + + foreach (TraitTreeLoadoutEntryRecord loadoutEntry in loadoutEntries) + { + int addedRanks = loadoutEntry.NumPoints; + Node node = _traitNodes.LookupByKey(loadoutEntry.SelectedTraitNodeID); + + TraitEntryPacket newEntry = new(); + newEntry.TraitNodeID = loadoutEntry.SelectedTraitNodeID; + newEntry.TraitNodeEntryID = loadoutEntry.SelectedTraitNodeEntryID; + if (newEntry.TraitNodeEntryID == 0) + newEntry.TraitNodeEntryID = (int)node.Entries[0].Data.Id; + + TraitEntryPacket entryInConfig = findEntry(traitConfig, newEntry.TraitNodeID, newEntry.TraitNodeEntryID); + + if (entryInConfig != null) + addedRanks -= entryInConfig.Rank; + + newEntry.Rank = addedRanks; + + if (!HasEnoughCurrency(newEntry, currencies)) + break; + + if (entryInConfig != null) + entryInConfig.Rank += addedRanks; + else + traitConfig.Entries.Add(newEntry); + + TakeCurrencyCost(newEntry, currencies); + } + } + } + } + + class NodeEntry + { + public TraitNodeEntryRecord Data; + public List Conditions = new(); + public List Costs = new(); + } + + class Node + { + public TraitNodeRecord Data; + public List Entries = new(); + public List Groups = new(); + public List> ParentNodes = new(); // TraitEdge::LeftTraitNodeID + public List Conditions = new(); + public List Costs = new(); + } + + class NodeGroup + { + public TraitNodeGroupRecord Data; + public List Conditions = new(); + public List Costs = new(); + public List Nodes = new(); + } + + class Tree + { + public TraitTreeRecord Data; + public List Nodes = new(); + public List Costs = new(); + public List Currencies = new(); + public TraitConfigType ConfigType; + } +}