Core/Spells: Implemented SpellLearnSpell.db2 for auto learning linked spells

This commit is contained in:
Shauren
2015-02-08 16:23:31 +01:00
parent e6eadc1f3b
commit a043d539f0
8 changed files with 135 additions and 65 deletions
+2
View File
@@ -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");
+1
View File
@@ -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
+1
View File
@@ -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";
+12 -5
View File
@@ -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;
+1
View File
@@ -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;
+106 -57
View File
@@ -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;
}
}
+4 -3
View File
@@ -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;