diff --git a/modules/mod-Forge/src/ForgeCache.cpp b/modules/mod-Forge/src/ForgeCache.cpp index 44acb170807626..427d5c1e9cc02c 100644 --- a/modules/mod-Forge/src/ForgeCache.cpp +++ b/modules/mod-Forge/src/ForgeCache.cpp @@ -75,6 +75,7 @@ struct ForgeCharacterTalent uint32 SpellId; uint32 TabId; uint8 CurrentRank; + uint8 type; }; struct ForgeTalentPrereq @@ -559,12 +560,23 @@ class ForgeCache : public DatabaseScript for (auto& tabIdKvp : spec->Talents) for (auto& tabTypeKvp : tabIdKvp.second) - UpdateChacterTalentInternal(acct, charId, trans, spec->Id, tabTypeKvp.second->SpellId, tabTypeKvp.second->TabId, tabTypeKvp.second->CurrentRank); + if (tabTypeKvp.second->type == NodeType::CHOICE) + UpdateChacterChoiceNodeInternal(trans, acct, charId, spec->Id, tabTypeKvp.second->TabId, tabTypeKvp.second->SpellId, spec->ChoiceNodesChosen.at(tabTypeKvp.second->SpellId)); + else + UpdateChacterTalentInternal(acct, charId, trans, spec->Id, tabTypeKvp.second->SpellId, tabTypeKvp.second->TabId, tabTypeKvp.second->CurrentRank); - CharacterDatabase.CommitTransaction(trans); } + void UpdateChacterChoiceNodeInternal(CharacterDatabaseTransaction trans, uint32 account, uint32 guid, uint32 specId, uint32 tabId, uint32 choiceNodeId, uint32 choiceNodeSelection) { + if (TalentTabs[tabId]->TalentType != ACCOUNT_WIDE_TYPE) + trans->Append("INSERT INTO `forge_character_node_choices` (`guid`,`spec`,`tabId`,`node`,`choice`) VALUES ({},{},{},{},{}) ON DUPLICATE KEY UPDATE `choice` = {}", + guid, specId, choiceNodeId, tabId, choiceNodeSelection, choiceNodeSelection); + else + trans->Append("INSERT INTO `forge_character_node_choices` (`guid`,`spec`,`tabId`,`node`,`choice`) VALUES ({},{},{},{},{}) ON DUPLICATE KEY UPDATE `choice` = {}", + account, ACCOUNT_WIDE_KEY, choiceNodeId, tabId, choiceNodeSelection, choiceNodeSelection); + } + void UpdateCharacterSpecDetailsOnly(Player* player, ForgeCharacterSpec*& spec) { uint32 charId = player->GetGUID().GetCounter(); @@ -574,13 +586,6 @@ class ForgeCache : public DatabaseScript CharacterDatabase.CommitTransaction(trans); } - void UpdateChacterTalent(Player* player, uint32 spec, uint32 spellId, uint32 tabId, uint8 known) - { - auto trans = CharacterDatabase.BeginTransaction(); - UpdateChacterTalentInternal(player->GetSession()->GetAccountId(), player->GetGUID().GetCounter(), trans, spec, spellId, tabId, known); - CharacterDatabase.CommitTransaction(trans); - } - void ApplyAccountBoundTalents(Player* player) { ForgeCharacterSpec* currentSpec; @@ -871,6 +876,15 @@ class ForgeCache : public DatabaseScript // choiceNodeId is the id of the node in forge_talents std::unordered_map> _choiceNodes; + std::unordered_map _choiceNodesRev; + + uint32 GetChoiceNodeFromSpell(uint32 spellId) { + auto out = _choiceNodesRev.find(spellId); + if (out != _choiceNodesRev.end()) + return out->second; + + return 0; + } private: std::unordered_map CharacterActiveSpecs; @@ -1278,6 +1292,7 @@ class ForgeCache : public DatabaseScript QueryResult exclTalents = WorldDatabase.Query("SELECT * FROM forge_talent_choice_nodes"); _choiceNodes.clear(); + _choiceNodesRev.clear(); if (!exclTalents) return; @@ -1294,6 +1309,7 @@ class ForgeCache : public DatabaseScript choice->spellId = spellChoice; _choiceNodes[choiceNodeId].push_back(spellChoice); + _choiceNodesRev[spellChoice] = choiceNodeId; ForgeTalent* lt = TalentTabs[talentTabId]->Talents[choiceNodeId]; if (lt != nullptr) @@ -1478,6 +1494,7 @@ class ForgeCache : public DatabaseScript { ForgeTalent* ft = TalentTabs[talent->TabId]->Talents[talent->SpellId]; ForgeCharacterSpec* spec = CharacterSpecs[characterGuid][specId]; + talent->type = ft->nodeType; spec->Talents[talent->TabId][talent->SpellId] = talent; } @@ -1489,6 +1506,7 @@ class ForgeCache : public DatabaseScript for (auto& spec : CharacterSpecs[ch]) { ForgeTalent* ft = TalentTabs[talent->TabId]->Talents[talent->SpellId]; + talent->type = ft->nodeType; spec.second->Talents[talent->TabId][talent->SpellId] = talent; } } diff --git a/modules/mod-Forge/src/ForgeCommonMessage.cpp b/modules/mod-Forge/src/ForgeCommonMessage.cpp index 9aea1f7da5d251..88766400efc3b4 100644 --- a/modules/mod-Forge/src/ForgeCommonMessage.cpp +++ b/modules/mod-Forge/src/ForgeCommonMessage.cpp @@ -394,9 +394,9 @@ std::string ForgeCommonMessage::DoBuildRanks(std::unordered_mapTryGetTalentTab(player, tabId, tab)) + if (fc->TryGetTalentTab(player, tabId, tab) && fc->TryGetCharacterActiveSpec(player, fs)) { for(auto& sp : tab->Talents) { @@ -404,14 +404,21 @@ std::string ForgeCommonMessage::DoBuildRanks(std::unordered_mapsecond->CurrentRank == 0 && !CanLearnTalent(player, tabId, sp.second->SpellId)) - clientMsg = clientMsg + delimiter + std::to_string(sp.second->SpellId) + "~-1"; + if (itt != spec.end()) { + if (itt->second->type == NodeType::CHOICE) + if (itt->second->CurrentRank == 0 || !CanLearnTalent(player, tabId, sp.second->SpellId)) + clientMsg = clientMsg + delimiter + std::to_string(sp.second->SpellId) + "~-1"; + else + clientMsg = clientMsg + delimiter + std::to_string(itt->second->SpellId) + "~" + std::to_string(fs->ChoiceNodesChosen.at(itt->second->SpellId)); else - clientMsg = clientMsg + delimiter + std::to_string(itt->second->SpellId) + "~" + std::to_string(itt->second->CurrentRank); + if (itt->second->CurrentRank == 0 && !CanLearnTalent(player, tabId, sp.second->SpellId)) + clientMsg = clientMsg + delimiter + std::to_string(sp.second->SpellId) + "~-1"; + else + clientMsg = clientMsg + delimiter + std::to_string(itt->second->SpellId) + "~" + std::to_string(itt->second->CurrentRank); + } else if (!CanLearnTalent(player, tabId, sp.second->SpellId)) clientMsg = clientMsg + delimiter + std::to_string(sp.second->SpellId) + "~-1"; else diff --git a/modules/mod-Forge/src/TopicHandlers/LearnTalentHandler.cpp b/modules/mod-Forge/src/TopicHandlers/LearnTalentHandler.cpp index 4a5870d469e2be..bb656e6454b075 100644 --- a/modules/mod-Forge/src/TopicHandlers/LearnTalentHandler.cpp +++ b/modules/mod-Forge/src/TopicHandlers/LearnTalentHandler.cpp @@ -26,11 +26,15 @@ class LearnTalentHandler : public ForgeTopicHandler std::vector results; boost::algorithm::split(results, iam.message, boost::is_any_of(";")); - if (results.empty() || results.size() != 2 || !fc->isNumber(results[0]) || !fc->isNumber(results[1])) + if (results.empty() || results.size() != 3 || !fc->isNumber(results[0]) || !fc->isNumber(results[1]) || !fc->isNumber(results[2])) return; uint32 tabId = static_cast(std::stoul(results[0])); uint32 spellId = static_cast(std::stoul(results[1])); + uint32 nodeType = static_cast(std::stoul(results[2])); + + bool choiceNode = nodeType == NodeType::CHOICE; + ForgeTalentTab* tab; ForgeCharacterSpec* spec; CharacterPointType tabType; @@ -52,7 +56,12 @@ class LearnTalentHandler : public ForgeTopicHandler } // check dependants, rank requirements - auto talItt = tab->Talents.find(spellId); + uint32 choiceId = fc->GetChoiceNodeFromSpell(spellId); + if (!choiceId && choiceNode) { + iam.player->SendForgeUIMsg(ForgeTopic::LEARN_TALENT_ERROR, "Attempt to unlearn unknown choice node talent: " + std::to_string(choiceId)); + return; + } + auto talItt = choiceNode ? tab->Talents.find(choiceId) : tab->Talents.find(spellId); if (talItt == tab->Talents.end()) { @@ -184,18 +193,6 @@ class LearnTalentHandler : public ForgeTopicHandler } } - // TODO: FIX - //for (auto& exclu : ft->Choices) - //{ - // auto typeItt = skillTabs.find(exclu); - - // if (typeItt != skillTabs.end() && typeItt->second->CurrentRank > 0) - // { - // RequirementsNotMet(iam); - // return; - // } - //} - auto spellItter = skillTabs.find(ft->SpellId); ForgeCharacterTalent* ct = new ForgeCharacterTalent(); @@ -204,6 +201,7 @@ class LearnTalentHandler : public ForgeTopicHandler ct->CurrentRank = 0; ct->SpellId = ft->SpellId; ct->TabId = tabId; + ct->type = ft->nodeType; spec->Talents[tabId][ft->SpellId] = ct; } else @@ -223,25 +221,39 @@ class LearnTalentHandler : public ForgeTopicHandler auto ranksItt = ft->Ranks.find(ct->CurrentRank); - if (ranksItt != ft->Ranks.end()) { - auto spellInfo = sSpellMgr->GetSpellInfo(ranksItt->second); - if (!spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) - iam.player->removeSpell(ranksItt->second, SPEC_MASK_ALL, false); + if (!choiceNode) + if (ranksItt != ft->Ranks.end()) { + auto spellInfo = sSpellMgr->GetSpellInfo(ranksItt->second); + if (!spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) + iam.player->removeSpell(ranksItt->second, SPEC_MASK_ALL, false); + else + iam.player->RemoveAura(ranksItt->second); + } else - iam.player->RemoveAura(ranksItt->second); - } + for (auto s : ft->Choices) + iam.player->removeSpell(s->spellId, SPEC_MASK_ALL, false); ct->CurrentRank++; ranksItt = ft->Ranks.find(ct->CurrentRank); - if (ranksItt != ft->Ranks.end()) { - auto spellInfo = sSpellMgr->GetSpellInfo(ranksItt->second); + if (choiceNode) { + auto spellInfo = sSpellMgr->GetSpellInfo(spellId); if (!spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) - iam.player->learnSpell(ranksItt->second); + iam.player->learnSpell(spellId); else - iam.player->AddAura(ranksItt->second, iam.player); + iam.player->AddAura(spellId, iam.player); + + spec->ChoiceNodesChosen[choiceId] = spellId; } + else + if (ranksItt != ft->Ranks.end()) { + auto spellInfo = sSpellMgr->GetSpellInfo(ranksItt->second); + if (!spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) + iam.player->learnSpell(ranksItt->second); + else + iam.player->AddAura(ranksItt->second, iam.player); + } fc->UpdateCharPoints(iam.player, curPoints); fc->UpdateCharacterSpec(iam.player, spec); diff --git a/modules/mod-Forge/src/TopicHandlers/UnlearnTalentHandler.cpp b/modules/mod-Forge/src/TopicHandlers/UnlearnTalentHandler.cpp index a6be85b1e924ac..4b8728cda2e685 100644 --- a/modules/mod-Forge/src/TopicHandlers/UnlearnTalentHandler.cpp +++ b/modules/mod-Forge/src/TopicHandlers/UnlearnTalentHandler.cpp @@ -100,11 +100,27 @@ class UnlearnTalentHandler : public ForgeTopicHandler sfp->Sum += refund; sfp->Max -= refund; - auto spellInfo = sSpellMgr->GetSpellInfo(spellId); - if (spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) - iam.player->RemoveOwnedAura(tab->Talents[spellId]->Ranks[spellItt->second->CurrentRank]); - else - iam.player->removeSpell(tab->Talents[spellId]->Ranks[spellItt->second->CurrentRank], SPEC_MASK_ALL, false); + if (spellItt->second->type == NodeType::CHOICE) { + auto chosen = spec->ChoiceNodesChosen.find(spellId); + + if (chosen == spec->ChoiceNodesChosen.end()) { + iam.player->SendForgeUIMsg(ForgeTopic::UNLEARN_TALENT_ERROR, "Attempted to forget unknown choice node talent."); + return; + } + + auto spellInfo = sSpellMgr->GetSpellInfo(chosen->second); + if (spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) + iam.player->RemoveOwnedAura(chosen->second); + else + iam.player->removeSpell(chosen->second, SPEC_MASK_ALL, false); + } + else { + auto spellInfo = sSpellMgr->GetSpellInfo(spellId); + if (spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE)) + iam.player->RemoveOwnedAura(tab->Talents[spellId]->Ranks[spellItt->second->CurrentRank]); + else + iam.player->removeSpell(tab->Talents[spellId]->Ranks[spellItt->second->CurrentRank], SPEC_MASK_ALL, false); + } iam.player->UpdateAllStats(); spellItt->second->CurrentRank = 0;