Skip to content

Commit

Permalink
[11022] Create template for loading spell ranks from DB to allow bett…
Browse files Browse the repository at this point in the history
…er code re-use.
  • Loading branch information
Lynx3d committed Jan 17, 2011
1 parent 2991714 commit ab0945c
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 104 deletions.
236 changes: 133 additions & 103 deletions src/game/SpellMgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 spellId_2)
&& spellInfo_1->EffectApplyAuraName[i] == spellInfo_2->EffectApplyAuraName[j]
&& spellInfo_1->EffectMiscValue[i] == spellInfo_2->EffectMiscValue[j]
&& spellInfo_1->EffectItemType[i] == spellInfo_2->EffectItemType[j]
&& (spellInfo_1->Effect[i] != 0 || spellInfo_1->EffectApplyAuraName[i] != 0 ||
&& (spellInfo_1->Effect[i] != 0 || spellInfo_1->EffectApplyAuraName[i] != 0 ||
spellInfo_1->EffectMiscValue[i] != 0 || spellInfo_1->EffectItemType[i] != 0))
return true;
}
Expand Down Expand Up @@ -1046,11 +1046,69 @@ void SpellMgr::LoadSpellTargetPositions()
sLog.outString( ">> Loaded %u spell teleport coordinates", count );
}

template <typename EntryType, typename WorkerType, typename StorageType>
struct SpellRankHelper
{
SpellRankHelper(SpellMgr &_mgr, StorageType &_storage): mgr(_mgr), worker(_storage), customRank(0) {}
void RecordRank(EntryType &entry, uint32 spell_id)
{
const SpellEntry *spell = sSpellStore.LookupEntry(spell_id);
if (!spell)
{
sLog.outErrorDb("Spell %u listed in `%s` does not exist", spell_id, worker.TableName());
return;
}

uint32 first_id = mgr.GetFirstSpellInChain(spell_id);

// most spell ranks expected same data
if(first_id)
{
firstRankSpells.insert(first_id);

if (first_id != spell_id)
{
if (!worker.IsValidCustomRank(entry, spell_id, first_id))
return;
// for later check that first rank also added
else
{
firstRankSpellsWithCustomRanks.insert(first_id);
++customRank;
}
}
}

worker.AddEntry(entry, spell);
}
void FillHigherRanks()
{
// check that first rank added for custom ranks
for (std::set<uint32>::const_iterator itr = firstRankSpellsWithCustomRanks.begin(); itr != firstRankSpellsWithCustomRanks.end(); ++itr)
if (!worker.HasEntry(*itr))
sLog.outErrorDb("Spell %u must be listed in `%s` as first rank for listed custom ranks of spell but not found!", *itr, worker.TableName());

// fill absent non first ranks data base at first rank data
for (std::set<uint32>::const_iterator itr = firstRankSpells.begin(); itr != firstRankSpells.end(); ++itr)
{
if (worker.SetStateToEntry(*itr))
mgr.doForHighRanks(*itr, worker);
}
}
std::set<uint32> firstRankSpells;
std::set<uint32> firstRankSpellsWithCustomRanks;

SpellMgr &mgr;
WorkerType worker;
uint32 customRank;
};

struct DoSpellProcEvent
{
DoSpellProcEvent(SpellProcEventMap& _spe_map, SpellProcEventEntry const& _spe) : spe_map(_spe_map), spe(_spe) {}
DoSpellProcEvent(SpellProcEventMap& _spe_map) : spe_map(_spe_map), customProc(0), count(0) {}
void operator() (uint32 spell_id)
{
SpellProcEventEntry const& spe = state->second;
// add ranks only for not filled data (some ranks have ppm data different for ranks for example)
SpellProcEventMap::const_iterator spellItr = spe_map.find(spell_id);
if (spellItr == spe_map.end())
Expand Down Expand Up @@ -1096,102 +1154,33 @@ struct DoSpellProcEvent
}
}

SpellProcEventMap& spe_map;
SpellProcEventEntry const& spe;
};

void SpellMgr::LoadSpellProcEvents()
{
mSpellProcEventMap.clear(); // need for reload case

uint32 count = 0;

// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMaskA0, SpellFamilyMaskA1, SpellFamilyMaskA2, SpellFamilyMaskB0, SpellFamilyMaskB1, SpellFamilyMaskB2, SpellFamilyMaskC0, SpellFamilyMaskC1, SpellFamilyMaskC2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
if( !result )
{
barGoLink bar( 1 );
bar.step();
sLog.outString();
sLog.outString( ">> Loaded %u spell proc event conditions", count );
return;
}

std::set<uint32> firstRankSpells;
std::set<uint32> firstRankSpellsWithCustomRanks;

barGoLink bar( (int)result->GetRowCount() );
uint32 customProc = 0;
uint32 customRank = 0;
do
const char* TableName() { return "spell_proc_event"; }
bool IsValidCustomRank(SpellProcEventEntry const &spe, uint32 entry, uint32 first_id)
{
Field *fields = result->Fetch();

bar.step();

uint32 entry = fields[0].GetUInt32();

const SpellEntry *spell = sSpellStore.LookupEntry(entry);
if (!spell)
{
sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry);
continue;
}

SpellProcEventEntry spe;

spe.schoolMask = fields[1].GetUInt32();
spe.spellFamilyName = fields[2].GetUInt32();

for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
spe.spellFamilyMask[i] = (uint64)fields[i+3].GetUInt32()|((uint64)fields[i+6].GetUInt32()<<32);
spe.spellFamilyMask2[i] = fields[i+9].GetUInt32();
}
spe.procFlags = fields[12].GetUInt32();
spe.procEx = fields[13].GetUInt32();
spe.ppmRate = fields[14].GetFloat();
spe.customChance = fields[15].GetFloat();
spe.cooldown = fields[16].GetUInt32();

uint32 first_id = GetFirstSpellInChain(entry);

// most spell ranks expected same data
if(first_id)
// let have independent data in table for spells with ppm rates (exist rank dependent ppm rate spells)
if (!spe.ppmRate)
{
firstRankSpells.insert(first_id);

if ( first_id != entry)
{
// let have independent data in table for spells with ppm rates (exist rank dependent ppm rate spells)
if (!spe.ppmRate)
{
sLog.outErrorDb("Spell %u listed in `spell_proc_event` is not first rank (%u) in chain", entry, first_id);
// prevent loading since it won't have an effect anyway
continue;
}
// for later check that first rank als added
else
{
firstRankSpellsWithCustomRanks.insert(first_id);
++customRank;
}
}
sLog.outErrorDb("Spell %u listed in `spell_proc_event` is not first rank (%u) in chain", entry, first_id);
// prevent loading since it won't have an effect anyway
return false;
}

mSpellProcEventMap[entry] = spe;
return true;
}
bool AddEntry(SpellProcEventEntry const &spe, SpellEntry const *spell)
{
spe_map[spell->Id] = spe;

bool isCustom = false;

if (spe.procFlags == 0)
{
if (spell->procFlags==0)
sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell (no proc flags)", entry);
sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell (no proc flags)", spell->Id);
}
else
{
if (spell->procFlags==spe.procFlags)
sLog.outErrorDb("Spell %u listed in `spell_proc_event` have exactly same proc flags as in spell.dbc, field value redundent", entry);
sLog.outErrorDb("Spell %u listed in `spell_proc_event` has exactly same proc flags as in spell.dbc, field value redundant", spell->Id);
else
isCustom = true;
}
Expand All @@ -1200,13 +1189,13 @@ void SpellMgr::LoadSpellProcEvents()
{
/* enable for re-check cases, 0 chance ok for some cases because in some cases it set by another spell/talent spellmod)
if (spell->procChance==0 && !spe.ppmRate)
sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell (no chance or ppm)", entry);
sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell (no chance or ppm)", spell->Id);
*/
}
else
{
if (spell->procChance==spe.customChance)
sLog.outErrorDb("Spell %u listed in `spell_proc_event` have exactly same custom chance as in spell.dbc, field value redundent", entry);
sLog.outErrorDb("Spell %u listed in `spell_proc_event` has exactly same custom chance as in spell.dbc, field value redundant", spell->Id);
else
isCustom = true;
}
Expand All @@ -1223,39 +1212,80 @@ void SpellMgr::LoadSpellProcEvents()
empty = false;
uint32 const* ptr = spell->GetEffectSpellClassMask(SpellEffectIndex(i));
if ((((uint64*)ptr)[0] != 0 && spe.spellFamilyMask[i] == ((uint64*)ptr)[0]) && (ptr[2] == 0 || spe.spellFamilyMask2[i] == ptr[2]))
sLog.outErrorDb("Spell %u listed in `spell_proc_event` have same class mask as in Spell.dbc (EffectIndex %u) and doesn't have any other data", entry, i);
sLog.outErrorDb("Spell %u listed in `spell_proc_event` has same class mask as in Spell.dbc (EffectIndex %u) and doesn't have any other data", spell->Id, i);
}
}
if (empty)
sLog.outErrorDb("Spell %u listed in `spell_proc_event` not have any useful data", entry);
sLog.outErrorDb("Spell %u listed in `spell_proc_event` doesn't have any useful data", spell->Id);
}

if (isCustom)
++customProc;
else
++count;
} while( result->NextRow() );
}

bool HasEntry(uint32 spellId) { return spe_map.count(spellId) > 0; }
bool SetStateToEntry(uint32 spellId) { return (state = spe_map.find(spellId)) != spe_map.end(); }
SpellProcEventMap& spe_map;
SpellProcEventMap::const_iterator state;

uint32 customProc;
uint32 count;
};

void SpellMgr::LoadSpellProcEvents()
{
mSpellProcEventMap.clear(); // need for reload case

// check that first rank added for custom ranks
for(std::set<uint32>::const_iterator itr = firstRankSpellsWithCustomRanks.begin(); itr != firstRankSpellsWithCustomRanks.end(); ++itr)
if (mSpellProcEventMap.find(*itr) == mSpellProcEventMap.end())
sLog.outErrorDb("Spell %u must be listed in `spell_proc_event` as first rank for listed custom ranks of spell but not found!", *itr);
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMaskA0, SpellFamilyMaskA1, SpellFamilyMaskA2, SpellFamilyMaskB0, SpellFamilyMaskB1, SpellFamilyMaskB2, SpellFamilyMaskC0, SpellFamilyMaskC1, SpellFamilyMaskC2, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
if( !result )
{
barGoLink bar( 1 );
bar.step();
sLog.outString();
sLog.outString( ">> No spell proc event conditions loaded");
return;
}

// fill absent non first ranks data base at first rank data
for(std::set<uint32>::const_iterator itr = firstRankSpells.begin(); itr != firstRankSpells.end(); ++itr)
SpellRankHelper<SpellProcEventEntry, DoSpellProcEvent, SpellProcEventMap> rankHelper(*this, mSpellProcEventMap);

barGoLink bar( (int)result->GetRowCount() );
do
{
SpellProcEventMap::const_iterator speItr = mSpellProcEventMap.find(*itr);
if (speItr != mSpellProcEventMap.end())
Field *fields = result->Fetch();

bar.step();

uint32 entry = fields[0].GetUInt32();

SpellProcEventEntry spe;

spe.schoolMask = fields[1].GetUInt32();
spe.spellFamilyName = fields[2].GetUInt32();

for (int32 i = 0; i < MAX_EFFECT_INDEX; ++i)
{
DoSpellProcEvent worker(mSpellProcEventMap, speItr->second);
doForHighRanks(speItr->first,worker);
spe.spellFamilyMask[i] = (uint64)fields[i+3].GetUInt32()|((uint64)fields[i+6].GetUInt32()<<32);
spe.spellFamilyMask2[i] = fields[i+9].GetUInt32();
}
}
spe.procFlags = fields[12].GetUInt32();
spe.procEx = fields[13].GetUInt32();
spe.ppmRate = fields[14].GetFloat();
spe.customChance = fields[15].GetFloat();
spe.cooldown = fields[16].GetUInt32();

rankHelper.RecordRank(spe, entry);

} while (result->NextRow());

rankHelper.FillHigherRanks();

delete result;

sLog.outString();
sLog.outString( ">> Loaded %u extra spell proc event conditions +%u custom proc (inc. +%u custom ranks)", count, customProc, customRank );
sLog.outString( ">> Loaded %u extra spell proc event conditions +%u custom proc (inc. +%u custom ranks)", rankHelper.worker.count, rankHelper.worker.customProc, rankHelper.customRank);
}

struct DoSpellProcItemEnchant
Expand Down Expand Up @@ -2495,7 +2525,7 @@ void SpellMgr::LoadSpellChains()
mSpellChains[forward_id] = node;
continue;
}

// need temporary store for later rank calculation
prevRanks[forward_id] = spell_id;
}
Expand Down
2 changes: 1 addition & 1 deletion src/shared/revision_nr.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11021"
#define REVISION_NR "11022"
#endif // __REVISION_NR_H__

3 comments on commit ab0945c

@Fra298
Copy link

@Fra298 Fra298 commented on ab0945c Jan 17, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't compile X64 under vs2010, returnng this error : 

5>d:\mangos\mangos\src\game\spellmgr.cpp(1226): error C4716: 'DoSpellProcEvent::AddEntry' : must return a value

@VladimirMangos
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already fixed in [11025]. Anyway thank you for reporting :)

@Lynx3d
Copy link
Contributor Author

@Lynx3d Lynx3d commented on ab0945c Jan 17, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, i guess i should pay more attention to compiler warnings...

Please sign in to comment.