you can now reload creatures from creature_template table

NOTE: reload is limited to one creature at a time
Usage: .reload creature_template $entry
Warning: this is mainly for developers, reloading a creature can cause unexpected behaviors!!

--HG--
branch : trunk
This commit is contained in:
Rat@walamy
2010-05-16 17:45:45 +02:00
parent c26399a968
commit 9771757c4c
13 changed files with 478 additions and 297 deletions
+3
View File
@@ -0,0 +1,3 @@
DELETE FROM `command` WHERE `name` IN ('reload creature_template');
INSERT INTO `command` VALUES
('reload creature_template','3','Syntax: .reload creature_template $entry\r\nReload the specified creature\'s template.');
@@ -0,0 +1,4 @@
DELETE FROM `trinity_string` WHERE `entry` IN (817,818);
INSERT INTO `trinity_string` VALUES
(817,'Entry %u not found in creature_template table.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(818,'Entry %u not found in sCreatureStorage. Possible new line in creature_template, but you can not add new creatures without restarting. Only modifing is allowed.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+3
View File
@@ -622,6 +622,7 @@ INSERT INTO `command` VALUES
('reload spell_script_target',3,'Syntax: .reload spell_script_target\nReload spell_script_target table.'), ('reload spell_script_target',3,'Syntax: .reload spell_script_target\nReload spell_script_target table.'),
('reload spell_target_position',3,'Syntax: .reload spell_target_position\nReload spell_target_position table.'), ('reload spell_target_position',3,'Syntax: .reload spell_target_position\nReload spell_target_position table.'),
('reload spell_threats',3,'Syntax: .reload spell_threats\nReload spell_threats table.'), ('reload spell_threats',3,'Syntax: .reload spell_threats\nReload spell_threats table.'),
('reload creature_template','3','Syntax: .reload creature_template $entry\r\nReload the specified creature\'s template.'),
('reload trinity_string',3,'Syntax: .reload trinity_string\nReload trinity_string table.'), ('reload trinity_string',3,'Syntax: .reload trinity_string\nReload trinity_string table.'),
('reload waypoint_scripts',3,'Syntax: .reload waypoint_scripts\nReload waypoint_scripts table.'), ('reload waypoint_scripts',3,'Syntax: .reload waypoint_scripts\nReload waypoint_scripts table.'),
('repairitems',2,'Syntax: .repairitems\r\n\r\nRepair all selected player''s items.'), ('repairitems',2,'Syntax: .repairitems\r\n\r\nRepair all selected player''s items.'),
@@ -15126,6 +15127,8 @@ INSERT INTO `trinity_string` (`entry`,`content_default`,`content_loc1`,`content_
(814, 'Member', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (814, 'Member', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(815, 'Initiate', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (815, 'Initiate', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(816, 'Warning: You''ve entered a no-fly zone and are about to be dismounted!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (816, 'Warning: You''ve entered a no-fly zone and are about to be dismounted!', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(817, 'Entry %u not found in creature_template table.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(818, 'Entry %u not found in sCreatureStorage. Possible new line in creature_template, but you can not add new creatures without restarting. Only modifing is allowed.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(1000, 'Exiting daemon...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (1000, 'Exiting daemon...', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(1001, 'Account deleted: %s', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (1001, 'Account deleted: %s', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
(1002, 'Account %s NOT deleted (probably sql file format was updated)', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), (1002, 'Account %s NOT deleted (probably sql file format was updated)', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+1
View File
@@ -458,6 +458,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "creature_linked_respawn", SEC_GAMEMASTER, true, &ChatHandler::HandleReloadCreatureLinkedRespawnCommand, "", NULL }, { "creature_linked_respawn", SEC_GAMEMASTER, true, &ChatHandler::HandleReloadCreatureLinkedRespawnCommand, "", NULL },
{ "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL }, { "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", NULL },
{ "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL }, { "creature_questrelation", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureQuestRelationsCommand, "", NULL },
{ "creature_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadCreatureTemplateCommand, "", NULL },
//{ "db_script_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDbScriptStringCommand, "", NULL }, //{ "db_script_string", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadDbScriptStringCommand, "", NULL },
{ "disenchant_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL }, { "disenchant_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL },
{ "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL }, { "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL },
+1
View File
@@ -361,6 +361,7 @@ class ChatHandler
bool HandleReloadEventAISummonsCommand(const char* args); bool HandleReloadEventAISummonsCommand(const char* args);
bool HandleReloadEventAIScriptsCommand(const char* args); bool HandleReloadEventAIScriptsCommand(const char* args);
bool HandleReloadCommandCommand(const char* args); bool HandleReloadCommandCommand(const char* args);
bool HandleReloadCreatureTemplateCommand(const char* args);
bool HandleReloadCreatureQuestRelationsCommand(const char* args); bool HandleReloadCreatureQuestRelationsCommand(const char* args);
bool HandleReloadCreatureQuestInvRelationsCommand(const char* args); bool HandleReloadCreatureQuestInvRelationsCommand(const char* args);
bool HandleReloadCreatureLinkedRespawnCommand(const char* args); bool HandleReloadCreatureLinkedRespawnCommand(const char* args);
+3
View File
@@ -803,6 +803,9 @@ bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry,
AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING); AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
} }
} }
LastUsedScriptID = m_creatureInfo->ScriptID;
return bResult; return bResult;
} }
+2
View File
@@ -216,6 +216,8 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
SetZoneScript(); SetZoneScript();
LastUsedScriptID = GetGOInfo()->ScriptId;
return true; return true;
} }
+4 -1
View File
@@ -725,7 +725,10 @@ enum TrinityStrings
LANG_GUILD_MEMBER = 814, LANG_GUILD_MEMBER = 814,
LANG_GUILD_INITIATE = 815, LANG_GUILD_INITIATE = 815,
LANG_ZONE_NOFLYZONE = 816, LANG_ZONE_NOFLYZONE = 816,
// Room for in-game strings 817-999 not used
LANG_COMMAND_CREATURETEMPLATE_NOTFOUND = 817,
LANG_COMMAND_CREATURESTORAGE_NOTFOUND = 818,
// Room for in-game strings 819-999 not used
// Level 4 (CLI only commands) // Level 4 (CLI only commands)
LANG_COMMAND_EXIT = 1000, LANG_COMMAND_EXIT = 1000,
+145
View File
@@ -749,6 +749,151 @@ bool ChatHandler::HandleReloadCommandCommand(const char*)
return true; return true;
} }
bool ChatHandler::HandleReloadCreatureTemplateCommand(const char* args)
{
if (!*args)
return false;
uint32 entry = (uint32) atoi((char*)args);
QueryResult_AutoPtr result = WorldDatabase.PQuery("SELECT difficulty_entry_1,difficulty_entry_2,difficulty_entry_3,KillCredit1,KillCredit2,modelid1,modelid2,modelid3,modelid4,name,subname,IconName,gossip_menu_id,minlevel,maxlevel,exp,faction_A,faction_H,npcflag,speed_walk,speed_run,scale,rank,mindmg,maxdmg,dmgschool,attackpower,dmg_multiplier,baseattacktime,rangeattacktime,unit_class,unit_flags,dynamicflags,family,trainer_type,trainer_spell,trainer_class,trainer_race,minrangedmg,maxrangedmg,rangedattackpower,type,type_flags,lootid,pickpocketloot,skinloot,resistance1,resistance2,resistance3,resistance4,resistance5,resistance6,spell1,spell2,spell3,spell4,spell5,spell6,spell7,spell8,PetSpellDataId,VehicleId,mingold,maxgold,AIName,MovementType,InhabitType,Health_mod,Mana_mod,Armor_mod,RacialLeader,questItem1,questItem2,questItem3,questItem4,questItem5,questItem6,movementId,RegenHealth,equipment_id,mechanic_immune_mask,flags_extra,ScriptName FROM creature_template WHERE entry = %u", entry);
if (!result)
{
PSendSysMessage(LANG_COMMAND_CREATURETEMPLATE_NOTFOUND, entry);
SetSentErrorMessage(true);
return false;
}
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(entry);
if (!cInfo)
{
PSendSysMessage(LANG_COMMAND_CREATURESTORAGE_NOTFOUND, entry);
SetSentErrorMessage(true);
return false;
}
sLog.outString("Reloading creature template entry %u", entry);
Field *fields = result->Fetch();
const_cast<CreatureInfo*>(cInfo)->DifficultyEntry[0] = fields[0].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->DifficultyEntry[1] = fields[1].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->DifficultyEntry[2] = fields[2].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->KillCredit[0] = fields[3].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->KillCredit[1] = fields[4].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->Modelid1 = fields[5].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->Modelid2 = fields[6].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->Modelid3 = fields[7].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->Modelid4 = fields[8].GetUInt32();
size_t len = 0;
if (const char* temp = fields[9].GetString())
{
if (cInfo->Name)
delete cInfo->Name;
len = strlen(temp)+1;
const_cast<CreatureInfo*>(cInfo)->Name = new char[len];
strncpy(cInfo->Name, temp, len);
}
if (const char* temp = fields[10].GetString())
{
if (cInfo->SubName)
delete cInfo->SubName;
len = strlen(temp)+1;
const_cast<CreatureInfo*>(cInfo)->SubName = new char[len];
strncpy(cInfo->SubName, temp, len);
}
if (const char* temp = fields[11].GetString())
{
if (cInfo->IconName)
delete cInfo->IconName;
len = strlen(temp)+1;
const_cast<CreatureInfo*>(cInfo)->IconName = new char[len];
strncpy(cInfo->IconName, temp, len);
}
const_cast<CreatureInfo*>(cInfo)->GossipMenuId = fields[12].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->minlevel = fields[13].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->maxlevel = fields[14].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->expansion = fields[15].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->faction_A = fields[16].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->faction_H = fields[17].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->npcflag = fields[18].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->speed_walk = fields[19].GetFloat();
const_cast<CreatureInfo*>(cInfo)->speed_run = fields[20].GetFloat();
const_cast<CreatureInfo*>(cInfo)->scale = fields[21].GetFloat();
const_cast<CreatureInfo*>(cInfo)->rank = fields[22].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->mindmg = fields[23].GetFloat();
const_cast<CreatureInfo*>(cInfo)->maxdmg = fields[24].GetFloat();
const_cast<CreatureInfo*>(cInfo)->dmgschool = fields[25].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->attackpower = fields[26].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->dmg_multiplier = fields[27].GetFloat();
const_cast<CreatureInfo*>(cInfo)->baseattacktime = fields[28].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->rangeattacktime = fields[29].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->unit_class = fields[30].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->unit_flags = fields[31].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->dynamicflags = fields[32].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->family = fields[33].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->trainer_type = fields[34].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->trainer_spell = fields[35].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->trainer_class = fields[36].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->trainer_race = fields[37].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->minrangedmg = fields[38].GetFloat();
const_cast<CreatureInfo*>(cInfo)->maxrangedmg = fields[39].GetFloat();
const_cast<CreatureInfo*>(cInfo)->rangedattackpower = fields[40].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->type = fields[41].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->type_flags = fields[42].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->lootid = fields[43].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->pickpocketLootId = fields[44].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->SkinLootId = fields[45].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->resistance1 = fields[46].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->resistance2 = fields[47].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->resistance3 = fields[48].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->resistance4 = fields[49].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->resistance5 = fields[50].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->resistance6 = fields[51].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[0] = fields[52].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[1] = fields[53].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[2] = fields[54].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[3] = fields[55].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[4] = fields[56].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[5] = fields[57].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[6] = fields[58].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->spells[7] = fields[59].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->PetSpellDataId = fields[60].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->VehicleId = fields[61].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->mingold = fields[62].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->maxgold = fields[63].GetUInt32();
if (const char* temp = fields[64].GetString())
{
if (cInfo->AIName)
delete cInfo->AIName;
len = strlen(temp)+1;
const_cast<CreatureInfo*>(cInfo)->AIName = new char[len];
strncpy(const_cast<char*>(cInfo->AIName), temp, len);
}
const_cast<CreatureInfo*>(cInfo)->MovementType = fields[65].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->InhabitType = fields[66].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->ModHealth = fields[67].GetFloat();
const_cast<CreatureInfo*>(cInfo)->ModMana = fields[68].GetFloat();
const_cast<CreatureInfo*>(cInfo)->ModArmor = fields[69].GetFloat();
const_cast<CreatureInfo*>(cInfo)->RacialLeader = fields[70].GetBool();
const_cast<CreatureInfo*>(cInfo)->questItems[0] = fields[71].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->questItems[1] = fields[72].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->questItems[2] = fields[73].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->questItems[3] = fields[74].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->questItems[4] = fields[75].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->questItems[5] = fields[76].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->movementId = fields[77].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->RegenHealth = fields[78].GetBool();
const_cast<CreatureInfo*>(cInfo)->equipmentId = fields[79].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->MechanicImmuneMask = fields[80].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->flags_extra = fields[81].GetUInt32();
const_cast<CreatureInfo*>(cInfo)->ScriptID = objmgr.GetScriptId(fields[82].GetString());
objmgr.CheckCreatureTemplate(cInfo);
SendGlobalGMSysMessage("Creature template reloaded.");
return true;
}
bool ChatHandler::HandleReloadCreatureQuestRelationsCommand(const char*) bool ChatHandler::HandleReloadCreatureQuestRelationsCommand(const char*)
{ {
sLog.outString("Loading Quests Relations... (`creature_questrelation`)"); sLog.outString("Loading Quests Relations... (`creature_questrelation`)");
+10
View File
@@ -126,6 +126,16 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
if ((unit && unit->GetCreatureInfo()->ScriptID != unit->LastUsedScriptID) || (go && go->GetGOInfo()->ScriptId != go->LastUsedScriptID))
{
sLog.outDebug("WORLD: HandleGossipSelectOptionOpcode - Script reloaded while in use, ignoring and set new scipt id");
if (unit)
unit->LastUsedScriptID = unit->GetCreatureInfo()->ScriptID;
if (go)
go->LastUsedScriptID = go->GetGOInfo()->ScriptId;
_player->PlayerTalkClass->CloseGossip();
return;
}
if (!code.empty()) if (!code.empty())
{ {
if (unit) if (unit)
+1
View File
@@ -688,6 +688,7 @@ class WorldObject : public Object, public WorldLocation
#endif #endif
bool m_isWorldObject; bool m_isWorldObject;
uint32 LastUsedScriptID;
protected: protected:
explicit WorldObject(); explicit WorldObject();
std::string m_name; std::string m_name;
+296 -296
View File
@@ -497,309 +497,309 @@ void ObjectMgr::LoadCreatureTemplates()
sLog.outString(">> Loaded %u creature definitions", sCreatureStorage.RecordCount); sLog.outString(">> Loaded %u creature definitions", sCreatureStorage.RecordCount);
sLog.outString(); sLog.outString();
std::set<uint32> difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures
std::set<uint32> hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values
// check data correctness // check data correctness
for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i) for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
{ {
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i); CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i);
if (!cInfo) CheckCreatureTemplate(cInfo);
continue;
bool ok = true; // bool to allow continue outside this loop
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff)
{
if (!cInfo->DifficultyEntry[diff])
continue;
ok = false; // will be set to true at the end of this loop again
CreatureInfo const* difficultyInfo = GetCreatureTemplate(cInfo->DifficultyEntry[diff]);
if (!difficultyInfo)
{
sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u not exist.",
i, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff]);
continue;
}
if (difficultyEntries[diff].find(i) != difficultyEntries[diff].end())
{
sLog.outErrorDb("Creature (Entry: %u) listed as difficulty %u but have value in `difficulty_entry_1`.", i, diff + 1);
continue;
}
bool ok2 = true;
for (uint32 diff2 = 0; diff2 < MAX_DIFFICULTY - 1 && ok2; ++diff2)
{
ok2 = false;
if (difficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != difficultyEntries[diff2].end())
{
sLog.outErrorDb("Creature (Entry: %u) already listed as difficulty %u for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1);
continue;
}
if (hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != hasDifficultyEntries[diff2].end())
{
sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u have difficulty %u entry also.",
i, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff], diff2 + 1);
continue;
}
ok2 = true;
}
if (!ok2)
continue;
if (cInfo->unit_class != difficultyInfo->unit_class)
{
sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).",
i, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class);
continue;
}
if (cInfo->npcflag != difficultyInfo->npcflag)
{
sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_class != difficultyInfo->trainer_class)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_race != difficultyInfo->trainer_race)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_type != difficultyInfo->trainer_type)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_spell != difficultyInfo->trainer_spell)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", i, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (difficultyInfo->AIName && *difficultyInfo->AIName)
{
sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `AIName`, but in any case will used difficulty 0 mode creature (Entry: %u) AIName.",
diff, cInfo->DifficultyEntry[diff], i);
continue;
}
if (difficultyInfo->ScriptID)
{
sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `ScriptName`, but in any case will used difficulty 0 mode creature (Entry: %u) ScriptName.",
diff, cInfo->DifficultyEntry[diff], i);
continue;
}
hasDifficultyEntries[diff].insert(i);
difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]);
ok = true;
}
if (!ok)
continue;
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A);
if (!factionTemplate)
sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A);
factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H);
if (!factionTemplate)
sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H);
// used later for scale
CreatureDisplayInfoEntry const* displayScaleEntry = NULL;
if (cInfo->Modelid1)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid1 id (%u), can crash client", cInfo->Entry, cInfo->Modelid1);
const_cast<CreatureInfo*>(cInfo)->Modelid1 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid1);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid1 (%u)", cInfo->Entry, cInfo->Modelid1);
}
if (cInfo->Modelid2)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid2 id (%u), can crash client", cInfo->Entry, cInfo->Modelid2);
const_cast<CreatureInfo*>(cInfo)->Modelid2 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid2);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid2 (%u)", cInfo->Entry, cInfo->Modelid2);
}
if (cInfo->Modelid3)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid3 id (%u), can crash client", cInfo->Entry, cInfo->Modelid3);
const_cast<CreatureInfo*>(cInfo)->Modelid3 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid3);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid3 (%u)", cInfo->Entry, cInfo->Modelid3);
}
if (cInfo->Modelid4)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid4 id (%u), can crash client", cInfo->Entry, cInfo->Modelid4);
const_cast<CreatureInfo*>(cInfo)->Modelid4 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid4);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid4 (%u)", cInfo->Entry, cInfo->Modelid4);
}
if (!displayScaleEntry)
sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in Modelid1/Modelid2/Modelid3/Modelid4", cInfo->Entry);
for (int k = 0; k < MAX_KILL_CREDIT; ++k)
{
if (cInfo->KillCredit[k])
{
if (!GetCreatureTemplate(cInfo->KillCredit[k]))
{
sLog.outErrorDb("Creature (Entry: %u) has not existed creature entry in `KillCredit%d` (%u)",cInfo->Entry,k+1,cInfo->KillCredit[k]);
const_cast<CreatureInfo*>(cInfo)->KillCredit[k] = 0;
}
}
}
if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template. Set to 1 (UNIT_CLASS_WARRIOR).", cInfo->Entry, cInfo->unit_class);
const_cast<CreatureInfo*>(cInfo)->unit_class = UNIT_CLASS_WARRIOR;
}
if (cInfo->dmgschool >= MAX_SPELL_SCHOOL)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool);
const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
}
if (cInfo->baseattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
if (cInfo->rangeattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
if (cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK)
{
sLog.outErrorDb("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, it expect to be set by code base at `npc_spellclick_spells` content.",cInfo->Entry,UNIT_NPC_FLAG_SPELLCLICK);
const_cast<CreatureInfo*>(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK;
}
if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
{
sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`",cInfo->Entry,cInfo->type);
const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
}
// must exist or used hidden but used in data horse case
if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`",cInfo->Entry,cInfo->family);
const_cast<CreatureInfo*>(cInfo)->family = 0;
}
if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType);
const_cast<CreatureInfo*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
}
if (cInfo->VehicleId)
{
VehicleEntry const* vehId = sVehicleStore.LookupEntry(cInfo->VehicleId);
if (!vehId)
sLog.outErrorDb("Creature (Entry: %u) has a non-existing VehicleId (%u). This *WILL* cause the client to freeze!", cInfo->Entry, cInfo->VehicleId);
}
if (cInfo->PetSpellDataId)
{
CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
if (!spellDataId)
sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
}
for (uint8 j = 0; j < CREATURE_MAX_SPELLS; ++j)
{
if (cInfo->spells[j] && !sSpellStore.LookupEntry(cInfo->spells[j]))
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Spell%d (%u), set to 0", cInfo->Entry, j+1,cInfo->spells[j]);
const_cast<CreatureInfo*>(cInfo)->spells[j] = 0;
}
}
if (cInfo->MovementType >= MAX_DB_MOTION_TYPE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType);
const_cast<CreatureInfo*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
}
if (cInfo->equipmentId > 0) // 0 no equipment
{
if (!GetEquipmentInfo(cInfo->equipmentId))
{
sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId);
const_cast<CreatureInfo*>(cInfo)->equipmentId = 0;
}
}
/// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
if (cInfo->scale <= 0.0f)
{
if (displayScaleEntry)
const_cast<CreatureInfo*>(cInfo)->scale = displayScaleEntry->scale;
else
const_cast<CreatureInfo*>(cInfo)->scale = 1.0f;
}
if (cInfo->expansion > (MAX_CREATURE_BASE_HP - 1))
{
sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with expansion %u ignore and set to NULL.", cInfo->expansion);
const_cast<CreatureInfo*>(cInfo)->expansion = 0;
}
const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank);
} }
} }
void ObjectMgr::CheckCreatureTemplate(CreatureInfo const* cInfo)
{
if (!cInfo)
return;
bool ok = true; // bool to allow continue outside this loop
for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff)
{
if (!cInfo->DifficultyEntry[diff])
continue;
ok = false; // will be set to true at the end of this loop again
CreatureInfo const* difficultyInfo = GetCreatureTemplate(cInfo->DifficultyEntry[diff]);
if (!difficultyInfo)
{
sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u not exist.",
cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff]);
continue;
}
if (difficultyEntries[diff].find(cInfo->Entry) != difficultyEntries[diff].end())
{
sLog.outErrorDb("Creature (Entry: %u) listed as difficulty %u but have value in `difficulty_entry_1`.", cInfo->Entry, diff + 1);
continue;
}
bool ok2 = true;
for (uint32 diff2 = 0; diff2 < MAX_DIFFICULTY - 1 && ok2; ++diff2)
{
ok2 = false;
if (difficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != difficultyEntries[diff2].end())
{
sLog.outErrorDb("Creature (Entry: %u) already listed as difficulty %u for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1);
continue;
}
if (hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != hasDifficultyEntries[diff2].end())
{
sLog.outErrorDb("Creature (Entry: %u) have `difficulty_entry_%u`=%u but creature entry %u have difficulty %u entry also.",
cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff], diff2 + 1);
continue;
}
ok2 = true;
}
if (!ok2)
continue;
if (cInfo->unit_class != difficultyInfo->unit_class)
{
sLog.outErrorDb("Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).",
cInfo->Entry, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class);
continue;
}
if (cInfo->npcflag != difficultyInfo->npcflag)
{
sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_class != difficultyInfo->trainer_class)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_race != difficultyInfo->trainer_race)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_type != difficultyInfo->trainer_type)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (cInfo->trainer_spell != difficultyInfo->trainer_spell)
{
sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
continue;
}
if (difficultyInfo->AIName && *difficultyInfo->AIName)
{
sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `AIName`, but in any case will used difficulty 0 mode creature (Entry: %u) AIName.",
diff, cInfo->DifficultyEntry[diff], cInfo->Entry);
continue;
}
if (difficultyInfo->ScriptID)
{
sLog.outErrorDb("Difficulty %u mode creature (Entry: %u) has `ScriptName`, but in any case will used difficulty 0 mode creature (Entry: %u) ScriptName.",
diff, cInfo->DifficultyEntry[diff], cInfo->Entry);
continue;
}
hasDifficultyEntries[diff].insert(cInfo->Entry);
difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]);
ok = true;
}
FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A);
if (!factionTemplate)
sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A);
factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H);
if (!factionTemplate)
sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H);
// used later for scale
CreatureDisplayInfoEntry const* displayScaleEntry = NULL;
if (cInfo->Modelid1)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid1 id (%u), can crash client", cInfo->Entry, cInfo->Modelid1);
const_cast<CreatureInfo*>(cInfo)->Modelid1 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid1);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid1 (%u)", cInfo->Entry, cInfo->Modelid1);
}
if (cInfo->Modelid2)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid2 id (%u), can crash client", cInfo->Entry, cInfo->Modelid2);
const_cast<CreatureInfo*>(cInfo)->Modelid2 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid2);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid2 (%u)", cInfo->Entry, cInfo->Modelid2);
}
if (cInfo->Modelid3)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid3 id (%u), can crash client", cInfo->Entry, cInfo->Modelid3);
const_cast<CreatureInfo*>(cInfo)->Modelid3 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid3);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid3 (%u)", cInfo->Entry, cInfo->Modelid3);
}
if (cInfo->Modelid4)
{
CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4);
if (!displayEntry)
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Modelid4 id (%u), can crash client", cInfo->Entry, cInfo->Modelid4);
const_cast<CreatureInfo*>(cInfo)->Modelid4 = 0;
}
else if (!displayScaleEntry)
displayScaleEntry = displayEntry;
CreatureModelInfo const* minfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid4);
if (!minfo)
sLog.outErrorDb("Creature (Entry: %u) not has model data for Modelid4 (%u)", cInfo->Entry, cInfo->Modelid4);
}
if (!displayScaleEntry)
sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in Modelid1/Modelid2/Modelid3/Modelid4", cInfo->Entry);
for (int k = 0; k < MAX_KILL_CREDIT; ++k)
{
if (cInfo->KillCredit[k])
{
if (!GetCreatureTemplate(cInfo->KillCredit[k]))
{
sLog.outErrorDb("Creature (Entry: %u) has not existed creature entry in `KillCredit%d` (%u)",cInfo->Entry,k+1,cInfo->KillCredit[k]);
const_cast<CreatureInfo*>(cInfo)->KillCredit[k] = 0;
}
}
}
if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template. Set to 1 (UNIT_CLASS_WARRIOR).", cInfo->Entry, cInfo->unit_class);
const_cast<CreatureInfo*>(cInfo)->unit_class = UNIT_CLASS_WARRIOR;
}
if (cInfo->dmgschool >= MAX_SPELL_SCHOOL)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool);
const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
}
if (cInfo->baseattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
if (cInfo->rangeattacktime == 0)
const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
if (cInfo->npcflag & UNIT_NPC_FLAG_SPELLCLICK)
{
sLog.outErrorDb("Creature (Entry: %u) has dynamic flag UNIT_NPC_FLAG_SPELLCLICK (%u) set, it expect to be set by code base at `npc_spellclick_spells` content.",cInfo->Entry,UNIT_NPC_FLAG_SPELLCLICK);
const_cast<CreatureInfo*>(cInfo)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK;
}
if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
{
sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`",cInfo->Entry,cInfo->type);
const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
}
// must exist or used hidden but used in data horse case
if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM)
{
sLog.outErrorDb("Creature (Entry: %u) has invalid creature family (%u) in `family`",cInfo->Entry,cInfo->family);
const_cast<CreatureInfo*>(cInfo)->family = 0;
}
if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType);
const_cast<CreatureInfo*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
}
if (cInfo->VehicleId)
{
VehicleEntry const* vehId = sVehicleStore.LookupEntry(cInfo->VehicleId);
if (!vehId)
sLog.outErrorDb("Creature (Entry: %u) has a non-existing VehicleId (%u). This *WILL* cause the client to freeze!", cInfo->Entry, cInfo->VehicleId);
}
if (cInfo->PetSpellDataId)
{
CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
if (!spellDataId)
sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
}
for (uint8 j = 0; j < CREATURE_MAX_SPELLS; ++j)
{
if (cInfo->spells[j] && !sSpellStore.LookupEntry(cInfo->spells[j]))
{
sLog.outErrorDb("Creature (Entry: %u) has non-existing Spell%d (%u), set to 0", cInfo->Entry, j+1,cInfo->spells[j]);
const_cast<CreatureInfo*>(cInfo)->spells[j] = 0;
}
}
if (cInfo->MovementType >= MAX_DB_MOTION_TYPE)
{
sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType);
const_cast<CreatureInfo*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
}
if (cInfo->equipmentId > 0) // 0 no equipment
{
if (!GetEquipmentInfo(cInfo->equipmentId))
{
sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId);
const_cast<CreatureInfo*>(cInfo)->equipmentId = 0;
}
}
/// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
if (cInfo->scale <= 0.0f)
{
if (displayScaleEntry)
const_cast<CreatureInfo*>(cInfo)->scale = displayScaleEntry->scale;
else
const_cast<CreatureInfo*>(cInfo)->scale = 1.0f;
}
if (cInfo->expansion > (MAX_CREATURE_BASE_HP - 1))
{
sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with expansion %u ignore and set to NULL.", cInfo->expansion);
const_cast<CreatureInfo*>(cInfo)->expansion = 0;
}
const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank);
}
void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr) void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr)
{ {
// Now add the auras, format "spellid effectindex spellid effectindex..." // Now add the auras, format "spellid effectindex spellid effectindex..."
+5
View File
@@ -635,6 +635,7 @@ class ObjectMgr
void LoadCreatureClassLevelStats(); void LoadCreatureClassLevelStats();
void LoadCreatureLocales(); void LoadCreatureLocales();
void LoadCreatureTemplates(); void LoadCreatureTemplates();
void CheckCreatureTemplate(CreatureInfo const* cInfo);
void LoadCreatures(); void LoadCreatures();
void LoadCreatureLinkedRespawn(); void LoadCreatureLinkedRespawn();
bool CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const; bool CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const;
@@ -1115,6 +1116,10 @@ class ObjectMgr
CacheNpcTextIdMap m_mCacheNpcTextIdMap; CacheNpcTextIdMap m_mCacheNpcTextIdMap;
CacheVendorItemMap m_mCacheVendorItemMap; CacheVendorItemMap m_mCacheVendorItemMap;
CacheTrainerSpellMap m_mCacheTrainerSpellMap; CacheTrainerSpellMap m_mCacheTrainerSpellMap;
std::set<uint32> difficultyEntries[MAX_DIFFICULTY - 1]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate
std::set<uint32> hasDifficultyEntries[MAX_DIFFICULTY - 1]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate
}; };
#define objmgr Trinity::Singleton<ObjectMgr>::Instance() #define objmgr Trinity::Singleton<ObjectMgr>::Instance()