aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRat@walamy <none@none>2010-05-16 17:45:45 +0200
committerRat@walamy <none@none>2010-05-16 17:45:45 +0200
commit9771757c4c9c2210a258e9bf477f06a4981d4794 (patch)
treedf021d18706b254ad1a0969c49686d7f158c2853
parentc26399a96804cf4231dd6ec2e6f4e3ec437aac64 (diff)
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
-rw-r--r--sql/updates/8214_world_command.sql3
-rw-r--r--sql/updates/8214_world_trinity_string.sql4
-rw-r--r--sql/world.sql3
-rw-r--r--src/game/Chat.cpp1
-rw-r--r--src/game/Chat.h1
-rw-r--r--src/game/Creature.cpp3
-rw-r--r--src/game/GameObject.cpp2
-rw-r--r--src/game/Language.h5
-rw-r--r--src/game/Level3.cpp145
-rw-r--r--src/game/MiscHandler.cpp10
-rw-r--r--src/game/Object.h1
-rw-r--r--src/game/ObjectMgr.cpp458
-rw-r--r--src/game/ObjectMgr.h5
13 files changed, 411 insertions, 230 deletions
diff --git a/sql/updates/8214_world_command.sql b/sql/updates/8214_world_command.sql
new file mode 100644
index 00000000000..93873716247
--- /dev/null
+++ b/sql/updates/8214_world_command.sql
@@ -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.');
diff --git a/sql/updates/8214_world_trinity_string.sql b/sql/updates/8214_world_trinity_string.sql
new file mode 100644
index 00000000000..49156eeefbd
--- /dev/null
+++ b/sql/updates/8214_world_trinity_string.sql
@@ -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);
diff --git a/sql/world.sql b/sql/world.sql
index 2c42e2658b8..c00fa49db71 100644
--- a/sql/world.sql
+++ b/sql/world.sql
@@ -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_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 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 waypoint_scripts',3,'Syntax: .reload waypoint_scripts\nReload waypoint_scripts table.'),
('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),
(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),
+(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),
(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),
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index f24cc41130a..76a5f688d37 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -458,6 +458,7 @@ ChatCommand * ChatHandler::getCommandTable()
{ "creature_linked_respawn", SEC_GAMEMASTER, true, &ChatHandler::HandleReloadCreatureLinkedRespawnCommand, "", NULL },
{ "creature_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesCreatureCommand, "", 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 },
{ "disenchant_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesDisenchantCommand, "", NULL },
{ "event_scripts", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadEventScriptsCommand, "", NULL },
diff --git a/src/game/Chat.h b/src/game/Chat.h
index 4b33c51f612..9545588db7c 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -361,6 +361,7 @@ class ChatHandler
bool HandleReloadEventAISummonsCommand(const char* args);
bool HandleReloadEventAIScriptsCommand(const char* args);
bool HandleReloadCommandCommand(const char* args);
+ bool HandleReloadCreatureTemplateCommand(const char* args);
bool HandleReloadCreatureQuestRelationsCommand(const char* args);
bool HandleReloadCreatureQuestInvRelationsCommand(const char* args);
bool HandleReloadCreatureLinkedRespawnCommand(const char* args);
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index a78829f1669..4eefce656a7 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -803,6 +803,9 @@ bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry,
AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
}
}
+
+ LastUsedScriptID = m_creatureInfo->ScriptID;
+
return bResult;
}
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index 5a5b28d85b9..d8d376c0608 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -216,6 +216,8 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
SetZoneScript();
+ LastUsedScriptID = GetGOInfo()->ScriptId;
+
return true;
}
diff --git a/src/game/Language.h b/src/game/Language.h
index db1c348c899..d421344bd30 100644
--- a/src/game/Language.h
+++ b/src/game/Language.h
@@ -725,7 +725,10 @@ enum TrinityStrings
LANG_GUILD_MEMBER = 814,
LANG_GUILD_INITIATE = 815,
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)
LANG_COMMAND_EXIT = 1000,
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index e55e12d2138..89e4f200e8e 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -749,6 +749,151 @@ bool ChatHandler::HandleReloadCommandCommand(const char*)
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*)
{
sLog.outString("Loading Quests Relations... (`creature_questrelation`)");
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index f993adc9a64..e27a4cb491e 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -126,6 +126,16 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
if (GetPlayer()->hasUnitState(UNIT_STAT_DIED))
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 (unit)
diff --git a/src/game/Object.h b/src/game/Object.h
index 34e90b1c1c4..bda53fd655a 100644
--- a/src/game/Object.h
+++ b/src/game/Object.h
@@ -688,6 +688,7 @@ class WorldObject : public Object, public WorldLocation
#endif
bool m_isWorldObject;
+ uint32 LastUsedScriptID;
protected:
explicit WorldObject();
std::string m_name;
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 79438739ce4..2f90e6a6685 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -497,307 +497,307 @@ void ObjectMgr::LoadCreatureTemplates()
sLog.outString(">> Loaded %u creature definitions", sCreatureStorage.RecordCount);
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
for (uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
{
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i);
- if (!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;
- }
+ CheckCreatureTemplate(cInfo);
+ }
+}
- 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;
- }
+void ObjectMgr::CheckCreatureTemplate(CreatureInfo const* cInfo)
+{
+ if (!cInfo)
+ return;
- 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;
- }
+ 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
- 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;
- }
+ 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 (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 (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;
+ }
- if (difficultyInfo->AIName && *difficultyInfo->AIName)
+ 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("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);
+ sLog.outErrorDb("Creature (Entry: %u) already listed as difficulty %u for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1);
continue;
}
- if (difficultyInfo->ScriptID)
+ if (hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != hasDifficultyEntries[diff2].end())
{
- 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);
+ 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;
}
-
- hasDifficultyEntries[diff].insert(i);
- difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]);
- ok = true;
+ ok2 = true;
}
- if (!ok)
+ if (!ok2)
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)
+ if (cInfo->unit_class != difficultyInfo->unit_class)
{
- 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);
+ 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->Modelid2)
+ if (cInfo->npcflag != difficultyInfo->npcflag)
{
- 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);
+ sLog.outErrorDb("Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
+ continue;
}
- if (cInfo->Modelid3)
+ if (cInfo->trainer_class != difficultyInfo->trainer_class)
{
- 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);
+ 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->Modelid4)
+ if (cInfo->trainer_race != difficultyInfo->trainer_race)
{
- 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);
+ sLog.outErrorDb("Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
+ continue;
}
- if (!displayScaleEntry)
- sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in Modelid1/Modelid2/Modelid3/Modelid4", cInfo->Entry);
+ 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;
+ }
- for (int k = 0; k < MAX_KILL_CREDIT; ++k)
+ if (cInfo->trainer_spell != difficultyInfo->trainer_spell)
{
- 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;
- }
- }
+ sLog.outErrorDb("Creature (Entry: %u) has different `trainer_spell` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
+ continue;
}
- if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0)
+ if (difficultyInfo->AIName && *difficultyInfo->AIName)
{
- 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;
+ 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 (cInfo->dmgschool >= MAX_SPELL_SCHOOL)
+ if (difficultyInfo->ScriptID)
{
- 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;
+ 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;
}
- if (cInfo->baseattacktime == 0)
- const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
+ hasDifficultyEntries[diff].insert(cInfo->Entry);
+ difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]);
+ ok = true;
+ }
- if (cInfo->rangeattacktime == 0)
- const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
+ 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);
- 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;
- }
+ 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);
- 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);
+ // used later for scale
+ CreatureDisplayInfoEntry const* displayScaleEntry = NULL;
- if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
+ if (cInfo->Modelid1)
+ {
+ CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1);
+ if (!displayEntry)
{
- sLog.outErrorDb("Creature (Entry: %u) has invalid creature type (%u) in `type`",cInfo->Entry,cInfo->type);
- const_cast<CreatureInfo*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
+ 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;
- // 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;
- }
+ 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->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
+ if (cInfo->Modelid2)
+ {
+ CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2);
+ if (!displayEntry)
{
- 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;
+ 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;
- 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);
- }
+ 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->PetSpellDataId)
+ if (cInfo->Modelid3)
+ {
+ CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3);
+ if (!displayEntry)
{
- CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
- if (!spellDataId)
- sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
+ 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;
- 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;
- }
- }
+ 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->MovementType >= MAX_DB_MOTION_TYPE)
+ if (cInfo->Modelid4)
+ {
+ CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4);
+ if (!displayEntry)
{
- 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;
+ 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 (cInfo->equipmentId > 0) // 0 no equipment
+ 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 (!GetEquipmentInfo(cInfo->equipmentId))
+ if (!GetCreatureTemplate(cInfo->KillCredit[k]))
{
- 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;
+ 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 not set custom creature scale then load scale from CreatureDisplayInfo.dbc
- if (cInfo->scale <= 0.0f)
+ 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]))
{
- if (displayScaleEntry)
- const_cast<CreatureInfo*>(cInfo)->scale = displayScaleEntry->scale;
- else
- const_cast<CreatureInfo*>(cInfo)->scale = 1.0f;
+ 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->expansion > (MAX_CREATURE_BASE_HP - 1))
+ 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 expansion %u ignore and set to NULL.", cInfo->expansion);
- const_cast<CreatureInfo*>(cInfo)->expansion = 0;
+ 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;
}
+ }
- const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank);
+ /// 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)
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index 5abe59453a8..2586d987a05 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -635,6 +635,7 @@ class ObjectMgr
void LoadCreatureClassLevelStats();
void LoadCreatureLocales();
void LoadCreatureTemplates();
+ void CheckCreatureTemplate(CreatureInfo const* cInfo);
void LoadCreatures();
void LoadCreatureLinkedRespawn();
bool CheckCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid) const;
@@ -1115,6 +1116,10 @@ class ObjectMgr
CacheNpcTextIdMap m_mCacheNpcTextIdMap;
CacheVendorItemMap m_mCacheVendorItemMap;
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()