Core/Spells: Implemented SpellLearnSpell.db2 for auto learning linked spells
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
// 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)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
SpellLearnSpellNode masteryNode;
|
||||
masteryNode.spell = mastery;
|
||||
masteryNode.active = true;
|
||||
masteryNode.autoLearned = false;
|
||||
|
||||
mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(masteryMainSpell, masteryNode));
|
||||
++mastery_count;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (itr->second.Spell == mastery)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
SpellLearnSpellNode masteryNode;
|
||||
masteryNode.Spell = mastery;
|
||||
masteryNode.OverridesSpell = 0;
|
||||
masteryNode.Active = true;
|
||||
masteryNode.AutoLearned = false;
|
||||
|
||||
mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(masteryMainSpell, masteryNode));
|
||||
++mastery_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user