diff --git a/sql/updates/hotfixes/master/2021_10_10_00_hotfixes.sql b/sql/updates/hotfixes/master/2021_10_10_00_hotfixes.sql new file mode 100644 index 0000000000..8ec989f1b6 --- /dev/null +++ b/sql/updates/hotfixes/master/2021_10_10_00_hotfixes.sql @@ -0,0 +1,23 @@ +-- +-- Table structure for table `spell_reagents_currency` +-- +DROP TABLE IF EXISTS `spell_reagents_currency`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `spell_reagents_currency` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `SpellID` int(11) NOT NULL DEFAULT '0', + `CurrencyTypesID` smallint(5) unsigned NOT NULL DEFAULT '0', + `CurrencyCount` smallint(5) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`VerifiedBuild`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table data for table `spell_reagents_currency` +-- +INSERT INTO `spell_reagents_currency` +SELECT hb.`RecordId`, CONV(HEX(SUBSTRING(hb.`Blob`, 1, 4)), 16, 10), CONV(HEX(SUBSTRING(hb.`Blob`, 5, 2)), 16, 10), CONV(HEX(SUBSTRING(hb.`Blob`, 7, 2)), 16, 10), hb.`VerifiedBuild` FROM `hotfix_blob` hb WHERE hb.`TableHash`=0x2049B60C AND hb.`locale`='enUS'; + +DELETE FROM `hotfix_blob` WHERE `TableHash`=0x2049B60C; diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 67420de932..4ec6219cb4 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -1423,6 +1423,11 @@ void HotfixDatabaseConnection::DoPrepareStatements() " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_SPELL_REAGENTS, "SELECT MAX(ID) + 1 FROM spell_reagents", CONNECTION_SYNCH); + // SpellReagentsCurrency.db2 + PrepareStatement(HOTFIX_SEL_SPELL_REAGENTS_CURRENCY, "SELECT ID, SpellID, CurrencyTypesID, CurrencyCount FROM spell_reagents_currency" + " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); + PREPARE_MAX_ID_STMT(HOTFIX_SEL_SPELL_REAGENTS_CURRENCY, "SELECT MAX(ID) + 1 FROM spell_reagents_currency", CONNECTION_SYNCH); + // SpellScaling.db2 PrepareStatement(HOTFIX_SEL_SPELL_SCALING, "SELECT ID, SpellID, MinScalingLevel, MaxScalingLevel, ScalesFromItemLevel FROM spell_scaling" " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index 431dfef994..e11c93a7fb 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -826,6 +826,9 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_SPELL_REAGENTS, HOTFIX_SEL_SPELL_REAGENTS_MAX_ID, + HOTFIX_SEL_SPELL_REAGENTS_CURRENCY, + HOTFIX_SEL_SPELL_REAGENTS_CURRENCY_MAX_ID, + HOTFIX_SEL_SPELL_SCALING, HOTFIX_SEL_SPELL_SCALING_MAX_ID, diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index 460e49c73b..9ad1558fc0 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -5467,6 +5467,22 @@ struct SpellReagentsLoadInfo } }; +struct SpellReagentsCurrencyLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { true, FT_INT, "SpellID" }, + { false, FT_SHORT, "CurrencyTypesID" }, + { false, FT_SHORT, "CurrencyCount" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent::value, SpellReagentsCurrencyMeta::Instance(), HOTFIX_SEL_SPELL_REAGENTS_CURRENCY); + return &loadInfo; + } +}; + struct SpellScalingLoadInfo { static DB2LoadInfo const* Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index cabdc8606a..7254de7c37 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -284,6 +284,7 @@ DB2Storage sSpellProcsPerMinuteModStore("Sp DB2Storage sSpellRadiusStore("SpellRadius.db2", SpellRadiusLoadInfo::Instance()); DB2Storage sSpellRangeStore("SpellRange.db2", SpellRangeLoadInfo::Instance()); DB2Storage sSpellReagentsStore("SpellReagents.db2", SpellReagentsLoadInfo::Instance()); +DB2Storage sSpellReagentsCurrencyStore("SpellReagentsCurrency.db2", SpellReagentsCurrencyLoadInfo::Instance()); DB2Storage sSpellScalingStore("SpellScaling.db2", SpellScalingLoadInfo::Instance()); DB2Storage sSpellShapeshiftStore("SpellShapeshift.db2", SpellShapeshiftLoadInfo::Instance()); DB2Storage sSpellShapeshiftFormStore("SpellShapeshiftForm.db2", SpellShapeshiftFormLoadInfo::Instance()); @@ -834,6 +835,7 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul LOAD_DB2(sSpellRadiusStore); LOAD_DB2(sSpellRangeStore); LOAD_DB2(sSpellReagentsStore); + LOAD_DB2(sSpellReagentsCurrencyStore); LOAD_DB2(sSpellScalingStore); LOAD_DB2(sSpellShapeshiftStore); LOAD_DB2(sSpellShapeshiftFormStore); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 55bce5e6a4..278fab3fa1 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -212,6 +212,7 @@ TC_GAME_API extern DB2Storage sSpellProcsP TC_GAME_API extern DB2Storage sSpellRadiusStore; TC_GAME_API extern DB2Storage sSpellRangeStore; TC_GAME_API extern DB2Storage sSpellReagentsStore; +TC_GAME_API extern DB2Storage sSpellReagentsCurrencyStore; TC_GAME_API extern DB2Storage sSpellScalingStore; TC_GAME_API extern DB2Storage sSpellShapeshiftStore; TC_GAME_API extern DB2Storage sSpellShapeshiftFormStore; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 351f6e3d94..39805e50e1 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -3322,6 +3322,14 @@ struct SpellReagentsEntry int16 ReagentCount[MAX_SPELL_REAGENTS]; }; +struct SpellReagentsCurrencyEntry +{ + uint32 ID; + int32 SpellID; + uint16 CurrencyTypesID; + uint16 CurrencyCount; +}; + struct SpellScalingEntry { uint32 ID; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index bb1ab3c733..dac726f2c5 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4152,7 +4152,6 @@ inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo cons packet.FailedArg1 = *param1; else { - uint32 missingItem = 0; for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++) { if (spellInfo->Reagent[i] <= 0) @@ -4163,12 +4162,27 @@ inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo cons if (!caster->HasItemCount(itemid, itemcount)) { - missingItem = itemid; + packet.FailedArg1 = itemid; // first missing item break; } } - packet.FailedArg1 = missingItem; // first missing item } + + if (param2) + packet.FailedArg2 = *param2; + else if (!param1) + { + for (SpellReagentsCurrencyEntry const* reagentsCurrency : spellInfo->ReagentsCurrency) + { + if (!caster->HasCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount)) + { + packet.FailedArg1 = -1; + packet.FailedArg2 = reagentsCurrency->CurrencyTypesID; + break; + } + } + } + break; } case SPELL_FAILED_CANT_UNTALENT: @@ -5019,6 +5033,9 @@ void Spell::TakeReagents() p_caster->DestroyItemCount(itemid, itemcount, true); } + + for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency) + p_caster->ModifyCurrency(reagentsCurrency->CurrencyTypesID, -int32(reagentsCurrency->CurrencyCount), false, true); } void Spell::HandleThreatSpells() @@ -6753,6 +6770,20 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*= return SPELL_FAILED_REAGENTS; } } + + for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency) + { + if (!player->HasCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount)) + { + if (param1) + *param1 = -1; + + if (param2) + *param2 = reagentsCurrency->CurrencyTypesID; + + return SPELL_FAILED_REAGENTS; + } + } } // check totem-item requirements (items presence in inventory) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 61e04f1c8e..0e5b1cb59f 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -1228,6 +1228,8 @@ SpellInfo::SpellInfo(SpellNameEntry const* spellName, ::Difficulty difficulty, S std::copy(std::begin(_reagents->ReagentCount), std::end(_reagents->ReagentCount), ReagentCount.begin()); } + ReagentsCurrency = data.ReagentsCurrency; + // SpellShapeshiftEntry if (SpellShapeshiftEntry const* _shapeshift = data.Shapeshift) { diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index fbd18c7eb0..7e29f202a7 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -402,6 +402,7 @@ class TC_GAME_API SpellInfo std::array TotemCategory = {}; std::array Reagent = {}; std::array ReagentCount = {}; + std::vector ReagentsCurrency; int32 EquippedItemClass = -1; int32 EquippedItemSubClassMask = 0; int32 EquippedItemInventoryTypeMask = 0; diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 8425b6a1a5..c026128278 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2557,6 +2557,9 @@ void SpellMgr::LoadSpellInfoStore() for (SpellReagentsEntry const* reagents : sSpellReagentsStore) loadData[{ reagents->SpellID, DIFFICULTY_NONE }].Reagents = reagents; + for (SpellReagentsCurrencyEntry const* reagentsCurrency : sSpellReagentsCurrencyStore) + loadData[{ reagentsCurrency->SpellID, DIFFICULTY_NONE }].ReagentsCurrency.push_back(reagentsCurrency); + for (SpellScalingEntry const* scaling : sSpellScalingStore) loadData[{ scaling->SpellID, DIFFICULTY_NONE }].Scaling = scaling; @@ -2639,6 +2642,9 @@ void SpellMgr::LoadSpellInfoStore() if (!data.second.Reagents) data.second.Reagents = fallbackData->Reagents; + if (data.second.ReagentsCurrency.empty()) + data.second.ReagentsCurrency = fallbackData->ReagentsCurrency; + if (!data.second.Scaling) data.second.Scaling = fallbackData->Scaling; diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index df6ebba3a4..840648ecdf 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -56,6 +56,7 @@ struct SpellMiscEntry; struct SpellNameEntry; struct SpellPowerEntry; struct SpellReagentsEntry; +struct SpellReagentsCurrencyEntry; struct SpellScalingEntry; struct SpellShapeshiftEntry; struct SpellTargetRestrictionsEntry; @@ -617,6 +618,7 @@ struct SpellInfoLoadHelper SpellMiscEntry const* Misc = nullptr; std::array Powers; SpellReagentsEntry const* Reagents = nullptr; + std::vector ReagentsCurrency; SpellScalingEntry const* Scaling = nullptr; SpellShapeshiftEntry const* Shapeshift = nullptr; SpellTargetRestrictionsEntry const* TargetRestrictions = nullptr;