[8169] Implement new optional table spell_check and console command .debug spellcheck Author: VladimirMangos
* Table expected to be store data mirror same data in code:
- explicit spell ids with related expected spell properties like effects, spell family or auras
- implicit requirements for select some spell sets like spell family masks, icons or visual values
* For check can be used .debug spellcheck _console_ only command.
* Main purpose table and related command check code parts for outdated data at client switch.
It also can be used for check data in patch writing time to be sure code correctness.
--HG--
branch : trunk
This commit is contained in:
+2
-1
@@ -163,6 +163,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
{ "setaurastate", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetAuraStateCommand, "", NULL },
|
||||
{ "setitemflag", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetItemFlagCommand, "", NULL },
|
||||
{ "setvalue", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetValueCommand, "", NULL },
|
||||
{ "spellcheck", SEC_CONSOLE, true, &ChatHandler::HandleDebugSpellCheckCommand, "", NULL },
|
||||
{ "spawnvehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSpawnVehicle, "", NULL },
|
||||
{ "setvid", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugSetVehicleId, "", NULL },
|
||||
{ "entervehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleDebugEnterVehicle, "", NULL },
|
||||
@@ -628,7 +629,7 @@ ChatCommand * ChatHandler::getCommandTable()
|
||||
{ "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
|
||||
{ "learn", SEC_MODERATOR, false, NULL, "", learnCommandTable },
|
||||
{ "modify", SEC_MODERATOR, false, NULL, "", modifyCommandTable },
|
||||
{ "debug", SEC_MODERATOR, false, NULL, "", debugCommandTable },
|
||||
{ "debug", SEC_MODERATOR, true, NULL, "", debugCommandTable },
|
||||
{ "tele", SEC_MODERATOR, true, NULL, "", teleCommandTable },
|
||||
{ "character", SEC_GAMEMASTER, false, NULL, "", characterCommandTable},
|
||||
{ "event", SEC_GAMEMASTER, false, NULL, "", eventCommandTable },
|
||||
|
||||
@@ -148,6 +148,7 @@ class ChatHandler
|
||||
bool HandleDebugEnterVehicle(const char * args);
|
||||
bool HandleDebugSetValueCommand(const char* args);
|
||||
bool HandleDebugSpawnVehicle(const char * args);
|
||||
bool HandleDebugSpellCheckCommand(const char* args);
|
||||
bool HandleDebugUpdateCommand(const char* args);
|
||||
bool HandleDebugUpdateWorldStateCommand(const char* args);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiers.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "SpellMgr.h"
|
||||
|
||||
bool ChatHandler::HandleDebugSendSpellFailCommand(const char* args)
|
||||
{
|
||||
@@ -800,6 +801,14 @@ bool ChatHandler::HandleDebugSpawnVehicle(const char* args)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatHandler::HandleDebugSpellCheckCommand(const char* /*args*/)
|
||||
{
|
||||
sLog.outString( "Check expected in code spell properties base at table 'spell_check' content...");
|
||||
spellmgr.CheckUsedSpells("spell_check");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ChatHandler::HandleDebugSendLargePacketCommand(const char* /*args*/)
|
||||
{
|
||||
const char* stuffingString = "This is a dummy string to push the packet's size beyond 128000 bytes. ";
|
||||
|
||||
+255
-11
@@ -889,17 +889,6 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId)
|
||||
{
|
||||
SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
|
||||
if (!spellproto) return false;
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
if (spellproto->EffectApplyAuraName[i] == auraType)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
|
||||
{
|
||||
// talents that learn spells can have stance requirements that need ignore
|
||||
@@ -2593,6 +2582,261 @@ void SpellMgr::LoadSkillLineAbilityMap()
|
||||
sLog.outString(">> Loaded %u SkillLineAbility MultiMap Data", count);
|
||||
}
|
||||
|
||||
void SpellMgr::CheckUsedSpells(char const* table)
|
||||
{
|
||||
uint32 countSpells = 0;
|
||||
uint32 countMasks = 0;
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
QueryResult *result = WorldDatabase.PQuery("SELECT spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMaskB,SpellIcon,SpellVisual,SpellCategory,EffectType,EffectAura,EffectIdx,Name,Code FROM %s",table);
|
||||
|
||||
if( !result )
|
||||
{
|
||||
barGoLink bar( 1 );
|
||||
|
||||
bar.step();
|
||||
|
||||
sLog.outString();
|
||||
sLog.outErrorDb("`%s` table is empty!",table);
|
||||
return;
|
||||
}
|
||||
|
||||
barGoLink bar( result->GetRowCount() );
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
bar.step();
|
||||
|
||||
uint32 spell = fields[0].GetUInt32();
|
||||
int32 family = fields[1].GetInt32();
|
||||
uint64 familyMaskA = fields[2].GetUInt64();
|
||||
uint32 familyMaskB = fields[3].GetUInt32();
|
||||
flag96 familyMask(familyMaskA, familyMaskB);
|
||||
int32 spellIcon = fields[4].GetInt32();
|
||||
int32 spellVisual = fields[5].GetInt32();
|
||||
int32 category = fields[6].GetInt32();
|
||||
int32 effectType = fields[7].GetInt32();
|
||||
int32 auraType = fields[8].GetInt32();
|
||||
int32 effectIdx = fields[9].GetInt32();
|
||||
std::string name = fields[10].GetCppString();
|
||||
std::string code = fields[11].GetCppString();
|
||||
|
||||
// checks of correctness requirements itself
|
||||
|
||||
if (family < -1 || family > SPELLFAMILY_PET)
|
||||
{
|
||||
sLog.outError("Table '%s' for spell %u have wrong SpellFamily value(%u), skipped.",table,spell,family);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: spellIcon check need dbc loading
|
||||
if (spellIcon < -1)
|
||||
{
|
||||
sLog.outError("Table '%s' for spell %u have wrong SpellIcon value(%u), skipped.",table,spell,spellIcon);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: spellVisual check need dbc loading
|
||||
if (spellVisual < -1)
|
||||
{
|
||||
sLog.outError("Table '%s' for spell %u have wrong SpellVisual value(%u), skipped.",table,spell,spellVisual);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: for spellCategory better check need dbc loading
|
||||
if (category < -1 || category >=0 && sSpellCategoryStore.find(category) == sSpellCategoryStore.end())
|
||||
{
|
||||
sLog.outError("Table '%s' for spell %u have wrong SpellCategory value(%u), skipped.",table,spell,category);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (effectType < -1 || effectType >= TOTAL_SPELL_EFFECTS)
|
||||
{
|
||||
sLog.outError("Table '%s' for spell %u have wrong SpellEffect type value(%u), skipped.",table,spell,effectType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auraType < -1 || auraType >= TOTAL_AURAS)
|
||||
{
|
||||
sLog.outError("Table '%s' for spell %u have wrong SpellAura type value(%u), skipped.",table,spell,auraType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (effectIdx < -1 || effectIdx >= 3)
|
||||
{
|
||||
sLog.outError("Table '%s' for spell %u have wrong EffectIdx value(%u), skipped.",table,spell,effectIdx);
|
||||
continue;
|
||||
}
|
||||
|
||||
// now checks of requirements
|
||||
|
||||
if(spell)
|
||||
{
|
||||
++countSpells;
|
||||
|
||||
SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell);
|
||||
if(!spellEntry)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' not exist but used in %s.",spell,name.c_str(),code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(family >= 0 && spellEntry->SpellFamilyName != family)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' family(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->SpellFamilyName,family,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(familyMaskA != UI64LIT(0xFFFFFFFFFFFFFFFF) || familyMaskB != 0xFFFFFFFF)
|
||||
{
|
||||
if(familyMaskA == UI64LIT(0x0000000000000000) && familyMaskB == 0x00000000)
|
||||
{
|
||||
if(spellEntry->SpellFamilyFlags)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' not fit to (" I64FMT "," I32FMT ") but used in %s.",spell,name.c_str(),familyMaskA,familyMaskB,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!(spellEntry->SpellFamilyFlags & familyMask))
|
||||
{
|
||||
sLog.outError("Spell %u '%s' not fit to (" I64FMT "," I32FMT ") but used in %s.",spell,name.c_str(),familyMaskA,familyMaskB,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(spellIcon >= 0 && spellEntry->SpellIconID != spellIcon)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' icon(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->SpellIconID,spellIcon,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(spellVisual >= 0 && spellEntry->SpellVisual[0] != spellVisual)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' visual(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->SpellVisual[0],spellVisual,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(category >= 0 && spellEntry->Category != category)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' category(%u) <> %u but used in %s.",spell,name.c_str(),spellEntry->Category,category,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(effectIdx >= 0)
|
||||
{
|
||||
if(effectType >= 0 && spellEntry->Effect[effectIdx] != effectType)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' effect%d <> %u but used in %s.",spell,name.c_str(),effectIdx+1,effectType,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(auraType >= 0 && spellEntry->EffectApplyAuraName[effectIdx] != auraType)
|
||||
{
|
||||
sLog.outError("Spell %u '%s' aura%d <> %u but used in %s.",spell,name.c_str(),effectIdx+1,auraType,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(effectType >= 0 && !IsSpellHaveEffect(spellEntry,SpellEffects(effectType)))
|
||||
{
|
||||
sLog.outError("Spell %u '%s' not have effect %u but used in %s.",spell,name.c_str(),effectType,code.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if(auraType >= 0 && !IsSpellHaveAura(spellEntry,AuraType(auraType)))
|
||||
{
|
||||
sLog.outError("Spell %u '%s' not have aura %u but used in %s.",spell,name.c_str(),auraType,code.c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++countMasks;
|
||||
|
||||
bool found = false;
|
||||
for(uint32 spellId = 1; spellId < sSpellStore.GetNumRows(); ++spellId)
|
||||
{
|
||||
SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellId);
|
||||
if(!spellEntry)
|
||||
continue;
|
||||
|
||||
if(family >=0 && spellEntry->SpellFamilyName != family)
|
||||
continue;
|
||||
|
||||
if(familyMaskA != UI64LIT(0xFFFFFFFFFFFFFFFF) || familyMaskB != 0xFFFFFFFF)
|
||||
{
|
||||
if(familyMaskA == UI64LIT(0x0000000000000000) && familyMaskB == 0x00000000)
|
||||
{
|
||||
if(spellEntry->SpellFamilyFlags)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!(spellEntry->SpellFamilyFlags & familyMask))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(spellIcon >= 0 && spellEntry->SpellIconID != spellIcon)
|
||||
continue;
|
||||
|
||||
if(spellVisual >= 0 && spellEntry->SpellVisual[0] != spellVisual)
|
||||
continue;
|
||||
|
||||
if(category >= 0 && spellEntry->Category != category)
|
||||
continue;
|
||||
|
||||
if(effectIdx >= 0)
|
||||
{
|
||||
if(effectType >=0 && spellEntry->Effect[effectIdx] != effectType)
|
||||
continue;
|
||||
|
||||
if(auraType >=0 && spellEntry->EffectApplyAuraName[effectIdx] != auraType)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(effectType >=0 && !IsSpellHaveEffect(spellEntry,SpellEffects(effectType)))
|
||||
continue;
|
||||
|
||||
if(auraType >=0 && !IsSpellHaveAura(spellEntry,AuraType(auraType)))
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!found)
|
||||
{
|
||||
if(effectIdx >= 0)
|
||||
sLog.outError("Spells '%s' not found for family %i (" I64FMT "," I32FMT ") icon(%i) visual(%i) category(%i) effect%d(%i) aura%d(%i) but used in %s",
|
||||
name.c_str(),family,familyMaskA,familyMaskB,spellIcon,spellVisual,category,effectIdx+1,effectType,effectIdx+1,auraType,code.c_str());
|
||||
else
|
||||
sLog.outError("Spells '%s' not found for family %i (" I64FMT "," I32FMT ") icon(%i) visual(%i) category(%i) effect(%i) aura(%i) but used in %s",
|
||||
name.c_str(),family,familyMaskA,familyMaskB,spellIcon,spellVisual,category,effectType,auraType,code.c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
} while( result->NextRow() );
|
||||
|
||||
delete result;
|
||||
|
||||
sLog.outString();
|
||||
sLog.outString( ">> Checked %u spells and %u spell masks", countSpells, countMasks );
|
||||
}
|
||||
|
||||
DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellEntry const* spellproto, bool triggered)
|
||||
{
|
||||
// Explicit Diminishing Groups
|
||||
|
||||
+10
-2
@@ -193,6 +193,14 @@ inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect)
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool IsSpellHaveAura(SpellEntry const *spellInfo, AuraType aura)
|
||||
{
|
||||
for(int i= 0; i < 3; ++i)
|
||||
if(SpellEffects(spellInfo->EffectApplyAuraName[i])==aura)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2);
|
||||
|
||||
inline bool IsSealSpell(SpellEntry const *spellInfo)
|
||||
@@ -256,8 +264,6 @@ bool IsDispelableBySpell(SpellEntry const * dispelSpell, uint32 spellId, bool de
|
||||
bool IsSingleTargetSpell(SpellEntry const *spellInfo);
|
||||
bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2);
|
||||
|
||||
bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
|
||||
|
||||
extern bool IsAreaEffectTarget[TOTAL_SPELL_TARGETS];
|
||||
|
||||
inline bool IsAreaOfEffectSpell(SpellEntry const *spellInfo)
|
||||
@@ -1045,6 +1051,8 @@ class SpellMgr
|
||||
public:
|
||||
static SpellMgr& Instance();
|
||||
|
||||
void CheckUsedSpells(char const* table);
|
||||
|
||||
// Loading data at server startup
|
||||
void LoadSpellChains();
|
||||
void LoadSpellRequired();
|
||||
|
||||
Reference in New Issue
Block a user