diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/game/Chat.cpp | 1 | ||||
-rw-r--r-- | src/game/Chat.h | 1 | ||||
-rw-r--r-- | src/game/Creature.cpp | 3 | ||||
-rw-r--r-- | src/game/GameObject.cpp | 2 | ||||
-rw-r--r-- | src/game/Language.h | 5 | ||||
-rw-r--r-- | src/game/Level3.cpp | 145 | ||||
-rw-r--r-- | src/game/MiscHandler.cpp | 10 | ||||
-rw-r--r-- | src/game/Object.h | 1 | ||||
-rw-r--r-- | src/game/ObjectMgr.cpp | 458 | ||||
-rw-r--r-- | src/game/ObjectMgr.h | 5 |
10 files changed, 401 insertions, 230 deletions
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() |