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:
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -803,6 +803,9 @@ bool Creature::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry,
|
||||
AddUnitMovementFlag(MOVEMENTFLAG_SWIMMING);
|
||||
}
|
||||
}
|
||||
|
||||
LastUsedScriptID = m_creatureInfo->ScriptID;
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
|
||||
@@ -216,6 +216,8 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa
|
||||
|
||||
SetZoneScript();
|
||||
|
||||
LastUsedScriptID = GetGOInfo()->ScriptId;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -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,
|
||||
|
||||
@@ -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`)");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -688,6 +688,7 @@ class WorldObject : public Object, public WorldLocation
|
||||
#endif
|
||||
|
||||
bool m_isWorldObject;
|
||||
uint32 LastUsedScriptID;
|
||||
protected:
|
||||
explicit WorldObject();
|
||||
std::string m_name;
|
||||
|
||||
+296
-296
@@ -497,309 +497,309 @@ 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;
|
||||
}
|
||||
|
||||
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);
|
||||
CheckCreatureTemplate(cInfo);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Now add the auras, format "spellid effectindex spellid effectindex..."
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user