PageRenderTime 72ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 2ms

/src/server/game/Globals/ObjectMgr.cpp

https://gitlab.com/IlluminatiCore/IlluminatiCore
C++ | 9357 lines | 7458 code | 1565 blank | 334 comment | 1633 complexity | edca2f07d7e750a1406a24f1de8e96b8 MD5 | raw file
Possible License(s): GPL-2.0, BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
  3. * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "AccountMgr.h"
  19. #include "AchievementMgr.h"
  20. #include "ArenaTeam.h"
  21. #include "ArenaTeamMgr.h"
  22. #include "BattlegroundMgr.h"
  23. #include "Chat.h"
  24. #include "Common.h"
  25. #include "DatabaseEnv.h"
  26. #include "DB2Structure.h"
  27. #include "DB2Stores.h"
  28. #include "DisableMgr.h"
  29. #include "GameEventMgr.h"
  30. #include "GossipDef.h"
  31. #include "GroupMgr.h"
  32. #include "GuildMgr.h"
  33. #include "InstanceSaveMgr.h"
  34. #include "Language.h"
  35. #include "LFGMgr.h"
  36. #include "Log.h"
  37. #include "MapManager.h"
  38. #include "Object.h"
  39. #include "ObjectMgr.h"
  40. #include "Pet.h"
  41. #include "PoolMgr.h"
  42. #include "ReputationMgr.h"
  43. #include "ScriptMgr.h"
  44. #include "SpellAuras.h"
  45. #include "Spell.h"
  46. #include "SpellMgr.h"
  47. #include "SpellScript.h"
  48. #include "Transport.h"
  49. #include "UpdateMask.h"
  50. #include "Util.h"
  51. #include "Vehicle.h"
  52. #include "WaypointManager.h"
  53. #include "World.h"
  54. ScriptMapMap sSpellScripts;
  55. ScriptMapMap sEventScripts;
  56. ScriptMapMap sWaypointScripts;
  57. std::string GetScriptsTableNameByType(ScriptsType type)
  58. {
  59. std::string res = "";
  60. switch (type)
  61. {
  62. case SCRIPTS_SPELL: res = "spell_scripts"; break;
  63. case SCRIPTS_EVENT: res = "event_scripts"; break;
  64. case SCRIPTS_WAYPOINT: res = "waypoint_scripts"; break;
  65. default: break;
  66. }
  67. return res;
  68. }
  69. ScriptMapMap* GetScriptsMapByType(ScriptsType type)
  70. {
  71. ScriptMapMap* res = NULL;
  72. switch (type)
  73. {
  74. case SCRIPTS_SPELL: res = &sSpellScripts; break;
  75. case SCRIPTS_EVENT: res = &sEventScripts; break;
  76. case SCRIPTS_WAYPOINT: res = &sWaypointScripts; break;
  77. default: break;
  78. }
  79. return res;
  80. }
  81. std::string GetScriptCommandName(ScriptCommands command)
  82. {
  83. std::string res = "";
  84. switch (command)
  85. {
  86. case SCRIPT_COMMAND_TALK: res = "SCRIPT_COMMAND_TALK"; break;
  87. case SCRIPT_COMMAND_EMOTE: res = "SCRIPT_COMMAND_EMOTE"; break;
  88. case SCRIPT_COMMAND_FIELD_SET: res = "SCRIPT_COMMAND_FIELD_SET"; break;
  89. case SCRIPT_COMMAND_MOVE_TO: res = "SCRIPT_COMMAND_MOVE_TO"; break;
  90. case SCRIPT_COMMAND_FLAG_SET: res = "SCRIPT_COMMAND_FLAG_SET"; break;
  91. case SCRIPT_COMMAND_FLAG_REMOVE: res = "SCRIPT_COMMAND_FLAG_REMOVE"; break;
  92. case SCRIPT_COMMAND_TELEPORT_TO: res = "SCRIPT_COMMAND_TELEPORT_TO"; break;
  93. case SCRIPT_COMMAND_QUEST_EXPLORED: res = "SCRIPT_COMMAND_QUEST_EXPLORED"; break;
  94. case SCRIPT_COMMAND_KILL_CREDIT: res = "SCRIPT_COMMAND_KILL_CREDIT"; break;
  95. case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: res = "SCRIPT_COMMAND_RESPAWN_GAMEOBJECT"; break;
  96. case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: res = "SCRIPT_COMMAND_TEMP_SUMMON_CREATURE"; break;
  97. case SCRIPT_COMMAND_OPEN_DOOR: res = "SCRIPT_COMMAND_OPEN_DOOR"; break;
  98. case SCRIPT_COMMAND_CLOSE_DOOR: res = "SCRIPT_COMMAND_CLOSE_DOOR"; break;
  99. case SCRIPT_COMMAND_ACTIVATE_OBJECT: res = "SCRIPT_COMMAND_ACTIVATE_OBJECT"; break;
  100. case SCRIPT_COMMAND_REMOVE_AURA: res = "SCRIPT_COMMAND_REMOVE_AURA"; break;
  101. case SCRIPT_COMMAND_CAST_SPELL: res = "SCRIPT_COMMAND_CAST_SPELL"; break;
  102. case SCRIPT_COMMAND_PLAY_SOUND: res = "SCRIPT_COMMAND_PLAY_SOUND"; break;
  103. case SCRIPT_COMMAND_CREATE_ITEM: res = "SCRIPT_COMMAND_CREATE_ITEM"; break;
  104. case SCRIPT_COMMAND_DESPAWN_SELF: res = "SCRIPT_COMMAND_DESPAWN_SELF"; break;
  105. case SCRIPT_COMMAND_LOAD_PATH: res = "SCRIPT_COMMAND_LOAD_PATH"; break;
  106. case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: res = "SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT"; break;
  107. case SCRIPT_COMMAND_KILL: res = "SCRIPT_COMMAND_KILL"; break;
  108. // TrinityCore only
  109. case SCRIPT_COMMAND_ORIENTATION: res = "SCRIPT_COMMAND_ORIENTATION"; break;
  110. case SCRIPT_COMMAND_EQUIP: res = "SCRIPT_COMMAND_EQUIP"; break;
  111. case SCRIPT_COMMAND_MODEL: res = "SCRIPT_COMMAND_MODEL"; break;
  112. case SCRIPT_COMMAND_CLOSE_GOSSIP: res = "SCRIPT_COMMAND_CLOSE_GOSSIP"; break;
  113. case SCRIPT_COMMAND_PLAYMOVIE: res = "SCRIPT_COMMAND_PLAYMOVIE"; break;
  114. default:
  115. {
  116. char sz[32];
  117. sprintf(sz, "Unknown command: %d", command);
  118. res = sz;
  119. break;
  120. }
  121. }
  122. return res;
  123. }
  124. std::string ScriptInfo::GetDebugInfo() const
  125. {
  126. char sz[256];
  127. sprintf(sz, "%s ('%s' script id: %u)", GetScriptCommandName(command).c_str(), GetScriptsTableNameByType(type).c_str(), id);
  128. return std::string(sz);
  129. }
  130. bool normalizePlayerName(std::string& name)
  131. {
  132. if (name.empty())
  133. return false;
  134. wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1];
  135. size_t wstr_len = MAX_INTERNAL_PLAYER_NAME;
  136. if (!Utf8toWStr(name, &wstr_buf[0], wstr_len))
  137. return false;
  138. wstr_buf[0] = wcharToUpper(wstr_buf[0]);
  139. for (size_t i = 1; i < wstr_len; ++i)
  140. wstr_buf[i] = wcharToLower(wstr_buf[i]);
  141. if (!WStrToUtf8(wstr_buf, wstr_len, name))
  142. return false;
  143. return true;
  144. }
  145. LanguageDesc lang_description[LANGUAGES_COUNT] =
  146. {
  147. { LANG_ADDON, 0, 0 },
  148. { LANG_UNIVERSAL, 0, 0 },
  149. { LANG_ORCISH, 669, SKILL_LANG_ORCISH },
  150. { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN },
  151. { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE },
  152. { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN },
  153. { LANG_COMMON, 668, SKILL_LANG_COMMON },
  154. { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE },
  155. { LANG_TITAN, 816, SKILL_LANG_TITAN },
  156. { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN },
  157. { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC },
  158. { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE },
  159. { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH },
  160. { LANG_TROLL, 7341, SKILL_LANG_TROLL },
  161. { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK },
  162. { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI },
  163. { LANG_ZOMBIE, 0, 0 },
  164. { LANG_GNOMISH_BINARY, 0, 0 },
  165. { LANG_GOBLIN_BINARY, 0, 0 },
  166. { LANG_WORGEN, 69270, SKILL_LANG_WORGEN },
  167. { LANG_GOBLIN, 69269, SKILL_LANG_GOBLIN }
  168. };
  169. LanguageDesc const* GetLanguageDescByID(uint32 lang)
  170. {
  171. for (uint8 i = 0; i < LANGUAGES_COUNT; ++i)
  172. {
  173. if (uint32(lang_description[i].lang_id) == lang)
  174. return &lang_description[i];
  175. }
  176. return NULL;
  177. }
  178. bool SpellClickInfo::IsFitToRequirements(Unit const* clicker, Unit const* clickee) const
  179. {
  180. Player const* playerClicker = clicker->ToPlayer();
  181. if (!playerClicker)
  182. return true;
  183. Unit const* summoner = NULL;
  184. // Check summoners for party
  185. if (clickee->IsSummon())
  186. summoner = clickee->ToTempSummon()->GetSummoner();
  187. if (!summoner)
  188. summoner = clickee;
  189. // This only applies to players
  190. switch (userType)
  191. {
  192. case SPELL_CLICK_USER_FRIEND:
  193. if (!playerClicker->IsFriendlyTo(summoner))
  194. return false;
  195. break;
  196. case SPELL_CLICK_USER_RAID:
  197. if (!playerClicker->IsInRaidWith(summoner))
  198. return false;
  199. break;
  200. case SPELL_CLICK_USER_PARTY:
  201. if (!playerClicker->IsInPartyWith(summoner))
  202. return false;
  203. break;
  204. default:
  205. break;
  206. }
  207. return true;
  208. }
  209. ObjectMgr::ObjectMgr():
  210. _auctionId(1),
  211. _equipmentSetGuid(1),
  212. _itemTextId(1),
  213. _mailId(1),
  214. _hiPetNumber(1),
  215. _voidItemId(1),
  216. _hiCharGuid(1),
  217. _hiCreatureGuid(1),
  218. _hiPetGuid(1),
  219. _hiVehicleGuid(1),
  220. _hiItemGuid(1),
  221. _hiGoGuid(1),
  222. _hiDoGuid(1),
  223. _hiCorpseGuid(1),
  224. _hiAreaTriggerGuid(1),
  225. _hiMoTransGuid(1),
  226. DBCLocaleIndex(LOCALE_enUS)
  227. {
  228. for (uint8 i = 0; i < MAX_CLASSES; ++i)
  229. for (uint8 j = 0; j < MAX_RACES; ++j)
  230. _playerInfo[j][i] = NULL;
  231. }
  232. ObjectMgr::~ObjectMgr()
  233. {
  234. for (QuestMap::iterator i = _questTemplates.begin(); i != _questTemplates.end(); ++i)
  235. delete i->second;
  236. for (PetLevelInfoContainer::iterator i = _petInfoStore.begin(); i != _petInfoStore.end(); ++i)
  237. delete[] i->second;
  238. for (int race = 0; race < MAX_RACES; ++race)
  239. {
  240. for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
  241. {
  242. if (_playerInfo[race][class_])
  243. delete[] _playerInfo[race][class_]->levelInfo;
  244. delete _playerInfo[race][class_];
  245. }
  246. }
  247. for (CacheVendorItemContainer::iterator itr = _cacheVendorItemStore.begin(); itr != _cacheVendorItemStore.end(); ++itr)
  248. itr->second.Clear();
  249. _cacheTrainerSpellStore.clear();
  250. _graveyardOrientations.clear();
  251. for (DungeonEncounterContainer::iterator itr =_dungeonEncounterStore.begin(); itr != _dungeonEncounterStore.end(); ++itr)
  252. for (DungeonEncounterList::iterator encounterItr = itr->second.begin(); encounterItr != itr->second.end(); ++encounterItr)
  253. delete *encounterItr;
  254. for (AccessRequirementContainer::iterator itr = _accessRequirementStore.begin(); itr != _accessRequirementStore.end(); ++itr)
  255. delete itr->second;
  256. }
  257. void ObjectMgr::AddLocaleString(std::string const& s, LocaleConstant locale, StringVector& data)
  258. {
  259. if (!s.empty())
  260. {
  261. if (data.size() <= size_t(locale))
  262. data.resize(locale + 1);
  263. data[locale] = s;
  264. }
  265. }
  266. void ObjectMgr::LoadGraveyardOrientations()
  267. {
  268. uint32 oldMSTime = getMSTime();
  269. _graveyardOrientations.clear();
  270. QueryResult result = WorldDatabase.Query("SELECT id, orientation FROM graveyard_orientation");
  271. if (!result)
  272. return;
  273. do
  274. {
  275. Field* fields = result->Fetch();
  276. uint32 id = fields[0].GetUInt32();
  277. if (!sWorldSafeLocsStore.LookupEntry(id))
  278. {
  279. TC_LOG_ERROR("server.loading", "Graveyard %u referenced in graveyard_orientation doesn't exist.", id);
  280. continue;
  281. }
  282. _graveyardOrientations[id] = fields[1].GetFloat();
  283. } while (result->NextRow());
  284. TC_LOG_INFO("server.loading", ">> Loaded %lu graveyard orientations in %u ms", (unsigned long)_graveyardOrientations.size(), GetMSTimeDiffToNow(oldMSTime));
  285. }
  286. void ObjectMgr::LoadCreatureLocales()
  287. {
  288. uint32 oldMSTime = getMSTime();
  289. _creatureLocaleStore.clear(); // need for reload case
  290. QueryResult result = WorldDatabase.Query("SELECT entry, "
  291. "name_loc1, femaleName_loc1, subname_loc1, "
  292. "name_loc2, femaleName_loc2, subname_loc2, "
  293. "name_loc3, femaleName_loc3, subname_loc3, "
  294. "name_loc4, femaleName_loc4, subname_loc4, "
  295. "name_loc5, femaleName_loc5, subname_loc5, "
  296. "name_loc6, femaleName_loc6, subname_loc6, "
  297. "name_loc7, femaleName_loc7, subname_loc7, "
  298. "name_loc8, femaleName_loc8, subname_loc8 "
  299. "FROM locales_creature");
  300. if (!result)
  301. return;
  302. do
  303. {
  304. Field* fields = result->Fetch();
  305. uint32 entry = fields[0].GetUInt32();
  306. CreatureLocale& data = _creatureLocaleStore[entry];
  307. for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i)
  308. {
  309. LocaleConstant locale = (LocaleConstant) i;
  310. AddLocaleString(fields[1 + 3 * (i - 1)].GetString(), locale, data.Name);
  311. AddLocaleString(fields[1 + 3 * (i - 1) + 1].GetString(), locale, data.FemaleName);
  312. AddLocaleString(fields[1 + 3 * (i - 1) + 2].GetString(), locale, data.SubName);
  313. }
  314. } while (result->NextRow());
  315. TC_LOG_INFO("server.loading", ">> Loaded %u creature locale strings in %u ms", uint32(_creatureLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
  316. }
  317. void ObjectMgr::LoadGossipMenuItemsLocales()
  318. {
  319. uint32 oldMSTime = getMSTime();
  320. _gossipMenuItemsLocaleStore.clear(); // need for reload case
  321. QueryResult result = WorldDatabase.Query("SELECT menu_id, id, "
  322. "option_text_loc1, box_text_loc1, option_text_loc2, box_text_loc2, "
  323. "option_text_loc3, box_text_loc3, option_text_loc4, box_text_loc4, "
  324. "option_text_loc5, box_text_loc5, option_text_loc6, box_text_loc6, "
  325. "option_text_loc7, box_text_loc7, option_text_loc8, box_text_loc8 "
  326. "FROM locales_gossip_menu_option");
  327. if (!result)
  328. return;
  329. do
  330. {
  331. Field* fields = result->Fetch();
  332. uint16 menuId = fields[0].GetUInt16();
  333. uint16 id = fields[1].GetUInt16();
  334. GossipMenuItemsLocale& data = _gossipMenuItemsLocaleStore[MAKE_PAIR32(menuId, id)];
  335. for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i)
  336. {
  337. LocaleConstant locale = (LocaleConstant) i;
  338. AddLocaleString(fields[2 + 2 * (i - 1)].GetString(), locale, data.OptionText);
  339. AddLocaleString(fields[2 + 2 * (i - 1) + 1].GetString(), locale, data.BoxText);
  340. }
  341. }
  342. while (result->NextRow());
  343. TC_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_option locale strings in %u ms", uint32(_gossipMenuItemsLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
  344. }
  345. void ObjectMgr::LoadPointOfInterestLocales()
  346. {
  347. uint32 oldMSTime = getMSTime();
  348. _pointOfInterestLocaleStore.clear(); // need for reload case
  349. QueryResult result = WorldDatabase.Query("SELECT entry, icon_name_loc1, icon_name_loc2, icon_name_loc3, icon_name_loc4, icon_name_loc5, icon_name_loc6, icon_name_loc7, icon_name_loc8 FROM locales_points_of_interest");
  350. if (!result)
  351. return;
  352. do
  353. {
  354. Field* fields = result->Fetch();
  355. uint32 entry = fields[0].GetUInt32();
  356. PointOfInterestLocale& data = _pointOfInterestLocaleStore[entry];
  357. for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i)
  358. AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.IconName);
  359. } while (result->NextRow());
  360. TC_LOG_INFO("server.loading", ">> Loaded %u points_of_interest locale strings in %u ms", uint32(_pointOfInterestLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime));
  361. }
  362. void ObjectMgr::LoadCreatureTemplates()
  363. {
  364. uint32 oldMSTime = getMSTime();
  365. // 0 1 2 3 4 5 6 7 8
  366. QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, "
  367. // 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  368. "modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, "
  369. // 23 24 25 26 27 28 29 30 31 32
  370. "scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, "
  371. // 33 34 35 36 37 38
  372. "dynamicflags, family, trainer_type, trainer_class, trainer_race, type, "
  373. // 39 40 41 42 43 44 45 46 47 48 49
  374. "type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, "
  375. // 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  376. "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
  377. // 64 65 66 67 68 69 70 71 72
  378. "InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, "
  379. // 73 74 75 76 77 78 79
  380. "RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, "
  381. // 80 81 82 83 84
  382. "movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName "
  383. "FROM creature_template");
  384. if (!result)
  385. {
  386. TC_LOG_INFO("server.loading", ">> Loaded 0 creature template definitions. DB table `creature_template` is empty.");
  387. return;
  388. }
  389. _creatureTemplateStore.rehash(result->GetRowCount());
  390. uint32 count = 0;
  391. do
  392. {
  393. Field* fields = result->Fetch();
  394. LoadCreatureTemplate(fields);
  395. ++count;
  396. }
  397. while (result->NextRow());
  398. // Checking needs to be done after loading because of the difficulty self referencing
  399. for (CreatureTemplateContainer::const_iterator itr = _creatureTemplateStore.begin(); itr != _creatureTemplateStore.end(); ++itr)
  400. CheckCreatureTemplate(&itr->second);
  401. TC_LOG_INFO("server.loading", ">> Loaded %u creature definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
  402. }
  403. void ObjectMgr::LoadCreatureTemplate(Field* fields)
  404. {
  405. uint32 entry = fields[0].GetUInt32();
  406. CreatureTemplate& creatureTemplate = _creatureTemplateStore[entry];
  407. creatureTemplate.Entry = entry;
  408. for (uint8 i = 0; i < MAX_DIFFICULTY - 1; ++i)
  409. creatureTemplate.DifficultyEntry[i] = fields[1 + i].GetUInt32();
  410. for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i)
  411. creatureTemplate.KillCredit[i] = fields[4 + i].GetUInt32();
  412. creatureTemplate.Modelid1 = fields[6].GetUInt32();
  413. creatureTemplate.Modelid2 = fields[7].GetUInt32();
  414. creatureTemplate.Modelid3 = fields[8].GetUInt32();
  415. creatureTemplate.Modelid4 = fields[9].GetUInt32();
  416. creatureTemplate.Name = fields[10].GetString();
  417. creatureTemplate.FemaleName = fields[11].GetString();
  418. creatureTemplate.SubName = fields[12].GetString();
  419. creatureTemplate.IconName = fields[13].GetString();
  420. creatureTemplate.GossipMenuId = fields[14].GetUInt32();
  421. creatureTemplate.minlevel = fields[15].GetUInt8();
  422. creatureTemplate.maxlevel = fields[16].GetUInt8();
  423. creatureTemplate.expansion = uint32(fields[17].GetInt16());
  424. creatureTemplate.expansionUnknown = uint32(fields[18].GetUInt16());
  425. creatureTemplate.faction = uint32(fields[19].GetUInt16());
  426. creatureTemplate.npcflag = fields[20].GetUInt32();
  427. creatureTemplate.speed_walk = fields[21].GetFloat();
  428. creatureTemplate.speed_run = fields[22].GetFloat();
  429. creatureTemplate.scale = fields[23].GetFloat();
  430. creatureTemplate.rank = uint32(fields[24].GetUInt8());
  431. creatureTemplate.dmgschool = uint32(fields[25].GetInt8());
  432. creatureTemplate.BaseAttackTime = fields[26].GetUInt32();
  433. creatureTemplate.RangeAttackTime = fields[27].GetUInt32();
  434. creatureTemplate.BaseVariance = fields[28].GetFloat();
  435. creatureTemplate.RangeVariance = fields[29].GetFloat();
  436. creatureTemplate.unit_class = uint32(fields[30].GetUInt8());
  437. creatureTemplate.unit_flags = fields[31].GetUInt32();
  438. creatureTemplate.unit_flags2 = fields[32].GetUInt32();
  439. creatureTemplate.dynamicflags = fields[33].GetUInt32();
  440. creatureTemplate.family = uint32(fields[34].GetUInt8());
  441. creatureTemplate.trainer_type = uint32(fields[35].GetUInt8());
  442. creatureTemplate.trainer_class = uint32(fields[36].GetUInt8());
  443. creatureTemplate.trainer_race = uint32(fields[37].GetUInt8());
  444. creatureTemplate.type = uint32(fields[38].GetUInt8());
  445. creatureTemplate.type_flags = fields[39].GetUInt32();
  446. creatureTemplate.type_flags2 = fields[40].GetUInt32();
  447. creatureTemplate.lootid = fields[41].GetUInt32();
  448. creatureTemplate.pickpocketLootId = fields[42].GetUInt32();
  449. creatureTemplate.SkinLootId = fields[43].GetUInt32();
  450. for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
  451. creatureTemplate.resistance[i] = fields[44 + i - 1].GetInt16();
  452. for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
  453. creatureTemplate.spells[i] = fields[50 + i].GetUInt32();
  454. creatureTemplate.PetSpellDataId = fields[58].GetUInt32();
  455. creatureTemplate.VehicleId = fields[59].GetUInt32();
  456. creatureTemplate.mingold = fields[60].GetUInt32();
  457. creatureTemplate.maxgold = fields[61].GetUInt32();
  458. creatureTemplate.AIName = fields[62].GetString();
  459. creatureTemplate.MovementType = uint32(fields[63].GetUInt8());
  460. creatureTemplate.InhabitType = uint32(fields[64].GetUInt8());
  461. creatureTemplate.HoverHeight = fields[65].GetFloat();
  462. creatureTemplate.ModHealth = fields[66].GetFloat();
  463. creatureTemplate.ModHealthExtra = fields[67].GetFloat();
  464. creatureTemplate.ModMana = fields[68].GetFloat();
  465. creatureTemplate.ModManaExtra = fields[69].GetFloat();
  466. creatureTemplate.ModArmor = fields[70].GetFloat();
  467. creatureTemplate.ModDamage = fields[71].GetFloat();
  468. creatureTemplate.ModExperience = fields[72].GetFloat();
  469. creatureTemplate.RacialLeader = fields[73].GetBool();
  470. for (uint8 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
  471. creatureTemplate.questItems[i] = fields[74 + i].GetUInt32();
  472. creatureTemplate.movementId = fields[80].GetUInt32();
  473. creatureTemplate.RegenHealth = fields[81].GetBool();
  474. creatureTemplate.MechanicImmuneMask = fields[82].GetUInt32();
  475. creatureTemplate.flags_extra = fields[83].GetUInt32();
  476. creatureTemplate.ScriptID = GetScriptId(fields[84].GetCString());
  477. }
  478. void ObjectMgr::LoadCreatureTemplateAddons()
  479. {
  480. uint32 oldMSTime = getMSTime();
  481. // 0 1 2 3 4 5 6
  482. QueryResult result = WorldDatabase.Query("SELECT entry, path_id, mount, bytes1, bytes2, emote, auras FROM creature_template_addon");
  483. if (!result)
  484. {
  485. TC_LOG_INFO("server.loading", ">> Loaded 0 creature template addon definitions. DB table `creature_template_addon` is empty.");
  486. return;
  487. }
  488. uint32 count = 0;
  489. do
  490. {
  491. Field* fields = result->Fetch();
  492. uint32 entry = fields[0].GetUInt32();
  493. if (!sObjectMgr->GetCreatureTemplate(entry))
  494. {
  495. TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_template_addon`", entry);
  496. continue;
  497. }
  498. CreatureAddon& creatureAddon = _creatureTemplateAddonStore[entry];
  499. creatureAddon.path_id = fields[1].GetUInt32();
  500. creatureAddon.mount = fields[2].GetUInt32();
  501. creatureAddon.bytes1 = fields[3].GetUInt32();
  502. creatureAddon.bytes2 = fields[4].GetUInt32();
  503. creatureAddon.emote = fields[5].GetUInt32();
  504. Tokenizer tokens(fields[6].GetString(), ' ');
  505. uint8 i = 0;
  506. creatureAddon.auras.resize(tokens.size());
  507. for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
  508. {
  509. SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr)));
  510. if (!AdditionalSpellInfo)
  511. {
  512. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %u defined in `auras` field in `creature_template_addon`.", entry, uint32(atol(*itr)));
  513. continue;
  514. }
  515. if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
  516. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_template_addon`.", entry, uint32(atol(*itr)));
  517. creatureAddon.auras[i++] = uint32(atol(*itr));
  518. }
  519. if (creatureAddon.mount)
  520. {
  521. if (!sCreatureDisplayInfoStore.LookupEntry(creatureAddon.mount))
  522. {
  523. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid displayInfoId (%u) for mount defined in `creature_template_addon`", entry, creatureAddon.mount);
  524. creatureAddon.mount = 0;
  525. }
  526. }
  527. if (!sEmotesStore.LookupEntry(creatureAddon.emote))
  528. {
  529. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid emote (%u) defined in `creature_template_addon`.", entry, creatureAddon.emote);
  530. creatureAddon.emote = 0;
  531. }
  532. ++count;
  533. }
  534. while (result->NextRow());
  535. TC_LOG_INFO("server.loading", ">> Loaded %u creature template addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
  536. }
  537. void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
  538. {
  539. if (!cInfo)
  540. return;
  541. bool ok = true; // bool to allow continue outside this loop
  542. for (uint32 diff = 0; diff < MAX_DIFFICULTY - 1 && ok; ++diff)
  543. {
  544. if (!cInfo->DifficultyEntry[diff])
  545. continue;
  546. ok = false; // will be set to true at the end of this loop again
  547. CreatureTemplate const* difficultyInfo = GetCreatureTemplate(cInfo->DifficultyEntry[diff]);
  548. if (!difficultyInfo)
  549. {
  550. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has `difficulty_entry_%u`=%u but creature entry %u does not exist.",
  551. cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff]);
  552. continue;
  553. }
  554. bool ok2 = true;
  555. for (uint32 diff2 = 0; diff2 < MAX_DIFFICULTY - 1 && ok2; ++diff2)
  556. {
  557. ok2 = false;
  558. if (_difficultyEntries[diff2].find(cInfo->Entry) != _difficultyEntries[diff2].end())
  559. {
  560. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) is listed as `difficulty_entry_%u` of another creature, but itself lists %u in `difficulty_entry_%u`.",
  561. cInfo->Entry, diff2 + 1, cInfo->DifficultyEntry[diff], diff + 1);
  562. continue;
  563. }
  564. if (_difficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != _difficultyEntries[diff2].end())
  565. {
  566. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) already listed as `difficulty_entry_%u` for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1);
  567. continue;
  568. }
  569. if (_hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != _hasDifficultyEntries[diff2].end())
  570. {
  571. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has `difficulty_entry_%u`=%u but creature entry %u has itself a value in `difficulty_entry_%u`.",
  572. cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff], diff2 + 1);
  573. continue;
  574. }
  575. ok2 = true;
  576. }
  577. if (!ok2)
  578. continue;
  579. if (cInfo->expansion > difficultyInfo->expansion)
  580. {
  581. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, exp %u) has different `exp` in difficulty %u mode (Entry: %u, exp %u).",
  582. cInfo->Entry, cInfo->expansion, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->expansion);
  583. }
  584. if (cInfo->minlevel > difficultyInfo->minlevel)
  585. {
  586. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, minlevel %u) has lower `minlevel` in difficulty %u mode (Entry: %u, minlevel %u).",
  587. cInfo->Entry, cInfo->minlevel, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->minlevel);
  588. }
  589. if (cInfo->maxlevel > difficultyInfo->maxlevel)
  590. {
  591. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, maxlevel %u) has lower `maxlevel` in difficulty %u mode (Entry: %u, maxlevel %u).",
  592. cInfo->Entry, cInfo->maxlevel, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->maxlevel);
  593. }
  594. if (cInfo->faction != difficultyInfo->faction)
  595. {
  596. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, faction %u) has different `faction` in difficulty %u mode (Entry: %u, faction %u).",
  597. cInfo->Entry, cInfo->faction, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->faction);
  598. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `faction`=%u WHERE `entry`=%u;",
  599. cInfo->faction, cInfo->DifficultyEntry[diff]);
  600. }
  601. if (cInfo->unit_class != difficultyInfo->unit_class)
  602. {
  603. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).",
  604. cInfo->Entry, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class);
  605. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `unit_class`=%u WHERE `entry`=%u;",
  606. cInfo->unit_class, cInfo->DifficultyEntry[diff]);
  607. continue;
  608. }
  609. if (cInfo->npcflag != difficultyInfo->npcflag)
  610. {
  611. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, `npcflag`: %u) has different `npcflag` in difficulty %u mode (Entry: %u, `npcflag`: %u).",
  612. cInfo->Entry, cInfo->npcflag, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->npcflag);
  613. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `npcflag`=%u WHERE `entry`=%u;",
  614. cInfo->npcflag, cInfo->DifficultyEntry[diff]);
  615. continue;
  616. }
  617. if (cInfo->family != difficultyInfo->family)
  618. {
  619. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, family %u) has different `family` in difficulty %u mode (Entry: %u, family %u).",
  620. cInfo->Entry, cInfo->family, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->family);
  621. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `family`=%u WHERE `entry`=%u;",
  622. cInfo->family, cInfo->DifficultyEntry[diff]);
  623. }
  624. if (cInfo->trainer_class != difficultyInfo->trainer_class)
  625. {
  626. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, trainer_class: %u) has different `trainer_class` in difficulty %u mode (Entry: %u, trainer_class: %u).",
  627. cInfo->Entry, cInfo->trainer_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->trainer_class);
  628. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `trainer_class`=%u WHERE `entry`=%u;",
  629. cInfo->trainer_class, cInfo->DifficultyEntry[diff]);
  630. continue;
  631. }
  632. if (cInfo->trainer_race != difficultyInfo->trainer_race)
  633. {
  634. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, trainer_race: %u) has different `trainer_race` in difficulty %u mode (Entry: %u, trainer_race: %u).",
  635. cInfo->Entry, cInfo->trainer_race, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->trainer_race);
  636. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `trainer_race`=%u WHERE `entry`=%u;",
  637. cInfo->trainer_race, cInfo->DifficultyEntry[diff]);
  638. continue;
  639. }
  640. if (cInfo->trainer_type != difficultyInfo->trainer_type)
  641. {
  642. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, trainer_type: %u) has different `trainer_type` in difficulty %u mode (Entry: %u, trainer_type: %u).",
  643. cInfo->Entry, cInfo->trainer_type, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->trainer_type);
  644. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `trainer_type`=%u WHERE `entry`=%u;",
  645. cInfo->trainer_type, cInfo->DifficultyEntry[diff]);
  646. continue;
  647. }
  648. if (cInfo->type != difficultyInfo->type)
  649. {
  650. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, type %u) has different `type` in difficulty %u mode (Entry: %u, type %u).",
  651. cInfo->Entry, cInfo->type, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->type);
  652. TC_LOG_ERROR("sql.sql", "Possible FIX: UPDATE `creature_template` SET `type`=%u WHERE `entry`=%u;",
  653. cInfo->type, cInfo->DifficultyEntry[diff]);
  654. }
  655. if (!cInfo->VehicleId && difficultyInfo->VehicleId)
  656. {
  657. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, VehicleId %u) has different `VehicleId` in difficulty %u mode (Entry: %u, VehicleId %u).",
  658. cInfo->Entry, cInfo->VehicleId, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->VehicleId);
  659. }
  660. if (!difficultyInfo->AIName.empty())
  661. {
  662. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists difficulty %u mode entry %u with `AIName` filled in. `AIName` of difficulty 0 mode creature is always used instead.",
  663. cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
  664. continue;
  665. }
  666. if (difficultyInfo->ScriptID)
  667. {
  668. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists difficulty %u mode entry %u with `ScriptName` filled in. `ScriptName` of difficulty 0 mode creature is always used instead.",
  669. cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
  670. continue;
  671. }
  672. _hasDifficultyEntries[diff].insert(cInfo->Entry);
  673. _difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]);
  674. ok = true;
  675. }
  676. FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction);
  677. if (!factionTemplate)
  678. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing faction template (%u).", cInfo->Entry, cInfo->faction);
  679. // used later for scale
  680. CreatureDisplayInfoEntry const* displayScaleEntry = NULL;
  681. if (cInfo->Modelid1)
  682. {
  683. CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1);
  684. if (!displayEntry)
  685. {
  686. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid1 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid1);
  687. const_cast<CreatureTemplate*>(cInfo)->Modelid1 = 0;
  688. }
  689. else if (!displayScaleEntry)
  690. displayScaleEntry = displayEntry;
  691. CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid1);
  692. if (!modelInfo)
  693. TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid1` = %u listed by creature (Entry: %u).", cInfo->Modelid1, cInfo->Entry);
  694. }
  695. if (cInfo->Modelid2)
  696. {
  697. CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2);
  698. if (!displayEntry)
  699. {
  700. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid2 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid2);
  701. const_cast<CreatureTemplate*>(cInfo)->Modelid2 = 0;
  702. }
  703. else if (!displayScaleEntry)
  704. displayScaleEntry = displayEntry;
  705. CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid2);
  706. if (!modelInfo)
  707. TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid2` = %u listed by creature (Entry: %u).", cInfo->Modelid2, cInfo->Entry);
  708. }
  709. if (cInfo->Modelid3)
  710. {
  711. CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3);
  712. if (!displayEntry)
  713. {
  714. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid3 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid3);
  715. const_cast<CreatureTemplate*>(cInfo)->Modelid3 = 0;
  716. }
  717. else if (!displayScaleEntry)
  718. displayScaleEntry = displayEntry;
  719. CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid3);
  720. if (!modelInfo)
  721. TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid3` = %u listed by creature (Entry: %u).", cInfo->Modelid3, cInfo->Entry);
  722. }
  723. if (cInfo->Modelid4)
  724. {
  725. CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4);
  726. if (!displayEntry)
  727. {
  728. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid4 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid4);
  729. const_cast<CreatureTemplate*>(cInfo)->Modelid4 = 0;
  730. }
  731. else if (!displayScaleEntry)
  732. displayScaleEntry = displayEntry;
  733. CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid4);
  734. if (!modelInfo)
  735. TC_LOG_ERROR("sql.sql", "No model data exist for `Modelid4` = %u listed by creature (Entry: %u).", cInfo->Modelid4, cInfo->Entry);
  736. }
  737. if (!displayScaleEntry)
  738. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) does not have any existing display id in Modelid1/Modelid2/Modelid3/Modelid4.", cInfo->Entry);
  739. for (int k = 0; k < MAX_KILL_CREDIT; ++k)
  740. {
  741. if (cInfo->KillCredit[k])
  742. {
  743. if (!GetCreatureTemplate(cInfo->KillCredit[k]))
  744. {
  745. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing creature entry %u in `KillCredit%d`.", cInfo->Entry, cInfo->KillCredit[k], k + 1);
  746. const_cast<CreatureTemplate*>(cInfo)->KillCredit[k] = 0;
  747. }
  748. }
  749. }
  750. if (!cInfo->unit_class || ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0)
  751. {
  752. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid unit_class (%u) in creature_template. Set to 1 (UNIT_CLASS_WARRIOR).", cInfo->Entry, cInfo->unit_class);
  753. const_cast<CreatureTemplate*>(cInfo)->unit_class = UNIT_CLASS_WARRIOR;
  754. }
  755. if (cInfo->dmgschool >= MAX_SPELL_SCHOOL)
  756. {
  757. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`.", cInfo->Entry, cInfo->dmgschool);
  758. const_cast<CreatureTemplate*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
  759. }
  760. if (cInfo->BaseAttackTime == 0)
  761. const_cast<CreatureTemplate*>(cInfo)->BaseAttackTime = BASE_ATTACK_TIME;
  762. if (cInfo->RangeAttackTime == 0)
  763. const_cast<CreatureTemplate*>(cInfo)->RangeAttackTime = BASE_ATTACK_TIME;
  764. if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
  765. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong trainer type %u.", cInfo->Entry, cInfo->trainer_type);
  766. if (cInfo->speed_walk == 0.0f)
  767. {
  768. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in speed_walk, set to 1.", cInfo->Entry, cInfo->speed_walk);
  769. const_cast<CreatureTemplate*>(cInfo)->speed_walk = 1.0f;
  770. }
  771. if (cInfo->speed_run == 0.0f)
  772. {
  773. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in speed_run, set to 1.14286.", cInfo->Entry, cInfo->speed_run);
  774. const_cast<CreatureTemplate*>(cInfo)->speed_run = 1.14286f;
  775. }
  776. if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
  777. {
  778. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid creature type (%u) in `type`.", cInfo->Entry, cInfo->type);
  779. const_cast<CreatureTemplate*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
  780. }
  781. // must exist or used hidden but used in data horse case
  782. if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM)
  783. {
  784. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid creature family (%u) in `family`.", cInfo->Entry, cInfo->family);
  785. const_cast<CreatureTemplate*>(cInfo)->family = 0;
  786. }
  787. if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
  788. {
  789. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly.", cInfo->Entry, cInfo->InhabitType);
  790. const_cast<CreatureTemplate*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
  791. }
  792. if (cInfo->HoverHeight < 0.0f)
  793. {
  794. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in `HoverHeight`", cInfo->Entry, cInfo->HoverHeight);
  795. const_cast<CreatureTemplate*>(cInfo)->HoverHeight = 1.0f;
  796. }
  797. if (cInfo->VehicleId)
  798. {
  799. VehicleEntry const* vehId = sVehicleStore.LookupEntry(cInfo->VehicleId);
  800. if (!vehId)
  801. {
  802. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has a non-existing VehicleId (%u). This *WILL* cause the client to freeze!", cInfo->Entry, cInfo->VehicleId);
  803. const_cast<CreatureTemplate*>(cInfo)->VehicleId = 0;
  804. }
  805. }
  806. if (cInfo->PetSpellDataId)
  807. {
  808. CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
  809. if (!spellDataId)
  810. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing PetSpellDataId (%u).", cInfo->Entry, cInfo->PetSpellDataId);
  811. }
  812. for (uint8 j = 0; j < CREATURE_MAX_SPELLS; ++j)
  813. {
  814. if (cInfo->spells[j] && !sSpellMgr->GetSpellInfo(cInfo->spells[j]))
  815. {
  816. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing Spell%d (%u), set to 0.", cInfo->Entry, j+1, cInfo->spells[j]);
  817. const_cast<CreatureTemplate*>(cInfo)->spells[j] = 0;
  818. }
  819. }
  820. if (cInfo->MovementType >= MAX_DB_MOTION_TYPE)
  821. {
  822. TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong movement generator type (%u), ignored and set to IDLE.", cInfo->Entry, cInfo->MovementType);
  823. const_cast<CreatureTemplate*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
  824. }
  825. /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
  826. if (cInfo->scale <= 0.0f)
  827. {
  828. if (displayScaleEntry)
  829. const_cast<CreatureTemplate*>(cInfo)->scale = displayScaleEntry->scale;
  830. else
  831. const_cast<CreatureTemplate*>(cInfo)->scale = 1.0f;
  832. }
  833. if (cInfo->expansion > (MAX_EXPANSIONS - 1))
  834. {
  835. TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with `exp` %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansion);
  836. const_cast<CreatureTemplate*>(cInfo)->expansion = 0;
  837. }
  838. if (cInfo->expansionUnknown > MAX_EXPANSIONS)
  839. {
  840. TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with `exp_unk` %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansionUnknown);
  841. const_cast<CreatureTemplate*>(cInfo)->expansionUnknown = 0;
  842. }
  843. if (uint32 badFlags = (cInfo->flags_extra & ~CREATURE_FLAG_EXTRA_DB_ALLOWED))
  844. {
  845. TC_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with disallowed `flags_extra` %u, removing incorrect flag.", cInfo->Entry, badFlags);
  846. const_cast<CreatureTemplate*>(cInfo)->flags_extra &= CREATURE_FLAG_EXTRA_DB_ALLOWED;
  847. }
  848. const_cast<CreatureTemplate*>(cInfo)->ModDamage *= Creature::_GetDamageMod(cInfo->rank);
  849. }
  850. void ObjectMgr::LoadCreatureAddons()
  851. {
  852. uint32 oldMSTime = getMSTime();
  853. // 0 1 2 3 4 5 6
  854. QueryResult result = WorldDatabase.Query("SELECT guid, path_id, mount, bytes1, bytes2, emote, auras FROM creature_addon");
  855. if (!result)
  856. {
  857. TC_LOG_INFO("server.loading", ">> Loaded 0 creature addon definitions. DB table `creature_addon` is empty.");
  858. return;
  859. }
  860. uint32 count = 0;
  861. do
  862. {
  863. Field* fields = result->Fetch();
  864. uint32 guid = fields[0].GetUInt32();
  865. CreatureData const* creData = GetCreatureData(guid);
  866. if (!creData)
  867. {
  868. TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) does not exist but has a record in `creature_addon`", guid);
  869. continue;
  870. }
  871. CreatureAddon& creatureAddon = _creatureAddonStore[guid];
  872. creatureAddon.path_id = fields[1].GetUInt32();
  873. if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.path_id)
  874. {
  875. const_cast<CreatureData*>(creData)->movementType = IDLE_MOTION_TYPE;
  876. TC_LOG_ERROR("sql.sql", "Creature (GUID %u) has movement type set to WAYPOINT_MOTION_TYPE but no path assigned", guid);
  877. }
  878. creatureAddon.mount = fields[2].GetUInt32();
  879. creatureAddon.bytes1 = fields[3].GetUInt32();
  880. creatureAddon.bytes2 = fields[4].GetUInt32();
  881. creatureAddon.emote = fields[5].GetUInt32();
  882. Tokenizer tokens(fields[6].GetString(), ' ');
  883. uint8 i = 0;
  884. creatureAddon.auras.resize(tokens.size());
  885. for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
  886. {
  887. SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr)));
  888. if (!AdditionalSpellInfo)
  889. {
  890. TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has wrong spell %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr)));
  891. continue;
  892. }
  893. if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
  894. TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has SPELL_AURA_CONTROL_VEHICLE aura %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr)));
  895. creatureAddon.auras[i++] = uint32(atol(*itr));
  896. }
  897. if (creatureAddon.mount)
  898. {
  899. if (!sCreatureDisplayInfoStore.LookupEntry(creatureAddon.mount))
  900. {
  901. TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has invalid displayInfoId (%u) for mount defined in `creature_addon`", guid, creatureAddon.mount);
  902. creatureAddon.mount = 0;
  903. }
  904. }
  905. if (!sEmotesStore.LookupEntry(creatureAddon.emote))
  906. {
  907. TC_LOG_ERROR("sql.sql", "Creature (GUID: %u) has invalid emote (%u) defined in `creature_addon`.", guid, creatureAddon.emote);
  908. creatureAddon.emote = 0;
  909. }
  910. ++count;
  911. }
  912. while (result->NextRow());
  913. TC_LOG_INFO("server.loading", ">> Loaded %u creature addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
  914. }
  915. CreatureAddon const* ObjectMgr::GetCreatureAddon(uint32 lowguid)
  916. {
  917. CreatureAddonContainer::const_iterator itr = _creatureAddonStore.find(lowguid);
  918. if (itr != _creatureAddonStore.end())
  919. return &(itr->second);
  920. return NULL;
  921. }
  922. CreatureAddon const* ObjectMgr::GetCreatureTemplateAddon(uint32 entry)
  923. {
  924. CreatureAddonContainer::const_iterator itr = _creatureTemplateAddonStore.find(entry);
  925. if (itr != _creatureTemplateAddonStore.end())
  926. return &(itr->second);
  927. return NULL;
  928. }
  929. EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry, int8& id)
  930. {
  931. EquipmentInfoContainer::const_iterator itr = _equipmentInfoStore.find(entry);
  932. if (itr == _equipmentInfoStore.end())
  933. return NULL;
  934. if (itr->second.empty())
  935. return NULL;
  936. if (id == -1) // select a random element
  937. {
  938. EquipmentInfoContainerInternal::const_iterator ritr = itr->second.begin();
  939. std::advance(ritr, urand(0u, itr->second.size() - 1));
  940. id = std::distance(itr->second.begin(), ritr) + 1;
  941. return &ritr->second;
  942. }
  943. else
  944. {
  945. EquipmentInfoContainerInternal::const_iterator itr2 = itr->second.find(id);
  946. if (itr2 != itr->second.end())
  947. return &itr2->second;
  948. }
  949. return NULL;
  950. }
  951. void ObjectMgr::LoadEquipmentTemplates()
  952. {
  953. uint32 oldMSTime = getMSTime();
  954. // 0 1 2 3 4
  955. QueryResult result = WorldDatabase.Query("SELECT entry, id, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template");
  956. if (!result)
  957. {
  958. TC_LOG_INFO("server.loading", ">> Loaded 0 creature equipment templates. DB table `creature_equip_template` is empty!");
  959. return;
  960. }
  961. uint32 count = 0;
  962. do
  963. {
  964. Field* fields = result->Fetch();
  965. uint32 entry = fields[0].GetUInt32();
  966. if (!sObjectMgr->GetCreatureTemplate(entry))
  967. {
  968. TC_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_equip_template`", entry);
  969. continue;
  970. }
  971. uint8 id = fields[1].GetUInt8();
  972. if (!id)
  973. {
  974. TC_LOG_ERROR("sql.sql", "Creature equipment template with id 0 found for creature %u, skipped.", entry);

Large files files are truncated, but you can click here to view the full file