From 6c1c91b6b2ca4e3cd3add317586113212271be70 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Mon, 17 Jul 2023 14:53:30 +0200 Subject: [PATCH] Core/DataStores: implement PlayerCondition.dbc * additionally implemented a DB table for custom entries as many of these conditions are strictly server side * use server side conditions for Stormwind's faction vendor as example usage --- .../world/4.3.4/2023_07_17_00_world.sql | 13 ++++++++++++ src/server/game/Conditions/ConditionMgr.cpp | 20 +++++++++++++++++++ src/server/game/Conditions/ConditionMgr.h | 3 +++ src/server/game/DataStores/DBCStores.cpp | 10 ++++++---- src/server/game/DataStores/DBCStores.h | 2 +- src/server/game/DataStores/DBCStructure.h | 6 ++++++ src/server/game/DataStores/DBCfmt.h | 3 +++ src/server/game/Entities/Player/Player.cpp | 9 +++++++++ src/server/game/Handlers/ItemHandler.cpp | 3 --- 9 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 sql/updates/world/4.3.4/2023_07_17_00_world.sql diff --git a/sql/updates/world/4.3.4/2023_07_17_00_world.sql b/sql/updates/world/4.3.4/2023_07_17_00_world.sql new file mode 100644 index 0000000000..04b4e19fb5 --- /dev/null +++ b/sql/updates/world/4.3.4/2023_07_17_00_world.sql @@ -0,0 +1,13 @@ +DROP TABLE IF EXISTS `playercondition_dbc`; +CREATE TABLE `playercondition_dbc` ( + `ID` INT UNSIGNED NOT NULL, + `FailureDescription` VARCHAR(100) NOT NULL, + PRIMARY KEY (`ID`) +); + +INSERT INTO `playercondition_dbc` (`ID`, `FailureDescription`) VALUES +(12251, 'Serverside/Non-DB2: Requires Stormwind - Revered'), +(12252, 'Serverside/Non-DB2: Requires Stormwind - Exalted'); + +UPDATE `npc_vendor` SET `PlayerConditionID`= 12252 WHERE `item` IN (64901, 64902, 64903); +UPDATE `npc_vendor` SET `PlayerConditionID`= 12251 WHERE `item`= 67531; diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index dc50e42153..da3c0aced6 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1086,6 +1086,26 @@ bool ConditionMgr::IsSpellUsedInSpellClickConditions(uint32 spellId) const return SpellsUsedInSpellClickConditions.find(spellId) != SpellsUsedInSpellClickConditions.end(); } +/*static*/ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditionEntry const* playerCondition) +{ + // Blizzard has never shipped a proper PlayerCondition.dbc entry with Cataclysm and many of its entries are serverside. So we have to hardcode the checks on our own. + switch (playerCondition->ID) + { + case 9414: return player->GetQuestStatus(46) == QUEST_STATUS_REWARDED; + case 12161: return player->GetQuestStatus(29279) == QUEST_STATUS_REWARDED; + case 12163: return player->GetQuestStatus(29283) == QUEST_STATUS_REWARDED; + case 12212: return player->GetQuestStatus(29281) == QUEST_STATUS_REWARDED; + case 12251: return player->GetReputationRank(72) == REP_REVERED; + case 12252: return player->GetReputationRank(72) == REP_EXALTED; + case 12380: return player->GetQuestStatus(29281) == QUEST_STATUS_REWARDED && player->GetQuestStatus(29283) == QUEST_STATUS_REWARDED && player->GetQuestStatus(29279) == QUEST_STATUS_REWARDED; + case 12515: return player->GetQuestStatus(29201) == QUEST_STATUS_REWARDED; + default: + return true; + } + + return true; +} + ConditionMgr* ConditionMgr::instance() { static ConditionMgr instance; diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 1246c44eed..a42c1749f5 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -33,6 +33,7 @@ class Unit; class WorldObject; class LootTemplate; struct Condition; +struct PlayerConditionEntry; enum ConditionTypes { // value1 value2 value3 @@ -269,6 +270,8 @@ class TC_GAME_API ConditionMgr bool IsSpellUsedInSpellClickConditions(uint32 spellId) const; + static bool IsPlayerMeetingCondition(Player const* player, PlayerConditionEntry const* playerCondition); + struct ConditionTypeInfo { char const* Name; diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index ff93c0aea5..6542d5dc9c 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -170,6 +170,7 @@ NameValidationRegexContainer NamesReservedValidators; DBCStorage sOverrideSpellDataStore(OverrideSpellDatafmt); +DBCStorage sPlayerConditionStore(PlayerConditionfmt); DBCStorage sPowerDisplayStore(PowerDisplayfmt); DBCStorage sPvPDifficultyStore(PvPDifficultyfmt); @@ -522,10 +523,11 @@ void DBCManager::LoadStores(const std::string& dataPath, uint32 defaultLocale) #define LOAD_DBC_EXT(store, file, dbformat, dbpk) LoadDBC(availableDbcLocales, bad_dbc_files, store, dbcPath, file, defaultLocale, dbformat, dbpk) - LOAD_DBC_EXT(sAchievementStore, "Achievement.dbc", CustomAchievementfmt, CustomAchievementIndex);//15595 - LOAD_DBC_EXT(sSpellStore, "Spell.dbc", CustomSpellEntryfmt, CustomSpellEntryIndex);// - LOAD_DBC_EXT(sSpellEffectStore, "SpellEffect.dbc", CustomSpellEffectEntryfmt, CustomSpellEffectEntryIndex);//15595 - LOAD_DBC_EXT(sSpellDifficultyStore, "SpellDifficulty.dbc", CustomSpellDifficultyfmt, CustomSpellDifficultyIndex);//15595 + LOAD_DBC_EXT(sAchievementStore, "Achievement.dbc", CustomAchievementfmt, CustomAchievementIndex);//15595 + LOAD_DBC_EXT(sSpellStore, "Spell.dbc", CustomSpellEntryfmt, CustomSpellEntryIndex);//15595 + LOAD_DBC_EXT(sSpellEffectStore, "SpellEffect.dbc", CustomSpellEffectEntryfmt, CustomSpellEffectEntryIndex);//15595 + LOAD_DBC_EXT(sSpellDifficultyStore, "SpellDifficulty.dbc", CustomSpellDifficultyfmt, CustomSpellDifficultyIndex);//15595 + LOAD_DBC_EXT(sPlayerConditionStore, "PlayerCondition.dbc", CustomPlayerConditionEntryfmt, CustomPlayerConditionEntryIndex);//15595 #undef LOAD_DBC_EXT diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index f931d26406..a992243e74 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -80,7 +80,6 @@ TC_GAME_API extern DBCStorage sGameObjectDisplayI TC_GAME_API extern DBCStorage sGemPropertiesStore; TC_GAME_API extern DBCStorage sGlyphPropertiesStore; TC_GAME_API extern DBCStorage sGlyphSlotStore; - TC_GAME_API extern DBCStorage sGtBarberShopCostBaseStore; TC_GAME_API extern DBCStorage sGtCombatRatingsStore; TC_GAME_API extern DBCStorage sGtChanceToMeleeCritBaseStore; @@ -139,6 +138,7 @@ TC_GAME_API extern DBCStorage sLightStore; TC_GAME_API extern MapDifficultyMap sMapDifficultyMap; TC_GAME_API extern DBCStorage sMovieStore; TC_GAME_API extern DBCStorage sOverrideSpellDataStore; +TC_GAME_API extern DBCStorage sPlayerConditionStore; TC_GAME_API extern DBCStorage sPowerDisplayStore; TC_GAME_API extern DBCStorage sQuestSortStore; TC_GAME_API extern DBCStorage sQuestXPStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 0bea4627c4..ccc3ebb1d9 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1350,6 +1350,12 @@ struct OverrideSpellDataEntry // char* PlayerActionbar; // 12 }; +struct PlayerConditionEntry +{ + uint32 ID; // 0 + char* FailureDescription; // 1 +}; + struct PowerDisplayEntry { uint32 ID; // 0 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 2848c82bde..85d9b85958 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -124,6 +124,9 @@ const char QuestPOIBlobfmt[] = "niii"; const char QuestPOIPointfmt[] = "niii"; char const QuestSortEntryfmt[] = "nx"; char const QuestXPfmt[] = "niiiiiiiiii"; +char const PlayerConditionfmt[] = "ns"; +const std::string CustomPlayerConditionEntryfmt = "pa"; +const std::string CustomPlayerConditionEntryIndex = "ID"; char const PowerDisplayfmt[] = "nixxxx"; char const PvPDifficultyfmt[] = "diiiii"; char const RandomPropertiesPointsfmt[] = "niiiiiiiiiiiiiii"; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b33359e231..319d27db54 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -21690,6 +21690,15 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin return false; } + if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(crItem->PlayerConditionId)) + { + if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition)) + { + SendEquipError(EQUIP_ERR_ITEM_LOCKED, nullptr, nullptr); + return false; + } + } + // check current item amount if it limited if (crItem->maxcount != 0) { diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index e106c057f8..da90f40d4f 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -634,12 +634,9 @@ void WorldSession::SendListInventory(ObjectGuid vendorGuid) WorldPackets::NPC::VendorItem& item = packet.Items[count]; - /* - // Todo: implement dbc file and handling if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(vendorItem->PlayerConditionId)) if (!ConditionMgr::IsPlayerMeetingCondition(_player, playerCondition)) item.PlayerConditionFailed = playerCondition->ID; - */ if (vendorItem->Type == ITEM_VENDOR_TYPE_ITEM) {