aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp2
-rw-r--r--src/server/game/DataStores/DB2Stores.h1
-rw-r--r--src/server/game/DataStores/DB2Structure.h8
-rw-r--r--src/server/game/DataStores/DB2fmt.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp17
-rw-r--r--src/server/game/Spells/Spell.cpp1
-rw-r--r--src/server/game/Spells/SpellMgr.cpp151
-rw-r--r--src/server/game/Spells/SpellMgr.h7
8 files changed, 129 insertions, 59 deletions
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 0fcf1742382..875505425f5 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -42,6 +42,7 @@ DB2Storage<PhaseGroupEntry> sPhaseGroupStore(PhaseGroupEntryfmt)
DB2Storage<SpellAuraRestrictionsEntry> sSpellAuraRestrictionsStore(SpellAuraRestrictionsEntryfmt);
DB2Storage<SpellCastingRequirementsEntry> sSpellCastingRequirementsStore(SpellCastingRequirementsEntryfmt);
DB2Storage<SpellClassOptionsEntry> sSpellClassOptionsStore(SpellClassOptionsEntryfmt);
+DB2Storage<SpellLearnSpellEntry> sSpellLearnSpellStore(SpellLearnSpellEntryfmt);
DB2Storage<SpellMiscEntry> sSpellMiscStore(SpellMiscEntryfmt);
DB2Storage<SpellPowerEntry> sSpellPowerStore(SpellPowerEntryfmt);
SpellPowerBySpellIDMap sSpellPowerBySpellIDStore;
@@ -142,6 +143,7 @@ void DB2Manager::LoadStores(std::string const& dataPath)
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sSpellAuraRestrictionsStore, db2Path, "SpellAuraRestrictions.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sSpellCastingRequirementsStore, db2Path, "SpellCastingRequirements.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sSpellClassOptionsStore, db2Path, "SpellClassOptions.db2");
+ LoadDB2(availableDb2Locales, bad_db2_files, _stores, sSpellLearnSpellStore, db2Path, "SpellLearnSpell.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sSpellMiscStore, db2Path, "SpellMisc.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sSpellPowerStore, db2Path, "SpellPower.db2");
LoadDB2(availableDb2Locales, bad_db2_files, _stores, sSpellReagentsStore, db2Path, "SpellReagents.db2");
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 43aa1397c5b..f721fd4bc19 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -35,6 +35,7 @@ extern DB2Storage<PhaseGroupEntry> sPhaseGroupStore;
extern DB2Storage<SpellAuraRestrictionsEntry> sSpellAuraRestrictionsStore;
extern DB2Storage<SpellCastingRequirementsEntry> sSpellCastingRequirementsStore;
extern DB2Storage<SpellClassOptionsEntry> sSpellClassOptionsStore;
+extern DB2Storage<SpellLearnSpellEntry> sSpellLearnSpellStore;
extern DB2Storage<SpellMiscEntry> sSpellMiscStore;
extern DB2Storage<SpellPowerEntry> sSpellPowerStore;
extern SpellPowerBySpellIDMap sSpellPowerBySpellIDStore;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 70c54008401..7c68e5bb39a 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -288,6 +288,14 @@ struct SpellClassOptionsEntry
uint32 SpellClassSet; // 3
};
+struct SpellLearnSpellEntry
+{
+ uint32 ID; // 0
+ uint32 LearnSpellID; // 1
+ uint32 SpellID; // 2
+ uint32 OverridesSpellID; // 3
+};
+
struct SpellMiscEntry
{
uint32 ID; // 0
diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h
index 8076685dc03..3a56fb75ca5 100644
--- a/src/server/game/DataStores/DB2fmt.h
+++ b/src/server/game/DataStores/DB2fmt.h
@@ -37,6 +37,7 @@ char const PhaseGroupEntryfmt[] = "nii";
char const SpellAuraRestrictionsEntryfmt[] = "diiiiiiii";
char const SpellCastingRequirementsEntryfmt[] = "dixxixi";
char const SpellClassOptionsEntryfmt[] = "niiiiii";
+char const SpellLearnSpellEntryfmt[] = "niii";
char const SpellMiscEntryfmt[] = "niiiiiiiiiiiiiiiiifiiiiix";
char const SpellPowerEntryfmt[] = "niiiiiixxxffix";
char const SpellReagentsEntryfmt[] = "niiiiiiiiiiiiiiiixx";
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index a26a728de81..559e40137c3 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3658,13 +3658,16 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
{
- if (!itr2->second.autoLearned)
+ if (!itr2->second.AutoLearned)
{
- if (!IsInWorld() || !itr2->second.active) // at spells loading, no output, but allow save
- AddSpell(itr2->second.spell, itr2->second.active, true, true, false);
+ if (!IsInWorld() || !itr2->second.Active) // at spells loading, no output, but allow save
+ AddSpell(itr2->second.Spell, itr2->second.Active, true, true, false);
else // at normal learning
- LearnSpell(itr2->second.spell, true);
+ LearnSpell(itr2->second.Spell, true);
}
+
+ if (itr2->second.OverridesSpell && itr2->second.Active)
+ AddOverrideSpell(itr2->second.OverridesSpell, itr2->second.Spell);
}
if (!GetSession()->PlayerLoading())
@@ -3873,7 +3876,11 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spell_id);
for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
- RemoveSpell(itr2->second.spell, disabled);
+ {
+ RemoveSpell(itr2->second.Spell, disabled);
+ if (itr2->second.OverridesSpell)
+ RemoveOverrideSpell(itr2->second.OverridesSpell, itr2->second.Spell);
+ }
// activate lesser rank in spellbook/action bar, and cast it if need
bool prev_activate = false;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 387a01dbf0a..6e70c4ef696 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -543,6 +543,7 @@ SpellValue::SpellValue(Difficulty diff, SpellInfo const* proto)
// todo 6.x
SpellEffectInfoVector effects = proto->GetEffectsForDifficulty(diff);
ASSERT(effects.size() <= MAX_SPELL_EFFECTS);
+ memset(EffectBasePoints, 0, sizeof(EffectBasePoints));
for (SpellEffectInfo const* effect : effects)
if (effect)
EffectBasePoints[effect->EffectIndex] = effect->BasePoints;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 5dd41eb9bcf..77044f67fc1 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -677,7 +677,7 @@ bool SpellMgr::IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const
{
SpellLearnSpellMapBounds bounds = GetSpellLearnSpellMapBounds(spell_id1);
for (SpellLearnSpellMap::const_iterator i = bounds.first; i != bounds.second; ++i)
- if (i->second.spell == spell_id2)
+ if (i->second.Spell == spell_id2)
return true;
return false;
}
@@ -1484,9 +1484,10 @@ void SpellMgr::LoadSpellLearnSpells()
uint32 spell_id = fields[0].GetUInt32();
SpellLearnSpellNode node;
- node.spell = fields[1].GetUInt32();
- node.active = fields[2].GetBool();
- node.autoLearned = false;
+ node.Spell = fields[1].GetUInt32();
+ node.OverridesSpell = 0;
+ node.Active = fields[2].GetBool();
+ node.AutoLearned = false;
SpellInfo const* spellInfo = GetSpellInfo(spell_id);
if (!spellInfo)
@@ -1495,15 +1496,15 @@ void SpellMgr::LoadSpellLearnSpells()
continue;
}
- if (!GetSpellInfo(node.spell))
+ if (!GetSpellInfo(node.Spell))
{
- TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` learning not existed spell %u", spell_id, node.spell);
+ TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` learning not existed spell %u", spell_id, node.Spell);
continue;
}
if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
{
- TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped", spell_id, node.spell);
+ TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped", spell_id, node.Spell);
continue;
}
@@ -1529,27 +1530,28 @@ void SpellMgr::LoadSpellLearnSpells()
if (effect && effect->Effect == SPELL_EFFECT_LEARN_SPELL)
{
SpellLearnSpellNode dbc_node;
- dbc_node.spell = effect->TriggerSpell;
- dbc_node.active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
+ dbc_node.Spell = effect->TriggerSpell;
+ dbc_node.Active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
+ dbc_node.OverridesSpell = 0;
// ignore learning not existed spells (broken/outdated/or generic learnig spell 483
- if (!GetSpellInfo(dbc_node.spell))
+ if (!GetSpellInfo(dbc_node.Spell))
continue;
// talent or passive spells or skill-step spells auto-cast and not need dependent learning,
// pet teaching spells must not be dependent learning (cast)
// other required explicit dependent learning
- dbc_node.autoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || entry->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
+ dbc_node.AutoLearned = effect->TargetA.GetTarget() == TARGET_UNIT_PET || entry->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell);
bool found = false;
for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
{
- if (itr->second.spell == dbc_node.spell)
+ if (itr->second.Spell == dbc_node.Spell)
{
TC_LOG_ERROR("sql.sql", "Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.",
- spell, dbc_node.spell);
+ spell, dbc_node.Spell);
found = true;
break;
}
@@ -1564,6 +1566,55 @@ void SpellMgr::LoadSpellLearnSpells()
}
}
+ for (uint32 i = 0; i < sSpellLearnSpellStore.GetNumRows(); ++i)
+ {
+ SpellLearnSpellEntry const* spellLearnSpell = sSpellLearnSpellStore.LookupEntry(i);
+ if (!spellLearnSpell)
+ continue;
+
+ if (!GetSpellInfo(spellLearnSpell->SpellID))
+ continue;
+
+ SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spellLearnSpell->LearnSpellID);
+ bool found = false;
+ for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
+ {
+ if (itr->second.Spell == spellLearnSpell->SpellID)
+ {
+ TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically from SpellLearnSpell.db2", spellLearnSpell->LearnSpellID, spellLearnSpell->SpellID);
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ // Check if it is already found in Spell.dbc, ignore silently if yes
+ SpellLearnSpellMapBounds dbc_node_bounds = GetSpellLearnSpellMapBounds(spellLearnSpell->LearnSpellID);
+ found = false;
+ for (SpellLearnSpellMap::const_iterator itr = dbc_node_bounds.first; itr != dbc_node_bounds.second; ++itr)
+ {
+ if (itr->second.Spell == spellLearnSpell->SpellID)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ continue;
+
+ SpellLearnSpellNode dbcLearnNode;
+ dbcLearnNode.Spell = spellLearnSpell->SpellID;
+ dbcLearnNode.OverridesSpell = spellLearnSpell->OverridesSpellID;
+ dbcLearnNode.Active = true;
+ dbcLearnNode.AutoLearned = false;
+
+ mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spellLearnSpell->LearnSpellID, dbcLearnNode));
+ ++dbc_count;
+ }
+
uint32 mastery_count = 0;
for (uint32 i = 0; i < sChrSpecializationStore.GetNumRows(); ++i)
{
@@ -1571,57 +1622,55 @@ void SpellMgr::LoadSpellLearnSpells()
if (!chrSpec)
continue;
- for (uint32 c = CLASS_WARRIOR; c < MAX_CLASSES; ++c)
+ if (chrSpec->ClassID >= MAX_CLASSES)
+ continue;
+
+ uint32 masteryMainSpell = MasterySpells[chrSpec->ClassID];
+
+ for (uint32 m = 0; m < MAX_MASTERY_SPELLS; ++m)
{
- if (chrSpec->ClassID != c)
+ uint32 mastery = chrSpec->MasterySpellID[m];
+ if (!mastery)
continue;
- uint32 masteryMainSpell = MasterySpells[c];
-
- for (uint32 m = 0; m < MAX_MASTERY_SPELLS; ++m)
+ SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(masteryMainSpell);
+ bool found = false;
+ for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
{
- uint32 mastery = chrSpec->MasterySpellID[m];
- if (!mastery)
- continue;
-
- SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(masteryMainSpell);
- bool found = false;
- for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
+ if (itr->second.Spell == mastery)
{
- if (itr->second.spell == mastery)
- {
- TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from ChrSpecialization.dbc", masteryMainSpell, mastery);
- found = true;
- break;
- }
+ TC_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from ChrSpecialization.dbc", masteryMainSpell, mastery);
+ found = true;
+ break;
}
+ }
- if (found)
- continue;
+ if (found)
+ continue;
- // Check if it is already found in Spell.dbc, ignore silently if yes
- SpellLearnSpellMapBounds dbc_node_bounds = GetSpellLearnSpellMapBounds(masteryMainSpell);
- found = false;
- for (SpellLearnSpellMap::const_iterator itr = dbc_node_bounds.first; itr != dbc_node_bounds.second; ++itr)
+ // Check if it is already found in Spell.dbc, ignore silently if yes
+ SpellLearnSpellMapBounds dbc_node_bounds = GetSpellLearnSpellMapBounds(masteryMainSpell);
+ found = false;
+ for (SpellLearnSpellMap::const_iterator itr = dbc_node_bounds.first; itr != dbc_node_bounds.second; ++itr)
+ {
+ if (itr->second.Spell == mastery)
{
- if (itr->second.spell == mastery)
- {
- found = true;
- break;
- }
+ found = true;
+ break;
}
+ }
- if (found)
- continue;
+ if (found)
+ continue;
- SpellLearnSpellNode masteryNode;
- masteryNode.spell = mastery;
- masteryNode.active = true;
- masteryNode.autoLearned = false;
+ SpellLearnSpellNode masteryNode;
+ masteryNode.Spell = mastery;
+ masteryNode.OverridesSpell = 0;
+ masteryNode.Active = true;
+ masteryNode.AutoLearned = false;
- mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(masteryMainSpell, masteryNode));
- ++mastery_count;
- }
+ mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(masteryMainSpell, masteryNode));
+ ++mastery_count;
}
}
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index 36ffe105c54..9033ccddeca 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -535,9 +535,10 @@ typedef std::map<uint32, SpellLearnSkillNode> SpellLearnSkillMap;
struct SpellLearnSpellNode
{
- uint32 spell;
- bool active; // show in spellbook or not
- bool autoLearned;
+ uint32 Spell;
+ uint32 OverridesSpell;
+ bool Active; // show in spellbook or not
+ bool AutoLearned; // This marks the spell as automatically learned from another source that - will only be used for unlearning
};
typedef std::multimap<uint32, SpellLearnSpellNode> SpellLearnSpellMap;