From 0f83d52f4345e07f97a95fc48382a9715b99d962 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 16 Dec 2021 11:18:21 +0100 Subject: [PATCH] fix(Core/Trainers): add new column `ReqSpell` to `npc_trainer` table (#9490) Prevent learning gnomish and goblin engineering recipes at same time. Fixes #5390 Co-authored-by: Skjalf <47818697+Nyeriah@users.noreply.github.com> --- .../rev_1638616990639666200.sql | 3 ++ .../rev_1638617008671223200.sql | 48 +++++++++++++++++++ .../game/Entities/Creature/CreatureData.h | 1 + src/server/game/Globals/ObjectMgr.cpp | 14 ++++-- src/server/game/Globals/ObjectMgr.h | 2 +- src/server/game/Handlers/NPCHandler.cpp | 11 +++++ 6 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1638616990639666200.sql create mode 100644 data/sql/updates/pending_db_world/rev_1638617008671223200.sql diff --git a/data/sql/updates/pending_db_world/rev_1638616990639666200.sql b/data/sql/updates/pending_db_world/rev_1638616990639666200.sql new file mode 100644 index 000000000..4cf753e4e --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1638616990639666200.sql @@ -0,0 +1,3 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1638616990639666200'); + +ALTER TABLE `npc_trainer` ADD COLUMN `ReqSpell` INT UNSIGNED DEFAULT 0 NOT NULL AFTER `ReqLevel`; diff --git a/data/sql/updates/pending_db_world/rev_1638617008671223200.sql b/data/sql/updates/pending_db_world/rev_1638617008671223200.sql new file mode 100644 index 000000000..3f60e1abc --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1638617008671223200.sql @@ -0,0 +1,48 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1638617008671223200'); + +-- Gnomish Engineering +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12897; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=30575; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=30574; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12907; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=56473; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12905; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=30570; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12903; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=23096; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=30568; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=15633; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=23129; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=11454; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12906; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12759; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12902; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=30569; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=12899; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=23489; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=36955; +UPDATE `npc_trainer` SET `ReqSpell`=20219 WHERE `SpellID`=11454; + +-- Goblin Engineering +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=23486; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=36954; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=30565; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=30566; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12755; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12718; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12908; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=9273; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=23078; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12717; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12716; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=8895; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12758; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=30563; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12760; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=15628; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=30560; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12754; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=30558; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=12715; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=13240; +UPDATE `npc_trainer` SET `ReqSpell`=20222 WHERE `SpellID`=56514; diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h index 4e51a9c2c..114e73798 100644 --- a/src/server/game/Entities/Creature/CreatureData.h +++ b/src/server/game/Entities/Creature/CreatureData.h @@ -416,6 +416,7 @@ struct TrainerSpell uint32 reqSkillValue{0}; uint32 reqLevel{0}; uint32 learnedSpell[3]; + uint32 reqSpell{0}; // helpers [[nodiscard]] bool IsCastable() const { return learnedSpell[0] != spell; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 63fd918d9..a7cf4a781 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -8295,7 +8295,7 @@ void ObjectMgr::LoadMailLevelRewards() LOG_INFO("server.loading", " "); } -void ObjectMgr::AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel) +void ObjectMgr::AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel, uint32 reqSpell) { if (entry >= ACORE_TRAINER_START_REF) return; @@ -8332,6 +8332,12 @@ void ObjectMgr::AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, return; } + if (reqSpell && !sSpellMgr->GetSpellInfo(reqSpell)) + { + LOG_ERROR("sql.sql", "Table `npc_trainer` contains an entry (Entry: %u) for a non-existing reqSpell (Spell: %u), ignoring", entry, reqSpell); + return; + } + TrainerSpellData& data = _cacheTrainerSpellStore[entry]; TrainerSpell& trainerSpell = data.spellList[spell]; @@ -8340,6 +8346,7 @@ void ObjectMgr::AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, trainerSpell.reqSkill = reqSkill; trainerSpell.reqSkillValue = reqSkillValue; trainerSpell.reqLevel = reqLevel; + trainerSpell.reqSpell = reqSpell; if (!trainerSpell.reqLevel) trainerSpell.reqLevel = spellinfo->SpellLevel; @@ -8380,7 +8387,7 @@ void ObjectMgr::LoadTrainerSpell() // For reload case _cacheTrainerSpellStore.clear(); - QueryResult result = WorldDatabase.Query("SELECT b.ID, a.SpellID, a.MoneyCost, a.ReqSkillLine, a.ReqSkillRank, a.ReqLevel FROM npc_trainer AS a " + QueryResult result = WorldDatabase.Query("SELECT b.ID, a.SpellID, a.MoneyCost, a.ReqSkillLine, a.ReqSkillRank, a.ReqLevel, a.ReqSpell FROM npc_trainer AS a " "INNER JOIN npc_trainer AS b ON a.ID = -(b.SpellID) " "UNION SELECT * FROM npc_trainer WHERE SpellID > 0"); @@ -8403,8 +8410,9 @@ void ObjectMgr::LoadTrainerSpell() uint32 reqSkill = fields[3].GetUInt16(); uint32 reqSkillValue = fields[4].GetUInt16(); uint32 reqLevel = fields[5].GetUInt8(); + uint32 reqSpell = fields[6].GetUInt32(); - AddSpellToTrainer(entry, spell, spellCost, reqSkill, reqSkillValue, reqLevel); + AddSpellToTrainer(entry, spell, spellCost, reqSkill, reqSkillValue, reqLevel, reqSpell); ++count; } while (result->NextRow()); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 9f2c71927..818c276e7 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -1055,7 +1055,7 @@ public: void LoadVendors(); void LoadTrainerSpell(); - void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel); + void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel, uint32 reqSpell); std::string GeneratePetName(uint32 entry); uint32 GetBaseXP(uint8 level); diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 2f3aa412a..81f124733 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -182,9 +182,15 @@ void WorldSession::SendTrainerList(ObjectGuid guid, const std::string& strTitle) if (learnedSpellInfo && learnedSpellInfo->IsPrimaryProfessionFirstRank()) primary_prof_first_rank = true; } + if (!valid) continue; + if (tSpell->reqSpell && !_player->HasSpell(tSpell->reqSpell)) + { + continue; + } + TrainerSpellState state = _player->GetTrainerSpellState(tSpell); data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case) @@ -263,6 +269,11 @@ void WorldSession::HandleTrainerBuySpellOpcode(WorldPacket& recvData) if (!trainer_spell) return; + if (trainer_spell->reqSpell && !_player->HasSpell(trainer_spell->reqSpell)) + { + return; + } + // can't be learn, cheat? Or double learn with lags... if (_player->GetTrainerSpellState(trainer_spell) != TRAINER_SPELL_GREEN) return;