aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormegamage <none@none>2009-07-16 10:13:12 +0800
committermegamage <none@none>2009-07-16 10:13:12 +0800
commite1762e3e6d6a9cc82f2244b5c6d4e26d3315caf6 (patch)
tree9de6c38c8832b8627a782fe75ba418dd240b3b01 /src
parent6f256824233ae004cf3fc93d1626e91c279452ea (diff)
[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
Diffstat (limited to 'src')
-rw-r--r--src/game/Chat.cpp3
-rw-r--r--src/game/Chat.h1
-rw-r--r--src/game/Debugcmds.cpp9
-rw-r--r--src/game/SpellMgr.cpp266
-rw-r--r--src/game/SpellMgr.h12
-rw-r--r--src/shared/Util.h12
6 files changed, 289 insertions, 14 deletions
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index af643b50ce4..9ae5678c752 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -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 },
diff --git a/src/game/Chat.h b/src/game/Chat.h
index a2bc23217ac..55116bae711 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -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);
diff --git a/src/game/Debugcmds.cpp b/src/game/Debugcmds.cpp
index eabf720f17b..e504865cbc3 100644
--- a/src/game/Debugcmds.cpp
+++ b/src/game/Debugcmds.cpp
@@ -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. ";
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 9e0b69d0777..dfa25cef538 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -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
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index e087ec66502..2dde39abba9 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -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();
diff --git a/src/shared/Util.h b/src/shared/Util.h
index ddbf968b2c2..496411d8be3 100644
--- a/src/shared/Util.h
+++ b/src/shared/Util.h
@@ -321,6 +321,11 @@ uint32 CreatePIDFile(const std::string& filename);
#ifndef _FLAG96
#define _FLAG96
+#ifndef PAIR64_HIPART
+#define PAIR64_HIPART(x) (uint32)((uint64(x) >> 32) & UI64LIT(0x00000000FFFFFFFF))
+#define PAIR64_LOPART(x) (uint32)(uint64(x) & UI64LIT(0x00000000FFFFFFFF))
+#endif
+
class flag96
{
private:
@@ -333,6 +338,13 @@ public:
part[2]=p3;
}
+ flag96(uint64 p1, uint32 p2)
+ {
+ part[0]=PAIR64_LOPART(p1);
+ part[1]=PAIR64_HIPART(p1);
+ part[2]=p2;
+ }
+
inline bool IsEqual(uint32 p1=0, uint32 p2=0, uint32 p3=0) const
{
return (