Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
ObjectMgr.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "AccountMgr.h"
7#include "AchievementMgr.h"
8#include "ArenaTeam.h"
9#include "ArenaTeamMgr.h"
10#include "AreaTableUtils.h"
11#include "BattlePet.h"
12#include "Chat.h"
13#include "Common.h"
14#include "DatabaseEnv.h"
15#include "DB2Enums.h"
16#include "DB2Stores.h"
17#include "DB2Structure.h"
18#include "DisableMgr.h"
19#include "GameEventMgr.h"
20#include "GossipDef.h"
21#include "GossipSchema.h"
22#include "GroupMgr.h"
23#include "GuildMgr.h"
24#include "InstanceSaveMgr.h"
25#include "Language.h"
27#include "LFGMgr.h"
28#include "Log.h"
29#include "MapManager.h"
30#include "ObjectMgr.h"
31#include "Platform/TimeUtils.h"
32#include "Pet.h"
33#include "PlayerRestState.h"
34#include "PoolMgr.h"
35#include "ReputationMgr.h"
36#include "ScriptMgr.h"
37#include "Spell.h"
38#include "SpellAuras.h"
39#include "SpellMgr.h"
40#include "SpellScript.h"
41#include "Transport.h"
42#include "TransportMgr.h"
43#include "UpdateMask.h"
44#include "Util.h"
45#include "Vehicle.h"
46#include "WaypointManager.h"
47#include "World.h"
48#include "DBCStores.h"
49
53
54namespace
55{
56 bool IsCapturableBattlePetNpc(uint32 npcId)
57 {
58 if (!npcId)
59 return false;
60
61 for (uint32 speciesId = 0; speciesId < sBattlePetSpeciesStore.GetNumRows(); ++speciesId)
62 {
63 BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(speciesId);
64 if (speciesEntry && speciesEntry->NpcId == npcId
66 return true;
67 }
68
69 return false;
70 }
71
72 Skyfire::Rest::InnAreaBounds ToInnAreaBounds(TavernRestArea const& restArea)
73 {
75 bounds.MapId = restArea.MapId;
76 bounds.X = restArea.X;
77 bounds.Y = restArea.Y;
78 bounds.Z = restArea.Z;
79 bounds.Radius = restArea.Radius;
80 bounds.BoxX = restArea.BoxX;
81 bounds.BoxY = restArea.BoxY;
82 bounds.BoxZ = restArea.BoxZ;
83 bounds.BoxOrientation = restArea.BoxOrientation;
84 return bounds;
85 }
86}
87
89{
90 std::string res = "";
91 switch (type)
92 {
93 case ScriptsType::SCRIPTS_SPELL: res = "spell_scripts"; break;
94 case ScriptsType::SCRIPTS_EVENT: res = "event_scripts"; break;
95 case ScriptsType::SCRIPTS_WAYPOINT: res = "waypoint_scripts"; break;
96 default: break;
97 }
98 return res;
99}
100
102{
103 ScriptMapMap* res = NULL;
104 switch (type)
105 {
106 case ScriptsType::SCRIPTS_SPELL: res = &sSpellScripts; break;
107 case ScriptsType::SCRIPTS_EVENT: res = &sEventScripts; break;
109 default: break;
110 }
111 return res;
112}
113
115{
116 std::string res = "";
117 switch (command)
118 {
119 case ScriptCommands::SCRIPT_COMMAND_TALK: res = "SCRIPT_COMMAND_TALK"; break;
120 case ScriptCommands::SCRIPT_COMMAND_EMOTE: res = "SCRIPT_COMMAND_EMOTE"; break;
121 case ScriptCommands::SCRIPT_COMMAND_FIELD_SET: res = "SCRIPT_COMMAND_FIELD_SET"; break;
122 case ScriptCommands::SCRIPT_COMMAND_MOVE_TO: res = "SCRIPT_COMMAND_MOVE_TO"; break;
123 case ScriptCommands::SCRIPT_COMMAND_FLAG_SET: res = "SCRIPT_COMMAND_FLAG_SET"; break;
124 case ScriptCommands::SCRIPT_COMMAND_FLAG_REMOVE: res = "SCRIPT_COMMAND_FLAG_REMOVE"; break;
125 case ScriptCommands::SCRIPT_COMMAND_TELEPORT_TO: res = "SCRIPT_COMMAND_TELEPORT_TO"; break;
126 case ScriptCommands::SCRIPT_COMMAND_QUEST_EXPLORED: res = "SCRIPT_COMMAND_QUEST_EXPLORED"; break;
127 case ScriptCommands::SCRIPT_COMMAND_KILL_CREDIT: res = "SCRIPT_COMMAND_KILL_CREDIT"; break;
128 case ScriptCommands::SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: res = "SCRIPT_COMMAND_RESPAWN_GAMEOBJECT"; break;
129 case ScriptCommands::SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: res = "SCRIPT_COMMAND_TEMP_SUMMON_CREATURE"; break;
130 case ScriptCommands::SCRIPT_COMMAND_OPEN_DOOR: res = "SCRIPT_COMMAND_OPEN_DOOR"; break;
131 case ScriptCommands::SCRIPT_COMMAND_CLOSE_DOOR: res = "SCRIPT_COMMAND_CLOSE_DOOR"; break;
132 case ScriptCommands::SCRIPT_COMMAND_ACTIVATE_OBJECT: res = "SCRIPT_COMMAND_ACTIVATE_OBJECT"; break;
133 case ScriptCommands::SCRIPT_COMMAND_REMOVE_AURA: res = "SCRIPT_COMMAND_REMOVE_AURA"; break;
134 case ScriptCommands::SCRIPT_COMMAND_CAST_SPELL: res = "SCRIPT_COMMAND_CAST_SPELL"; break;
135 case ScriptCommands::SCRIPT_COMMAND_PLAY_SOUND: res = "SCRIPT_COMMAND_PLAY_SOUND"; break;
136 case ScriptCommands::SCRIPT_COMMAND_CREATE_ITEM: res = "SCRIPT_COMMAND_CREATE_ITEM"; break;
137 case ScriptCommands::SCRIPT_COMMAND_DESPAWN_SELF: res = "SCRIPT_COMMAND_DESPAWN_SELF"; break;
138 case ScriptCommands::SCRIPT_COMMAND_LOAD_PATH: res = "SCRIPT_COMMAND_LOAD_PATH"; break;
139 case ScriptCommands::SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: res = "SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT"; break;
140 case ScriptCommands::SCRIPT_COMMAND_KILL: res = "SCRIPT_COMMAND_KILL"; break;
141 // Skyfire only
142 case ScriptCommands::SCRIPT_COMMAND_ORIENTATION: res = "SCRIPT_COMMAND_ORIENTATION"; break;
143 case ScriptCommands::SCRIPT_COMMAND_EQUIP: res = "SCRIPT_COMMAND_EQUIP"; break;
144 case ScriptCommands::SCRIPT_COMMAND_MODEL: res = "SCRIPT_COMMAND_MODEL"; break;
145 case ScriptCommands::SCRIPT_COMMAND_CLOSE_GOSSIP: res = "SCRIPT_COMMAND_CLOSE_GOSSIP"; break;
146 case ScriptCommands::SCRIPT_COMMAND_PLAYMOVIE: res = "SCRIPT_COMMAND_PLAYMOVIE"; break;
147 default:
148 {
149 char sz[32];
150 snprintf(sz, sizeof(sz), "Unknown command: %d", uint32(command));
151 res = sz;
152 break;
153 }
154 }
155 return res;
156}
157
158std::string ScriptInfo::GetDebugInfo() const
159{
160 char sz[256];
161 snprintf(sz, sizeof(sz), "%s ('%s' script id: %u)", GetScriptCommandName(command).c_str(), GetScriptsTableNameByType(type).c_str(), id);
162 return std::string(sz);
163}
164
165bool normalizePlayerName(std::string& name)
166{
167 if (name.empty())
168 return false;
169
170 std::wstring tmp;
171
172 if (!Utf8toWStr(name, tmp))
173 return false;
174
175 wstrToLower(tmp);
176 if (!tmp.empty())
177 tmp[0] = wcharToUpper(tmp[0]);
178
179 if (!WStrToUtf8(tmp, name))
180 return false;
181
182 return true;
183}
184
212
214{
215 for (uint8 i = 0; i < LANGUAGES_COUNT; ++i)
216 {
217 if (lang_description[i].lang_id == lang)
218 return &lang_description[i];
219 }
220
221 return NULL;
222}
223
224bool SpellClickInfo::IsFitToRequirements(Unit const* clicker, Unit const* clickee) const
225{
226 Player const* playerClicker = clicker->ToPlayer();
227 if (!playerClicker)
228 return true;
229
230 Unit const* summoner = NULL;
231 // Check summoners for party
232 if (clickee->IsSummon())
233 summoner = clickee->ToTempSummon()->GetSummoner();
234 if (!summoner)
235 summoner = clickee;
236
237 // This only applies to players
238 switch (userType)
239 {
241 if (!playerClicker->IsFriendlyTo(summoner))
242 return false;
243 break;
245 if (!playerClicker->IsInRaidWith(summoner))
246 return false;
247 break;
249 if (!playerClicker->IsInPartyWith(summoner))
250 return false;
251 break;
252 default:
253 break;
254 }
255
256 return true;
257}
258
260 _auctionId(1),
262 _itemTextId(1),
263 _mailId(1),
264 _hiPetNumber(1),
265 _voidItemId(1),
266 _hiCharGuid(1),
268 _hiPetGuid(1),
270 _hiItemGuid(1),
271 _hiGoGuid(1),
272 _hiDoGuid(1),
273 _hiCorpseGuid(1),
277{
278 for (uint8 i = 0; i < MAX_CLASSES; ++i)
279 for (uint8 j = 0; j < MAX_RACES; ++j)
280 _playerInfo[j][i] = NULL;
281}
282
284{
285 for (QuestMap::iterator i = _questTemplates.begin(); i != _questTemplates.end(); ++i)
286 delete i->second;
287
288 for (PetLevelInfoContainer::iterator i = _petInfoStore.begin(); i != _petInfoStore.end(); ++i)
289 delete[] i->second;
290
291 for (int race = 0; race < MAX_RACES; ++race)
292 {
293 for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
294 {
295 if (_playerInfo[race][class_])
296 delete[] _playerInfo[race][class_]->levelInfo;
297 delete _playerInfo[race][class_];
298 }
299 }
300
301 for (CacheVendorItemContainer::iterator itr = _cacheVendorItemStore.begin(); itr != _cacheVendorItemStore.end(); ++itr)
302 itr->second.Clear();
303
306
307 for (DungeonEncounterContainer::iterator itr = _dungeonEncounterStore.begin(); itr != _dungeonEncounterStore.end(); ++itr)
308 for (DungeonEncounterList::iterator encounterItr = itr->second.begin(); encounterItr != itr->second.end(); ++encounterItr)
309 delete* encounterItr;
310
311 for (AccessRequirementContainer::iterator itr = _accessRequirementStore.begin(); itr != _accessRequirementStore.end(); ++itr)
312 delete itr->second;
313}
314
315void ObjectMgr::AddLocaleString(std::string const& s, LocaleConstant locale, StringVector& data)
316{
317 if (!s.empty())
318 {
319 if (data.size() <= size_t(locale))
320 data.resize(locale + 1);
321
322 data[locale] = s;
323 }
324}
325
327{
328 uint32 oldMSTime = getMSTime();
329
331
332 QueryResult result = WorldDatabase.Query("SELECT id, orientation FROM graveyard_orientation");
333
334 if (!result)
335 return;
336
337 do
338 {
339 Field* fields = result->Fetch();
340
341 uint32 id = fields[0].GetUInt32();
342 if (!sWorldSafeLocsStore.LookupEntry(id))
343 {
344 SF_LOG_ERROR("server.loading", "Graveyard %u referenced in graveyard_orientation doesn't exist.", id);
345 continue;
346 }
347 _graveyardOrientations[id] = fields[1].GetFloat();
348 } while (result->NextRow());
349
350 SF_LOG_INFO("server.loading", ">> Loaded %lu graveyard orientations in %u ms", (unsigned long)_graveyardOrientations.size(), GetMSTimeDiffToNow(oldMSTime));
351}
352
354{
355 uint32 oldMSTime = getMSTime();
356
357 _creatureLocaleStore.clear(); // need for reload case
358
359 QueryResult result = WorldDatabase.Query("SELECT entry, name_loc1, subname_loc1, name_loc2, subname_loc2, name_loc3, subname_loc3, name_loc4, subname_loc4, name_loc5, subname_loc5, name_loc6, subname_loc6, name_loc7, subname_loc7, name_loc8, subname_loc8, name_loc9, subname_loc9, name_loc10, subname_loc10, name_loc11, subname_loc11 FROM locales_creature");
360
361 if (!result)
362 return;
363
364 do
365 {
366 Field* fields = result->Fetch();
367
368 uint32 entry = fields[0].GetUInt32();
369
371
372 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
373 {
374 LocaleConstant locale = (LocaleConstant)i;
375 AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.Name);
376 AddLocaleString(fields[1 + 2 * (i - 1) + 1].GetString(), locale, data.SubName);
377 }
378 } while (result->NextRow());
379
380 SF_LOG_INFO("server.loading", ">> Loaded %lu creature locale strings in %u ms", (unsigned long)_creatureLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
381}
382
384{
385 uint32 oldMSTime = getMSTime();
386
387 _gossipMenuItemsLocaleStore.clear(); // need for reload case
388
390
391 if (!result)
392 return;
393
394 do
395 {
396 Field* fields = result->Fetch();
397
398 uint16 menuId = fields[0].GetUInt16();
399 uint16 id = fields[1].GetUInt16();
400 LocaleConstant locale = GetLocaleByName(fields[2].GetString());
401
403
404 AddLocaleString(fields[3].GetString(), locale, data.OptionText);
405 AddLocaleString(fields[4].GetString(), locale, data.BoxText);
406 } while (result->NextRow());
407
408 SF_LOG_INFO("server.loading", ">> Loaded %lu gossip_menu_option locale strings in %u ms", (unsigned long)_gossipMenuItemsLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
409}
410
412{
413 uint32 oldMSTime = getMSTime();
414
415 _pointOfInterestLocaleStore.clear(); // need for reload case
416
417 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, icon_name_loc9, icon_name_loc10, icon_name_loc11 FROM locales_points_of_interest");
418
419 if (!result)
420 return;
421
422 do
423 {
424 Field* fields = result->Fetch();
425
426 uint32 entry = fields[0].GetUInt32();
427
429
430 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
431 AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.IconName);
432 } while (result->NextRow());
433
434 SF_LOG_INFO("server.loading", ">> Loaded %lu points_of_interest locale strings in %u ms", (unsigned long)_pointOfInterestLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
435}
436
438{
439 uint32 oldMSTime = getMSTime();
440
441 // 0 1 2 3 4 5 6 7 8
442 QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, "
443 // 9 10 11 12 13 14 15 16 17 18 19 20 21
444 "modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction_A, faction_H, npcflag, speed_walk, "
445 // 22 23 24 25 26 27 28 29 30 31 32 33 34
446 "speed_run, scale, npc_rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, "
447 // 35 36 37 38 39 40 41 42 43
448 "dynamicflags, family, trainer_type, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, "
449 // 44 45 46 47 48 49 50 51 52 53 54
450 "type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, "
451 // 55 56 57 58 59 60 61 62 63 64 65 66 67 68
452 "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
453 // 69 70 71 72 73 74 75 76 77 78 79 80
454 "InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, "
455 // 81 82 83 84 85 86
456 " questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName, ModLevel "
457 "FROM creature_template;");
458
459 if (!result)
460 {
461 SF_LOG_INFO("server.loading", ">> Loaded 0 creature template definitions. DB table `creature_template` is empty.");
462 return;
463 }
464
465 _creatureTemplateStore.rehash(result->GetRowCount());
466 uint32 count = 0;
467 do
468 {
469 Field* fields = result->Fetch();
470
471 uint32 entry = fields[0].GetUInt32();
472
473
474 CreatureTemplate& creatureTemplate = _creatureTemplateStore[entry];
475
476 creatureTemplate.Entry = entry;
477
478 for (uint8 i = 0; i < 3; ++i)
479 creatureTemplate.DifficultyEntry[i] = fields[1 + i].GetUInt32();
480
481 for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i)
482 creatureTemplate.KillCredit[i] = fields[4 + i].GetUInt32();
483
484 creatureTemplate.Modelid1 = fields[6].GetUInt32();
485 creatureTemplate.Modelid2 = fields[7].GetUInt32();
486 creatureTemplate.Modelid3 = fields[8].GetUInt32();
487 creatureTemplate.Modelid4 = fields[9].GetUInt32();
488 creatureTemplate.Name = fields[10].GetString();
489 creatureTemplate.SubName = fields[11].GetString();
490 creatureTemplate.IconName = fields[12].GetString();
491 creatureTemplate.GossipMenuId = fields[13].GetUInt32();
492 creatureTemplate.minlevel = fields[14].GetInt8();
493 creatureTemplate.maxlevel = fields[15].GetInt8();
494 creatureTemplate.expansion = uint32(fields[16].GetInt16());
495 creatureTemplate.expansionUnknown = uint32(fields[17].GetUInt16());
496 creatureTemplate.faction_A = uint32(fields[18].GetUInt16());
497 creatureTemplate.faction_H = uint32(fields[19].GetUInt16());
498 creatureTemplate.npcflag = fields[20].GetUInt32();
499 if (IsCapturableBattlePetNpc(creatureTemplate.Entry))
500 creatureTemplate.npcflag |= UNIT_NPC_FLAG_WILDPET_CAPTURABLE;
501
502 creatureTemplate.speed_walk = fields[21].GetFloat();
503 creatureTemplate.speed_run = fields[22].GetFloat();
504 creatureTemplate.scale = fields[23].GetFloat();
505 creatureTemplate.rank = uint32(fields[24].GetUInt8());
506 creatureTemplate.mindmg = fields[25].GetFloat();
507 creatureTemplate.maxdmg = fields[26].GetFloat();
508 creatureTemplate.dmgschool = uint32(fields[27].GetInt8());
509 creatureTemplate.attackpower = fields[28].GetUInt32();
510 creatureTemplate.dmg_multiplier = fields[29].GetFloat();
511 creatureTemplate.baseattacktime = fields[30].GetUInt32();
512 creatureTemplate.rangeattacktime = fields[31].GetUInt32();
513 creatureTemplate.unit_class = uint32(fields[32].GetUInt8());
514 creatureTemplate.unit_flags = fields[33].GetUInt32();
515 creatureTemplate.unit_flags2 = fields[34].GetUInt32();
516 creatureTemplate.dynamicflags = fields[35].GetUInt32();
517 creatureTemplate.family = uint32(fields[36].GetUInt8());
518 creatureTemplate.trainer_type = uint32(fields[37].GetUInt8());
519 creatureTemplate.trainer_class = uint32(fields[38].GetUInt8());
520 creatureTemplate.trainer_race = uint32(fields[39].GetUInt8());
521 creatureTemplate.minrangedmg = fields[40].GetFloat();
522 creatureTemplate.maxrangedmg = fields[41].GetFloat();
523 creatureTemplate.rangedattackpower = uint32(fields[42].GetUInt16());
524 creatureTemplate.type = uint32(fields[43].GetUInt8());
525 creatureTemplate.type_flags = fields[44].GetUInt32();
526 creatureTemplate.type_flags2 = fields[45].GetUInt32();
527 creatureTemplate.lootid = fields[46].GetUInt32();
528 creatureTemplate.pickpocketLootId = fields[47].GetUInt32();
529 creatureTemplate.SkinLootId = fields[48].GetUInt32();
530
531 for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
532 creatureTemplate.resistance[i] = fields[49 + i - 1].GetInt16();
533
534 for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i)
535 creatureTemplate.spells[i] = fields[55 + i].GetUInt32();
536
537 creatureTemplate.PetSpellDataId = fields[63].GetUInt32();
538 creatureTemplate.VehicleId = fields[64].GetUInt32();
539 creatureTemplate.mingold = fields[65].GetUInt32();
540 creatureTemplate.maxgold = fields[66].GetUInt32();
541 creatureTemplate.AIName = fields[67].GetString();
542 creatureTemplate.MovementType = uint32(fields[68].GetUInt8());
543 creatureTemplate.InhabitType = uint32(fields[69].GetUInt8());
544 creatureTemplate.HoverHeight = fields[70].GetFloat();
545 creatureTemplate.ModHealth = fields[71].GetFloat();
546 creatureTemplate.ModMana = fields[72].GetFloat();
547 creatureTemplate.ModManaExtra = fields[73].GetFloat();
548 creatureTemplate.ModArmor = fields[74].GetFloat();
549 creatureTemplate.RacialLeader = fields[75].GetBool();
550
551 for (uint8 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
552 creatureTemplate.questItems[i] = fields[76 + i].GetUInt32();
553
554 creatureTemplate.movementId = fields[82].GetUInt32();
555 creatureTemplate.RegenHealth = fields[83].GetBool();
556 creatureTemplate.MechanicImmuneMask = fields[84].GetUInt32();
557 creatureTemplate.flags_extra = fields[85].GetUInt32();
558 creatureTemplate.ScriptID = GetScriptId(fields[86].GetCString());
559 creatureTemplate.ModLevel = fields[87].GetBool();
560
561 ++count;
562 } while (result->NextRow());
563
564 // Checking needs to be done after loading because of the difficulty self referencing
565 for (CreatureTemplateContainer::const_iterator itr = _creatureTemplateStore.begin(); itr != _creatureTemplateStore.end(); ++itr)
566 CheckCreatureTemplate(&itr->second);
567
568 SF_LOG_INFO("server.loading", ">> Loaded %u creature definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
569}
570
572{
573 uint32 oldMSTime = getMSTime();
574
575 // 0 1 2 3 4 5 6
576 QueryResult result = WorldDatabase.Query("SELECT entry, path_id, mount, bytes1, bytes2, emote, auras FROM creature_template_addon");
577
578 if (!result)
579 {
580 SF_LOG_INFO("server.loading", ">> Loaded 0 creature template addon definitions. DB table `creature_template_addon` is empty.");
581 return;
582 }
583
584 uint32 count = 0;
585 do
586 {
587 Field* fields = result->Fetch();
588
589 uint32 entry = fields[0].GetUInt32();
590
591 if (!sObjectMgr->GetCreatureTemplate(entry))
592 {
593 SF_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_template_addon`", entry);
594 continue;
595 }
596
597 CreatureAddon& creatureAddon = _creatureTemplateAddonStore[entry];
598
599 creatureAddon.path_id = fields[1].GetUInt32();
600 creatureAddon.mount = fields[2].GetUInt32();
601 creatureAddon.bytes1 = fields[3].GetUInt32();
602 creatureAddon.bytes2 = fields[4].GetUInt32();
603 creatureAddon.emote = fields[5].GetUInt32();
604
605 Tokenizer tokens(fields[6].GetString(), ' ');
606 uint8 i = 0;
607 creatureAddon.auras.resize(tokens.size());
608 for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
609 {
610 SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr)));
611 if (!AdditionalSpellInfo)
612 {
613 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong spell %u defined in `auras` field in `creature_template_addon`.", entry, uint32(atol(*itr)));
614 continue;
615 }
616
617 if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
618 SF_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)));
619
620 creatureAddon.auras[i++] = uint32(atol(*itr));
621 }
622
623 if (creatureAddon.mount)
624 {
625 if (!sCreatureDisplayInfoStore.LookupEntry(creatureAddon.mount))
626 {
627 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid displayInfoId (%u) for mount defined in `creature_template_addon`", entry, creatureAddon.mount);
628 creatureAddon.mount = 0;
629 }
630 }
631
632 if (!sEmotesStore.LookupEntry(creatureAddon.emote))
633 {
634 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid emote (%u) defined in `creature_template_addon`.", entry, creatureAddon.emote);
635 creatureAddon.emote = 0;
636 }
637
638 ++count;
639 } while (result->NextRow());
640
641 SF_LOG_INFO("server.loading", ">> Loaded %u creature template addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
642}
643
645{
646 if (!cInfo)
647 return;
648
649 bool ok = true; // bool to allow continue outside this loop
650 for (uint32 diff = 0; diff < 3 && ok; ++diff)
651 {
652 if (!cInfo->DifficultyEntry[diff])
653 continue;
654 ok = false; // will be set to true at the end of this loop again
655
656 CreatureTemplate const* difficultyInfo = GetCreatureTemplate(cInfo->DifficultyEntry[diff]);
657 if (!difficultyInfo)
658 {
659 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has `difficulty_entry_%u`=%u but creature entry %u does not exist.",
660 cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff]);
661 continue;
662 }
663
664 bool ok2 = true;
665 for (uint32 diff2 = 0; diff2 < 3 && ok2; ++diff2)
666 {
667 ok2 = false;
668 if (_difficultyEntries[diff2].find(cInfo->Entry) != _difficultyEntries[diff2].end())
669 {
670 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) is listed as `difficulty_entry_%u` of another creature, but itself lists %u in `difficulty_entry_%u`.",
671 cInfo->Entry, diff2 + 1, cInfo->DifficultyEntry[diff], diff + 1);
672 continue;
673 }
674
675 if (_difficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != _difficultyEntries[diff2].end())
676 {
677 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) already listed as `difficulty_entry_%u` for another entry.", cInfo->DifficultyEntry[diff], diff2 + 1);
678 continue;
679 }
680
681 if (_hasDifficultyEntries[diff2].find(cInfo->DifficultyEntry[diff]) != _hasDifficultyEntries[diff2].end())
682 {
683 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has `difficulty_entry_%u`=%u but creature entry %u has itself a value in `difficulty_entry_%u`.",
684 cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff], cInfo->DifficultyEntry[diff], diff2 + 1);
685 continue;
686 }
687 ok2 = true;
688 }
689 if (!ok2)
690 continue;
691
692 if (cInfo->unit_class != difficultyInfo->unit_class)
693 {
694 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u, class %u) has different `unit_class` in difficulty %u mode (Entry: %u, class %u).",
695 cInfo->Entry, cInfo->unit_class, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->unit_class);
696 continue;
697 }
698
699 if (cInfo->npcflag != difficultyInfo->npcflag)
700 {
701 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has different `npcflag` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
702 continue;
703 }
704
705 if (cInfo->trainer_class != difficultyInfo->trainer_class)
706 {
707 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has different `trainer_class` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
708 continue;
709 }
710
711 if (cInfo->trainer_race != difficultyInfo->trainer_race)
712 {
713 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has different `trainer_race` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
714 continue;
715 }
716
717 if (cInfo->trainer_type != difficultyInfo->trainer_type)
718 {
719 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has different `trainer_type` in difficulty %u mode (Entry: %u).", cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
720 continue;
721 }
722
723 if (!difficultyInfo->AIName.empty())
724 {
725 SF_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.",
726 cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
727 continue;
728 }
729
730 if (difficultyInfo->ScriptID)
731 {
732 SF_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.",
733 cInfo->Entry, diff + 1, cInfo->DifficultyEntry[diff]);
734 continue;
735 }
736
737 _hasDifficultyEntries[diff].insert(cInfo->Entry);
738 _difficultyEntries[diff].insert(cInfo->DifficultyEntry[diff]);
739 ok = true;
740 }
741
742 FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A);
743 if (!factionTemplate)
744 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing faction_A template (%u).", cInfo->Entry, cInfo->faction_A);
745
746 factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H);
747 if (!factionTemplate)
748 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing faction_H template (%u).", cInfo->Entry, cInfo->faction_H);
749
750 // used later for scale
751 CreatureDisplayInfoEntry const* displayScaleEntry = NULL;
752
753 if (cInfo->Modelid1)
754 {
755 CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid1);
756 if (!displayEntry)
757 {
758 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid1 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid1);
759 const_cast<CreatureTemplate*>(cInfo)->Modelid1 = 0;
760 }
761 else if (!displayScaleEntry)
762 displayScaleEntry = displayEntry;
763
764 CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid1);
765 if (!modelInfo)
766 SF_LOG_ERROR("sql.sql", "No model data exist for `Modelid1` = %u listed by creature (Entry: %u).", cInfo->Modelid1, cInfo->Entry);
767 }
768
769 if (cInfo->Modelid2)
770 {
771 CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid2);
772 if (!displayEntry)
773 {
774 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid2 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid2);
775 const_cast<CreatureTemplate*>(cInfo)->Modelid2 = 0;
776 }
777 else if (!displayScaleEntry)
778 displayScaleEntry = displayEntry;
779
780 CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid2);
781 if (!modelInfo)
782 SF_LOG_ERROR("sql.sql", "No model data exist for `Modelid2` = %u listed by creature (Entry: %u).", cInfo->Modelid2, cInfo->Entry);
783 }
784
785 if (cInfo->Modelid3)
786 {
787 CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid3);
788 if (!displayEntry)
789 {
790 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid3 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid3);
791 const_cast<CreatureTemplate*>(cInfo)->Modelid3 = 0;
792 }
793 else if (!displayScaleEntry)
794 displayScaleEntry = displayEntry;
795
796 CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid3);
797 if (!modelInfo)
798 SF_LOG_ERROR("sql.sql", "No model data exist for `Modelid3` = %u listed by creature (Entry: %u).", cInfo->Modelid3, cInfo->Entry);
799 }
800
801 if (cInfo->Modelid4)
802 {
803 CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->Modelid4);
804 if (!displayEntry)
805 {
806 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing Modelid4 id (%u), this can crash the client.", cInfo->Entry, cInfo->Modelid4);
807 const_cast<CreatureTemplate*>(cInfo)->Modelid4 = 0;
808 }
809 else if (!displayScaleEntry)
810 displayScaleEntry = displayEntry;
811
812 CreatureModelInfo const* modelInfo = GetCreatureModelInfo(cInfo->Modelid4);
813 if (!modelInfo)
814 SF_LOG_ERROR("sql.sql", "No model data exist for `Modelid4` = %u listed by creature (Entry: %u).", cInfo->Modelid4, cInfo->Entry);
815 }
816
817 if (!displayScaleEntry)
818 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) does not have any existing display id in Modelid1/Modelid2/Modelid3/Modelid4.", cInfo->Entry);
819
820 for (int k = 0; k < MAX_KILL_CREDIT; ++k)
821 {
822 if (cInfo->KillCredit[k])
823 {
824 if (!GetCreatureTemplate(cInfo->KillCredit[k]))
825 {
826 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) lists non-existing creature entry %u in `KillCredit%d`.", cInfo->Entry, cInfo->KillCredit[k], k + 1);
827 const_cast<CreatureTemplate*>(cInfo)->KillCredit[k] = 0;
828 }
829 }
830 }
831
832 if (!cInfo->unit_class || ((1 << (cInfo->unit_class - 1)) & CLASSMASK_ALL_CREATURES) == 0)
833 {
834 SF_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);
835 const_cast<CreatureTemplate*>(cInfo)->unit_class = UNIT_CLASS_WARRIOR;
836 }
837
838 if (cInfo->dmgschool >= MAX_SPELL_SCHOOL)
839 {
840 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`.", cInfo->Entry, cInfo->dmgschool);
841 const_cast<CreatureTemplate*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
842 }
843
844 if (cInfo->baseattacktime == 0)
845 const_cast<CreatureTemplate*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
846
847 if (cInfo->rangeattacktime == 0)
848 const_cast<CreatureTemplate*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
849
850 if (cInfo->GossipMenuId == 0 && (cInfo->npcflag & UNIT_NPC_FLAG_GOSSIP))
851 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has [UNIT_NPC_FLAG_GOSSIP] set, but does have (gossip_menu_id: %u) set.", cInfo->Entry, cInfo->GossipMenuId);
852
853 if (cInfo->GossipMenuId > 0 && !(cInfo->npcflag & UNIT_NPC_FLAG_GOSSIP))
854 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has (gossip_menu_id: %u) set, but does not have [UNIT_NPC_FLAG_GOSSIP] set.", cInfo->Entry, cInfo->GossipMenuId);
855
857 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong trainer type %u.", cInfo->Entry, cInfo->trainer_type);
858
859 if (cInfo->speed_walk == 0.0f)
860 {
861 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in speed_walk, set to 1.", cInfo->Entry, cInfo->speed_walk);
862 const_cast<CreatureTemplate*>(cInfo)->speed_walk = 1.0f;
863 }
864
865 if (cInfo->speed_run == 0.0f)
866 {
867 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in speed_run, set to 1.14286.", cInfo->Entry, cInfo->speed_run);
868 const_cast<CreatureTemplate*>(cInfo)->speed_run = 1.14286f;
869 }
870
871 if (cInfo->type && !sCreatureTypeStore.LookupEntry(cInfo->type))
872 {
873 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid creature type (%u) in `type`.", cInfo->Entry, cInfo->type);
874 const_cast<CreatureTemplate*>(cInfo)->type = CREATURE_TYPE_HUMANOID;
875 }
876
877 // must exist or used hidden but used in data horse case
878 if (cInfo->family && !sCreatureFamilyStore.LookupEntry(cInfo->family) && cInfo->family != CREATURE_FAMILY_HORSE_CUSTOM)
879 {
880 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has invalid creature family (%u) in `family`.", cInfo->Entry, cInfo->family);
881 const_cast<CreatureTemplate*>(cInfo)->family = 0;
882 }
883
884 if (cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
885 {
886 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly.", cInfo->Entry, cInfo->InhabitType);
887 const_cast<CreatureTemplate*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
888 }
889
890 if (cInfo->HoverHeight < 0.0f)
891 {
892 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in `HoverHeight`", cInfo->Entry, cInfo->HoverHeight);
893 const_cast<CreatureTemplate*>(cInfo)->HoverHeight = 1.0f;
894 }
895
896 if (cInfo->VehicleId)
897 {
898 VehicleEntry const* vehId = sVehicleStore.LookupEntry(cInfo->VehicleId);
899 if (!vehId)
900 {
901 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has a non-existing VehicleId (%u). This *WILL* cause the client to freeze!", cInfo->Entry, cInfo->VehicleId);
902 const_cast<CreatureTemplate*>(cInfo)->VehicleId = 0;
903 }
904 }
905
906 if (cInfo->PetSpellDataId)
907 {
908 CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
909 if (!spellDataId)
910 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing PetSpellDataId (%u).", cInfo->Entry, cInfo->PetSpellDataId);
911 }
912
913 for (uint8 j = 0; j < CREATURE_MAX_SPELLS; ++j)
914 {
915 if (cInfo->spells[j] && !sSpellMgr->GetSpellInfo(cInfo->spells[j]))
916 {
917 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has non-existing Spell%d (%u), set to 0.", cInfo->Entry, j + 1, cInfo->spells[j]);
918 const_cast<CreatureTemplate*>(cInfo)->spells[j] = 0;
919 }
920 }
921
922 if (cInfo->MovementType >= MAX_DB_MOTION_TYPE)
923 {
924 SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong movement generator type (%u), ignored and set to IDLE.", cInfo->Entry, cInfo->MovementType);
925 const_cast<CreatureTemplate*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
926 }
927
929 if (cInfo->scale <= 0.0f)
930 {
931 if (displayScaleEntry)
932 const_cast<CreatureTemplate*>(cInfo)->scale = displayScaleEntry->scale;
933 else
934 const_cast<CreatureTemplate*>(cInfo)->scale = 1.0f;
935 }
936
937 if (cInfo->expansion > CURRENT_CONTENT_EXP)
938 {
939 SF_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with `exp` %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansion);
940 const_cast<CreatureTemplate*>(cInfo)->expansion = 0;
941 }
942
944 {
945 SF_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with `exp_unk` %u. Ignored and set to 0.", cInfo->Entry, cInfo->expansionUnknown);
946 const_cast<CreatureTemplate*>(cInfo)->expansionUnknown = 0;
947 }
948
949 if (uint32 badFlags = (cInfo->flags_extra & ~CREATURE_FLAG_EXTRA_DB_ALLOWED))
950 {
951 SF_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with disallowed `flags_extra` %u, removing incorrect flag.", cInfo->Entry, badFlags);
952 const_cast<CreatureTemplate*>(cInfo)->flags_extra &= CREATURE_FLAG_EXTRA_DB_ALLOWED;
953 }
954
955 if (cInfo->ModLevel == true)
956 {
957 if (cInfo->minlevel < DEFAULT_MAX_LEVEL)
958 {
959 SF_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with enabled ModLevel and minlevel %u, minlevel set to 90.", cInfo->Entry, cInfo->minlevel);
960 const_cast<CreatureTemplate*>(cInfo)->minlevel = 90;
961 }
962
963 if (cInfo->maxlevel < DEFAULT_MAX_LEVEL)
964 {
965 SF_LOG_ERROR("sql.sql", "Table `creature_template` lists creature (Entry: %u) with enabled ModLevel and maxlevel %u, maxlevel set to 90.", cInfo->Entry, cInfo->maxlevel);
966 const_cast<CreatureTemplate*>(cInfo)->maxlevel = 90;
967 }
968 }
969
970 const_cast<CreatureTemplate*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank);
971}
972
974{
975 uint32 oldMSTime = getMSTime();
976
977 // 0 1 2 3 4 5 6
978 QueryResult result = WorldDatabase.Query("SELECT guid, path_id, mount, bytes1, bytes2, emote, auras FROM creature_addon");
979
980 if (!result)
981 {
982 SF_LOG_INFO("server.loading", ">> Loaded 0 creature addon definitions. DB table `creature_addon` is empty.");
983 return;
984 }
985
986 uint32 count = 0;
987 do
988 {
989 Field* fields = result->Fetch();
990
991 uint32 guid = fields[0].GetUInt32();
992
993 CreatureData const* creData = GetCreatureData(guid);
994 if (!creData)
995 {
996 SF_LOG_ERROR("sql.sql", "Creature (GUID: %u) does not exist but has a record in `creature_addon`", guid);
997 continue;
998 }
999
1000 CreatureAddon& creatureAddon = _creatureAddonStore[guid];
1001
1002 creatureAddon.path_id = fields[1].GetUInt32();
1003 if (creData->movementType == WAYPOINT_MOTION_TYPE && !creatureAddon.path_id)
1004 {
1005 const_cast<CreatureData*>(creData)->movementType = IDLE_MOTION_TYPE;
1006 SF_LOG_ERROR("sql.sql", "Creature (GUID %u) has movement type set to WAYPOINT_MOTION_TYPE but no path assigned", guid);
1007 }
1008
1009 creatureAddon.mount = fields[2].GetUInt32();
1010 creatureAddon.bytes1 = fields[3].GetUInt32();
1011 creatureAddon.bytes2 = fields[4].GetUInt32();
1012 creatureAddon.emote = fields[5].GetUInt32();
1013
1014 Tokenizer tokens(fields[6].GetString(), ' ');
1015 uint8 i = 0;
1016 creatureAddon.auras.resize(tokens.size());
1017 for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
1018 {
1019 SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(uint32(atol(*itr)));
1020 if (!AdditionalSpellInfo)
1021 {
1022 SF_LOG_ERROR("sql.sql", "Creature (GUID: %u) has wrong spell %u defined in `auras` field in `creature_addon`.", guid, uint32(atol(*itr)));
1023 continue;
1024 }
1025
1026 if (AdditionalSpellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
1027 SF_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)));
1028
1029 creatureAddon.auras[i++] = uint32(atol(*itr));
1030 }
1031
1032 if (creatureAddon.mount)
1033 {
1034 if (!sCreatureDisplayInfoStore.LookupEntry(creatureAddon.mount))
1035 {
1036 SF_LOG_ERROR("sql.sql", "Creature (GUID: %u) has invalid displayInfoId (%u) for mount defined in `creature_addon`", guid, creatureAddon.mount);
1037 creatureAddon.mount = 0;
1038 }
1039 }
1040
1041 if (!sEmotesStore.LookupEntry(creatureAddon.emote))
1042 {
1043 SF_LOG_ERROR("sql.sql", "Creature (GUID: %u) has invalid emote (%u) defined in `creature_addon`.", guid, creatureAddon.emote);
1044 creatureAddon.emote = 0;
1045 }
1046
1047 ++count;
1048 } while (result->NextRow());
1049
1050 SF_LOG_INFO("server.loading", ">> Loaded %u creature addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1051}
1052
1054{
1055 CreatureAddonContainer::const_iterator itr = _creatureAddonStore.find(lowguid);
1056 if (itr != _creatureAddonStore.end())
1057 return &(itr->second);
1058
1059 return NULL;
1060}
1061
1063{
1064 CreatureAddonContainer::const_iterator itr = _creatureTemplateAddonStore.find(entry);
1065 if (itr != _creatureTemplateAddonStore.end())
1066 return &(itr->second);
1067
1068 return NULL;
1069}
1070
1072{
1073 EquipmentInfoContainer::const_iterator itr = _equipmentInfoStore.find(entry);
1074 if (itr == _equipmentInfoStore.end())
1075 return NULL;
1076
1077 if (itr->second.empty())
1078 return NULL;
1079
1080 if (id == -1) // select a random element
1081 {
1082 EquipmentInfoContainerInternal::const_iterator ritr = itr->second.begin();
1083 std::advance(ritr, std::rand() % itr->second.size());
1084 id = std::distance(itr->second.begin(), ritr) + 1;
1085 return &ritr->second;
1086 }
1087 else
1088 {
1089 EquipmentInfoContainerInternal::const_iterator itr2 = itr->second.find(id);
1090 if (itr2 != itr->second.end())
1091 return &itr2->second;
1092 }
1093
1094 return NULL;
1095}
1096
1098{
1099 uint32 oldMSTime = getMSTime();
1100
1101 // 0 1 2 3 4
1102 QueryResult result = WorldDatabase.Query("SELECT entry, id, itemEntry1, itemEntry2, itemEntry3 FROM creature_equip_template");
1103
1104 if (!result)
1105 {
1106 SF_LOG_INFO("server.loading", ">> Loaded 0 creature equipment templates. DB table `creature_equip_template` is empty!");
1107 return;
1108 }
1109
1110 uint32 count = 0;
1111 do
1112 {
1113 Field* fields = result->Fetch();
1114
1115 uint32 entry = fields[0].GetUInt32();
1116
1117 if (!sObjectMgr->GetCreatureTemplate(entry))
1118 {
1119 SF_LOG_ERROR("sql.sql", "Creature template (Entry: %u) does not exist but has a record in `creature_equip_template`", entry);
1120 continue;
1121 }
1122
1123 uint8 id = fields[1].GetUInt8();
1124
1125 EquipmentInfo& equipmentInfo = _equipmentInfoStore[entry][id];
1126
1127 equipmentInfo.ItemEntry[0] = fields[2].GetUInt32();
1128 equipmentInfo.ItemEntry[1] = fields[3].GetUInt32();
1129 equipmentInfo.ItemEntry[2] = fields[4].GetUInt32();
1130
1131 for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
1132 {
1133 if (!equipmentInfo.ItemEntry[i])
1134 continue;
1135
1136 ItemEntry const* dbcItem = sItemStore.LookupEntry(equipmentInfo.ItemEntry[i]);
1137
1138 if (!dbcItem)
1139 {
1140 SF_LOG_ERROR("sql.sql", "Unknown item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id=%u, forced to 0.",
1141 equipmentInfo.ItemEntry[i], i + 1, entry, id);
1142 equipmentInfo.ItemEntry[i] = 0;
1143 continue;
1144 }
1145
1146 if (dbcItem->InventoryType != INVTYPE_WEAPON &&
1147 dbcItem->InventoryType != INVTYPE_SHIELD &&
1148 dbcItem->InventoryType != INVTYPE_RANGED &&
1149 dbcItem->InventoryType != INVTYPE_2HWEAPON &&
1152 dbcItem->InventoryType != INVTYPE_HOLDABLE &&
1153 dbcItem->InventoryType != INVTYPE_THROWN &&
1155 {
1156 SF_LOG_ERROR("sql.sql", "Item (entry=%u) in creature_equip_template.itemEntry%u for entry = %u and id = %u is not equipable in a hand, forced to 0.",
1157 equipmentInfo.ItemEntry[i], i + 1, entry, id);
1158 equipmentInfo.ItemEntry[i] = 0;
1159 }
1160 }
1161
1162 ++count;
1163 } while (result->NextRow());
1164
1165 SF_LOG_INFO("server.loading", ">> Loaded %u equipment templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1166}
1167
1169{
1170 CreatureModelContainer::const_iterator itr = _creatureModelStore.find(modelId);
1171 if (itr != _creatureModelStore.end())
1172 return &(itr->second);
1173
1174 return NULL;
1175}
1176
1178{
1179 // Load creature model (display id)
1180 if (data && data->displayid)
1181 return data->displayid;
1182
1183 return cinfo->GetRandomValidModelId();
1184}
1185
1186void ObjectMgr::ChooseCreatureFlags(const CreatureTemplate* cinfo, uint32& npcflag, uint32& unit_flags, uint32& dynamicflags, const CreatureData* data /*= NULL*/)
1187{
1188 npcflag = cinfo->npcflag;
1189 unit_flags = cinfo->unit_flags;
1190 dynamicflags = cinfo->dynamicflags;
1191
1192 if (data)
1193 {
1194 if (data->npcflag)
1195 npcflag = data->npcflag;
1196
1197 if (data->unit_flags)
1198 unit_flags = data->unit_flags;
1199
1200 if (data->dynamicflags)
1201 dynamicflags = data->dynamicflags;
1202 }
1203
1204 if (IsCapturableBattlePetNpc(cinfo->Entry))
1206}
1207
1209{
1210 CreatureModelInfo const* modelInfo = GetCreatureModelInfo(*displayID);
1211 if (!modelInfo)
1212 return NULL;
1213
1214 // If a model for another gender exists, 50% chance to use it
1215 if (modelInfo->modelid_other_gender != 0 && std::rand() % 1 == 0)
1216 {
1217 CreatureModelInfo const* minfo_tmp = GetCreatureModelInfo(modelInfo->modelid_other_gender);
1218 if (!minfo_tmp)
1219 SF_LOG_ERROR("sql.sql", "Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", *displayID, modelInfo->modelid_other_gender);
1220 else
1221 {
1222 // Model ID changed
1223 *displayID = modelInfo->modelid_other_gender;
1224 return minfo_tmp;
1225 }
1226 }
1227
1228 return modelInfo;
1229}
1230
1232{
1233 uint32 oldMSTime = getMSTime();
1234
1235 QueryResult result = WorldDatabase.Query("SELECT modelid, bounding_radius, combat_reach, gender, modelid_other_gender FROM creature_model_info");
1236
1237 if (!result)
1238 {
1239 SF_LOG_INFO("server.loading", ">> Loaded 0 creature model definitions. DB table `creature_model_info` is empty.");
1240 return;
1241 }
1242
1243 _creatureModelStore.rehash(result->GetRowCount());
1244 uint32 count = 0;
1245
1246 do
1247 {
1248 Field* fields = result->Fetch();
1249
1250 uint32 modelId = fields[0].GetUInt32();
1251
1252 CreatureModelInfo& modelInfo = _creatureModelStore[modelId];
1253
1254 modelInfo.bounding_radius = fields[1].GetFloat();
1255 modelInfo.combat_reach = fields[2].GetFloat();
1256 modelInfo.gender = fields[3].GetUInt8();
1257 modelInfo.modelid_other_gender = fields[4].GetUInt32();
1258
1259 // Checks
1260
1261 if (!sCreatureDisplayInfoStore.LookupEntry(modelId))
1262 SF_LOG_ERROR("sql.sql", "Table `creature_model_info` has model for not existed display id (%u).", modelId);
1263
1264 if (modelInfo.gender > GENDER_NONE)
1265 {
1266 SF_LOG_ERROR("sql.sql", "Table `creature_model_info` has wrong gender (%u) for display id (%u).", uint32(modelInfo.gender), modelId);
1267 modelInfo.gender = GENDER_MALE;
1268 }
1269
1270 if (modelInfo.modelid_other_gender && !sCreatureDisplayInfoStore.LookupEntry(modelInfo.modelid_other_gender))
1271 {
1272 SF_LOG_ERROR("sql.sql", "Table `creature_model_info` has not existed alt.gender model (%u) for existed display id (%u).", modelInfo.modelid_other_gender, modelId);
1273 modelInfo.modelid_other_gender = 0;
1274 }
1275
1276 if (modelInfo.combat_reach < 0.1f)
1278
1279 ++count;
1280 } while (result->NextRow());
1281
1282 SF_LOG_INFO("server.loading", ">> Loaded %u creature model based info in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1283}
1284
1286{
1287 uint32 oldMSTime = getMSTime();
1288
1289 _linkedRespawnStore.clear();
1290 // 0 1 2
1291 QueryResult result = WorldDatabase.Query("SELECT guid, linkedGuid, linkType FROM linked_respawn ORDER BY guid ASC");
1292
1293 if (!result)
1294 {
1295 SF_LOG_ERROR("server.loading", ">> Loaded 0 linked respawns. DB table `linked_respawn` is empty.");
1296 return;
1297 }
1298
1299 do
1300 {
1301 Field* fields = result->Fetch();
1302
1303 uint32 guidLow = fields[0].GetUInt32();
1304 uint32 linkedGuidLow = fields[1].GetUInt32();
1305 uint8 linkType = fields[2].GetUInt8();
1306
1307 uint64 guid = 0, linkedGuid = 0;
1308 bool error = false;
1309 switch (linkType)
1310 {
1312 {
1313 const CreatureData* slave = GetCreatureData(guidLow);
1314 if (!slave)
1315 {
1316 SF_LOG_ERROR("sql.sql", "Couldn't get creature data for GUIDLow %u", guidLow);
1317 error = true;
1318 break;
1319 }
1320
1321 const CreatureData* master = GetCreatureData(linkedGuidLow);
1322 if (!master)
1323 {
1324 SF_LOG_ERROR("sql.sql", "Couldn't get creature data for GUIDLow %u", linkedGuidLow);
1325 error = true;
1326 break;
1327 }
1328
1329 const MapEntry* const map = sMapStore.LookupEntry(master->mapid);
1330 if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
1331 {
1332 SF_LOG_ERROR("sql.sql", "Creature '%u' linking to '%u' on an unpermitted map.", guidLow, linkedGuidLow);
1333 error = true;
1334 break;
1335 }
1336
1337 if (!(master->spawnMask & slave->spawnMask)) // they must have a possibility to meet (normal/heroic difficulty)
1338 {
1339 SF_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask", guidLow, linkedGuidLow);
1340 error = true;
1341 break;
1342 }
1343
1344 guid = MAKE_NEW_GUID(guidLow, slave->id, HIGHGUID_UNIT);
1345 linkedGuid = MAKE_NEW_GUID(linkedGuidLow, master->id, HIGHGUID_UNIT);
1346 break;
1347 }
1348 case CREATURE_TO_GO:
1349 {
1350 const CreatureData* slave = GetCreatureData(guidLow);
1351 if (!slave)
1352 {
1353 SF_LOG_ERROR("sql.sql", "Couldn't get creature data for GUIDLow %u", guidLow);
1354 error = true;
1355 break;
1356 }
1357
1358 const GameObjectData* master = GetGOData(linkedGuidLow);
1359 if (!master)
1360 {
1361 SF_LOG_ERROR("sql.sql", "Couldn't get gameobject data for GUIDLow %u", linkedGuidLow);
1362 error = true;
1363 break;
1364 }
1365
1366 const MapEntry* const map = sMapStore.LookupEntry(master->mapid);
1367 if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
1368 {
1369 SF_LOG_ERROR("sql.sql", "Creature '%u' linking to '%u' on an unpermitted map.", guidLow, linkedGuidLow);
1370 error = true;
1371 break;
1372 }
1373
1374 if (!(master->spawnMask & slave->spawnMask)) // they must have a possibility to meet (normal/heroic difficulty)
1375 {
1376 SF_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask", guidLow, linkedGuidLow);
1377 error = true;
1378 break;
1379 }
1380
1381 guid = MAKE_NEW_GUID(guidLow, slave->id, HIGHGUID_UNIT);
1382 linkedGuid = MAKE_NEW_GUID(linkedGuidLow, master->id, HIGHGUID_GAMEOBJECT);
1383 break;
1384 }
1385 case GO_TO_GO:
1386 {
1387 const GameObjectData* slave = GetGOData(guidLow);
1388 if (!slave)
1389 {
1390 SF_LOG_ERROR("sql.sql", "Couldn't get gameobject data for GUIDLow %u", guidLow);
1391 error = true;
1392 break;
1393 }
1394
1395 const GameObjectData* master = GetGOData(linkedGuidLow);
1396 if (!master)
1397 {
1398 SF_LOG_ERROR("sql.sql", "Couldn't get gameobject data for GUIDLow %u", linkedGuidLow);
1399 error = true;
1400 break;
1401 }
1402
1403 const MapEntry* const map = sMapStore.LookupEntry(master->mapid);
1404 if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
1405 {
1406 SF_LOG_ERROR("sql.sql", "Creature '%u' linking to '%u' on an unpermitted map.", guidLow, linkedGuidLow);
1407 error = true;
1408 break;
1409 }
1410
1411 if (!(master->spawnMask & slave->spawnMask)) // they must have a possibility to meet (normal/heroic difficulty)
1412 {
1413 SF_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask", guidLow, linkedGuidLow);
1414 error = true;
1415 break;
1416 }
1417
1418 guid = MAKE_NEW_GUID(guidLow, slave->id, HIGHGUID_GAMEOBJECT);
1419 linkedGuid = MAKE_NEW_GUID(linkedGuidLow, master->id, HIGHGUID_GAMEOBJECT);
1420 break;
1421 }
1422 case GO_TO_CREATURE:
1423 {
1424 const GameObjectData* slave = GetGOData(guidLow);
1425 if (!slave)
1426 {
1427 SF_LOG_ERROR("sql.sql", "Couldn't get gameobject data for GUIDLow %u", guidLow);
1428 error = true;
1429 break;
1430 }
1431
1432 const CreatureData* master = GetCreatureData(linkedGuidLow);
1433 if (!master)
1434 {
1435 SF_LOG_ERROR("sql.sql", "Couldn't get creature data for GUIDLow %u", linkedGuidLow);
1436 error = true;
1437 break;
1438 }
1439
1440 const MapEntry* const map = sMapStore.LookupEntry(master->mapid);
1441 if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
1442 {
1443 SF_LOG_ERROR("sql.sql", "Creature '%u' linking to '%u' on an unpermitted map.", guidLow, linkedGuidLow);
1444 error = true;
1445 break;
1446 }
1447
1448 if (!(master->spawnMask & slave->spawnMask)) // they must have a possibility to meet (normal/heroic difficulty)
1449 {
1450 SF_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask", guidLow, linkedGuidLow);
1451 error = true;
1452 break;
1453 }
1454
1455 guid = MAKE_NEW_GUID(guidLow, slave->id, HIGHGUID_GAMEOBJECT);
1456 linkedGuid = MAKE_NEW_GUID(linkedGuidLow, master->id, HIGHGUID_UNIT);
1457 break;
1458 }
1459 }
1460
1461 if (!error)
1462 _linkedRespawnStore[guid] = linkedGuid;
1463 } while (result->NextRow());
1464
1465 SF_LOG_INFO("server.loading", ">> Loaded " UI64FMTD " linked respawns in %u ms", uint64(_linkedRespawnStore.size()), GetMSTimeDiffToNow(oldMSTime));
1466}
1467
1469{
1470 if (!guidLow)
1471 return false;
1472
1473 const CreatureData* master = GetCreatureData(guidLow);
1474 uint64 guid = MAKE_NEW_GUID(guidLow, master->id, HIGHGUID_UNIT);
1475
1476 if (!linkedGuidLow) // we're removing the linking
1477 {
1478 _linkedRespawnStore.erase(guid);
1479 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CRELINKED_RESPAWN);
1480 stmt->setUInt32(0, guidLow);
1481 WorldDatabase.Execute(stmt);
1482 return true;
1483 }
1484
1485 const CreatureData* slave = GetCreatureData(linkedGuidLow);
1486
1487 const MapEntry* const map = sMapStore.LookupEntry(master->mapid);
1488 if (!map || !map->Instanceable() || (master->mapid != slave->mapid))
1489 {
1490 SF_LOG_ERROR("sql.sql", "Creature '%u' linking to '%u' on an unpermitted map.", guidLow, linkedGuidLow);
1491 return false;
1492 }
1493
1494 if (!(master->spawnMask & slave->spawnMask)) // they must have a possibility to meet (normal/heroic difficulty)
1495 {
1496 SF_LOG_ERROR("sql.sql", "LinkedRespawn: Creature '%u' linking to '%u' with not corresponding spawnMask", guidLow, linkedGuidLow);
1497 return false;
1498 }
1499
1500 uint64 linkedGuid = MAKE_NEW_GUID(linkedGuidLow, slave->id, HIGHGUID_UNIT);
1501
1502 _linkedRespawnStore[guid] = linkedGuid;
1504 stmt->setUInt32(0, guidLow);
1505 stmt->setUInt32(1, linkedGuidLow);
1506 WorldDatabase.Execute(stmt);
1507 return true;
1508}
1509
1511{
1512 uint32 oldMSTime = getMSTime();
1513
1514 _tempSummonDataStore.clear(); // needed for reload case
1515
1516 // 0 1 2 3 4 5 6 7 8 9
1517 QueryResult result = WorldDatabase.Query("SELECT summonerId, summonerType, groupId, entry, position_x, position_y, position_z, orientation, summonType, summonTime FROM creature_summon_groups");
1518
1519 if (!result)
1520 {
1521 SF_LOG_INFO("server.loading", ">> Loaded 0 temp summons. DB table `creature_summon_groups` is empty.");
1522 return;
1523 }
1524
1525 uint32 count = 0;
1526 do
1527 {
1528 Field* fields = result->Fetch();
1529
1530 uint32 summonerId = fields[0].GetUInt32();
1531 SummonerType summonerType = SummonerType(fields[1].GetUInt8());
1532 uint8 group = fields[2].GetUInt8();
1533
1534 switch (summonerType)
1535 {
1537 if (!GetCreatureTemplate(summonerId))
1538 {
1539 SF_LOG_ERROR("sql.sql", "Table `creature_summon_groups` has summoner with non existing entry %u for creature summoner type, skipped.", summonerId);
1540 continue;
1541 }
1542 break;
1544 if (!GetGameObjectTemplate(summonerId))
1545 {
1546 SF_LOG_ERROR("sql.sql", "Table `creature_summon_groups` has summoner with non existing entry %u for gameobject summoner type, skipped.", summonerId);
1547 continue;
1548 }
1549 break;
1551 if (!sMapStore.LookupEntry(summonerId))
1552 {
1553 SF_LOG_ERROR("sql.sql", "Table `creature_summon_groups` has summoner with non existing entry %u for map summoner type, skipped.", summonerId);
1554 continue;
1555 }
1556 break;
1557 default:
1558 SF_LOG_ERROR("sql.sql", "Table `creature_summon_groups` has unhandled summoner type %u for summoner %u, skipped.", uint8(summonerType), summonerId);
1559 continue;
1560 }
1561
1562 TempSummonData data;
1563 data.entry = fields[3].GetUInt32();
1564
1565 if (!GetCreatureTemplate(data.entry))
1566 {
1567 SF_LOG_ERROR("sql.sql", "Table `creature_summon_groups` has creature in group [Summoner ID: %u, Summoner Type: %u, Group ID: %u] with non existing creature entry %u, skipped.", summonerId, uint8(summonerType), group, data.entry);
1568 continue;
1569 }
1570
1571 float posX = fields[4].GetFloat();
1572 float posY = fields[5].GetFloat();
1573 float posZ = fields[6].GetFloat();
1574 float orientation = fields[7].GetFloat();
1575
1576 data.pos.Relocate(posX, posY, posZ, orientation);
1577
1578 data.type = TempSummonType(fields[8].GetUInt8());
1579
1581 {
1582 SF_LOG_ERROR("sql.sql", "Table `creature_summon_groups` has unhandled temp summon type %u in group [Summoner ID: %u, Summoner Type: %u, Group ID: %u] for creature entry %u, skipped.", uint32(data.type), summonerId, uint8(summonerType), group, data.entry);
1583 continue;
1584 }
1585
1586 data.time = fields[9].GetUInt32();
1587
1588 TempSummonGroupKey key(summonerId, summonerType, group);
1589 _tempSummonDataStore[key].push_back(data);
1590
1591 ++count;
1592 } while (result->NextRow());
1593
1594 SF_LOG_INFO("server.loading", ">> Loaded %u temp summons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1595}
1596
1598{
1599 uint32 oldMSTime = getMSTime();
1600
1601 // 0 1 2 3 4 5 6 7 8 9 10
1602 QueryResult result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, "
1603 // 11 12 13 14 15 16 17 18 19 20 21 22 23
1604 "currentwaypoint, curhealth, curmana, MovementType, spawnMask, creature.phaseid, creature.phasegroup, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.dynamicflags "
1605 "FROM creature "
1606 "LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid "
1607 "LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid");
1608
1609 if (!result)
1610 {
1611 SF_LOG_ERROR("server.loading", ">> Loaded 0 creatures. DB table `creature` is empty.");
1612 return;
1613 }
1614
1615 // Build single time for check spawnmask
1616 std::map<uint32, uint32> spawnMasks;
1617 for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i)
1618 if (sMapStore.LookupEntry(i))
1619 for (int k = 0; k < 15; ++k)
1621 spawnMasks[i] |= (1 << k);
1622
1623 _creatureDataStore.rehash(result->GetRowCount());
1624 uint32 count = 0;
1625 do
1626 {
1627 Field* fields = result->Fetch();
1628
1629 uint32 guid = fields[0].GetUInt32();
1630 uint32 entry = fields[1].GetUInt32();
1631
1632 CreatureTemplate const* cInfo = GetCreatureTemplate(entry);
1633 if (!cInfo)
1634 {
1635 SF_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u) with non existing creature entry %u, skipped.", guid, entry);
1636 continue;
1637 }
1638
1639 CreatureData& data = _creatureDataStore[guid];
1640 data.id = entry;
1641 data.mapid = fields[2].GetUInt16();
1642 data.displayid = fields[3].GetUInt32();
1643 data.equipmentId = fields[4].GetInt8();
1644 data.posX = fields[5].GetFloat();
1645 data.posY = fields[6].GetFloat();
1646 data.posZ = fields[7].GetFloat();
1647 data.orientation = fields[8].GetFloat();
1648 data.spawntimesecs = fields[9].GetUInt32();
1649 data.spawndist = fields[10].GetFloat();
1650 data.currentwaypoint = fields[11].GetUInt32();
1651 data.curhealth = fields[12].GetUInt32();
1652 data.curmana = fields[13].GetUInt32();
1653 data.movementType = fields[14].GetUInt8();
1654 data.spawnMask = fields[15].GetUInt32();
1655 data.phaseid = fields[16].GetUInt32();
1656 data.phaseGroup = fields[17].GetUInt32();
1657 int16 gameEvent = fields[18].GetInt8();
1658 uint32 PoolId = fields[19].GetUInt32();
1659 data.npcflag = fields[20].GetUInt32();
1660 data.unit_flags = fields[21].GetUInt32();
1661 data.dynamicflags = fields[22].GetUInt32();
1662
1663 MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid);
1664 if (!mapEntry)
1665 {
1666 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that spawned at not existed map (Id: %u), skipped.", guid, data.mapid);
1667 continue;
1668 }
1669
1670 if (data.spawnMask & ~spawnMasks[data.mapid])
1671 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that have wrong spawn mask %u including not supported difficulty modes for map (Id: %u) spawnMasks[data.mapid]: %u.", guid, data.spawnMask, data.mapid, spawnMasks[data.mapid]);
1672
1673 bool ok = true;
1674 for (uint32 diff = 0; diff < 3 && ok; ++diff)
1675 {
1676 if (_difficultyEntries[diff].find(data.id) != _difficultyEntries[diff].end())
1677 {
1678 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u) that listed as difficulty %u template (entry: %u) in `creature_template`, skipped.",
1679 guid, diff + 1, data.id);
1680 ok = false;
1681 }
1682 }
1683 if (!ok)
1684 continue;
1685
1686 // -1 random, 0 no equipment,
1687 if (data.equipmentId != 0)
1688 {
1689 if (!GetEquipmentInfo(data.id, data.equipmentId))
1690 {
1691 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId);
1692 data.equipmentId = 0;
1693 }
1694 }
1695
1697 {
1698 if (!mapEntry || !mapEntry->IsInstance())
1699 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`flags_extra` including CREATURE_FLAG_EXTRA_INSTANCE_BIND but creature are not in instance.", guid, data.id);
1700 }
1701
1702 if (data.spawndist < 0.0f)
1703 {
1704 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.", guid, data.id);
1705 data.spawndist = 0.0f;
1706 }
1707 else if (data.movementType == RANDOM_MOTION_TYPE)
1708 {
1709 if (data.spawndist == 0.0f)
1710 {
1711 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).", guid, data.id);
1713 }
1714 }
1715 else if (data.movementType == IDLE_MOTION_TYPE)
1716 {
1717 if (data.spawndist != 0.0f)
1718 {
1719 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.", guid, data.id);
1720 data.spawndist = 0.0f;
1721 }
1722 }
1723
1724 if (data.phaseGroup && GetPhasesForGroup(data.phaseGroup).empty())
1725 {
1726 SF_LOG_ERROR("sql.sql", "Table `creature` has creature (GUID: %u Entry: %u) with non-existing `phasegroup` (%u) set, `phasegroup` set to 0", guid, data.id, data.phaseGroup);
1727 data.phaseGroup = 0;
1728 }
1729
1730 if (data.phaseGroup && data.phaseid)
1731 {
1732 SF_LOG_ERROR("sql.sql", "Table `creature` have creature (GUID: %u Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id);
1733 data.phaseGroup = 0;
1734 }
1735
1736 // Add to grid if not managed by the game event or pool system
1737 if (gameEvent == 0 && PoolId == 0)
1738 AddCreatureToGrid(guid, &data);
1739
1740 ++count;
1741 } while (result->NextRow());
1742
1743 SF_LOG_INFO("server.loading", ">> Loaded %u creatures in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1744}
1745
1747{
1748 uint32 mask = data->spawnMask;
1749 for (uint32 i = 0; mask != 0; i++, mask >>= 1)
1750 {
1751 if (mask & 1)
1752 {
1753 CellCoord cellCoord = Skyfire::ComputeCellCoord(data->posX, data->posY);
1754 CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
1755 cell_guids.creatures.insert(guid);
1756 }
1757 }
1758}
1759
1761{
1762 uint32 mask = data->spawnMask;
1763 for (uint32 i = 0; mask != 0; i++, mask >>= 1)
1764 {
1765 if (mask & 1)
1766 {
1767 CellCoord cellCoord = Skyfire::ComputeCellCoord(data->posX, data->posY);
1768 CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
1769 cell_guids.creatures.erase(guid);
1770 }
1771 }
1772}
1773
1774uint32 ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay, float rotation0, float rotation1, float rotation2, float rotation3)
1775{
1776 GameObjectTemplate const* goinfo = GetGameObjectTemplate(entry);
1777 if (!goinfo)
1778 return 0;
1779
1780 Map* map = sMapMgr->CreateBaseMap(mapId);
1781 if (!map)
1782 return 0;
1783
1785 GameObjectData& data = NewGOData(guid);
1786 data.id = entry;
1787 data.mapid = mapId;
1788 data.posX = x;
1789 data.posY = y;
1790 data.posZ = z;
1791 data.orientation = o;
1792 data.rotation0 = rotation0;
1793 data.rotation1 = rotation1;
1794 data.rotation2 = rotation2;
1795 data.rotation3 = rotation3;
1796 data.spawntimesecs = spawntimedelay;
1797 data.animprogress = 100;
1798 data.spawnMask = 1;
1800 data.phaseid = 169;
1801 data.phaseGroup = 0;
1802 data.artKit = goinfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT ? 21 : 0;
1803 data.dbData = false;
1804
1805 AddGameobjectToGrid(guid, &data);
1806
1807 // Spawn if necessary (loaded grids only)
1808 // We use spawn coords to spawn
1809 if (!map->Instanceable() && map->IsGridLoaded(x, y))
1810 {
1811 GameObject* go = new GameObject;
1812 if (!go->LoadGameObjectFromDB(guid, map))
1813 {
1814 SF_LOG_ERROR("misc", "AddGOData: cannot add gameobject entry %u to map", entry);
1815 delete go;
1816 return 0;
1817 }
1818 }
1819
1820 SF_LOG_DEBUG("maps", "AddGOData: dbguid %u entry %u map %u x %f y %f z %f o %f", guid, entry, mapId, x, y, z, o);
1821
1822 return guid;
1823}
1824
1825bool ObjectMgr::MoveCreData(uint32 guid, uint32 mapId, const Position& pos)
1826{
1828 if (!data.id)
1829 return false;
1830
1831 RemoveCreatureFromGrid(guid, &data);
1832 if (data.posX == pos.GetPositionX() && data.posY == pos.GetPositionY() && data.posZ == pos.GetPositionZ())
1833 return true;
1834 data.posX = pos.GetPositionX();
1835 data.posY = pos.GetPositionY();
1836 data.posZ = pos.GetPositionZ();
1837 data.orientation = pos.GetOrientation();
1838 AddCreatureToGrid(guid, &data);
1839
1840 // Spawn if necessary (loaded grids only)
1841 if (Map* map = sMapMgr->CreateBaseMap(mapId))
1842 {
1843 // We use spawn coords to spawn
1844 if (!map->Instanceable() && map->IsGridLoaded(data.posX, data.posY))
1845 {
1846 Creature* creature = new Creature;
1847 if (!creature->LoadCreatureFromDB(guid, map))
1848 {
1849 SF_LOG_ERROR("misc", "MoveCreData: Cannot add creature guid %u to map", guid);
1850 delete creature;
1851 return false;
1852 }
1853 }
1854 }
1855 return true;
1856}
1857
1858uint32 ObjectMgr::AddCreData(uint32 entry, uint32 /*team*/, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay)
1859{
1860 CreatureTemplate const* cInfo = GetCreatureTemplate(entry);
1861 if (!cInfo)
1862 return 0;
1863
1864 uint32 level = cInfo->minlevel == cInfo->maxlevel ? cInfo->minlevel : uint32(std::rand() % (cInfo->maxlevel - cInfo->minlevel + 1) + cInfo->minlevel); // Only used for extracting creature base stats
1865 CreatureBaseStats const* stats = GetCreatureBaseStats(level, cInfo->unit_class);
1866
1869 data.id = entry;
1870 data.mapid = mapId;
1871 data.displayid = 0;
1872 data.equipmentId = 0;
1873 data.posX = x;
1874 data.posY = y;
1875 data.posZ = z;
1876 data.orientation = o;
1877 data.spawntimesecs = spawntimedelay;
1878 data.spawndist = 0;
1879 data.currentwaypoint = 0;
1880 data.curhealth = stats->GenerateHealth(cInfo);
1881 data.curmana = stats->GenerateMana(cInfo);
1882 data.movementType = cInfo->MovementType;
1883 data.spawnMask = 1;
1884 data.phaseid = 169;
1885 data.phaseGroup = 0;
1886 data.dbData = false;
1887 data.npcflag = cInfo->npcflag;
1888 data.unit_flags = cInfo->unit_flags;
1889 data.dynamicflags = cInfo->dynamicflags;
1890
1891 AddCreatureToGrid(guid, &data);
1892
1893 // Spawn if necessary (loaded grids only)
1894 if (Map* map = sMapMgr->CreateBaseMap(mapId))
1895 {
1896 // We use spawn coords to spawn
1897 if (!map->Instanceable() && !map->IsRemovalGrid(x, y))
1898 {
1899 Creature* creature = new Creature;
1900 if (!creature->LoadCreatureFromDB(guid, map))
1901 {
1902 SF_LOG_ERROR("misc", "AddCreature: Cannot add creature entry %u to map", entry);
1903 delete creature;
1904 return 0;
1905 }
1906 }
1907 }
1908
1909 return guid;
1910}
1911
1913{
1914 uint32 oldMSTime = getMSTime();
1915
1916 uint32 count = 0;
1917
1918 // 0 1 2 3 4 5 6
1919 QueryResult result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, "
1920 // 7 8 9 10 11 12 13 14 15 16 17 18
1921 "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, phaseid, phasegroup, eventEntry, pool_entry "
1922 "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid "
1923 "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid");
1924
1925 if (!result)
1926 {
1927 SF_LOG_ERROR("server.loading", ">> Loaded 0 gameobjects. DB table `gameobject` is empty.");
1928 return;
1929 }
1930
1931 // build single time for check spawnmask
1932 std::map<uint32, uint32> spawnMasks;
1933 for (uint32 i = 0; i < sMapStore.GetNumRows(); ++i)
1934 if (sMapStore.LookupEntry(i))
1935 for (int k = 0; k < 15; ++k)
1937 spawnMasks[i] |= (1 << k);
1938
1939 _gameObjectDataStore.rehash(result->GetRowCount());
1940 do
1941 {
1942 Field* fields = result->Fetch();
1943
1944 uint32 guid = fields[0].GetUInt32();
1945 uint32 entry = fields[1].GetUInt32();
1946
1947 GameObjectTemplate const* gInfo = GetGameObjectTemplate(entry);
1948 if (!gInfo)
1949 {
1950 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u) with non existing gameobject entry %u, skipped.", guid, entry);
1951 continue;
1952 }
1953
1954 if (!gInfo->displayId)
1955 {
1956 switch (gInfo->type)
1957 {
1960 break;
1961 default:
1962 SF_LOG_ERROR("sql.sql", "Gameobject (GUID: %u Entry %u GoType: %u) doesn't have a displayId (%u), not loaded.", guid, entry, gInfo->type, gInfo->displayId);
1963 break;
1964 }
1965 }
1966
1967 if (gInfo->displayId && !sGameObjectDisplayInfoStore.LookupEntry(gInfo->displayId))
1968 {
1969 SF_LOG_ERROR("sql.sql", "Gameobject (GUID: %u Entry %u GoType: %u) has an invalid displayId (%u), not loaded.", guid, entry, gInfo->type, gInfo->displayId);
1970 continue;
1971 }
1972
1974
1975 data.id = entry;
1976 data.mapid = fields[2].GetUInt16();
1977 data.posX = fields[3].GetFloat();
1978 data.posY = fields[4].GetFloat();
1979 data.posZ = fields[5].GetFloat();
1980 data.orientation = fields[6].GetFloat();
1981 data.rotation0 = fields[7].GetFloat();
1982 data.rotation1 = fields[8].GetFloat();
1983 data.rotation2 = fields[9].GetFloat();
1984 data.rotation3 = fields[10].GetFloat();
1985 data.spawntimesecs = fields[11].GetInt32();
1986
1987 MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid);
1988 if (!mapEntry)
1989 {
1990 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) spawned on a non-existed map (Id: %u), skip", guid, data.id, data.mapid);
1991 continue;
1992 }
1993
1994 if (data.spawntimesecs == 0 && gInfo->IsDespawnAtAction())
1995 {
1996 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but the gameobejct is marked as despawnable at action.", guid, data.id);
1997 }
1998
1999 data.animprogress = fields[12].GetUInt8();
2000 data.artKit = 0;
2001
2002 uint32 go_state = fields[13].GetUInt8();
2003 switch (GOState(go_state))
2004 {
2010 break;
2011 default:
2012 {
2013 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid `state` (%u) value, skip", guid, data.id, go_state);
2014 continue;
2015 }
2016 break;
2017 }
2018 data.go_state = GOState(go_state);
2019
2020 data.spawnMask = fields[14].GetUInt8();
2021
2022 if (data.spawnMask & ~spawnMasks[data.mapid])
2023 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) that has wrong spawn mask %u including not supported difficulty modes for map (Id: %u), skip", guid, data.id, data.spawnMask, data.mapid);
2024
2025 data.phaseid = fields[15].GetUInt32();
2026 data.phaseGroup = fields[16].GetUInt32();
2027 int16 gameEvent = fields[17].GetInt8();
2028 uint32 PoolId = fields[18].GetUInt32();
2029
2030 if (data.phaseGroup && GetPhasesForGroup(data.phaseGroup).empty())
2031 {
2032 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with non-existing `phasegroup` (%u) set, `phasegroup` set to 0", guid, data.id, data.phaseGroup);
2033 data.phaseGroup = 0;
2034 }
2035
2036 if (data.phaseGroup && data.phaseid)
2037 {
2038 SF_LOG_ERROR("sql.sql", "Table `gameobject` have gameobject (GUID: %u Entry: %u) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0", guid, data.id);
2039 data.phaseGroup = 0;
2040 }
2041
2042 if (data.rotation2 < -1.0f || data.rotation2 > 1.0f)
2043 {
2044 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid rotation2 (%f) value, skip", guid, data.id, data.rotation2);
2045 continue;
2046 }
2047
2048 if (data.rotation3 < -1.0f || data.rotation3 > 1.0f)
2049 {
2050 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid rotation3 (%f) value, skip", guid, data.id, data.rotation3);
2051 continue;
2052 }
2053
2054 if (!MapManager::IsValidMapCoord(data.mapid, data.posX, data.posY, data.posZ, data.orientation))
2055 {
2056 SF_LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid coordinates, skip", guid, data.id);
2057 continue;
2058 }
2059
2060 if (gInfo->type == GAMEOBJECT_TYPE_TRANSPORT)
2061 {
2062 uint32 const transportEntry = sTransportMgr->GetLocalTransportEntry(gInfo->entry);
2063 uint32 const allowedSpawnMask = LegacyTransport::GetAllowedSpawnMask(data.id, data.mapid, data.spawnMask);
2064 if (allowedSpawnMask)
2065 {
2066 if (TransportAnimation const* animationInfo = sTransportMgr->GetTransportAnimInfo(transportEntry))
2067 {
2068 LegacyTransport::LogRegisteredSpawn({ guid, data.id, transportEntry, data.mapid, allowedSpawnMask, data.posX, data.posY, data.posZ, data.orientation, animationInfo->TotalTime, uint32(animationInfo->Path.size()) });
2069 sTransportMgr->AddLocalTransportSpawn(data.mapid, allowedSpawnMask, guid);
2070 }
2071 else
2072 LegacyTransport::LogMissingAnimationData(guid, data.id, transportEntry);
2073 }
2074 }
2075 else if (gameEvent == 0 && PoolId == 0) // if not this is to be managed by GameEvent System or Pool system
2076 AddGameobjectToGrid(guid, &data);
2077 ++count;
2078 } while (result->NextRow());
2079
2080 SF_LOG_INFO("server.loading", ">> Loaded %lu gameobjects in %u ms", (unsigned long)_gameObjectDataStore.size(), GetMSTimeDiffToNow(oldMSTime));
2081}
2082
2084{
2085 uint8 mask = data->spawnMask;
2086 for (uint8 i = 0; mask != 0; i++, mask >>= 1)
2087 {
2088 if (mask & 1)
2089 {
2090 CellCoord cellCoord = Skyfire::ComputeCellCoord(data->posX, data->posY);
2091 CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
2092 cell_guids.gameobjects.insert(guid);
2093 }
2094 }
2095}
2096
2098{
2099 uint8 mask = data->spawnMask;
2100 for (uint8 i = 0; mask != 0; i++, mask >>= 1)
2101 {
2102 if (mask & 1)
2103 {
2104 CellCoord cellCoord = Skyfire::ComputeCellCoord(data->posX, data->posY);
2105 CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(data->mapid, i)][cellCoord.GetId()];
2106 cell_guids.gameobjects.erase(guid);
2107 }
2108 }
2109}
2110
2112{
2113 uint64 guid = MAKE_NEW_GUID(lowguid, 0, HIGHGUID_PLAYER);
2114 return ObjectAccessor::FindPlayer(guid);
2115}
2116
2117// name must be checked to correctness (if received) before call this function
2118uint64 ObjectMgr::GetPlayerGUIDByName(std::string const& name) const
2119{
2120 uint64 guid = 0;
2121
2122 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUID_BY_NAME);
2123
2124 stmt->setString(0, name);
2125
2126 PreparedQueryResult result = CharacterDatabase.Query(stmt);
2127
2128 if (result)
2129 guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
2130
2131 return guid;
2132}
2133
2134bool ObjectMgr::GetPlayerNameByGUID(uint64 guid, std::string& name) const
2135{
2136 // prevent DB access for online player
2137 if (Player* player = ObjectAccessor::FindPlayer(guid))
2138 {
2139 name = player->GetName();
2140 return true;
2141 }
2142
2143 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_NAME);
2144
2145 stmt->setUInt32(0, GUID_LOPART(guid));
2146
2147 PreparedQueryResult result = CharacterDatabase.Query(stmt);
2148
2149 if (result)
2150 {
2151 name = (*result)[0].GetString();
2152 return true;
2153 }
2154
2155 return false;
2156}
2157
2159{
2160 // prevent DB access for online player
2161 if (Player* player = ObjectAccessor::FindPlayer(guid))
2162 {
2163 return Player::TeamForRace(player->getRace());
2164 }
2165
2166 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_RACE);
2167
2168 stmt->setUInt32(0, GUID_LOPART(guid));
2169
2170 PreparedQueryResult result = CharacterDatabase.Query(stmt);
2171
2172 if (result)
2173 {
2174 uint8 race = (*result)[0].GetUInt8();
2175 return Player::TeamForRace(race);
2176 }
2177
2178 return 0;
2179}
2180
2182{
2183 // prevent DB access for online player
2184 if (Player* player = ObjectAccessor::FindPlayer(guid))
2185 {
2186 return player->GetSession()->GetAccountId();
2187 }
2188
2189 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_BY_GUID);
2190
2191 stmt->setUInt32(0, GUID_LOPART(guid));
2192
2193 PreparedQueryResult result = CharacterDatabase.Query(stmt);
2194
2195 if (result)
2196 {
2197 uint32 acc = (*result)[0].GetUInt32();
2198 return acc;
2199 }
2200
2201 return 0;
2202}
2203
2205{
2206 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_BY_NAME);
2207
2208 stmt->setString(0, name);
2209
2210 PreparedQueryResult result = CharacterDatabase.Query(stmt);
2211
2212 if (result)
2213 {
2214 uint32 acc = (*result)[0].GetUInt32();
2215 return acc;
2216 }
2217
2218 return 0;
2219}
2220
2222{
2223 uint32 oldMSTime = getMSTime();
2224
2225 _itemLocaleStore.clear(); // need for reload case
2226
2227 QueryResult result = WorldDatabase.Query("SELECT entry, name_loc1, description_loc1, name_loc2, description_loc2, name_loc3, description_loc3, name_loc4, description_loc4, name_loc5, description_loc5, name_loc6, description_loc6, name_loc7, description_loc7, name_loc8, description_loc8, name_loc9, description_loc9, name_loc10, description_loc10, name_loc11, description_loc11 FROM locales_item");
2228
2229 if (!result)
2230 return;
2231
2232 do
2233 {
2234 Field* fields = result->Fetch();
2235
2236 uint32 entry = fields[0].GetUInt32();
2237
2238 ItemLocale& data = _itemLocaleStore[entry];
2239
2240 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
2241 {
2242 LocaleConstant locale = (LocaleConstant)i;
2243 AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.Name);
2244 AddLocaleString(fields[1 + 2 * (i - 1) + 1].GetString(), locale, data.Description);
2245 }
2246 } while (result->NextRow());
2247
2248 SF_LOG_INFO("server.loading", ">> Loaded %lu Item locale strings in %u ms", (unsigned long)_itemLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
2249}
2250
2251void FillItemDamageFields(float* minDamage, float* maxDamage, float* dps, uint32 itemLevel, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32 delay, float statScalingFactor, uint32 inventoryType, uint32 flags2)
2252{
2253 *minDamage = *maxDamage = *dps = 0.0f;
2254 if (itemClass != ITEM_CLASS_WEAPON || quality > ITEM_QUALITY_ARTIFACT)
2255 return;
2256
2257 DBCStorage<ItemDamageEntry>* store = NULL;
2258 // get the right store here
2259 if (inventoryType > 0xD + 13)
2260 return;
2261
2262 switch (inventoryType)
2263 {
2264 case INVTYPE_AMMO:
2265 store = &sItemDamageAmmoStore;
2266 break;
2267 case INVTYPE_2HWEAPON:
2268 if (flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON)
2270 else
2271 store = &sItemDamageTwoHandStore;
2272 break;
2273 case INVTYPE_RANGED:
2274 case INVTYPE_THROWN:
2276 switch (itemSubClass)
2277 {
2279 store = &sItemDamageWandStore;
2280 break;
2282 store = &sItemDamageThrownStore;
2283 break;
2287 store = &sItemDamageRangedStore;
2288 break;
2289 default:
2290 return;
2291 }
2292 break;
2293 case INVTYPE_WEAPON:
2296 if (flags2 & ITEM_FLAGS_EXTRA_CASTER_WEAPON)
2298 else
2299 store = &sItemDamageOneHandStore;
2300 break;
2301 default:
2302 return;
2303 }
2304
2305 if (!store)
2306 return;
2307
2308 ItemDamageEntry const* damageInfo = store->LookupEntry(itemLevel);
2309 if (!damageInfo)
2310 return;
2311
2312 *dps = damageInfo->DPS[quality];
2313 float avgDamage = *dps * delay * 0.001f;
2314 *minDamage = (statScalingFactor * -0.5f + 1.0f) * avgDamage;
2315 *maxDamage = floor(float(avgDamage * (statScalingFactor * 0.5f + 1.0f) + 0.5f));
2316}
2317
2318uint32 FillMaxDurability(uint32 itemClass, uint32 itemSubClass, uint32 inventoryType, uint32 quality, uint32 itemLevel)
2319{
2320 if (itemClass != ITEM_CLASS_ARMOR && itemClass != ITEM_CLASS_WEAPON)
2321 return 0;
2322
2323 static float const qualityMultipliers[MAX_ITEM_QUALITY] =
2324 {
2325 1.0f, 1.0f, 1.0f, 1.17f, 1.37f, 1.68f, 0.0f, 0.0f
2326 };
2327
2328 static float const armorMultipliers[MAX_INVTYPE] =
2329 {
2330 0.00f, // INVTYPE_NON_EQUIP
2331 0.59f, // INVTYPE_HEAD
2332 0.00f, // INVTYPE_NECK
2333 0.59f, // INVTYPE_SHOULDERS
2334 0.00f, // INVTYPE_BODY
2335 1.00f, // INVTYPE_CHEST
2336 0.35f, // INVTYPE_WAIST
2337 0.75f, // INVTYPE_LEGS
2338 0.49f, // INVTYPE_FEET
2339 0.35f, // INVTYPE_WRISTS
2340 0.35f, // INVTYPE_HANDS
2341 0.00f, // INVTYPE_FINGER
2342 0.00f, // INVTYPE_TRINKET
2343 0.00f, // INVTYPE_WEAPON
2344 1.00f, // INVTYPE_SHIELD
2345 0.00f, // INVTYPE_RANGED
2346 0.00f, // INVTYPE_CLOAK
2347 0.00f, // INVTYPE_2HWEAPON
2348 0.00f, // INVTYPE_BAG
2349 0.00f, // INVTYPE_TABARD
2350 1.00f, // INVTYPE_ROBE
2351 0.00f, // INVTYPE_WEAPONMAINHAND
2352 0.00f, // INVTYPE_WEAPONOFFHAND
2353 0.00f, // INVTYPE_HOLDABLE
2354 0.00f, // INVTYPE_AMMO
2355 0.00f, // INVTYPE_THROWN
2356 0.00f, // INVTYPE_RANGEDRIGHT
2357 0.00f, // INVTYPE_QUIVER
2358 0.00f, // INVTYPE_RELIC
2359 };
2360
2361 static float const weaponMultipliers[MAX_ITEM_SUBCLASS_WEAPON] =
2362 {
2363 0.89f, // ITEM_SUBCLASS_WEAPON_AXE
2364 1.03f, // ITEM_SUBCLASS_WEAPON_AXE2
2365 0.77f, // ITEM_SUBCLASS_WEAPON_BOW
2366 0.77f, // ITEM_SUBCLASS_WEAPON_GUN
2367 0.89f, // ITEM_SUBCLASS_WEAPON_MACE
2368 1.03f, // ITEM_SUBCLASS_WEAPON_MACE2
2369 1.03f, // ITEM_SUBCLASS_WEAPON_POLEARM
2370 0.89f, // ITEM_SUBCLASS_WEAPON_SWORD
2371 1.03f, // ITEM_SUBCLASS_WEAPON_SWORD2
2372 0.00f, // ITEM_SUBCLASS_WEAPON_Obsolete
2373 1.03f, // ITEM_SUBCLASS_WEAPON_STAFF
2374 0.00f, // ITEM_SUBCLASS_WEAPON_EXOTIC
2375 0.00f, // ITEM_SUBCLASS_WEAPON_EXOTIC2
2376 0.64f, // ITEM_SUBCLASS_WEAPON_FIST_WEAPON
2377 0.00f, // ITEM_SUBCLASS_WEAPON_MISCELLANEOUS
2378 0.64f, // ITEM_SUBCLASS_WEAPON_DAGGER
2379 0.64f, // ITEM_SUBCLASS_WEAPON_THROWN
2380 0.00f, // ITEM_SUBCLASS_WEAPON_SPEAR
2381 0.77f, // ITEM_SUBCLASS_WEAPON_CROSSBOW
2382 0.64f, // ITEM_SUBCLASS_WEAPON_WAND
2383 0.64f, // ITEM_SUBCLASS_WEAPON_FISHING_POLE
2384 };
2385
2386 float levelPenalty = 1.0f;
2387 if (itemLevel <= 28)
2388 levelPenalty = 0.966f - float(28u - itemLevel) / 54.0f;
2389
2390 if (itemClass == ITEM_CLASS_ARMOR)
2391 {
2392 if (inventoryType > INVTYPE_ROBE)
2393 return 0;
2394
2395 return 5 * uint32(23.0f * qualityMultipliers[quality] * armorMultipliers[inventoryType] * levelPenalty + 0.5f);
2396 }
2397
2398 return 5 * uint32(17.0f * qualityMultipliers[quality] * weaponMultipliers[itemSubClass] * levelPenalty + 0.5f);
2399};
2400
2401void FillDisenchantFields(uint32* disenchantID, uint32* requiredDisenchantSkill, ItemTemplate const& itemTemplate)
2402{
2403 *disenchantID = 0;
2404 *(int32*)requiredDisenchantSkill = -1;
2405 if ((itemTemplate.Flags & (ITEM_PROTO_FLAG_CONJURED | ITEM_PROTO_FLAG_UNK6)) ||
2406 itemTemplate.Bonding == BIND_QUEST_ITEM || itemTemplate.Area || itemTemplate.Map ||
2407 itemTemplate.Stackable > 1 ||
2408 itemTemplate.Quality < ITEM_QUALITY_UNCOMMON || itemTemplate.Quality > ITEM_QUALITY_EPIC ||
2409 !(itemTemplate.Class == ITEM_CLASS_ARMOR || itemTemplate.Class == ITEM_CLASS_WEAPON) ||
2410 !(Item::GetSpecialPrice(&itemTemplate) || sItemCurrencyCostStore.LookupEntry(itemTemplate.ItemId)))
2411 return;
2412
2413 for (uint32 i = 0; i < sItemDisenchantLootStore.GetNumRows(); ++i)
2414 {
2415 ItemDisenchantLootEntry const* disenchant = sItemDisenchantLootStore.LookupEntry(i);
2416 if (!disenchant)
2417 continue;
2418
2419 if (disenchant->ItemClass == itemTemplate.Class &&
2420 disenchant->ItemQuality == itemTemplate.Quality &&
2421 disenchant->MinItemLevel <= itemTemplate.ItemLevel &&
2422 disenchant->MaxItemLevel >= itemTemplate.ItemLevel)
2423 {
2424 if (disenchant->Id == 60 || disenchant->Id == 61) // epic item disenchant ilvl range 66-99 (classic)
2425 {
2426 if (itemTemplate.RequiredLevel > 60 || itemTemplate.RequiredSkillRank > 300)
2427 continue; // skip to epic item disenchant ilvl range 90-199 (TBC)
2428 }
2429 else if (disenchant->Id == 66 || disenchant->Id == 67) // epic item disenchant ilvl range 90-199 (TBC)
2430 {
2431 if (itemTemplate.RequiredLevel <= 60 || (itemTemplate.RequiredSkill && itemTemplate.RequiredSkillRank <= 300))
2432 continue;
2433 }
2434
2435 *disenchantID = disenchant->Id;
2436 *requiredDisenchantSkill = disenchant->RequiredDisenchantSkill;
2437 return;
2438 }
2439 }
2440}
2441
2443{
2444 uint32 oldMSTime = getMSTime();
2445 uint32 sparseCount = 0;
2446 uint32 dbCount = 0;
2447
2448 for (uint32 itemId = 0; itemId < sItemSparseStore.GetNumRows(); ++itemId)
2449 {
2450 ItemSparseEntry const* sparse = sItemSparseStore.LookupEntry(itemId);
2451 ItemEntry const* db2Data = sItemStore.LookupEntry(itemId);
2452 if (!sparse || !db2Data)
2453 continue;
2454
2455 ItemTemplate& itemTemplate = _itemTemplateStore[itemId];
2456
2457 itemTemplate.ItemId = itemId;
2458 itemTemplate.Class = db2Data->Class;
2459 itemTemplate.SubClass = db2Data->SubClass;
2460 itemTemplate.SoundOverrideSubclass = db2Data->SoundOverrideSubclass;
2461 itemTemplate.Name1 = sparse->Name->Str[sWorld->GetDefaultDbcLocale()];
2462 itemTemplate.DisplayInfoID = db2Data->DisplayId;
2463 itemTemplate.Quality = sparse->Quality;
2464 itemTemplate.Flags = sparse->Flags;
2465 itemTemplate.Flags2 = sparse->Flags2;
2466 itemTemplate.Flags3 = sparse->Flags3;
2467 itemTemplate.Unk430_1 = sparse->Unk430_1;
2468 itemTemplate.Unk430_2 = sparse->Unk430_2;
2469 itemTemplate.BuyCount = std::max(sparse->BuyCount, 1u);
2470 itemTemplate.BuyPrice = sparse->BuyPrice;
2471 itemTemplate.SellPrice = sparse->SellPrice;
2472 itemTemplate.InventoryType = db2Data->InventoryType;
2473 itemTemplate.AllowableClass = sparse->AllowableClass;
2474 itemTemplate.AllowableRace = sparse->AllowableRace;
2475 itemTemplate.ItemLevel = sparse->ItemLevel;
2476 itemTemplate.RequiredLevel = sparse->RequiredLevel;
2477 itemTemplate.RequiredSkill = sparse->RequiredSkill;
2478 itemTemplate.RequiredSkillRank = sparse->RequiredSkillRank;
2479 itemTemplate.RequiredSpell = sparse->RequiredSpell;
2480 itemTemplate.RequiredHonorRank = sparse->RequiredHonorRank;
2481 itemTemplate.RequiredCityRank = sparse->RequiredCityRank;
2483 itemTemplate.RequiredReputationRank = sparse->RequiredReputationRank;
2484 itemTemplate.MaxCount = sparse->MaxCount;
2485 itemTemplate.Stackable = sparse->Stackable;
2486 itemTemplate.ContainerSlots = sparse->ContainerSlots;
2487
2488 for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
2489 {
2490 itemTemplate.ItemStat[i].ItemStatType = sparse->ItemStatType[i];
2491 itemTemplate.ItemStat[i].ItemStatValue = sparse->ItemStatValue[i];
2492 itemTemplate.ItemStat[i].ItemStatUnk1 = sparse->ItemStatUnk1[i];
2493 itemTemplate.ItemStat[i].ItemStatUnk2 = sparse->ItemStatUnk2[i];
2494 }
2495
2496 itemTemplate.ScalingStatDistribution = sparse->ScalingStatDistribution;
2497
2498 // cache item damage
2499 FillItemDamageFields(&itemTemplate.DamageMin, &itemTemplate.DamageMax, &itemTemplate.DPS, sparse->ItemLevel,
2500 db2Data->Class, db2Data->SubClass, sparse->Quality, sparse->Delay, sparse->StatScalingFactor,
2501 sparse->InventoryType, sparse->Flags2);
2502
2503 itemTemplate.DamageType = sparse->DamageType;
2504
2505 itemTemplate.Delay = sparse->Delay;
2506 itemTemplate.RangedModRange = sparse->RangedModRange;
2507
2508 for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
2509 {
2510 itemTemplate.Spells[i].SpellId = sparse->SpellId[i];
2511 itemTemplate.Spells[i].SpellTrigger = sparse->SpellTrigger[i];
2512 itemTemplate.Spells[i].SpellCharges = sparse->SpellCharges[i];
2513 itemTemplate.Spells[i].SpellCooldown = sparse->SpellCooldown[i];
2514 itemTemplate.Spells[i].SpellCategory = sparse->SpellCategory[i];
2515 itemTemplate.Spells[i].SpellCategoryCooldown = sparse->SpellCategoryCooldown[i];
2516 }
2517
2518 itemTemplate.SpellPPMRate = 0.0f;
2519 itemTemplate.Bonding = sparse->Bonding;
2520 itemTemplate.Description = sparse->Description->Str[sWorld->GetDefaultDbcLocale()];
2521 itemTemplate.PageText = sparse->PageText;
2522 itemTemplate.LanguageID = sparse->LanguageID;
2523 itemTemplate.PageMaterial = sparse->PageMaterial;
2524 itemTemplate.StartQuest = sparse->StartQuest;
2525 itemTemplate.LockID = sparse->LockID;
2526 itemTemplate.Material = sparse->Material;
2527 itemTemplate.Sheath = sparse->Sheath;
2528 itemTemplate.RandomProperty = sparse->RandomProperty;
2529 itemTemplate.RandomSuffix = sparse->RandomSuffix;
2530 itemTemplate.ItemSet = sparse->ItemSet;
2531 itemTemplate.MaxDurability = FillMaxDurability(db2Data->Class, db2Data->SubClass, sparse->InventoryType, sparse->Quality, sparse->ItemLevel);
2532 itemTemplate.Area = sparse->Area;
2533 itemTemplate.Map = sparse->Map;
2534 itemTemplate.BagFamily = sparse->BagFamily;
2535 itemTemplate.TotemCategory = sparse->TotemCategory;
2536
2537 for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
2538 {
2539 itemTemplate.Socket[i].Color = sparse->Color[i];
2540 itemTemplate.Socket[i].Content = sparse->Content[i];
2541 }
2542
2543 itemTemplate.socketBonus = sparse->SocketBonus;
2544 itemTemplate.GemProperties = sparse->GemProperties;
2545 FillDisenchantFields(&itemTemplate.DisenchantID, &itemTemplate.RequiredDisenchantSkill, itemTemplate);
2546
2547 itemTemplate.ArmorDamageModifier = sparse->ArmorDamageModifier;
2548 itemTemplate.Duration = sparse->Duration;
2549 itemTemplate.ItemLimitCategory = sparse->ItemLimitCategory;
2550 itemTemplate.HolidayId = sparse->HolidayId;
2551 itemTemplate.StatScalingFactor = sparse->StatScalingFactor;
2552 itemTemplate.CurrencySubstitutionId = sparse->CurrencySubstitutionId;
2554 itemTemplate.ScriptId = 0;
2555 itemTemplate.FoodType = 0;
2556 itemTemplate.MinMoneyLoot = 0;
2557 itemTemplate.MaxMoneyLoot = 0;
2558 ++sparseCount;
2559 }
2560
2561 // Load missing items from item_template AND overwrite data from Item-sparse.db2 (item_template is supposed to contain Item-sparse.adb data)
2562 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
2563 QueryResult result = WorldDatabase.Query("SELECT entry, Class, SubClass, SoundOverrideSubclass, Name, DisplayId, Quality, Flags, FlagsExtra, Flags3, Unk430_1, Unk430_2, BuyCount, BuyPrice, SellPrice, "
2564 // 15 16 17 18 19 20 21 22
2565 "InventoryType, AllowableClass, AllowableRace, ItemLevel, RequiredLevel, RequiredSkill, RequiredSkillRank, RequiredSpell, "
2566 // 23 24 25 26 27 28 29
2567 "RequiredHonorRank, RequiredCityRank, RequiredReputationFaction, RequiredReputationRank, MaxCount, Stackable, ContainerSlots, "
2568 // 30 31 32 33 34 35 36 37
2569 "stat_type1, stat_value1, stat_unk1_1, stat_unk2_1, stat_type2, stat_value2, stat_unk1_2, stat_unk2_2, "
2570 // 38 39 40 41 42 43 44 45
2571 "stat_type3, stat_value3, stat_unk1_3, stat_unk2_3, stat_type4, stat_value4, stat_unk1_4, stat_unk2_4, "
2572 // 46 47 48 49 50 51 52 53
2573 "stat_type5, stat_value5, stat_unk1_5, stat_unk2_5, stat_type6, stat_value6, stat_unk1_6, stat_unk2_6, "
2574 // 54 55 56 57 58 59 60 61
2575 "stat_type7, stat_value7, stat_unk1_7, stat_unk2_7, stat_type8, stat_value8, stat_unk1_8, stat_unk2_8, "
2576 // 62 63 64 65 66 67 68 69
2577 "stat_type9, stat_value9, stat_unk1_9, stat_unk2_9, stat_type10, stat_value10, stat_unk1_10, stat_unk2_10, "
2578 // 70 71 72 73
2579 "ScalingStatDistribution, DamageType, Delay, RangedModRange, "
2580 // 74 75 76 77 78 79
2581 "spellid_1, spelltrigger_1, spellcharges_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, "
2582 // 80 81 82 83 84 85
2583 "spellid_2, spelltrigger_2, spellcharges_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2, "
2584 // 86 87 88 89 90 91
2585 "spellid_3, spelltrigger_3, spellcharges_3, spellcooldown_3, spellcategory_3, spellcategorycooldown_3, "
2586 // 92 93 94 95 96 97
2587 "spellid_4, spelltrigger_4, spellcharges_4, spellcooldown_4, spellcategory_4, spellcategorycooldown_4, "
2588 // 98 99 100 101 102 103
2589 "spellid_5, spelltrigger_5, spellcharges_5, spellcooldown_5, spellcategory_5, spellcategorycooldown_5, "
2590 // 104 105 106 107 108 109 110 111
2591 "Bonding, Description, PageText, LanguageID, PageMaterial, StartQuest, LockID, Material, "
2592 // 112 113 114 115 116 117 118 119
2593 "Sheath, RandomProperty, RandomSuffix, ItemSet, Area, Map, BagFamily, TotemCategory, "
2594 // 120 121 122 123 124 125 126
2595 "SocketColor_1, SocketContent_1, SocketColor_2, SocketContent_2, SocketColor_3, SocketContent_3, SocketBonus, "
2596 // 127 128 129 130 131 132
2597 "GemProperties, ArmorDamageModifier, Duration, ItemLimitCategory, HolidayId, StatScalingFactor, "
2598 // 133 134
2599 "CurrencySubstitutionId, CurrencySubstitutionCount "
2600 "FROM item_template");
2601
2602 if (result)
2603 {
2604 do
2605 {
2606 Field* fields = result->Fetch();
2607 uint32 itemId = fields[0].GetUInt32();
2608 if (_itemTemplateStore.find(itemId) != _itemTemplateStore.end())
2609 --sparseCount;
2610
2611 ItemTemplate& itemTemplate = _itemTemplateStore[itemId];
2612
2613 itemTemplate.ItemId = itemId;
2614 itemTemplate.Class = uint32(fields[1].GetUInt8());
2615 itemTemplate.SubClass = uint32(fields[2].GetUInt8());
2616 itemTemplate.SoundOverrideSubclass = fields[3].GetInt32();
2617 itemTemplate.Name1 = fields[4].GetString();
2618 itemTemplate.DisplayInfoID = fields[5].GetUInt32();
2619 itemTemplate.Quality = uint32(fields[6].GetUInt8());
2620 itemTemplate.Flags = fields[7].GetUInt32();
2621 itemTemplate.Flags2 = fields[8].GetUInt32();
2622 itemTemplate.Flags3 = fields[9].GetUInt32();
2623 itemTemplate.Unk430_1 = fields[10].GetFloat();
2624 itemTemplate.Unk430_2 = fields[11].GetFloat();
2625 itemTemplate.BuyCount = uint32(fields[12].GetUInt8());
2626 itemTemplate.BuyPrice = int32(fields[13].GetInt64());
2627 itemTemplate.SellPrice = fields[14].GetUInt32();
2628 itemTemplate.InventoryType = uint32(fields[15].GetUInt8());
2629 itemTemplate.AllowableClass = fields[16].GetInt32();
2630 itemTemplate.AllowableRace = fields[17].GetInt32();
2631 itemTemplate.ItemLevel = uint32(fields[18].GetUInt16());
2632 itemTemplate.RequiredLevel = uint32(fields[19].GetUInt8());
2633 itemTemplate.RequiredSkill = uint32(fields[20].GetUInt16());
2634 itemTemplate.RequiredSkillRank = uint32(fields[21].GetUInt16());
2635 itemTemplate.RequiredSpell = fields[22].GetUInt32();
2636 itemTemplate.RequiredHonorRank = fields[23].GetUInt32();
2637 itemTemplate.RequiredCityRank = fields[24].GetUInt32();
2638 itemTemplate.RequiredReputationFaction = uint32(fields[25].GetUInt16());
2639 itemTemplate.RequiredReputationRank = uint32(fields[26].GetUInt16());
2640 itemTemplate.MaxCount = fields[27].GetInt32();
2641 itemTemplate.Stackable = fields[28].GetInt32();
2642 itemTemplate.ContainerSlots = uint32(fields[29].GetUInt8());
2643
2644 for (uint32 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
2645 {
2646 itemTemplate.ItemStat[i].ItemStatType = uint32(fields[30 + i * 4 + 0].GetUInt8());
2647 itemTemplate.ItemStat[i].ItemStatValue = int32(fields[30 + i * 4 + 1].GetInt16());
2648 itemTemplate.ItemStat[i].ItemStatUnk1 = fields[30 + i * 4 + 2].GetInt32();
2649 itemTemplate.ItemStat[i].ItemStatUnk2 = fields[30 + i * 4 + 3].GetInt32();
2650 }
2651
2652 itemTemplate.ScalingStatDistribution = uint32(fields[70].GetUInt16());
2653
2654 // cache item damage
2655 FillItemDamageFields(&itemTemplate.DamageMin, &itemTemplate.DamageMax, &itemTemplate.DPS, itemTemplate.ItemLevel,
2656 itemTemplate.Class, itemTemplate.SubClass, itemTemplate.Quality, fields[72].GetUInt16(),
2657 fields[132].GetFloat(), itemTemplate.InventoryType, itemTemplate.Flags2);
2658
2659 itemTemplate.DamageType = fields[71].GetUInt8();
2660
2661
2662 itemTemplate.Delay = fields[72].GetUInt16();
2663 itemTemplate.RangedModRange = fields[73].GetFloat();
2664
2665 for (uint32 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
2666 {
2667 itemTemplate.Spells[i].SpellId = fields[74 + 6 * i + 0].GetInt32();
2668 itemTemplate.Spells[i].SpellTrigger = uint32(fields[74 + 6 * i + 1].GetUInt8());
2669 itemTemplate.Spells[i].SpellCharges = int32(fields[74 + 6 * i + 2].GetInt16());
2670 itemTemplate.Spells[i].SpellCooldown = fields[74 + 6 * i + 3].GetInt32();
2671 itemTemplate.Spells[i].SpellCategory = uint32(fields[74 + 6 * i + 4].GetUInt16());
2672 itemTemplate.Spells[i].SpellCategoryCooldown = fields[74 + 6 * i + 5].GetInt32();
2673 }
2674
2675 itemTemplate.SpellPPMRate = 0.0f;
2676 itemTemplate.Bonding = uint32(fields[104].GetUInt8());
2677 itemTemplate.Description = fields[105].GetString();
2678 itemTemplate.PageText = fields[106].GetUInt32();
2679 itemTemplate.LanguageID = uint32(fields[107].GetUInt8());
2680 itemTemplate.PageMaterial = uint32(fields[108].GetUInt8());
2681 itemTemplate.StartQuest = fields[109].GetUInt32();
2682 itemTemplate.LockID = fields[110].GetUInt32();
2683 itemTemplate.Material = int32(fields[111].GetInt8());
2684 itemTemplate.Sheath = uint32(fields[112].GetUInt8());
2685 itemTemplate.RandomProperty = fields[113].GetUInt32();
2686 itemTemplate.RandomSuffix = fields[114].GetInt32();
2687 itemTemplate.ItemSet = fields[115].GetUInt32();
2688 itemTemplate.MaxDurability = FillMaxDurability(itemTemplate.Class, itemTemplate.SubClass,
2689 itemTemplate.InventoryType, itemTemplate.Quality, itemTemplate.ItemLevel);
2690
2691 itemTemplate.Area = fields[116].GetUInt32();
2692 itemTemplate.Map = uint32(fields[117].GetUInt16());
2693 itemTemplate.BagFamily = fields[118].GetUInt32();
2694 itemTemplate.TotemCategory = fields[119].GetUInt32();
2695
2696 for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
2697 {
2698 itemTemplate.Socket[i].Color = uint32(fields[120 + i * 2].GetUInt8());
2699 itemTemplate.Socket[i].Content = fields[120 + i * 2 + 1].GetUInt32();
2700 }
2701
2702 itemTemplate.socketBonus = fields[126].GetUInt32();
2703 itemTemplate.GemProperties = fields[127].GetUInt32();
2704 FillDisenchantFields(&itemTemplate.DisenchantID, &itemTemplate.RequiredDisenchantSkill, itemTemplate);
2705
2706 itemTemplate.ArmorDamageModifier = fields[128].GetFloat();
2707 itemTemplate.Duration = fields[129].GetUInt32();
2708 itemTemplate.ItemLimitCategory = uint32(fields[130].GetInt16());
2709 itemTemplate.HolidayId = fields[131].GetUInt32();
2710 itemTemplate.StatScalingFactor = fields[132].GetFloat();
2711 itemTemplate.CurrencySubstitutionId = fields[133].GetInt32();
2712 itemTemplate.CurrencySubstitutionCount = fields[134].GetInt32();
2713 itemTemplate.ScriptId = 0;
2714 itemTemplate.FoodType = 0;
2715 itemTemplate.MinMoneyLoot = 0;
2716 itemTemplate.MaxMoneyLoot = 0;
2717 ++dbCount;
2718 } while (result->NextRow());
2719 }
2720
2721 // Check if item templates for DBC referenced character start outfit are present
2722 std::set<uint32> notFoundOutfit;
2723 for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i)
2724 {
2725 CharStartOutfitEntry const* entry = sCharStartOutfitStore.LookupEntry(i);
2726 if (!entry)
2727 continue;
2728
2729 for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j)
2730 {
2731 if (entry->ItemId[j] <= 0)
2732 continue;
2733
2734 uint32 item_id = entry->ItemId[j];
2735
2736 if (!GetItemTemplate(item_id))
2737 notFoundOutfit.insert(item_id);
2738 }
2739 }
2740
2741 for (std::set<uint32>::const_iterator itr = notFoundOutfit.begin(); itr != notFoundOutfit.end(); ++itr)
2742 SF_LOG_ERROR("sql.sql", "Item (Entry: %u) does not exist in `item_template` but is referenced in `CharStartOutfit.dbc`", *itr);
2743
2744 SF_LOG_INFO("server.loading", ">> Loaded %u item templates from Item-sparse.db2 and %u from database in %u ms", sparseCount, dbCount, GetMSTimeDiffToNow(oldMSTime));
2745}
2746
2748{
2749 uint32 oldMSTime = getMSTime();
2750 uint32 count = 0;
2751
2752 QueryResult result = WorldDatabase.Query("SELECT Id, FlagsCu, FoodType, MinMoneyLoot, MaxMoneyLoot, SpellPPMChance FROM item_template_addon");
2753 if (result)
2754 {
2755 do
2756 {
2757 Field* fields = result->Fetch();
2758 uint32 itemId = fields[0].GetUInt32();
2759 if (!GetItemTemplate(itemId))
2760 {
2761 SF_LOG_ERROR("sql.sql", "Item %u specified in `item_template_addon` does not exist, skipped.", itemId);
2762 continue;
2763 }
2764
2765 uint32 minMoneyLoot = fields[3].GetUInt32();
2766 uint32 maxMoneyLoot = fields[4].GetUInt32();
2767 if (minMoneyLoot > maxMoneyLoot)
2768 {
2769 SF_LOG_ERROR("sql.sql", "Minimum money loot specified in `item_template_addon` for item %u was greater than maximum amount, swapping.", itemId);
2770 std::swap(minMoneyLoot, maxMoneyLoot);
2771 }
2772 ItemTemplate& itemTemplate = _itemTemplateStore[itemId];
2773 itemTemplate.FlagsCu = fields[1].GetUInt32();
2774 itemTemplate.FoodType = fields[2].GetUInt8();
2775 itemTemplate.MinMoneyLoot = minMoneyLoot;
2776 itemTemplate.MaxMoneyLoot = maxMoneyLoot;
2777 itemTemplate.SpellPPMRate = fields[5].GetFloat();
2778 ++count;
2779 } while (result->NextRow());
2780 }
2781 SF_LOG_INFO("server.loading", ">> Loaded %u item addon templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2782}
2783
2785{
2786 uint32 oldMSTime = getMSTime();
2787 uint32 count = 0;
2788
2789 QueryResult result = WorldDatabase.Query("SELECT Id, ScriptName FROM item_script_names");
2790 if (result)
2791 {
2792 do
2793 {
2794 Field* fields = result->Fetch();
2795 uint32 itemId = fields[0].GetUInt32();
2796 if (!GetItemTemplate(itemId))
2797 {
2798 SF_LOG_ERROR("sql.sql", "Item %u specified in `item_script_names` does not exist, skipped.", itemId);
2799 continue;
2800 }
2801
2802 _itemTemplateStore[itemId].ScriptId = GetScriptId(fields[1].GetCString());
2803 ++count;
2804 } while (result->NextRow());
2805 }
2806
2807 SF_LOG_INFO("server.loading", ">> Loaded %u item script names in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2808}
2810{
2811 ItemTemplateContainer::const_iterator itr = _itemTemplateStore.find(entry);
2812 if (itr != _itemTemplateStore.end())
2813 return &(itr->second);
2814 return NULL;
2815}
2816
2818{
2819 uint32 oldMSTime = getMSTime();
2820
2821 _vehicleTemplateAccessoryStore.clear(); // needed for reload case
2822
2823 uint32 count = 0;
2824
2825 // 0 1 2 3 4 5
2826 QueryResult result = WorldDatabase.Query("SELECT `entry`, `accessory_entry`, `seat_id`, `minion`, `summontype`, `summontimer` FROM `vehicle_template_accessory`");
2827
2828 if (!result)
2829 {
2830 SF_LOG_ERROR("server.loading", ">> Loaded 0 vehicle template accessories. DB table `vehicle_template_accessory` is empty.");
2831 return;
2832 }
2833
2834 do
2835 {
2836 Field* fields = result->Fetch();
2837
2838 uint32 uiEntry = fields[0].GetUInt32();
2839 uint32 uiAccessory = fields[1].GetUInt32();
2840 int8 uiSeat = int8(fields[2].GetInt8());
2841 bool bMinion = fields[3].GetBool();
2842 uint8 uiSummonType = fields[4].GetUInt8();
2843 uint32 uiSummonTimer = fields[5].GetUInt32();
2844
2845 if (!sObjectMgr->GetCreatureTemplate(uiEntry))
2846 {
2847 SF_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u does not exist.", uiEntry);
2848 continue;
2849 }
2850
2851 if (!sObjectMgr->GetCreatureTemplate(uiAccessory))
2852 {
2853 SF_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: Accessory %u does not exist.", uiAccessory);
2854 continue;
2855 }
2856
2857 if (_spellClickInfoStore.find(uiEntry) == _spellClickInfoStore.end())
2858 {
2859 SF_LOG_ERROR("sql.sql", "Table `vehicle_template_accessory`: creature template entry %u has no data in npc_spellclick_spells", uiEntry);
2860 continue;
2861 }
2862
2863 _vehicleTemplateAccessoryStore[uiEntry].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer));
2864
2865 ++count;
2866 } while (result->NextRow());
2867
2868 SF_LOG_INFO("server.loading", ">> Loaded %u Vehicle Template Accessories in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2869}
2870
2872{
2873 uint32 oldMSTime = getMSTime();
2874
2875 _vehicleAccessoryStore.clear(); // needed for reload case
2876
2877 uint32 count = 0;
2878
2879 // 0 1 2 3 4 5
2880 QueryResult result = WorldDatabase.Query("SELECT `guid`, `accessory_entry`, `seat_id`, `minion`, `summontype`, `summontimer` FROM `vehicle_accessory`");
2881
2882 if (!result)
2883 {
2884 SF_LOG_INFO("server.loading", ">> Loaded 0 Vehicle Accessories in %u ms", GetMSTimeDiffToNow(oldMSTime));
2885 return;
2886 }
2887
2888 do
2889 {
2890 Field* fields = result->Fetch();
2891
2892 uint32 uiGUID = fields[0].GetUInt32();
2893 uint32 uiAccessory = fields[1].GetUInt32();
2894 int8 uiSeat = int8(fields[2].GetInt16());
2895 bool bMinion = fields[3].GetBool();
2896 uint8 uiSummonType = fields[4].GetUInt8();
2897 uint32 uiSummonTimer = fields[5].GetUInt32();
2898
2899 if (!sObjectMgr->GetCreatureTemplate(uiAccessory))
2900 {
2901 SF_LOG_ERROR("sql.sql", "Table `vehicle_accessory`: Accessory %u does not exist.", uiAccessory);
2902 continue;
2903 }
2904
2905 _vehicleAccessoryStore[uiGUID].push_back(VehicleAccessory(uiAccessory, uiSeat, bMinion, uiSummonType, uiSummonTimer));
2906
2907 ++count;
2908 } while (result->NextRow());
2909
2910 SF_LOG_INFO("server.loading", ">> Loaded %u Vehicle Accessories in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2911}
2912
2914{
2915 uint32 oldMSTime = getMSTime();
2916
2917 // 0 1 2 3 4 5 6 7 8 9
2918 QueryResult result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats");
2919
2920 if (!result)
2921 {
2922 SF_LOG_ERROR("server.loading", ">> Loaded 0 level pet stats definitions. DB table `pet_levelstats` is empty.");
2923 return;
2924 }
2925
2926 uint32 count = 0;
2927
2928 do
2929 {
2930 Field* fields = result->Fetch();
2931
2932 uint32 creature_id = fields[0].GetUInt32();
2933 if (!sObjectMgr->GetCreatureTemplate(creature_id))
2934 {
2935 SF_LOG_ERROR("sql.sql", "Wrong creature id %u in `pet_levelstats` table, ignoring.", creature_id);
2936 continue;
2937 }
2938
2939 uint32 current_level = fields[1].GetUInt8();
2940 if (current_level > sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL))
2941 {
2942 if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
2943 SF_LOG_ERROR("sql.sql", "Wrong (> %u) level %u in `pet_levelstats` table, ignoring.", STRONG_MAX_LEVEL, current_level);
2944 else
2945 {
2946 SF_LOG_INFO("misc", "Unused (> MaxPlayerLevel in worldserver.conf) level %u in `pet_levelstats` table, ignoring.", current_level);
2947 ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
2948 }
2949 continue;
2950 }
2951 else if (current_level < 1)
2952 {
2953 SF_LOG_ERROR("sql.sql", "Wrong (<1) level %u in `pet_levelstats` table, ignoring.", current_level);
2954 continue;
2955 }
2956
2957 PetLevelInfo*& pInfoMapEntry = _petInfoStore[creature_id];
2958
2959 if (pInfoMapEntry == NULL)
2960 pInfoMapEntry = new PetLevelInfo[sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL)];
2961
2962 // data for level 1 stored in [0] array element, ...
2963 PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level - 1];
2964
2965 pLevelInfo->health = fields[2].GetUInt16();
2966 pLevelInfo->mana = fields[3].GetUInt16();
2967 pLevelInfo->armor = fields[9].GetUInt32();
2968
2969 for (int i = 0; i < MAX_STATS; i++)
2970 {
2971 pLevelInfo->stats[i] = fields[i + 4].GetUInt16();
2972 }
2973
2974 ++count;
2975 } while (result->NextRow());
2976
2977 // Fill gaps and check integrity
2978 for (PetLevelInfoContainer::iterator itr = _petInfoStore.begin(); itr != _petInfoStore.end(); ++itr)
2979 {
2980 PetLevelInfo* pInfo = itr->second;
2981
2982 // fatal error if no level 1 data
2983 if (!pInfo || pInfo[0].health == 0)
2984 {
2985 SF_LOG_ERROR("sql.sql", "Creature %u does not have pet stats data for Level 1!", itr->first);
2986 exit(1);
2987 }
2988
2989 // fill level gaps
2990 for (uint8 level = 1; level < sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL); ++level)
2991 {
2992 if (pInfo[level].health == 0)
2993 {
2994 SF_LOG_ERROR("sql.sql", "Creature %u has no data for Level %i pet stats data, using data of Level %i.", itr->first, level + 1, level);
2995 pInfo[level] = pInfo[level - 1];
2996 }
2997 }
2998 }
2999
3000 SF_LOG_INFO("server.loading", ">> Loaded %u level pet stats definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3001}
3002
3003PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint8 level) const
3004{
3005 if (level > sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL))
3006 level = sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL);
3007
3008 PetLevelInfoContainer::const_iterator itr = _petInfoStore.find(creature_id);
3009 if (itr == _petInfoStore.end())
3010 return NULL;
3011
3012 return &itr->second[level - 1]; // data for level 1 stored in [0] array element, ...
3013}
3014
3016{
3017 if (!_playerInfo[race_][class_])
3018 return;
3019
3020 if (count > 0)
3021 _playerInfo[race_][class_]->item.push_back(PlayerCreateInfoItem(itemId, count));
3022 else
3023 {
3024 if (count < -1)
3025 SF_LOG_ERROR("sql.sql", "Invalid count %i specified on item %u be removed from original player create info (use -1)!", count, itemId);
3026
3027 for (uint32 gender = 0; gender < GENDER_NONE; ++gender)
3028 {
3029 if (CharStartOutfitEntry const* entry = GetCharStartOutfitEntry(race_, class_, gender))
3030 {
3031 bool found = false;
3032 for (uint8 x = 0; x < MAX_OUTFIT_ITEMS; ++x)
3033 {
3034 if (entry->ItemId[x] > 0 && uint32(entry->ItemId[x]) == itemId)
3035 {
3036 found = true;
3037 const_cast<CharStartOutfitEntry*>(entry)->ItemId[x] = 0;
3038 break;
3039 }
3040 }
3041
3042 if (!found)
3043 SF_LOG_ERROR("sql.sql", "Item %u specified to be removed from original create info not found in dbc!", itemId);
3044 }
3045 }
3046 }
3047}
3048
3050{
3051 // Load playercreate
3052 {
3053 uint32 oldMSTime = getMSTime();
3054 // 0 1 2 3 4 5 6
3055 QueryResult result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z, orientation FROM playercreateinfo");
3056
3057 if (!result)
3058 {
3059 SF_LOG_ERROR("server.loading", ">> Loaded 0 player create definitions. DB table `playercreateinfo` is empty.");
3060 exit(1);
3061 }
3062 else
3063 {
3064 uint32 count = 0;
3065
3066 do
3067 {
3068 Field* fields = result->Fetch();
3069
3070 uint32 current_race = fields[0].GetUInt8();
3071 uint32 current_class = fields[1].GetUInt8();
3072 uint32 mapId = fields[2].GetUInt16();
3073 uint32 areaId = fields[3].GetUInt32(); // zone
3074 float positionX = fields[4].GetFloat();
3075 float positionY = fields[5].GetFloat();
3076 float positionZ = fields[6].GetFloat();
3077 float orientation = fields[7].GetFloat();
3078
3079 ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race);
3080 if (!rEntry || !IsValidPlayerCreateRace(current_race))
3081 {
3082 SF_LOG_ERROR("sql.sql", "Wrong race %u in `playercreateinfo` table, ignoring.", current_race);
3083 continue;
3084 }
3085
3086 if (!sChrClassesStore.LookupEntry(current_class) || !IsValidPlayerCreateClass(current_class))
3087 {
3088 SF_LOG_ERROR("sql.sql", "Wrong class %u in `playercreateinfo` table, ignoring.", current_class);
3089 continue;
3090 }
3091
3092 // accept DB data only for valid position (and non instanceable)
3093 if (!MapManager::IsValidMapCoord(mapId, positionX, positionY, positionZ, orientation))
3094 {
3095 SF_LOG_ERROR("sql.sql", "Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.", current_class, current_race);
3096 continue;
3097 }
3098
3099 if (sMapStore.LookupEntry(mapId)->Instanceable())
3100 {
3101 SF_LOG_ERROR("sql.sql", "Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.", current_class, current_race);
3102 continue;
3103 }
3104
3105 PlayerInfo* info = new PlayerInfo();
3106 info->mapId = mapId;
3107 info->areaId = areaId;
3108 info->positionX = positionX;
3109 info->positionY = positionY;
3110 info->positionZ = positionZ;
3111 info->orientation = orientation;
3112 info->displayId_m = rEntry->model_m;
3113 info->displayId_f = rEntry->model_f;
3114 _playerInfo[current_race][current_class] = info;
3115
3116 ++count;
3117 } while (result->NextRow());
3118
3119 SF_LOG_INFO("server.loading", ">> Loaded %u player create definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3120 }
3121 }
3122
3129}
3130
3132{
3133 if (currentRace >= MAX_RACES)
3134 return false;
3135
3136 return true;
3137}
3138
3140{
3141 if (currentClass >= MAX_CLASSES)
3142 return false;
3143
3144 return true;
3145}
3146
3148{
3149 // Load playercreate items
3150 SF_LOG_INFO("server.loading", "Loading Player Create Items Data...");
3151 {
3152 uint32 oldMSTime = getMSTime();
3153 // 0 1 2 3
3154 QueryResult result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item");
3155
3156 if (!result)
3157 {
3158 SF_LOG_INFO("server.loading", ">> Loaded 0 custom player create items. DB table `playercreateinfo_item` is empty.");
3159 }
3160 else
3161 {
3162 uint32 count = 0;
3163
3164 do
3165 {
3166 Field* fields = result->Fetch();
3167
3168 uint32 current_race = fields[0].GetUInt8();
3169 if (!IsValidPlayerCreateRace(current_race))
3170 {
3171 SF_LOG_ERROR("sql.sql", "Wrong race %u in `playercreateinfo_item` table, ignoring.", current_race);
3172 continue;
3173 }
3174
3175 uint32 current_class = fields[1].GetUInt8();
3176 if (!IsValidPlayerCreateClass(current_class))
3177 {
3178 SF_LOG_ERROR("sql.sql", "Wrong class %u in `playercreateinfo_item` table, ignoring.", current_class);
3179 continue;
3180 }
3181
3182 uint32 item_id = fields[2].GetUInt32();
3183
3184 if (!GetItemTemplate(item_id))
3185 {
3186 SF_LOG_ERROR("sql.sql", "Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.", item_id, current_race, current_class);
3187 continue;
3188 }
3189
3190 int32 amount = fields[3].GetInt8();
3191
3192 if (!amount)
3193 {
3194 SF_LOG_ERROR("sql.sql", "Item id %u (class %u race %u) have amount == 0 in `playercreateinfo_item` table, ignoring.", item_id, current_race, current_class);
3195 continue;
3196 }
3197
3198 if (!current_race || !current_class)
3199 {
3200 uint32 min_race = current_race ? current_race : 1;
3201 uint32 max_race = current_race ? current_race + 1 : MAX_RACES;
3202 uint32 min_class = current_class ? current_class : 1;
3203 uint32 max_class = current_class ? current_class + 1 : MAX_CLASSES;
3204 for (uint32 r = min_race; r < max_race; ++r)
3205 for (uint32 c = min_class; c < max_class; ++c)
3206 PlayerCreateInfoAddItemHelper(r, c, item_id, amount);
3207 }
3208 else
3209 PlayerCreateInfoAddItemHelper(current_race, current_class, item_id, amount);
3210
3211 ++count;
3212 } while (result->NextRow());
3213
3214 SF_LOG_INFO("server.loading", ">> Loaded %u custom player create items in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3215 }
3216 }
3217}
3218
3220{
3221 // Load playercreate spells
3222 SF_LOG_INFO("server.loading", "Loading Player Create Spell Data...");
3223 {
3224 uint32 oldMSTime = getMSTime();
3225
3226 std::string tableName = sWorld->GetBoolConfig(WorldBoolConfigs::CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell";
3227 QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM %s", tableName.c_str());
3228
3229 if (!result)
3230 {
3231 SF_LOG_ERROR("server.loading", ">> Loaded 0 player create spells. DB table `%s` is empty.", sWorld->GetBoolConfig(WorldBoolConfigs::CONFIG_START_ALL_SPELLS) ? "playercreateinfo_spell_custom" : "playercreateinfo_spell");
3232 }
3233 else
3234 {
3235 uint32 count = 0;
3236
3237 do
3238 {
3239 Field* fields = result->Fetch();
3240 uint32 raceMask = fields[0].GetUInt32();
3241 uint32 classMask = fields[1].GetUInt32();
3242 uint32 spellId = fields[2].GetUInt32();
3243
3244 if (!sSpellMgr->GetSpellInfo(spellId))
3245 {
3246 SF_LOG_ERROR("sql.sql", "Spell %u in `%s` does not exist in SpellStore, ignoring.", spellId, tableName.c_str());
3247 continue;
3248 }
3249
3250 if (raceMask != 0 && !(raceMask & RACEMASK_ALL_PLAYABLE))
3251 {
3252 SF_LOG_ERROR("sql.sql", "Wrong race mask %u in `%s` table, ignoring.", raceMask, tableName.c_str());
3253 continue;
3254 }
3255
3256 if (classMask != 0 && !(classMask & CLASSMASK_ALL_PLAYABLE))
3257 {
3258 SF_LOG_ERROR("sql.sql", "Wrong class mask %u in `%s` table, ignoring.", classMask, tableName.c_str());
3259 continue;
3260 }
3261
3262 for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex)
3263 {
3264 if (raceMask == 0 || ((1 << (raceIndex - 1)) & raceMask))
3265 {
3266 for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex)
3267 {
3268 if (classMask == 0 || ((1 << (classIndex - 1)) & classMask))
3269 {
3270 if (PlayerInfo* info = _playerInfo[raceIndex][classIndex])
3271 {
3272 info->spell.push_back(spellId);
3273 ++count;
3274 }
3275 // We need something better here, the check is not accounting for spells used by multiple races/classes but not all of them.
3276 // Either split the masks per class, or per race, which kind of kills the point yet.
3277 // else if (raceMask != 0 && classMask != 0)
3278 // SF_LOG_ERROR("sql.sql", "Racemask/classmask (%u/%u) combination was found containing an invalid race/class combination (%u/%u) in `playercreateinfo_spell` (Spell %u), ignoring.", raceMask, classMask, raceIndex, classIndex, spellId);
3279 }
3280 }
3281 }
3282 }
3283 } while (result->NextRow());
3284
3285 SF_LOG_INFO("server.loading", ">> Loaded %u player create spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3286 }
3287 }
3288}
3289
3291{
3292 // Load playercreate actions
3293 SF_LOG_INFO("server.loading", "Loading Player Create Action Data...");
3294 {
3295 uint32 oldMSTime = getMSTime();
3296
3297 // 0 1 2 3 4
3298 QueryResult result = WorldDatabase.Query("SELECT race, class, button, action, type FROM playercreateinfo_action");
3299
3300 if (!result)
3301 {
3302 SF_LOG_ERROR("server.loading", ">> Loaded 0 player create actions. DB table `playercreateinfo_action` is empty.");
3303 }
3304 else
3305 {
3306 uint32 count = 0;
3307
3308 do
3309 {
3310 Field* fields = result->Fetch();
3311
3312 uint32 current_race = fields[0].GetUInt8();
3313 if (!IsValidPlayerCreateRace(current_race))
3314 {
3315 SF_LOG_ERROR("sql.sql", "Wrong race %u in `playercreateinfo_action` table, ignoring.", current_race);
3316 continue;
3317 }
3318
3319 uint32 current_class = fields[1].GetUInt8();
3320 if (!IsValidPlayerCreateClass(current_class))
3321 {
3322 SF_LOG_ERROR("sql.sql", "Wrong class %u in `playercreateinfo_action` table, ignoring.", current_class);
3323 continue;
3324 }
3325
3326 if (PlayerInfo* info = _playerInfo[current_race][current_class])
3327 info->action.push_back(PlayerCreateInfoAction(fields[2].GetUInt16(), fields[3].GetUInt32(), fields[4].GetUInt16()));
3328
3329 ++count;
3330 } while (result->NextRow());
3331
3332 SF_LOG_INFO("server.loading", ">> Loaded %u player create actions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3333 }
3334 }
3335}
3336
3338{
3339 // Loading levels data (class/race dependent)
3340 SF_LOG_INFO("server.loading", "Loading Player Create Level Stats Data...");
3341 {
3342 uint32 oldMSTime = getMSTime();
3343
3344 // 0 1 2 3 4 5 6 7
3345 QueryResult result = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats");
3346
3347 if (!result)
3348 {
3349 SF_LOG_ERROR("server.loading", ">> Loaded 0 level stats definitions. DB table `player_levelstats` is empty.");
3350 exit(1);
3351 }
3352
3353 uint32 count = 0;
3354
3355 do
3356 {
3357 Field* fields = result->Fetch();
3358
3359 uint32 current_race = fields[0].GetUInt8();
3360 if (!IsValidPlayerCreateRace(current_race))
3361 {
3362 SF_LOG_ERROR("sql.sql", "Wrong race %u in `player_levelstats` table, ignoring.", current_race);
3363 continue;
3364 }
3365
3366 uint32 current_class = fields[1].GetUInt8();
3367 if (!IsValidPlayerCreateClass(current_class))
3368 {
3369 SF_LOG_ERROR("sql.sql", "Wrong class %u in `player_levelstats` table, ignoring.", current_class);
3370 continue;
3371 }
3372
3373 uint32 current_level = fields[2].GetUInt8();
3374 if (current_level > sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL))
3375 {
3376 if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
3377 SF_LOG_ERROR("sql.sql", "Wrong (> %u) level %u in `player_levelstats` table, ignoring.", STRONG_MAX_LEVEL, current_level);
3378 else
3379 {
3380 SF_LOG_INFO("misc", "Unused (> MaxPlayerLevel in worldserver.conf) level %u in `player_levelstats` table, ignoring.", current_level);
3381 ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
3382 }
3383 continue;
3384 }
3385
3386 if (PlayerInfo* info = _playerInfo[current_race][current_class])
3387 {
3388 if (!info->levelInfo)
3389 info->levelInfo = new PlayerLevelInfo[sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL)];
3390
3391 PlayerLevelInfo& levelInfo = info->levelInfo[current_level - 1];
3392 for (int i = 0; i < MAX_STATS; i++)
3393 levelInfo.stats[i] = fields[i + 3].GetUInt16();
3394 }
3395
3396 ++count;
3397 } while (result->NextRow());
3398
3399 // Fill gaps and check integrity
3400 for (int race = 0; race < MAX_RACES; ++race)
3401 {
3402 // skip non existed races
3403 if (!sChrRacesStore.LookupEntry(race))
3404 continue;
3405
3406 for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
3407 {
3408 // skip non existed classes
3409 if (!sChrClassesStore.LookupEntry(class_))
3410 continue;
3411
3412 PlayerInfo* info = _playerInfo[race][class_];
3413 if (!info)
3414 continue;
3415
3416 // skip expansion races if not playing with expansion
3417 if (sWorld->getIntConfig(WorldIntConfigs::CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI))
3418 continue;
3419
3420 // skip expansion classes if not playing with expansion
3421 if (sWorld->getIntConfig(WorldIntConfigs::CONFIG_EXPANSION) < 2 && class_ == CLASS_DEATH_KNIGHT)
3422 continue;
3423
3424 // skip expansion classes / races if not playing with expansion
3425 if (sWorld->getIntConfig(WorldIntConfigs::CONFIG_EXPANSION) < 4 && (class_ == CLASS_MONK || race == RACE_PANDAREN_NEUTRAL || race == RACE_PANDAREN_ALLIANCE || race == RACE_PANDAREN_HORDE))
3426 continue;
3427
3428 // fatal error if no level 1 data
3429 if (!info->levelInfo || info->levelInfo[0].stats[0] == 0)
3430 {
3431 SF_LOG_ERROR("sql.sql", "Race %i Class %i Level 1 does not have stats data!", race, class_);
3432 exit(1);
3433 }
3434
3435 // fill level gaps
3436 for (uint8 level = 1; level < sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL); ++level)
3437 {
3438 if (info->levelInfo[level].stats[0] == 0)
3439 {
3440 SF_LOG_ERROR("sql.sql", "Race %i Class %i Level %i does not have stats data. Using stats data of level %i.", race, class_, level + 1, level);
3441 info->levelInfo[level] = info->levelInfo[level - 1];
3442 }
3443 }
3444 }
3445 }
3446
3447 SF_LOG_INFO("server.loading", ">> Loaded %u level stats definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3448 }
3449}
3450
3452{
3453 // Loading xp per level data
3454 SF_LOG_INFO("server.loading", "Loading Player Create XP Data...");
3455 {
3456 uint32 oldMSTime = getMSTime();
3457
3459 for (uint8 level = 0; level < sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL); ++level)
3460 _playerXPperLevel[level] = 0;
3461
3462 // 0 1
3463 QueryResult result = WorldDatabase.Query("SELECT lvl, xp_for_next_level FROM player_xp_for_level");
3464
3465 if (!result)
3466 {
3467 SF_LOG_ERROR("server.loading", ">> Loaded 0 xp for level definitions. DB table `player_xp_for_level` is empty.");
3468 exit(1);
3469 }
3470
3471 uint32 count = 0;
3472
3473 do
3474 {
3475 Field* fields = result->Fetch();
3476
3477 uint32 current_level = fields[0].GetUInt8();
3478 uint32 current_xp = fields[1].GetUInt32();
3479
3480 if (current_level >= sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL))
3481 {
3482 if (current_level > STRONG_MAX_LEVEL) // hardcoded level maximum
3483 SF_LOG_ERROR("sql.sql", "Wrong (> %u) level %u in `player_xp_for_level` table, ignoring.", STRONG_MAX_LEVEL, current_level);
3484 else
3485 {
3486 SF_LOG_INFO("misc", "Unused (> MaxPlayerLevel in worldserver.conf) level %u in `player_xp_for_level` table, ignoring.", current_level);
3487 ++count; // make result loading percent "expected" correct in case disabled detail mode for example.
3488 }
3489 continue;
3490 }
3491 //PlayerXPperLevel
3492 _playerXPperLevel[current_level] = current_xp;
3493 ++count;
3494 } while (result->NextRow());
3495
3496 // fill level gaps
3497 for (uint8 level = 1; level < sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL); ++level)
3498 {
3499 if (_playerXPperLevel[level] == 0)
3500 {
3501 SF_LOG_ERROR("sql.sql", "Level %i does not have XP for level data. Using data of level [%i] + 100.", level + 1, level);
3502 _playerXPperLevel[level] = _playerXPperLevel[level - 1] + 100;
3503 }
3504 }
3505
3506 SF_LOG_INFO("server.loading", ">> Loaded %u xp for level definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3507 }
3508}
3509
3511{
3512 // Load playercreate cast spell
3513 SF_LOG_INFO("server.loading", "Loading Player Create Spell Cast Data...");
3514 {
3515 uint32 oldMSTime = getMSTime();
3516
3517 QueryResult result = WorldDatabase.PQuery("SELECT racemask, classmask, Spell FROM playercreateinfo_spell_cast");
3518
3519 if (!result)
3520 SF_LOG_ERROR("server.loading", ">> Loaded 0 player create cast spells. DB table `playercreateinfo_spell_cast` is empty.");
3521 else
3522 {
3523 uint32 count = 0;
3524
3525 do
3526 {
3527 Field* fields = result->Fetch();
3528 uint32 racemask = fields[0].GetUInt32();
3529 uint32 classmask = fields[1].GetUInt32();
3530 uint32 spellId = fields[2].GetUInt32();
3531
3532 if (racemask != 0 && !(racemask & RACEMASK_ALL_PLAYABLE))
3533 {
3534 SF_LOG_ERROR("sql.sql", "Wrong race mask %u in `playercreateinfo_spell_cast` table, ignoring.", racemask);
3535 continue;
3536 }
3537
3538 if (classmask != 0 && !(classmask & CLASSMASK_ALL_PLAYABLE))
3539 {
3540 SF_LOG_ERROR("sql.sql", "Wrong class mask %u in `playercreateinfo_spell_cast` table, ignoring.", classmask);
3541 continue;
3542 }
3543
3544 for (uint32 raceIndex = RACE_HUMAN; raceIndex < MAX_RACES; ++raceIndex)
3545 {
3546 if (racemask == 0 || ((1 << (raceIndex - 1)) & racemask))
3547 {
3548 for (uint32 classIndex = CLASS_WARRIOR; classIndex < MAX_CLASSES; ++classIndex)
3549 {
3550 if (classmask == 0 || ((1 << (classIndex - 1)) & classmask))
3551 {
3552 if (PlayerInfo* info = _playerInfo[raceIndex][classIndex])
3553 {
3554 info->spell_cast.push_back(spellId);
3555 ++count;
3556 }
3557 }
3558 }
3559 }
3560 }
3561 } while (result->NextRow());
3562
3563 SF_LOG_INFO("server.loading", ">> Loaded %u player create spell casts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
3564 }
3565 }
3566}
3567
3568void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint8 level, uint32& baseHP, uint32& baseMana) const
3569{
3570 if (level < 1 || class_ >= MAX_CLASSES)
3571 return;
3572
3573 if (level > sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL))
3574 level = sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL);
3575
3576 GtOCTBaseHPByClassEntry const* hp = sGtOCTBaseHPByClassStore.LookupEntry((class_ - 1) * GT_MAX_LEVEL + level - 1);
3577 GtOCTBaseMPByClassEntry const* mp = sGtOCTBaseMPByClassStore.LookupEntry((class_ - 1) * GT_MAX_LEVEL + level - 1);
3578
3579 if (!hp || !mp)
3580 {
3581 SF_LOG_ERROR("misc", "Tried to get non-existant Class-Level combination data for base hp/mp. Class %u Level %u", class_, level);
3582 return;
3583 }
3584
3585 baseHP = uint32(hp->ratio);
3586 baseMana = uint32(mp->ratio);
3587}
3588
3590{
3591 if (level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES)
3592 return;
3593
3594 PlayerInfo const* pInfo = _playerInfo[race][class_];
3595 if (!pInfo)
3596 return;
3597
3598 if (level <= sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL))
3599 *info = pInfo->levelInfo[level - 1];
3600 else
3601 BuildPlayerLevelInfo(race, class_, level, info);
3602}
3603
3605{
3606 // base data (last known level)
3607 *info = _playerInfo[race][_class]->levelInfo[sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL) - 1];
3608
3609 // if conversion from uint32 to uint8 causes unexpected behaviour, change lvl to uint32
3610 for (uint8 lvl = sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL) - 1; lvl < level; ++lvl)
3611 {
3612 switch (_class)
3613 {
3614 case CLASS_WARRIOR:
3615 info->stats[STAT_STRENGTH] += (lvl > 23 ? 2 : (lvl > 1 ? 1 : 0));
3616 info->stats[STAT_STAMINA] += (lvl > 23 ? 2 : (lvl > 1 ? 1 : 0));
3617 info->stats[STAT_AGILITY] += (lvl > 36 ? 1 : (lvl > 6 && (lvl % 2) ? 1 : 0));
3618 info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl % 2) ? 1 : 0);
3619 info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl % 2) ? 1 : 0);
3620 break;
3621 case CLASS_PALADIN:
3622 info->stats[STAT_STRENGTH] += (lvl > 3 ? 1 : 0);
3623 info->stats[STAT_STAMINA] += (lvl > 33 ? 2 : (lvl > 1 ? 1 : 0));
3624 info->stats[STAT_AGILITY] += (lvl > 38 ? 1 : (lvl > 7 && !(lvl % 2) ? 1 : 0));
3625 info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl % 2) ? 1 : 0);
3626 info->stats[STAT_SPIRIT] += (lvl > 7 ? 1 : 0);
3627 break;
3628 case CLASS_HUNTER:
3629 info->stats[STAT_STRENGTH] += (lvl > 4 ? 1 : 0);
3630 info->stats[STAT_STAMINA] += (lvl > 4 ? 1 : 0);
3631 info->stats[STAT_AGILITY] += (lvl > 33 ? 2 : (lvl > 1 ? 1 : 0));
3632 info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl % 2) ? 1 : 0);
3633 info->stats[STAT_SPIRIT] += (lvl > 38 ? 1 : (lvl > 9 && !(lvl % 2) ? 1 : 0));
3634 break;
3635 case CLASS_ROGUE:
3636 info->stats[STAT_STRENGTH] += (lvl > 5 ? 1 : 0);
3637 info->stats[STAT_STAMINA] += (lvl > 4 ? 1 : 0);
3638 info->stats[STAT_AGILITY] += (lvl > 16 ? 2 : (lvl > 1 ? 1 : 0));
3639 info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl % 2) ? 1 : 0);
3640 info->stats[STAT_SPIRIT] += (lvl > 38 ? 1 : (lvl > 9 && !(lvl % 2) ? 1 : 0));
3641 break;
3642 case CLASS_PRIEST:
3643 info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl % 2) ? 1 : 0);
3644 info->stats[STAT_STAMINA] += (lvl > 5 ? 1 : 0);
3645 info->stats[STAT_AGILITY] += (lvl > 38 ? 1 : (lvl > 8 && (lvl % 2) ? 1 : 0));
3646 info->stats[STAT_INTELLECT] += (lvl > 22 ? 2 : (lvl > 1 ? 1 : 0));
3647 info->stats[STAT_SPIRIT] += (lvl > 3 ? 1 : 0);
3648 break;
3649 case CLASS_SHAMAN:
3650 info->stats[STAT_STRENGTH] += (lvl > 34 ? 1 : (lvl > 6 && (lvl % 2) ? 1 : 0));
3651 info->stats[STAT_STAMINA] += (lvl > 4 ? 1 : 0);
3652 info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl % 2) ? 1 : 0);
3653 info->stats[STAT_INTELLECT] += (lvl > 5 ? 1 : 0);
3654 info->stats[STAT_SPIRIT] += (lvl > 4 ? 1 : 0);
3655 break;
3656 case CLASS_MAGE:
3657 info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl % 2) ? 1 : 0);
3658 info->stats[STAT_STAMINA] += (lvl > 5 ? 1 : 0);
3659 info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl % 2) ? 1 : 0);
3660 info->stats[STAT_INTELLECT] += (lvl > 24 ? 2 : (lvl > 1 ? 1 : 0));
3661 info->stats[STAT_SPIRIT] += (lvl > 33 ? 2 : (lvl > 2 ? 1 : 0));
3662 break;
3663 case CLASS_WARLOCK:
3664 info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl % 2) ? 1 : 0);
3665 info->stats[STAT_STAMINA] += (lvl > 38 ? 2 : (lvl > 3 ? 1 : 0));
3666 info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl % 2) ? 1 : 0);
3667 info->stats[STAT_INTELLECT] += (lvl > 33 ? 2 : (lvl > 2 ? 1 : 0));
3668 info->stats[STAT_SPIRIT] += (lvl > 38 ? 2 : (lvl > 3 ? 1 : 0));
3669 break;
3670 case CLASS_MONK:
3671 info->stats[STAT_STRENGTH] += (lvl > 38 ? 2 : (lvl > 6 && (lvl % 2) ? 1 : 0));
3672 info->stats[STAT_STAMINA] += (lvl > 32 ? 2 : (lvl > 4 ? 1 : 0));
3673 info->stats[STAT_AGILITY] += (lvl > 38 ? 2 : (lvl > 8 && (lvl % 2) ? 1 : 0));
3674 info->stats[STAT_INTELLECT] += (lvl > 38 ? 3 : (lvl > 4 ? 1 : 0));
3675 info->stats[STAT_SPIRIT] += (lvl > 38 ? 3 : (lvl > 5 ? 1 : 0));
3676 break;
3677 case CLASS_DRUID:
3678 info->stats[STAT_STRENGTH] += (lvl > 38 ? 2 : (lvl > 6 && (lvl % 2) ? 1 : 0));
3679 info->stats[STAT_STAMINA] += (lvl > 32 ? 2 : (lvl > 4 ? 1 : 0));
3680 info->stats[STAT_AGILITY] += (lvl > 38 ? 2 : (lvl > 8 && (lvl % 2) ? 1 : 0));
3681 info->stats[STAT_INTELLECT] += (lvl > 38 ? 3 : (lvl > 4 ? 1 : 0));
3682 info->stats[STAT_SPIRIT] += (lvl > 38 ? 3 : (lvl > 5 ? 1 : 0));
3683 }
3684 }
3685}
3686
3688{
3689 uint32 oldMSTime = getMSTime();
3690
3691 // For reload case
3692 for (QuestMap::const_iterator itr = _questTemplates.begin(); itr != _questTemplates.end(); ++itr)
3693 delete itr->second;
3694
3695 _questTemplates.clear();
3696
3697 mExclusiveQuestGroups.clear();
3698
3699 QueryResult result = WorldDatabase.Query("SELECT "
3700 "Id, Method, Level, MinLevel, MaxLevel, ZoneOrSort, Type, SuggestedPlayers, LimitTime, RequiredClasses, RequiredRaces, RequiredSkillId, RequiredSkillPoints, "
3701 "RequiredMinRepFaction, RequiredMaxRepFaction, RequiredMinRepValue, RequiredMaxRepValue, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestIdChain, RewardXPId, RewardMoney, RewardMoneyMaxLevel, RewardSpell, RewardSpellCast, "
3702 "RewardHonor, RewardHonorMultiplier, RewardMailTemplateId, RewardMailDelay, SourceItemId, SourceSpellId, Flags, Flags2, SpecialFlags, MinimapTargetMark, RewardTitleId, RewardTalents, RewardArenaPoints, "
3703 "RewardSkillId, RewardSkillPoints, RewardReputationMask, QuestGiverPortrait, QuestTurnInPortrait, RewardPackageItemId, RewardItemId1, RewardItemId2, RewardItemId3, RewardItemId4, RewardItemCount1, RewardItemCount2, RewardItemCount3, RewardItemCount4, "
3704 "RewardChoiceItemId1, RewardChoiceItemId2, RewardChoiceItemId3, RewardChoiceItemId4, RewardChoiceItemId5, RewardChoiceItemId6, RewardChoiceItemCount1, RewardChoiceItemCount2, RewardChoiceItemCount3, RewardChoiceItemCount4, RewardChoiceItemCount5, RewardChoiceItemCount6, "
3705 "RewardFactionId1, RewardFactionId2, RewardFactionId3, RewardFactionId4, RewardFactionId5, RewardFactionValueId1, RewardFactionValueId2, RewardFactionValueId3, RewardFactionValueId4, RewardFactionValueId5, "
3706 "RewardFactionValueIdOverride1, RewardFactionValueIdOverride2, RewardFactionValueIdOverride3, RewardFactionValueIdOverride4, RewardFactionValueIdOverride5, "
3707 "PointMapId, PointX, PointY, PointOption, Title, Objectives, Details, EndText, OfferRewardText, RequestItemsText, CompletedText,"
3708 "RequiredSourceItemId1, RequiredSourceItemId2, RequiredSourceItemId3, RequiredSourceItemId4, RequiredSourceItemCount1, RequiredSourceItemCount2, RequiredSourceItemCount3, RequiredSourceItemCount4, "
3709 "RewardCurrencyId1, RewardCurrencyId2, RewardCurrencyId3, RewardCurrencyId4, RewardCurrencyCount1, RewardCurrencyCount2, RewardCurrencyCount3, RewardCurrencyCount4, "
3710 "QuestGiverTextWindow, QuestGiverTargetName, QuestTurnTextWindow, QuestTurnTargetName, SoundAccept, SoundTurnIn, "
3711 "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4, DetailsEmoteDelay1, DetailsEmoteDelay2, DetailsEmoteDelay3, DetailsEmoteDelay4, EmoteOnIncomplete, EmoteOnComplete, "
3712 "OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4, OfferRewardEmoteDelay1, OfferRewardEmoteDelay2, OfferRewardEmoteDelay3, OfferRewardEmoteDelay4, WDBVerified"
3713 " FROM quest_template");
3714
3715 if (!result)
3716 {
3717 SF_LOG_ERROR("server.loading", ">> Loaded 0 quests definitions. DB table `quest_template` is empty.");
3718 return;
3719 }
3720
3721 // create multimap previous quest for each existed quest
3722 // some quests can have many previous maps set by NextQuestId in previous quest
3723 // for example set of race quests can lead to single not race specific quest
3724 do
3725 {
3726 Field* fields = result->Fetch();
3727
3728 Quest* newQuest = new Quest(fields);
3729 _questTemplates[newQuest->GetQuestId()] = newQuest;
3730 } while (result->NextRow());
3731
3732 std::map<uint32, uint32> usedMailTemplates;
3733
3734 // Post processing
3735 for (QuestMap::iterator iter = _questTemplates.begin(); iter != _questTemplates.end(); ++iter)
3736 {
3737 // skip post-loading checks for disabled quests
3738 if (DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, iter->first, NULL))
3739 continue;
3740
3741 Quest* qinfo = iter->second;
3742
3743 // additional quest integrity checks (GO, creature_template and item_template must be loaded already)
3744
3745 if (qinfo->GetQuestMethod() >= 3)
3746 SF_LOG_ERROR("sql.sql", "Quest %u has `Method` = %u, expected values are 0, 1 or 2.", qinfo->GetQuestId(), qinfo->GetQuestMethod());
3747
3749 {
3750 SF_LOG_ERROR("sql.sql", "Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u",
3753 }
3754
3755 if (qinfo->Flags & QUEST_FLAGS_DAILY && qinfo->Flags & QUEST_FLAGS_WEEKLY)
3756 {
3757 SF_LOG_ERROR("sql.sql", "Weekly Quest %u is marked as daily quest in `Flags`, removed daily flag.", qinfo->GetQuestId());
3758 qinfo->Flags &= ~QUEST_FLAGS_DAILY;
3759 }
3760
3761 if (qinfo->Flags & QUEST_FLAGS_DAILY)
3762 {
3764 {
3765 SF_LOG_ERROR("sql.sql", "Daily Quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId());
3767 }
3768 }
3769
3770 if (qinfo->Flags & QUEST_FLAGS_WEEKLY)
3771 {
3773 {
3774 SF_LOG_ERROR("sql.sql", "Weekly Quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId());
3776 }
3777 }
3778
3780 {
3782 {
3783 SF_LOG_ERROR("sql.sql", "Monthly quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId());
3785 }
3786 }
3787
3788 if (qinfo->Flags & QUEST_FLAGS_TRACKING_EVENT)
3789 {
3790 // at auto-reward can be rewarded only RewardChoiceItemId[0]
3791 for (int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j)
3792 {
3793 if (uint32 id = qinfo->RewardChoiceItemId[j])
3794 {
3795 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardChoiceItemId%d` = %u but item from `RewardChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_TRACKING_EVENT.",
3796 qinfo->GetQuestId(), j + 1, id, j + 1);
3797 // no changes, quest ignore this data
3798 }
3799 }
3800 }
3801
3802 if (qinfo->MinLevel == uint32(-1) || qinfo->MinLevel > DEFAULT_MAX_LEVEL)
3803 {
3804 SF_LOG_ERROR("sql.sql", "Quest %u should be disabled because `MinLevel` = %i", qinfo->GetQuestId(), int32(qinfo->MinLevel));
3805 // no changes needed, sending -1 in SMSG_QUEST_QUERY_RESPONSE is valid
3806 }
3807
3808 // client quest log visual (area case)
3809 if (qinfo->ZoneOrSort > 0)
3810 {
3811 if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
3812 {
3813 SF_LOG_ERROR("sql.sql", "Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
3814 qinfo->GetQuestId(), qinfo->ZoneOrSort);
3815 // no changes, quest not dependent from this value but can have problems at client
3816 }
3817 }
3818 // client quest log visual (sort case)
3819 if (qinfo->ZoneOrSort < 0)
3820 {
3821 QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort));
3822 if (!qSort)
3823 {
3824 SF_LOG_ERROR("sql.sql", "Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.",
3825 qinfo->GetQuestId(), qinfo->ZoneOrSort);
3826 // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check)
3827 }
3828 //check for proper RequiredSkillId value (skill case)
3829 if (uint32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort)))
3830 {
3831 if (qinfo->RequiredSkillId != skill_id)
3832 {
3833 SF_LOG_ERROR("sql.sql", "Quest %u has `ZoneOrSort` = %i but `RequiredSkillId` does not have a corresponding value (%d).",
3834 qinfo->GetQuestId(), qinfo->ZoneOrSort, skill_id);
3835 //override, and force proper value here?
3836 }
3837 }
3838 }
3839
3840 // RequiredClasses, can be 0/CLASSMASK_ALL_PLAYABLE to allow any class
3841 if (qinfo->RequiredClasses)
3842 {
3844 {
3845 SF_LOG_ERROR("sql.sql", "Quest %u does not contain any playable classes in `RequiredClasses` (%u), value set to 0 (all classes).", qinfo->GetQuestId(), qinfo->RequiredClasses);
3846 qinfo->RequiredClasses = 0;
3847 }
3848 }
3849 // RequiredRaces, can be 0/RACEMASK_ALL_PLAYABLE to allow any race
3850 if (qinfo->RequiredRaces)
3851 {
3852 if (!(qinfo->RequiredRaces & RACEMASK_ALL_PLAYABLE))
3853 {
3854 SF_LOG_ERROR("sql.sql", "Quest %u does not contain any playable races in `RequiredRaces` (%u), value set to 0 (all races).", qinfo->GetQuestId(), qinfo->RequiredRaces);
3855 qinfo->RequiredRaces = 0;
3856 }
3857 }
3858 // RequiredSkillId, can be 0
3859 if (qinfo->RequiredSkillId)
3860 {
3861 if (!sSkillLineStore.LookupEntry(qinfo->RequiredSkillId))
3862 {
3863 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredSkillId` = %u but this skill does not exist",
3864 qinfo->GetQuestId(), qinfo->RequiredSkillId);
3865 }
3866 }
3867
3868 if (qinfo->RequiredSkillPoints)
3869 {
3870 if (qinfo->RequiredSkillPoints > sWorld->GetConfigMaxSkillValue())
3871 {
3872 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredSkillPoints` = %u but max possible skill is %u, quest can't be done.",
3873 qinfo->GetQuestId(), qinfo->RequiredSkillPoints, sWorld->GetConfigMaxSkillValue());
3874 // no changes, quest can't be done for this requirement
3875 }
3876 }
3877 // else Skill quests can have 0 skill level, this is ok
3878
3879 if (qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction))
3880 {
3881 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.",
3882 qinfo->GetQuestId(), qinfo->RequiredMinRepFaction, qinfo->RequiredMinRepFaction);
3883 // no changes, quest can't be done for this requirement
3884 }
3885
3886 if (qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction))
3887 {
3888 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.",
3889 qinfo->GetQuestId(), qinfo->RequiredMaxRepFaction, qinfo->RequiredMaxRepFaction);
3890 // no changes, quest can't be done for this requirement
3891 }
3892
3894 {
3895 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.",
3897 // no changes, quest can't be done for this requirement
3898 }
3899
3900 if (qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue)
3901 {
3902 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.",
3903 qinfo->GetQuestId(), qinfo->RequiredMaxRepValue, qinfo->RequiredMinRepValue);
3904 // no changes, quest can't be done for this requirement
3905 }
3906
3907 if (!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue != 0)
3908 {
3909 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect",
3910 qinfo->GetQuestId(), qinfo->RequiredMinRepValue);
3911 // warning
3912 }
3913
3914 if (!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue != 0)
3915 {
3916 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect",
3917 qinfo->GetQuestId(), qinfo->RequiredMaxRepValue);
3918 // warning
3919 }
3920
3921 if (qinfo->RewardTitleId && !sCharTitlesStore.LookupEntry(qinfo->RewardTitleId))
3922 {
3923 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.",
3924 qinfo->GetQuestId(), qinfo->GetCharTitleId(), qinfo->GetCharTitleId());
3925 qinfo->RewardTitleId = 0;
3926 // quest can't reward this title
3927 }
3928
3929 if (qinfo->SourceItemId)
3930 {
3931 if (!sObjectMgr->GetItemTemplate(qinfo->SourceItemId))
3932 {
3933 SF_LOG_ERROR("sql.sql", "Quest %u has `SourceItemId` = %u but item with entry %u does not exist, quest can't be done.",
3934 qinfo->GetQuestId(), qinfo->SourceItemId, qinfo->SourceItemId);
3935 qinfo->SourceItemId = 0; // quest can't be done for this requirement
3936 }
3937 }
3938
3939 if (qinfo->SourceSpellid)
3940 {
3941 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->SourceSpellid);
3942 if (!spellInfo)
3943 {
3944 SF_LOG_ERROR("sql.sql", "Quest %u has `SourceSpellid` = %u but spell %u doesn't exist, quest can't be done.",
3945 qinfo->GetQuestId(), qinfo->SourceSpellid, qinfo->SourceSpellid);
3946 qinfo->SourceSpellid = 0; // quest can't be done for this requirement
3947 }
3948 else if (!SpellMgr::IsSpellValid(spellInfo))
3949 {
3950 SF_LOG_ERROR("sql.sql", "Quest %u has `SourceSpellid` = %u but spell %u is broken, quest can't be done.",
3951 qinfo->GetQuestId(), qinfo->SourceSpellid, qinfo->SourceSpellid);
3952 qinfo->SourceSpellid = 0; // quest can't be done for this requirement
3953 }
3954 }
3955
3956 for (uint8 j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j)
3957 {
3958 uint32 id = qinfo->RequiredSourceItemId[j];
3959 if (id)
3960 {
3961 if (!sObjectMgr->GetItemTemplate(id))
3962 {
3963 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredSourceItemId%d` = %u but item with entry %u does not exist, quest can't be done.",
3964 qinfo->GetQuestId(), j + 1, id, id);
3965 // no changes, quest can't be done for this requirement
3966 }
3967 }
3968 else
3969 {
3970 if (qinfo->RequiredSourceItemCount[j] > 0)
3971 {
3972 SF_LOG_ERROR("sql.sql", "Quest %u has `RequiredSourceItemId%d` = 0 but `RequiredSourceItemCount%d` = %u.",
3973 qinfo->GetQuestId(), j + 1, j + 1, qinfo->RequiredSourceItemCount[j]);
3974 // no changes, quest ignore this data
3975 }
3976 }
3977 }
3978
3979 for (uint8 j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j)
3980 {
3981 uint32 id = qinfo->RewardChoiceItemId[j];
3982 if (id)
3983 {
3984 if (!sObjectMgr->GetItemTemplate(id))
3985 {
3986 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
3987 qinfo->GetQuestId(), j + 1, id, id);
3988 qinfo->RewardChoiceItemId[j] = 0; // no changes, quest will not reward this
3989 }
3990
3991 if (!qinfo->RewardChoiceItemCount[j])
3992 {
3993 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardChoiceItemId%d` = %u but `RewardChoiceItemCount%d` = 0, quest can't be done.",
3994 qinfo->GetQuestId(), j + 1, id, j + 1);
3995 // no changes, quest can't be done
3996 }
3997 }
3998 else if (qinfo->RewardChoiceItemCount[j] > 0)
3999 {
4000 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardChoiceItemId%d` = 0 but `RewardChoiceItemCount%d` = %u.",
4001 qinfo->GetQuestId(), j + 1, j + 1, qinfo->RewardChoiceItemCount[j]);
4002 // no changes, quest ignore this data
4003 }
4004 }
4005
4006 for (uint8 j = 0; j < QUEST_REWARDS_COUNT; ++j)
4007 {
4008 uint32 id = qinfo->RewardItemId[j];
4009 if (id)
4010 {
4011 if (!sObjectMgr->GetItemTemplate(id))
4012 {
4013 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
4014 qinfo->GetQuestId(), j + 1, id, id);
4015 qinfo->RewardItemId[j] = 0; // no changes, quest will not reward this item
4016 }
4017
4018 if (!qinfo->RewardItemIdCount[j])
4019 {
4020 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardItemId%d` = %u but `RewardItemIdCount%d` = 0, quest will not reward this item.",
4021 qinfo->GetQuestId(), j + 1, id, j + 1);
4022 // no changes
4023 }
4024 }
4025 else if (qinfo->RewardItemIdCount[j] > 0)
4026 {
4027 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardItemId%d` = 0 but `RewardItemIdCount%d` = %u.",
4028 qinfo->GetQuestId(), j + 1, j + 1, qinfo->RewardItemIdCount[j]);
4029 // no changes, quest ignore this data
4030 }
4031 }
4032
4033 for (uint8 j = 0; j < QUEST_REPUTATIONS_COUNT; ++j)
4034 {
4035 if (qinfo->RewardFactionId[j])
4036 {
4037 if (abs(qinfo->RewardFactionValueId[j]) > 9)
4038 {
4039 SF_LOG_ERROR("sql.sql", "Quest %u has RewardFactionValueId%d = %i. That is outside the range of valid values (-9 to 9).", qinfo->GetQuestId(), j + 1, qinfo->RewardFactionValueId[j]);
4040 }
4041 if (!sFactionStore.LookupEntry(qinfo->RewardFactionId[j]))
4042 {
4043 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardFactionId%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.", qinfo->GetQuestId(), j + 1, qinfo->RewardFactionId[j], qinfo->RewardFactionId[j]);
4044 qinfo->RewardFactionId[j] = 0; // quest will not reward this
4045 }
4046 }
4047
4048 else if (qinfo->RewardFactionValueIdOverride[j] != 0)
4049 {
4050 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardFactionId%d` = 0 but `RewardFactionValueIdOverride%d` = %i.",
4051 qinfo->GetQuestId(), j + 1, j + 1, qinfo->RewardFactionValueIdOverride[j]);
4052 // no changes, quest ignore this data
4053 }
4054 }
4055
4056 if (qinfo->RewardSpell)
4057 {
4058 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpell);
4059
4060 if (!spellInfo)
4061 {
4062 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u does not exist, spell removed as display reward.",
4063 qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
4064 qinfo->RewardSpell = 0; // no spell reward will display for this quest
4065 }
4066
4067 else if (!SpellMgr::IsSpellValid(spellInfo))
4068 {
4069 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is broken, quest will not have a spell reward.",
4070 qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
4071 qinfo->RewardSpell = 0; // no spell reward will display for this quest
4072 }
4073
4074 else if (GetTalentSpellCost(qinfo->RewardSpell))
4075 {
4076 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.",
4077 qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
4078 qinfo->RewardSpell = 0; // no spell reward will display for this quest
4079 }
4080 }
4081
4082 if (qinfo->RewardSpellCast > 0)
4083 {
4084 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(qinfo->RewardSpellCast);
4085
4086 if (!spellInfo)
4087 {
4088 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.",
4089 qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
4090 qinfo->RewardSpellCast = 0; // no spell will be casted on player
4091 }
4092
4093 else if (!SpellMgr::IsSpellValid(spellInfo))
4094 {
4095 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSpellCast` = %u but spell %u is broken, quest will not have a spell reward.",
4096 qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
4097 qinfo->RewardSpellCast = 0; // no spell will be casted on player
4098 }
4099
4100 else if (GetTalentSpellCost(qinfo->RewardSpellCast))
4101 {
4102 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.",
4103 qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
4104 qinfo->RewardSpellCast = 0; // no spell will be casted on player
4105 }
4106 }
4107
4108 if (qinfo->RewardMailTemplateId)
4109 {
4110 if (!sMailTemplateStore.LookupEntry(qinfo->RewardMailTemplateId))
4111 {
4112 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.",
4113 qinfo->GetQuestId(), qinfo->RewardMailTemplateId, qinfo->RewardMailTemplateId);
4114 qinfo->RewardMailTemplateId = 0; // no mail will send to player
4115 qinfo->RewardMailDelay = 0; // no mail will send to player
4116 }
4117 else if (usedMailTemplates.find(qinfo->RewardMailTemplateId) != usedMailTemplates.end())
4118 {
4119 std::map<uint32, uint32>::const_iterator used_mt_itr = usedMailTemplates.find(qinfo->RewardMailTemplateId);
4120 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardMailTemplateId` = %u but mail template %u already used for quest %u, quest will not have a mail reward.",
4121 qinfo->GetQuestId(), qinfo->RewardMailTemplateId, qinfo->RewardMailTemplateId, used_mt_itr->second);
4122 qinfo->RewardMailTemplateId = 0; // no mail will send to player
4123 qinfo->RewardMailDelay = 0; // no mail will send to player
4124 }
4125 else
4126 usedMailTemplates[qinfo->RewardMailTemplateId] = qinfo->GetQuestId();
4127 }
4128
4129 if (qinfo->NextQuestIdChain)
4130 {
4131 QuestMap::iterator qNextItr = _questTemplates.find(qinfo->NextQuestIdChain);
4132 if (qNextItr == _questTemplates.end())
4133 {
4134 SF_LOG_ERROR("sql.sql", "Quest %u has `NextQuestIdChain` = %u but quest %u does not exist, quest chain will not work.",
4135 qinfo->GetQuestId(), qinfo->NextQuestIdChain, qinfo->NextQuestIdChain);
4136 qinfo->NextQuestIdChain = 0;
4137 }
4138 else
4139 qNextItr->second->prevChainQuests.push_back(qinfo->GetQuestId());
4140 }
4141
4142 for (uint8 j = 0; j < QUEST_REWARD_CURRENCY_COUNT; ++j)
4143 {
4144 if (qinfo->RewardCurrencyId[j])
4145 {
4146 if (qinfo->RewardCurrencyCount[j] == 0)
4147 {
4148 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardCurrencyId%d` = %u but `RewardCurrencyCount%d` = 0, quest can't be done.",
4149 qinfo->GetQuestId(), j + 1, qinfo->RewardCurrencyId[j], j + 1);
4150 // no changes, quest can't be done for this requirement
4151 }
4152
4153 if (!sCurrencyTypesStore.LookupEntry(qinfo->RewardCurrencyId[j]))
4154 {
4155 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardCurrencyId%d` = %u but currency with entry %u does not exist, quest can't be done.",
4156 qinfo->GetQuestId(), j + 1, qinfo->RewardCurrencyId[j], qinfo->RewardCurrencyId[j]);
4157 qinfo->RewardCurrencyCount[j] = 0; // prevent incorrect work of quest
4158 }
4159 }
4160 else if (qinfo->RewardCurrencyCount[j] > 0)
4161 {
4162 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardCurrencyId%d` = 0 but `RewardCurrencyCount%d` = %u, quest can't be done.",
4163 qinfo->GetQuestId(), j + 1, j + 1, qinfo->RewardCurrencyCount[j]);
4164 qinfo->RewardCurrencyCount[j] = 0; // prevent incorrect work of quest
4165 }
4166 }
4167
4168 if (qinfo->SoundAccept)
4169 {
4170 if (!sSoundEntriesStore.LookupEntry(qinfo->SoundAccept))
4171 {
4172 SF_LOG_ERROR("sql.sql", "Quest %u has `SoundAccept` = %u but sound %u does not exist, set to 0.",
4173 qinfo->GetQuestId(), qinfo->SoundAccept, qinfo->SoundAccept);
4174 qinfo->SoundAccept = 0; // no sound will be played
4175 }
4176 }
4177
4178 if (qinfo->SoundTurnIn)
4179 {
4180 if (!sSoundEntriesStore.LookupEntry(qinfo->SoundTurnIn))
4181 {
4182 SF_LOG_ERROR("sql.sql", "Quest %u has `SoundTurnIn` = %u but sound %u does not exist, set to 0.",
4183 qinfo->GetQuestId(), qinfo->SoundTurnIn, qinfo->SoundTurnIn);
4184 qinfo->SoundTurnIn = 0; // no sound will be played
4185 }
4186 }
4187
4188 if (qinfo->RewardSkillId)
4189 {
4190 if (!sSkillLineStore.LookupEntry(qinfo->RewardSkillId))
4191 {
4192 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillId` = %u but this skill does not exist",
4193 qinfo->GetQuestId(), qinfo->RewardSkillId);
4194 }
4195 if (!qinfo->RewardSkillPoints)
4196 {
4197 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillId` = %u but `RewardSkillPoints` is 0",
4198 qinfo->GetQuestId(), qinfo->RewardSkillId);
4199 }
4200 }
4201
4202 if (qinfo->RewardSkillPoints)
4203 {
4204 if (qinfo->RewardSkillPoints > sWorld->GetConfigMaxSkillValue())
4205 {
4206 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillPoints` = %u but max possible skill is %u, quest can't be done.",
4207 qinfo->GetQuestId(), qinfo->RewardSkillPoints, sWorld->GetConfigMaxSkillValue());
4208 // no changes, quest can't be done for this requirement
4209 }
4210 if (!qinfo->RewardSkillId)
4211 {
4212 SF_LOG_ERROR("sql.sql", "Quest %u has `RewardSkillPoints` = %u but `RewardSkillId` is 0",
4213 qinfo->GetQuestId(), qinfo->RewardSkillPoints);
4214 }
4215 }
4216
4217 // fill additional data stores
4218 if (qinfo->PrevQuestId)
4219 {
4220 if (_questTemplates.find(abs(qinfo->GetPrevQuestId())) == _questTemplates.end())
4221 SF_LOG_ERROR("sql.sql", "Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId());
4222 else
4223 qinfo->prevQuests.push_back(qinfo->PrevQuestId);
4224 }
4225
4226 if (qinfo->NextQuestId)
4227 {
4228 QuestMap::iterator qNextItr = _questTemplates.find(abs(qinfo->GetNextQuestId()));
4229 if (qNextItr == _questTemplates.end())
4230 SF_LOG_ERROR("sql.sql", "Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
4231 else
4232 {
4233 int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
4234 qNextItr->second->prevQuests.push_back(signedQuestId);
4235 }
4236 }
4237
4238 if (qinfo->ExclusiveGroup)
4239 mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId()));
4240 if (qinfo->LimitTime)
4242 }
4243
4244 // check QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
4245 for (uint32 i = 0; i < sSpellMgr->GetSpellInfoStoreSize(); ++i)
4246 {
4247 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i);
4248 if (!spellInfo)
4249 continue;
4250
4251 for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
4252 {
4253 if (spellInfo->Effects[j].Effect != SPELL_EFFECT_QUEST_COMPLETE)
4254 continue;
4255
4256 uint32 quest_id = spellInfo->Effects[j].MiscValue;
4257
4258 Quest const* quest = GetQuestTemplate(quest_id);
4259
4260 // some quest referenced in spells not exist (outdated spells)
4261 if (!quest)
4262 continue;
4263
4265 {
4266 SF_LOG_ERROR("sql.sql", "Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u, but quest not have flag QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.", spellInfo->Id, quest_id);
4267
4268 // this will prevent quest completing without objective
4269 const_cast<Quest*>(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT);
4270 }
4271 }
4272 }
4273
4274 SF_LOG_INFO("server.loading", ">> Loaded %lu quests definitions in %u ms", (unsigned long)_questTemplates.size(), GetMSTimeDiffToNow(oldMSTime));
4275}
4276
4278{
4279 uint32 oldMSTime = getMSTime();
4280
4281 _questLocaleStore.clear(); // need for reload case
4282
4283 QueryResult result = WorldDatabase.Query("SELECT Id, "
4284 "Title_loc1, Details_loc1, Objectives_loc1, OfferRewardText_loc1, RequestItemsText_loc1, EndText_loc1, CompletedText_loc1, QuestGiverTextWindow_loc1, QuestGiverTargetName_loc1, QuestTurnTextWindow_loc1, QuestTurnTargetName_loc1,"
4285 "Title_loc2, Details_loc2, Objectives_loc2, OfferRewardText_loc2, RequestItemsText_loc2, EndText_loc2, CompletedText_loc2, QuestGiverTextWindow_loc2, QuestGiverTargetName_loc2, QuestTurnTextWindow_loc2, QuestTurnTargetName_loc2,"
4286 "Title_loc3, Details_loc3, Objectives_loc3, OfferRewardText_loc3, RequestItemsText_loc3, EndText_loc3, CompletedText_loc3, QuestGiverTextWindow_loc3, QuestGiverTargetName_loc3, QuestTurnTextWindow_loc3, QuestTurnTargetName_loc3,"
4287 "Title_loc4, Details_loc4, Objectives_loc4, OfferRewardText_loc4, RequestItemsText_loc4, EndText_loc4, CompletedText_loc4, QuestGiverTextWindow_loc4, QuestGiverTargetName_loc4, QuestTurnTextWindow_loc4, QuestTurnTargetName_loc4,"
4288 "Title_loc5, Details_loc5, Objectives_loc5, OfferRewardText_loc5, RequestItemsText_loc5, EndText_loc5, CompletedText_loc5, QuestGiverTextWindow_loc5, QuestGiverTargetName_loc5, QuestTurnTextWindow_loc5, QuestTurnTargetName_loc5,"
4289 "Title_loc6, Details_loc6, Objectives_loc6, OfferRewardText_loc6, RequestItemsText_loc6, EndText_loc6, CompletedText_loc6, QuestGiverTextWindow_loc6, QuestGiverTargetName_loc6, QuestTurnTextWindow_loc6, QuestTurnTargetName_loc6,"
4290 "Title_loc7, Details_loc7, Objectives_loc7, OfferRewardText_loc7, RequestItemsText_loc7, EndText_loc7, CompletedText_loc7, QuestGiverTextWindow_loc7, QuestGiverTargetName_loc7, QuestTurnTextWindow_loc7, QuestTurnTargetName_loc7,"
4291 "Title_loc8, Details_loc8, Objectives_loc8, OfferRewardText_loc8, RequestItemsText_loc8, EndText_loc8, CompletedText_loc8, QuestGiverTextWindow_loc8, QuestGiverTargetName_loc8, QuestTurnTextWindow_loc8, QuestTurnTargetName_loc8,"
4292 "Title_loc9, Details_loc9, Objectives_loc9, OfferRewardText_loc9, RequestItemsText_loc9, EndText_loc9, CompletedText_loc9, QuestGiverTextWindow_loc9, QuestGiverTargetName_loc9, QuestTurnTextWindow_loc9, QuestTurnTargetName_loc9,"
4293 "Title_loc10, Details_loc10, Objectives_loc10, OfferRewardText_loc10, RequestItemsText_loc10, EndText_loc10, CompletedText_loc10, QuestGiverTextWindow_loc10, QuestGiverTargetName_loc10, QuestTurnTextWindow_loc10, QuestTurnTargetName_loc10,"
4294 "Title_loc11, Details_loc11, Objectives_loc11, OfferRewardText_loc11, RequestItemsText_loc11, EndText_loc11, CompletedText_loc11, QuestGiverTextWindow_loc11, QuestGiverTargetName_loc11, QuestTurnTextWindow_loc11, QuestTurnTargetName_loc11"
4295 " FROM locales_quest");
4296
4297 if (!result)
4298 return;
4299
4300 do
4301 {
4302 Field* fields = result->Fetch();
4303
4304 uint32 entry = fields[0].GetUInt32();
4305
4306 QuestLocale& data = _questLocaleStore[entry];
4307
4308 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
4309 {
4310 LocaleConstant locale = (LocaleConstant)i;
4311
4312 AddLocaleString(fields[1 + 11 * (i - 1)].GetString(), locale, data.Title);
4313 AddLocaleString(fields[1 + 11 * (i - 1) + 1].GetString(), locale, data.Details);
4314 AddLocaleString(fields[1 + 11 * (i - 1) + 2].GetString(), locale, data.Objectives);
4315 AddLocaleString(fields[1 + 11 * (i - 1) + 3].GetString(), locale, data.OfferRewardText);
4316 AddLocaleString(fields[1 + 11 * (i - 1) + 4].GetString(), locale, data.RequestItemsText);
4317 AddLocaleString(fields[1 + 11 * (i - 1) + 5].GetString(), locale, data.EndText);
4318 AddLocaleString(fields[1 + 11 * (i - 1) + 6].GetString(), locale, data.CompletedText);
4319 AddLocaleString(fields[1 + 11 * (i - 1) + 7].GetString(), locale, data.QuestGiverTextWindow);
4320 AddLocaleString(fields[1 + 11 * (i - 1) + 8].GetString(), locale, data.QuestGiverTargetName);
4321 AddLocaleString(fields[1 + 11 * (i - 1) + 9].GetString(), locale, data.QuestTurnTextWindow);
4322 AddLocaleString(fields[1 + 11 * (i - 1) + 10].GetString(), locale, data.QuestTurnTargetName);
4323 }
4324 } while (result->NextRow());
4325
4326 SF_LOG_INFO("server.loading", ">> Loaded %lu Quest locale strings in %u ms", (unsigned long)_questLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
4327}
4328
4330{
4331 uint32 oldMSTime = getMSTime();
4332
4333 ScriptMapMap* scripts = GetScriptsMapByType(type);
4334 if (!scripts)
4335 return;
4336
4337 std::string tableName = GetScriptsTableNameByType(type);
4338 if (tableName.empty())
4339 return;
4340
4341 if (sScriptMgr->IsScriptScheduled()) // function cannot be called when scripts are in use.
4342 return;
4343
4344 SF_LOG_INFO("server.loading", "Loading %s...", tableName.c_str());
4345
4346 scripts->clear(); // need for reload support
4347
4348 bool isSpellScriptTable = (type == ScriptsType::SCRIPTS_SPELL);
4349 // 0 1 2 3 4 5 6 7 8 9
4350 QueryResult result = WorldDatabase.PQuery("SELECT id, delay, command, datalong, datalong2, dataint, x, y, z, o%s FROM %s", isSpellScriptTable ? ", effIndex" : "", tableName.c_str());
4351
4352 if (!result)
4353 {
4354 SF_LOG_INFO("server.loading", ">> Loaded 0 script definitions. DB table `%s` is empty!", tableName.c_str());
4355 return;
4356 }
4357
4358 uint32 count = 0;
4359
4360 do
4361 {
4362 Field* fields = result->Fetch();
4363 ScriptInfo tmp;
4364 tmp.type = type;
4365 tmp.id = fields[0].GetUInt32();
4366 if (isSpellScriptTable)
4367 tmp.id |= fields[10].GetUInt8() << 24;
4368 tmp.delay = fields[1].GetUInt32();
4369 tmp.command = ScriptCommands(fields[2].GetUInt32());
4370 tmp.Raw.nData[0] = fields[3].GetUInt32();
4371 tmp.Raw.nData[1] = fields[4].GetUInt32();
4372 tmp.Raw.nData[2] = fields[5].GetInt32();
4373 tmp.Raw.fData[0] = fields[6].GetFloat();
4374 tmp.Raw.fData[1] = fields[7].GetFloat();
4375 tmp.Raw.fData[2] = fields[8].GetFloat();
4376 tmp.Raw.fData[3] = fields[9].GetFloat();
4377
4378 // generic command args check
4379 switch (tmp.command)
4380 {
4382 {
4384 {
4385 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",
4386 tableName.c_str(), tmp.Talk.ChatType, tmp.id);
4387 continue;
4388 }
4389 if (!tmp.Talk.TextID)
4390 {
4391 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",
4392 tableName.c_str(), tmp.Talk.TextID, tmp.id);
4393 continue;
4394 }
4396 {
4397 SF_LOG_ERROR("sql.sql", "Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",
4398 tableName.c_str(), tmp.Talk.TextID, MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID, tmp.id);
4399 continue;
4400 }
4401
4402 break;
4403 }
4404
4406 {
4407 if (!sEmotesStore.LookupEntry(tmp.Emote.EmoteID))
4408 {
4409 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid emote id (datalong = %u) in SCRIPT_COMMAND_EMOTE for script id %u",
4410 tableName.c_str(), tmp.Emote.EmoteID, tmp.id);
4411 continue;
4412 }
4413 break;
4414 }
4415
4417 {
4418 if (!sMapStore.LookupEntry(tmp.TeleportTo.MapID))
4419 {
4420 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",
4421 tableName.c_str(), tmp.TeleportTo.MapID, tmp.id);
4422 continue;
4423 }
4424
4426 {
4427 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid coordinates (X: %f Y: %f Z: %f O: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",
4428 tableName.c_str(), tmp.TeleportTo.DestX, tmp.TeleportTo.DestY, tmp.TeleportTo.DestZ, tmp.TeleportTo.Orientation, tmp.id);
4429 continue;
4430 }
4431 break;
4432 }
4433
4435 {
4436 Quest const* quest = GetQuestTemplate(tmp.QuestExplored.QuestID);
4437 if (!quest)
4438 {
4439 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
4440 tableName.c_str(), tmp.QuestExplored.QuestID, tmp.id);
4441 continue;
4442 }
4443
4445 {
4446 SF_LOG_ERROR("sql.sql", "Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",
4447 tableName.c_str(), tmp.QuestExplored.QuestID, tmp.id);
4448
4449 // this will prevent quest completing without objective
4450 const_cast<Quest*>(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT);
4451
4452 // continue; - quest objective requirement set and command can be allowed
4453 }
4454
4456 {
4457 SF_LOG_ERROR("sql.sql", "Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
4458 tableName.c_str(), tmp.QuestExplored.Distance, tmp.id);
4459 continue;
4460 }
4461
4463 {
4464 SF_LOG_ERROR("sql.sql", "Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %f or 0 for disable distance check",
4465 tableName.c_str(), tmp.QuestExplored.Distance, tmp.id, DEFAULT_VISIBILITY_DISTANCE);
4466 continue;
4467 }
4468
4470 {
4471 SF_LOG_ERROR("sql.sql", "Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %f or 0 for disable distance check",
4472 tableName.c_str(), tmp.QuestExplored.Distance, tmp.id, INTERACTION_DISTANCE);
4473 continue;
4474 }
4475
4476 break;
4477 }
4478
4480 {
4482 {
4483 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_KILL_CREDIT for script id %u",
4484 tableName.c_str(), tmp.KillCredit.CreatureEntry, tmp.id);
4485 continue;
4486 }
4487 break;
4488 }
4489
4491 {
4493 if (!data)
4494 {
4495 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",
4496 tableName.c_str(), tmp.RespawnGameobject.GOGuid, tmp.id);
4497 continue;
4498 }
4499
4500 GameObjectTemplate const* info = GetGameObjectTemplate(data->id);
4501 if (!info)
4502 {
4503 SF_LOG_ERROR("sql.sql", "Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",
4504 tableName.c_str(), tmp.RespawnGameobject.GOGuid, data->id, tmp.id);
4505 continue;
4506 }
4507
4508 if (info->type == GAMEOBJECT_TYPE_FISHINGNODE ||
4510 info->type == GAMEOBJECT_TYPE_DOOR ||
4511 info->type == GAMEOBJECT_TYPE_BUTTON ||
4512 info->type == GAMEOBJECT_TYPE_TRAP)
4513 {
4514 SF_LOG_ERROR("sql.sql", "Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",
4515 tableName.c_str(), info->entry, tmp.id);
4516 continue;
4517 }
4518 break;
4519 }
4520
4522 {
4524 {
4525 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid coordinates (X: %f Y: %f Z: %f O: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",
4527 continue;
4528 }
4529
4531 {
4532 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",
4533 tableName.c_str(), tmp.TempSummonCreature.CreatureEntry, tmp.id);
4534 continue;
4535 }
4536 break;
4537 }
4538
4541 {
4542 GameObjectData const* data = GetGOData(tmp.ToggleDoor.GOGuid);
4543 if (!data)
4544 {
4545 SF_LOG_ERROR("sql.sql", "Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",
4546 tableName.c_str(), tmp.ToggleDoor.GOGuid, GetScriptCommandName(tmp.command).c_str(), tmp.id);
4547 continue;
4548 }
4549
4550 GameObjectTemplate const* info = GetGameObjectTemplate(data->id);
4551 if (!info)
4552 {
4553 SF_LOG_ERROR("sql.sql", "Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",
4554 tableName.c_str(), tmp.ToggleDoor.GOGuid, data->id, GetScriptCommandName(tmp.command).c_str(), tmp.id);
4555 continue;
4556 }
4557
4558 if (info->type != GAMEOBJECT_TYPE_DOOR)
4559 {
4560 SF_LOG_ERROR("sql.sql", "Table `%s` has gameobject type (%u) non supported by command %s for script id %u",
4561 tableName.c_str(), info->entry, GetScriptCommandName(tmp.command).c_str(), tmp.id);
4562 continue;
4563 }
4564
4565 break;
4566 }
4567
4569 {
4570 if (!sSpellMgr->GetSpellInfo(tmp.RemoveAura.SpellID))
4571 {
4572 SF_LOG_ERROR("sql.sql", "Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA for script id %u",
4573 tableName.c_str(), tmp.RemoveAura.SpellID, tmp.id);
4574 continue;
4575 }
4576 if (tmp.RemoveAura.Flags & ~0x1) // 1 bits (0, 1)
4577 {
4578 SF_LOG_ERROR("sql.sql", "Table `%s` using unknown flags in datalong2 (%u) in SCRIPT_COMMAND_REMOVE_AURA for script id %u",
4579 tableName.c_str(), tmp.RemoveAura.Flags, tmp.id);
4580 continue;
4581 }
4582 break;
4583 }
4584
4586 {
4587 if (!sSpellMgr->GetSpellInfo(tmp.CastSpell.SpellID))
4588 {
4589 SF_LOG_ERROR("sql.sql", "Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
4590 tableName.c_str(), tmp.CastSpell.SpellID, tmp.id);
4591 continue;
4592 }
4593 if (tmp.CastSpell.Flags > 4) // targeting type
4594 {
4595 SF_LOG_ERROR("sql.sql", "Table `%s` using unknown target in datalong2 (%u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
4596 tableName.c_str(), tmp.CastSpell.Flags, tmp.id);
4597 continue;
4598 }
4599 if (tmp.CastSpell.Flags != 4 && tmp.CastSpell.CreatureEntry & ~0x1) // 1 bit (0, 1)
4600 {
4601 SF_LOG_ERROR("sql.sql", "Table `%s` using unknown flags in dataint (%u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
4602 tableName.c_str(), tmp.CastSpell.CreatureEntry, tmp.id);
4603 continue;
4604 }
4605 else if (tmp.CastSpell.Flags == 4 && !GetCreatureTemplate(tmp.CastSpell.CreatureEntry))
4606 {
4607 SF_LOG_ERROR("sql.sql", "Table `%s` using invalid creature entry in dataint (%u) in SCRIPT_COMMAND_CAST_SPELL for script id %u",
4608 tableName.c_str(), tmp.CastSpell.CreatureEntry, tmp.id);
4609 continue;
4610 }
4611 break;
4612 }
4613
4615 {
4617 {
4618 SF_LOG_ERROR("sql.sql", "Table `%s` has nonexistent item (entry: %u) in SCRIPT_COMMAND_CREATE_ITEM for script id %u",
4619 tableName.c_str(), tmp.CreateItem.ItemEntry, tmp.id);
4620 continue;
4621 }
4622 if (!tmp.CreateItem.Amount)
4623 {
4624 SF_LOG_ERROR("sql.sql", "Table `%s` SCRIPT_COMMAND_CREATE_ITEM but amount is %u for script id %u",
4625 tableName.c_str(), tmp.CreateItem.Amount, tmp.id);
4626 continue;
4627 }
4628 break;
4629 }
4630 default:
4631 break;
4632 }
4633
4634 if (scripts->find(tmp.id) == scripts->end())
4635 {
4636 ScriptMap emptyMap;
4637 (*scripts)[tmp.id] = emptyMap;
4638 }
4639 (*scripts)[tmp.id].insert(std::pair<uint32, ScriptInfo>(tmp.delay, tmp));
4640
4641 ++count;
4642 } while (result->NextRow());
4643
4644 SF_LOG_INFO("server.loading", ">> Loaded %u script definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
4645}
4646
4648{
4650
4651 // check ids
4652 for (ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr)
4653 {
4654 uint32 spellId = uint32(itr->first) & 0x00FFFFFF;
4655 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
4656
4657 if (!spellInfo)
4658 {
4659 SF_LOG_ERROR("sql.sql", "Table `spell_scripts` has not existing spell (Id: %u) as script id", spellId);
4660 continue;
4661 }
4662
4663 uint8 i = (uint8)((uint32(itr->first) >> 24) & 0x000000FF);
4664 //check for correct spellEffect
4665 if (!spellInfo->Effects[i].Effect || (spellInfo->Effects[i].Effect != SPELL_EFFECT_SCRIPT_EFFECT && spellInfo->Effects[i].Effect != SPELL_EFFECT_DUMMY))
4666 SF_LOG_ERROR("sql.sql", "Table `spell_scripts` - spell %u effect %u is not SPELL_EFFECT_SCRIPT_EFFECT or SPELL_EFFECT_DUMMY", spellId, i);
4667 }
4668}
4669
4671{
4673
4674 std::set<uint32> evt_scripts;
4675 // Load all possible script entries from gameobjects
4676 GameObjectTemplateContainer const* gotc = sObjectMgr->GetGameObjectTemplates();
4677 for (GameObjectTemplateContainer::const_iterator itr = gotc->begin(); itr != gotc->end(); ++itr)
4678 if (uint32 eventId = itr->second.GetEventScriptId())
4679 evt_scripts.insert(eventId);
4680
4681 // Load all possible script entries from spells
4682 for (uint32 i = 1; i < sSpellMgr->GetSpellInfoStoreSize(); ++i)
4683 if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(i))
4684 for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
4685 if (spell->Effects[j].Effect == SPELL_EFFECT_SEND_EVENT)
4686 if (spell->Effects[j].MiscValue)
4687 evt_scripts.insert(spell->Effects[j].MiscValue);
4688
4689 for (size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx)
4690 {
4691 for (size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx)
4692 {
4693 TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx];
4694
4695 if (node.arrivalEventID)
4696 evt_scripts.insert(node.arrivalEventID);
4697
4698 if (node.departureEventID)
4699 evt_scripts.insert(node.departureEventID);
4700 }
4701 }
4702
4703 // Then check if all scripts are in above list of possible script entries
4704 for (ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr)
4705 {
4706 std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first);
4707 if (itr2 == evt_scripts.end())
4708 SF_LOG_ERROR("sql.sql", "Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field or any spell effect %u",
4709 itr->first, SPELL_EFFECT_SEND_EVENT);
4710 }
4711}
4712
4713//Load WP Scripts
4715{
4717
4718 std::set<uint32> actionSet;
4719
4720 for (ScriptMapMap::const_iterator itr = sWaypointScripts.begin(); itr != sWaypointScripts.end(); ++itr)
4721 actionSet.insert(itr->first);
4722
4724 PreparedQueryResult result = WorldDatabase.Query(stmt);
4725
4726 if (result)
4727 {
4728 do
4729 {
4730 Field* fields = result->Fetch();
4731 uint32 action = fields[0].GetUInt32();
4732
4733 actionSet.erase(action);
4734 } while (result->NextRow());
4735 }
4736
4737 for (std::set<uint32>::iterator itr = actionSet.begin(); itr != actionSet.end(); ++itr)
4738 SF_LOG_ERROR("sql.sql", "There is no waypoint which links to the waypoint script %u", *itr);
4739}
4740
4742{
4743 uint32 oldMSTime = getMSTime();
4744
4745 _spellScriptsStore.clear(); // need for reload case
4746
4747 QueryResult result = WorldDatabase.Query("SELECT spell_id, ScriptName FROM spell_script_names");
4748
4749 if (!result)
4750 {
4751 SF_LOG_INFO("server.loading", ">> Loaded 0 spell script names. DB table `spell_script_names` is empty!");
4752 return;
4753 }
4754
4755 uint32 count = 0;
4756
4757 do
4758 {
4759 Field* fields = result->Fetch();
4760
4761 int32 spellId = fields[0].GetInt32();
4762 char const* scriptName = fields[1].GetCString();
4763
4764 bool allRanks = false;
4765 if (spellId < 0)
4766 {
4767 allRanks = true;
4768 spellId = -spellId;
4769 }
4770
4771 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
4772 if (!spellInfo)
4773 {
4774 SF_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) does not exist.", scriptName, fields[0].GetInt32());
4775 continue;
4776 }
4777
4778 if (allRanks)
4779 {
4780 if (!spellInfo->IsRanked())
4781 SF_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) has no ranks of spell.", scriptName, fields[0].GetInt32());
4782
4783 if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
4784 {
4785 SF_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) is not first rank of spell.", scriptName, fields[0].GetInt32());
4786 continue;
4787 }
4788 while (spellInfo)
4789 {
4790 _spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, GetScriptId(scriptName)));
4791 spellInfo = spellInfo->GetNextRankSpell();
4792 }
4793 }
4794 else
4795 {
4796 if (spellInfo->IsRanked())
4797 SF_LOG_ERROR("sql.sql", "Scriptname: `%s` spell (Id: %d) is ranked spell. Perhaps not all ranks are assigned to this script.", scriptName, spellId);
4798
4799 _spellScriptsStore.insert(SpellScriptsContainer::value_type(spellInfo->Id, GetScriptId(scriptName)));
4800 }
4801
4802 ++count;
4803 } while (result->NextRow());
4804
4805 SF_LOG_INFO("server.loading", ">> Loaded %u spell script names in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
4806}
4807
4809{
4810 uint32 oldMSTime = getMSTime();
4811
4812 if (_spellScriptsStore.empty())
4813 {
4814 SF_LOG_INFO("server.loading", ">> Validated 0 scripts.");
4815 return;
4816 }
4817
4818 uint32 count = 0;
4819
4820 for (SpellScriptsContainer::iterator itr = _spellScriptsStore.begin(); itr != _spellScriptsStore.end();)
4821 {
4822 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(itr->first);
4823 std::vector<std::pair<SpellScriptLoader*, SpellScriptsContainer::iterator> > SpellScriptLoaders;
4824 sScriptMgr->CreateSpellScriptLoaders(itr->first, SpellScriptLoaders);
4825 itr = _spellScriptsStore.upper_bound(itr->first);
4826
4827 for (std::vector<std::pair<SpellScriptLoader*, SpellScriptsContainer::iterator> >::iterator sitr = SpellScriptLoaders.begin(); sitr != SpellScriptLoaders.end(); ++sitr)
4828 {
4829 SpellScript* spellScript = sitr->first->GetSpellScript();
4830 AuraScript* auraScript = sitr->first->GetAuraScript();
4831 bool valid = true;
4832 if (!spellScript && !auraScript)
4833 {
4834 SF_LOG_ERROR("scripts", "Functions GetSpellScript() and GetAuraScript() of script `%s` do not return objects - script skipped", GetScriptName(sitr->second->second));
4835 valid = false;
4836 }
4837 if (spellScript)
4838 {
4839 spellScript->_Init(&sitr->first->GetName(), spellEntry->Id);
4840 spellScript->_Register();
4841 if (!spellScript->_Validate(spellEntry))
4842 valid = false;
4843 delete spellScript;
4844 }
4845 if (auraScript)
4846 {
4847 auraScript->_Init(&sitr->first->GetName(), spellEntry->Id);
4848 auraScript->_Register();
4849 if (!auraScript->_Validate(spellEntry))
4850 valid = false;
4851 delete auraScript;
4852 }
4853 if (!valid)
4854 {
4855 _spellScriptsStore.erase(sitr->second);
4856 }
4857 }
4858 ++count;
4859 }
4860
4861 SF_LOG_INFO("server.loading", ">> Validated %u scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
4862}
4863
4865{
4866 uint32 oldMSTime = getMSTime();
4867
4868 // 0 1 2
4869 QueryResult result = WorldDatabase.Query("SELECT entry, text, next_page FROM page_text");
4870
4871 if (!result)
4872 {
4873 SF_LOG_INFO("server.loading", ">> Loaded 0 page texts. DB table `page_text` is empty!");
4874 return;
4875 }
4876
4877 uint32 count = 0;
4878 do
4879 {
4880 Field* fields = result->Fetch();
4881
4882 PageText& pageText = _pageTextStore[fields[0].GetUInt32()];
4883
4884 pageText.Text = fields[1].GetString();
4885 pageText.NextPage = fields[2].GetUInt32();
4886
4887 ++count;
4888 } while (result->NextRow());
4889
4890 for (PageTextContainer::const_iterator itr = _pageTextStore.begin(); itr != _pageTextStore.end(); ++itr)
4891 {
4892 if (itr->second.NextPage)
4893 {
4894 PageTextContainer::const_iterator itr2 = _pageTextStore.find(itr->second.NextPage);
4895 if (itr2 == _pageTextStore.end())
4896 SF_LOG_ERROR("sql.sql", "Page text (Id: %u) has not existing next page (Id: %u)", itr->first, itr->second.NextPage);
4897 }
4898 }
4899
4900 SF_LOG_INFO("server.loading", ">> Loaded %u page texts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
4901}
4902
4904{
4905 PageTextContainer::const_iterator itr = _pageTextStore.find(pageEntry);
4906 if (itr != _pageTextStore.end())
4907 return &(itr->second);
4908
4909 return NULL;
4910}
4911
4913{
4914 uint32 oldMSTime = getMSTime();
4915
4916 _pageTextLocaleStore.clear(); // need for reload case
4917
4918 QueryResult result = WorldDatabase.Query("SELECT entry, text_loc1, text_loc2, text_loc3, text_loc4, text_loc5, text_loc6, text_loc7, text_loc8, text_loc9, text_loc10, text_loc11 FROM locales_page_text");
4919
4920 if (!result)
4921 return;
4922
4923 do
4924 {
4925 Field* fields = result->Fetch();
4926
4927 uint32 entry = fields[0].GetUInt32();
4928
4929 PageTextLocale& data = _pageTextLocaleStore[entry];
4930
4931 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
4932 AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.Text);
4933 } while (result->NextRow());
4934
4935 SF_LOG_INFO("server.loading", ">> Loaded %lu PageText locale strings in %u ms", (unsigned long)_pageTextLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
4936}
4937
4939{
4940 uint32 oldMSTime = getMSTime();
4941
4942 // 0 1 2 4
4943 QueryResult result = WorldDatabase.Query("SELECT map, parent, script, allowMount FROM instance_template");
4944
4945 if (!result)
4946 {
4947 SF_LOG_INFO("server.loading", ">> Loaded 0 instance templates. DB table `page_text` is empty!");
4948 return;
4949 }
4950
4951 uint32 count = 0;
4952 do
4953 {
4954 Field* fields = result->Fetch();
4955
4956 uint16 mapID = fields[0].GetUInt16();
4957
4958 if (!MapManager::IsValidMAP(mapID, true))
4959 {
4960 SF_LOG_ERROR("sql.sql", "ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", mapID);
4961 continue;
4962 }
4963
4964 InstanceTemplate instanceTemplate;
4965
4966 instanceTemplate.AllowMount = fields[3].GetBool();
4967 instanceTemplate.Parent = uint32(fields[1].GetUInt16());
4968 instanceTemplate.ScriptId = sObjectMgr->GetScriptId(fields[2].GetCString());
4969
4970 _instanceTemplateStore[mapID] = instanceTemplate;
4971
4972 ++count;
4973 } while (result->NextRow());
4974
4975 SF_LOG_INFO("server.loading", ">> Loaded %u instance templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
4976}
4977
4979{
4980 InstanceTemplateContainer::const_iterator itr = _instanceTemplateStore.find(uint16(mapID));
4981 if (itr != _instanceTemplateStore.end())
4982 return &(itr->second);
4983
4984 return NULL;
4985}
4986
4988{
4989 uint32 oldMSTime = getMSTime();
4990
4991 // 0 1 2 3
4992 QueryResult result = WorldDatabase.Query("SELECT entry, creditType, creditEntry, lastEncounterDungeon FROM instance_encounters");
4993 if (!result)
4994 {
4995 SF_LOG_ERROR("server.loading", ">> Loaded 0 instance encounters, table is empty!");
4996 return;
4997 }
4998
4999 uint32 count = 0;
5000 std::map<uint32, std::pair<uint32, DungeonEncounterEntry const*>> dungeonLastBosses;
5001 do
5002 {
5003 Field* fields = result->Fetch();
5004 uint32 entry = fields[0].GetUInt32();
5005 uint8 creditType = fields[1].GetUInt8();
5006 uint32 creditEntry = fields[2].GetUInt32();
5007 uint32 lastEncounterDungeon = fields[3].GetUInt16();
5008 DungeonEncounterEntry const* dungeonEncounter = sDungeonEncounterStore.LookupEntry(entry);
5009 if (!dungeonEncounter)
5010 {
5011 SF_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid encounter id %u, skipped!", entry);
5012 continue;
5013 }
5014
5015 if (lastEncounterDungeon && !sLFGMgr->GetLFGDungeonEntry(lastEncounterDungeon))
5016 {
5017 SF_LOG_ERROR("sql.sql", "Table `instance_encounters` has an encounter %u (%s) marked as final for invalid dungeon id %u, skipped!", entry, dungeonEncounter->encounterName, lastEncounterDungeon);
5018 continue;
5019 }
5020
5021 std::map < uint32, std::pair<uint32, DungeonEncounterEntry const*>>::const_iterator itr = dungeonLastBosses.find(lastEncounterDungeon);
5022 if (lastEncounterDungeon)
5023 {
5024 if (itr != dungeonLastBosses.end())
5025 {
5026 SF_LOG_ERROR("sql.sql", "Table `instance_encounters` specified encounter %u (%s) as last encounter but %u (%s) is already marked as one, skipped!",
5027 entry, dungeonEncounter->encounterName, itr->second.first, itr->second.second->encounterName);
5028 continue;
5029 }
5030
5031 dungeonLastBosses[lastEncounterDungeon] = std::make_pair(entry, dungeonEncounter);
5032 }
5033
5034 switch (EncounterCreditType(creditType))
5035 {
5037 {
5038 CreatureTemplate const* creatureInfo = GetCreatureTemplate(creditEntry);
5039 if (!creatureInfo)
5040 {
5041 SF_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid creature (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName);
5042 continue;
5043 }
5044 const_cast<CreatureTemplate*>(creatureInfo)->flags_extra |= CREATURE_FLAG_EXTRA_DUNGEON_BOSS;
5045 break;
5046 }
5048 if (!sSpellMgr->GetSpellInfo(creditEntry))
5049 {
5050 SF_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid spell (entry %u) linked to the encounter %u (%s), skipped!", creditEntry, entry, dungeonEncounter->encounterName);
5051 continue;
5052 }
5053 break;
5054 default:
5055 SF_LOG_ERROR("sql.sql", "Table `instance_encounters` has an invalid credit type (%u) for encounter %u (%s), skipped!", creditType, entry, dungeonEncounter->encounterName);
5056 continue;
5057 }
5058
5059 if (dungeonEncounter->difficulty == DIFFICULTY_NONE)
5060 {
5061 for (uint32 i = 0; i < 14; ++i)
5062 {
5063 if (GetMapDifficultyData(dungeonEncounter->mapId, DifficultyID(i)))
5064 {
5065 DungeonEncounterList& encounters = _dungeonEncounterStore[MAKE_PAIR32(dungeonEncounter->mapId, i)];
5066 encounters.push_back(new DungeonEncounter(dungeonEncounter, EncounterCreditType(creditType), creditEntry, lastEncounterDungeon));
5067 }
5068 }
5069 }
5070 else
5071 {
5072 DungeonEncounterList& encounters = _dungeonEncounterStore[MAKE_PAIR32(dungeonEncounter->mapId, dungeonEncounter->difficulty)];
5073 encounters.push_back(new DungeonEncounter(dungeonEncounter, EncounterCreditType(creditType), creditEntry, lastEncounterDungeon));
5074 }
5075
5076 ++count;
5077 } while (result->NextRow());
5078
5079 SF_LOG_INFO("server.loading", ">> Loaded %u instance encounters in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
5080}
5081
5083{
5084 GossipTextContainer::const_iterator itr = _gossipTextStore.find(Text_ID);
5085 if (itr != _gossipTextStore.end())
5086 return &itr->second;
5087 return NULL;
5088}
5089
5091{
5092 uint32 oldMSTime = getMSTime();
5093
5094 QueryResult result = WorldDatabase.Query("SELECT * FROM npc_text");
5095
5096 int count = 0;
5097 if (!result)
5098 {
5099 SF_LOG_INFO("server.loading", ">> Loaded %u npc texts", count);
5100 return;
5101 }
5102 _gossipTextStore.rehash(result->GetRowCount());
5103
5104 int cic;
5105
5106 do
5107 {
5108 ++count;
5109 cic = 0;
5110
5111 Field* fields = result->Fetch();
5112
5113 uint32 Text_ID = fields[cic++].GetUInt32();
5114 if (!Text_ID)
5115 {
5116 SF_LOG_ERROR("sql.sql", "Table `npc_text` has record wit reserved id 0, ignore.");
5117 continue;
5118 }
5119
5120 GossipText& gText = _gossipTextStore[Text_ID];
5121
5122 for (int i = 0; i < MAX_GOSSIP_TEXT_OPTIONS; i++)
5123 {
5124 gText.Options[i].Text_0 = fields[cic++].GetString();
5125 gText.Options[i].Text_1 = fields[cic++].GetString();
5126
5127 gText.Options[i].Language = fields[cic++].GetUInt8();
5128 gText.Options[i].Probability = fields[cic++].GetFloat();
5129
5130 for (uint8 j = 0; j < MAX_GOSSIP_TEXT_EMOTES; ++j)
5131 {
5132 gText.Options[i].Emotes[j]._Delay = fields[cic++].GetUInt16();
5133 gText.Options[i].Emotes[j]._Emote = fields[cic++].GetUInt16();
5134 }
5135 }
5136 } while (result->NextRow());
5137
5138 SF_LOG_INFO("server.loading", ">> Loaded %u npc texts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
5139}
5140
5142{
5143 uint32 oldMSTime = getMSTime();
5144
5145 _npcTextLocaleStore.clear(); // need for reload case
5146
5147 QueryResult result = WorldDatabase.Query("SELECT ID, "
5148 "Text0_0_loc1, Text0_1_loc1, Text1_0_loc1, Text1_1_loc1, Text2_0_loc1, Text2_1_loc1, Text3_0_loc1, Text3_1_loc1, Text4_0_loc1, Text4_1_loc1, Text5_0_loc1, Text5_1_loc1, Text6_0_loc1, Text6_1_loc1, Text7_0_loc1, Text7_1_loc1, Text8_0_loc1, Text8_1_loc1, Text9_0_loc1, Text9_1_loc1, Text10_0_loc1, Text10_1_loc1, Text11_0_loc1, Text11_1_loc1,"
5149 "Text0_0_loc2, Text0_1_loc2, Text1_0_loc2, Text1_1_loc2, Text2_0_loc2, Text2_1_loc2, Text3_0_loc2, Text3_1_loc1, Text4_0_loc2, Text4_1_loc2, Text5_0_loc2, Text5_1_loc2, Text6_0_loc2, Text6_1_loc2, Text7_0_loc2, Text7_1_loc2, Text8_0_loc2, Text8_1_loc2, Text9_0_loc2, Text9_1_loc2, Text10_0_loc2, Text10_1_loc2, Text11_0_loc2, Text11_1_loc2,"
5150 "Text0_0_loc3, Text0_1_loc3, Text1_0_loc3, Text1_1_loc3, Text2_0_loc3, Text2_1_loc3, Text3_0_loc3, Text3_1_loc1, Text4_0_loc3, Text4_1_loc3, Text5_0_loc3, Text5_1_loc3, Text6_0_loc3, Text6_1_loc3, Text7_0_loc3, Text7_1_loc3, Text8_0_loc3, Text8_1_loc3, Text9_0_loc3, Text9_1_loc3, Text10_0_loc3, Text10_1_loc3, Text11_0_loc3, Text11_1_loc3,"
5151 "Text0_0_loc4, Text0_1_loc4, Text1_0_loc4, Text1_1_loc4, Text2_0_loc4, Text2_1_loc4, Text3_0_loc4, Text3_1_loc1, Text4_0_loc4, Text4_1_loc4, Text5_0_loc4, Text5_1_loc4, Text6_0_loc4, Text6_1_loc4, Text7_0_loc4, Text7_1_loc4, Text8_0_loc4, Text8_1_loc4, Text9_0_loc4, Text9_1_loc4, Text10_0_loc4, Text10_1_loc4, Text11_0_loc4, Text11_1_loc4,"
5152 "Text0_0_loc5, Text0_1_loc5, Text1_0_loc5, Text1_1_loc5, Text2_0_loc5, Text2_1_loc5, Text3_0_loc5, Text3_1_loc1, Text4_0_loc5, Text4_1_loc5, Text5_0_loc5, Text5_1_loc5, Text6_0_loc5, Text6_1_loc5, Text7_0_loc5, Text7_1_loc5, Text8_0_loc5, Text8_1_loc5, Text9_0_loc5, Text9_1_loc5, Text10_0_loc5, Text10_1_loc5, Text11_0_loc5, Text11_1_loc5,"
5153 "Text0_0_loc6, Text0_1_loc6, Text1_0_loc6, Text1_1_loc6, Text2_0_loc6, Text2_1_loc6, Text3_0_loc6, Text3_1_loc1, Text4_0_loc6, Text4_1_loc6, Text5_0_loc6, Text5_1_loc6, Text6_0_loc6, Text6_1_loc6, Text7_0_loc6, Text7_1_loc6, Text8_0_loc6, Text8_1_loc6, Text9_0_loc6, Text9_1_loc6, Text10_0_loc6, Text10_1_loc6, Text11_0_loc6, Text11_1_loc6,"
5154 "Text0_0_loc7, Text0_1_loc7, Text1_0_loc7, Text1_1_loc7, Text2_0_loc7, Text2_1_loc7, Text3_0_loc7, Text3_1_loc1, Text4_0_loc7, Text4_1_loc7, Text5_0_loc7, Text5_1_loc7, Text6_0_loc7, Text6_1_loc7, Text7_0_loc7, Text7_1_loc7, Text8_0_loc7, Text8_1_loc7, Text9_0_loc7, Text9_1_loc7, Text10_0_loc7, Text10_1_loc7, Text11_0_loc7, Text11_1_loc7,"
5155 "Text0_0_loc8, Text0_1_loc8, Text1_0_loc8, Text1_1_loc8, Text2_0_loc8, Text2_1_loc8, Text3_0_loc8, Text3_1_loc1, Text4_0_loc8, Text4_1_loc8, Text5_0_loc8, Text5_1_loc8, Text6_0_loc8, Text6_1_loc8, Text7_0_loc8, Text7_1_loc8, Text8_0_loc8, Text8_1_loc8, Text9_0_loc8, Text9_1_loc8, Text10_0_loc8, Text10_1_loc8, Text11_0_loc8, Text11_1_loc8,"
5156 "Text0_0_loc9, Text0_1_loc9, Text1_0_loc9, Text1_1_loc9, Text2_0_loc9, Text2_1_loc9, Text3_0_loc9, Text3_1_loc1, Text4_0_loc9, Text4_1_loc9, Text5_0_loc9, Text5_1_loc9, Text6_0_loc9, Text6_1_loc9, Text7_0_loc9, Text7_1_loc9, Text8_0_loc9, Text8_1_loc9, Text9_0_loc9, Text9_1_loc9, Text10_0_loc9, Text10_1_loc9, Text11_0_loc9, Text11_1_loc9,"
5157 "Text0_0_loc10, Text0_1_loc10, Text1_0_loc10, Text1_1_loc10, Text2_0_loc10, Text2_1_loc10, Text3_0_loc10, Text3_1_loc1, Text4_0_loc10, Text4_1_loc10, Text5_0_loc10, Text5_1_loc10, Text6_0_loc10, Text6_1_loc10, Text7_0_loc10, Text7_1_loc10, Text8_0_loc10, Text8_1_loc10, Text9_0_loc10, Text9_1_loc10, Text10_0_loc10, Text10_1_loc10, Text11_0_loc10, Text11_1_loc10,"
5158 "Text0_0_loc11, Text0_1_loc11, Text1_0_loc11, Text1_1_loc11, Text2_0_loc11, Text2_1_loc11, Text3_0_loc11, Text3_1_loc1, Text4_0_loc11, Text4_1_loc11, Text5_0_loc11, Text5_1_loc11, Text6_0_loc11, Text6_1_loc11, Text7_0_loc11, Text7_1_loc11 Text8_0_loc11, Text8_1_loc11, Text9_0_loc11, Text9_1_loc11, Text10_0_loc11, Text10_1_loc11, Text11_0_loc11, Text11_1_loc11"
5159 " FROM locales_npc_text");
5160
5161 if (!result)
5162 return;
5163
5164 do
5165 {
5166 Field* fields = result->Fetch();
5167
5168 uint32 entry = fields[0].GetUInt32();
5169
5170 NpcTextLocale& data = _npcTextLocaleStore[entry];
5171
5172 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
5173 {
5174 LocaleConstant locale = (LocaleConstant)i;
5175 for (uint8 j = 0; j < MAX_LOCALES; ++j)
5176 {
5177 AddLocaleString(fields[1 + 8 * 2 * (i - 1) + 2 * j].GetString(), locale, data.Text_0[j]);
5178 AddLocaleString(fields[1 + 8 * 2 * (i - 1) + 2 * j + 1].GetString(), locale, data.Text_1[j]);
5179 }
5180 }
5181 } while (result->NextRow());
5182
5183 SF_LOG_INFO("server.loading", ">> Loaded %lu NpcText locale strings in %u ms", (unsigned long)_npcTextLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
5184}
5185
5186//not very fast function but it is called only once a day, or on starting-up
5188{
5189 uint32 oldMSTime = getMSTime();
5190
5191 time_t curTime = time(NULL);
5192 tm lt;
5193 Skyfire::LocalTime(curTime, lt);
5194 uint64 basetime(curTime);
5195 SF_LOG_INFO("misc", "Returning mails current time: hour: %d, minute: %d, second: %d ", lt.tm_hour, lt.tm_min, lt.tm_sec);
5196
5197 // Delete all old mails without item and without body immediately, if starting server
5198 if (!serverUp)
5199 {
5201 stmt->setUInt64(0, basetime);
5202 CharacterDatabase.Execute(stmt);
5203 }
5204 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL);
5205 stmt->setUInt64(0, basetime);
5206 PreparedQueryResult result = CharacterDatabase.Query(stmt);
5207 if (!result)
5208 {
5209 SF_LOG_INFO("server.loading", ">> No expired mails found.");
5210 return; // any mails need to be returned or deleted
5211 }
5212
5213 std::map<uint32 /*messageId*/, MailItemInfoVec> itemsCache;
5214 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_EXPIRED_MAIL_ITEMS);
5215 stmt->setUInt32(0, (uint32)basetime);
5216 if (PreparedQueryResult items = CharacterDatabase.Query(stmt))
5217 {
5218 MailItemInfo item;
5219 do
5220 {
5221 Field* fields = items->Fetch();
5222 item.item_guid = fields[0].GetUInt32();
5223 item.item_template = fields[1].GetUInt32();
5224 uint32 mailId = fields[2].GetUInt32();
5225 itemsCache[mailId].push_back(item);
5226 } while (items->NextRow());
5227 }
5228
5229 uint32 deletedCount = 0;
5230 uint32 returnedCount = 0;
5231 do
5232 {
5233 Field* fields = result->Fetch();
5234 Mail* m = new Mail;
5235 m->messageID = fields[0].GetUInt32();
5236 m->messageType = fields[1].GetUInt8();
5237 m->sender = fields[2].GetUInt32();
5238 m->receiver = fields[3].GetUInt32();
5239 bool has_items = fields[4].GetBool();
5240 m->expire_time = time_t(fields[5].GetUInt32());
5241 m->deliver_time = 0;
5242 m->COD = fields[6].GetUInt64();
5243 m->checked = fields[7].GetUInt8();
5244 m->mailTemplateId = fields[8].GetInt16();
5245
5246 Player* player = NULL;
5247 if (serverUp)
5249
5250 if (player && player->m_mailsLoaded)
5251 { // this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail
5252 // his in mailbox and he has already listed his mails)
5253 delete m;
5254 continue;
5255 }
5256
5257 // Delete or return mail
5258 if (has_items)
5259 {
5260 // read items from cache
5261 m->items.swap(itemsCache[m->messageID]);
5262
5263 // if it is mail from non-player, or if it's already return mail, it shouldn't be returned, but deleted
5265 {
5266 // mail open and then not returned
5267 for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
5268 {
5269 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
5270 stmt->setUInt32(0, itr2->item_guid);
5271 CharacterDatabase.Execute(stmt);
5272 }
5273 }
5274 else
5275 {
5276 // Mail will be returned
5277 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL_RETURNED);
5278 stmt->setUInt32(0, m->receiver);
5279 stmt->setUInt32(1, m->sender);
5280 stmt->setUInt32(2, basetime + 30 * DAY);
5281 stmt->setUInt32(3, basetime);
5283 stmt->setUInt32(5, m->messageID);
5284 CharacterDatabase.Execute(stmt);
5285 for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
5286 {
5287 // Update receiver in mail items for its proper delivery, and in instance_item for avoid lost item at sender delete
5288 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL_ITEM_RECEIVER);
5289 stmt->setUInt32(0, m->sender);
5290 stmt->setUInt32(1, itr2->item_guid);
5291 CharacterDatabase.Execute(stmt);
5292
5293 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_OWNER);
5294 stmt->setUInt32(0, m->sender);
5295 stmt->setUInt32(1, itr2->item_guid);
5296 CharacterDatabase.Execute(stmt);
5297 }
5298 delete m;
5299 ++returnedCount;
5300 continue;
5301 }
5302 }
5303
5304 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
5305 stmt->setUInt32(0, m->messageID);
5306 CharacterDatabase.Execute(stmt);
5307 delete m;
5308 ++deletedCount;
5309 } while (result->NextRow());
5310
5311 SF_LOG_INFO("server.loading", ">> Processed %u expired mails: %u deleted and %u returned in %u ms", deletedCount + returnedCount, deletedCount, returnedCount, GetMSTimeDiffToNow(oldMSTime));
5312}
5313
5315{
5316 uint32 oldMSTime = getMSTime();
5317
5318 _questAreaTriggerStore.clear(); // need for reload case
5319
5320 QueryResult result = WorldDatabase.Query("SELECT id, quest FROM areatrigger_involvedrelation");
5321
5322 if (!result)
5323 {
5324 SF_LOG_INFO("server.loading", ">> Loaded 0 quest trigger points. DB table `areatrigger_involvedrelation` is empty.");
5325 return;
5326 }
5327
5328 uint32 count = 0;
5329
5330 do
5331 {
5332 ++count;
5333
5334 Field* fields = result->Fetch();
5335
5336 uint32 trigger_ID = fields[0].GetUInt32();
5337 uint32 quest_ID = fields[1].GetUInt32();
5338
5339 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID);
5340 if (!atEntry)
5341 {
5342 SF_LOG_ERROR("sql.sql", "Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.", trigger_ID);
5343 continue;
5344 }
5345
5346 Quest const* quest = GetQuestTemplate(quest_ID);
5347
5348 if (!quest)
5349 {
5350 SF_LOG_ERROR("sql.sql", "Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u", trigger_ID, quest_ID);
5351 continue;
5352 }
5353
5355 {
5356 SF_LOG_ERROR("sql.sql", "Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.", trigger_ID, quest_ID);
5357
5358 // this will prevent quest completing without objective
5359 const_cast<Quest*>(quest)->SetSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT);
5360
5361 // continue; - quest modified to required objective and trigger can be allowed.
5362 }
5363
5364 _questAreaTriggerStore[trigger_ID] = quest_ID;
5365 } while (result->NextRow());
5366
5367 SF_LOG_INFO("server.loading", ">> Loaded %u quest trigger points in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
5368}
5369
5371{
5372 uint32 oldMSTime = getMSTime();
5373
5374 _tavernAreaTriggerStore.clear(); // need for reload case
5375 _tavernRestAreaStore.clear();
5376
5377 QueryResult result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern");
5378
5379 if (!result)
5380 {
5381 SF_LOG_INFO("server.loading", ">> Loaded 0 tavern triggers. DB table `areatrigger_tavern` is empty.");
5382 return;
5383 }
5384
5385 uint32 count = 0;
5386
5387 do
5388 {
5389 ++count;
5390
5391 Field* fields = result->Fetch();
5392
5393 uint32 Trigger_ID = fields[0].GetUInt32();
5394
5395 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
5396 if (!atEntry)
5397 {
5398 SF_LOG_ERROR("sql.sql", "Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.", Trigger_ID);
5399 continue;
5400 }
5401
5402 _tavernAreaTriggerStore.insert(Trigger_ID);
5403 } while (result->NextRow());
5404
5405 SF_LOG_INFO("server.loading", ">> Loaded %u tavern triggers in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
5406
5407 oldMSTime = getMSTime();
5408
5409 QueryResult restAreaResult = WorldDatabase.Query(
5410 "SELECT id, map, position_x, position_y, position_z, radius, box_x, box_y, box_z, box_orientation "
5411 "FROM areatrigger_tavern_rest_area");
5412
5413 if (!restAreaResult)
5414 {
5415 SF_LOG_INFO("server.loading", ">> Loaded 0 tavern rest area overrides.");
5416 return;
5417 }
5418
5419 uint32 restAreaCount = 0;
5420
5421 do
5422 {
5423 Field* fields = restAreaResult->Fetch();
5424
5425 TavernRestArea restArea;
5426 restArea.TriggerId = fields[0].GetUInt32();
5427 restArea.MapId = fields[1].GetUInt32();
5428 restArea.X = fields[2].GetFloat();
5429 restArea.Y = fields[3].GetFloat();
5430 restArea.Z = fields[4].GetFloat();
5431 restArea.Radius = fields[5].GetFloat();
5432 restArea.BoxX = fields[6].GetFloat();
5433 restArea.BoxY = fields[7].GetFloat();
5434 restArea.BoxZ = fields[8].GetFloat();
5435 restArea.BoxOrientation = fields[9].GetFloat();
5436
5437 if (!IsTavernAreaTrigger(restArea.TriggerId))
5438 {
5439 SF_LOG_ERROR("sql.sql", "Table `areatrigger_tavern_rest_area` has override for non-tavern area trigger %u.", restArea.TriggerId);
5440 continue;
5441 }
5442
5443 if (!Skyfire::Rest::HasInnAreaBounds(ToInnAreaBounds(restArea)))
5444 {
5445 SF_LOG_ERROR("sql.sql", "Table `areatrigger_tavern_rest_area` has empty bounds for area trigger %u.", restArea.TriggerId);
5446 continue;
5447 }
5448
5449 _tavernRestAreaStore[restArea.TriggerId] = restArea;
5450 ++restAreaCount;
5451 } while (restAreaResult->NextRow());
5452
5453 SF_LOG_INFO("server.loading", ">> Loaded %u tavern rest area overrides in %u ms", restAreaCount, GetMSTimeDiffToNow(oldMSTime));
5454}
5455
5457{
5458 TavernRestAreaContainer::const_iterator itr = _tavernRestAreaStore.find(triggerId);
5459 if (itr == _tavernRestAreaStore.end())
5460 return NULL;
5461
5462 return &itr->second;
5463}
5464
5465bool ObjectMgr::IsInTavernRestArea(TavernRestArea const& restArea, uint32 mapId, float x, float y, float z, float padding) const
5466{
5467 return Skyfire::Rest::IsInsideInnArea(ToInnAreaBounds(restArea), mapId, x, y, z, padding);
5468}
5469
5470TavernRestArea const* ObjectMgr::GetTavernRestAreaAtPosition(uint32 mapId, float x, float y, float z) const
5471{
5472 for (TavernRestAreaContainer::const_iterator itr = _tavernRestAreaStore.begin(); itr != _tavernRestAreaStore.end(); ++itr)
5473 if (IsInTavernRestArea(itr->second, mapId, x, y, z))
5474 return &itr->second;
5475
5476 return NULL;
5477}
5478
5480{
5481 uint32 oldMSTime = getMSTime();
5482
5483 _areaTriggerScriptStore.clear(); // need for reload case
5484 QueryResult result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts");
5485
5486 if (!result)
5487 {
5488 SF_LOG_INFO("server.loading", ">> Loaded 0 areatrigger scripts. DB table `areatrigger_scripts` is empty.");
5489 return;
5490 }
5491
5492 uint32 count = 0;
5493
5494 do
5495 {
5496 ++count;
5497
5498 Field* fields = result->Fetch();
5499
5500 uint32 Trigger_ID = fields[0].GetUInt32();
5501 const char* scriptName = fields[1].GetCString();
5502
5503 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
5504 if (!atEntry)
5505 {
5506 SF_LOG_ERROR("sql.sql", "Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.", Trigger_ID);
5507 continue;
5508 }
5509 _areaTriggerScriptStore[Trigger_ID] = GetScriptId(scriptName);
5510 } while (result->NextRow());
5511
5512 SF_LOG_INFO("server.loading", ">> Loaded %u areatrigger scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
5513}
5514
5515uint32 ObjectMgr::GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team)
5516{
5517 bool found = false;
5518 float dist = 10000;
5519 uint32 id = 0;
5520
5521 for (uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
5522 {
5523 TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
5524
5525 if (!node || node->map_id != mapid || (!node->MountCreatureID[team == ALLIANCE ? 1 : 0] && node->MountCreatureID[0] != 32981)) // dk flight
5526 continue;
5527
5528 uint8 field = (uint8)((i - 1) / 8);
5529 uint32 submask = 1 << ((i - 1) % 8);
5530
5531 // skip not taxi network nodes
5532 if ((sTaxiNodesMask[field] & submask) == 0)
5533 continue;
5534
5535 float dist2 = (node->x - x) * (node->x - x) + (node->y - y) * (node->y - y) + (node->z - z) * (node->z - z);
5536 if (found)
5537 {
5538 if (dist2 < dist)
5539 {
5540 dist = dist2;
5541 id = i;
5542 }
5543 }
5544 else
5545 {
5546 found = true;
5547 dist = dist2;
5548 id = i;
5549 }
5550 }
5551
5552 return id;
5553}
5554
5555void ObjectMgr::GetTaxiPath(uint32 source, uint32 destination, uint32& path, uint32& cost)
5556{
5557 TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source);
5558 if (src_i == sTaxiPathSetBySource.end())
5559 {
5560 path = 0;
5561 cost = 0;
5562 return;
5563 }
5564
5565 TaxiPathSetForSource& pathSet = src_i->second;
5566
5567 TaxiPathSetForSource::iterator dest_i = pathSet.find(destination);
5568 if (dest_i == pathSet.end())
5569 {
5570 path = 0;
5571 cost = 0;
5572 return;
5573 }
5574
5575 cost = dest_i->second.price;
5576 path = dest_i->second.ID;
5577}
5578
5579uint32 ObjectMgr::GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team /* = false */)
5580{
5581 uint32 mount_id = 0;
5582
5583 // select mount creature id
5584 TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
5585 if (node)
5586 {
5587 uint32 mount_entry = 0;
5588 if (team == ALLIANCE)
5589 mount_entry = node->MountCreatureID[1];
5590 else
5591 mount_entry = node->MountCreatureID[0];
5592
5593 // Fix for Alliance not being able to use Acherus taxi
5594 // only one mount type for both sides
5595 if (mount_entry == 0 && allowed_alt_team)
5596 {
5597 // Simply reverse the selection. At least one team in theory should have a valid mount ID to choose.
5598 mount_entry = team == ALLIANCE ? node->MountCreatureID[0] : node->MountCreatureID[1];
5599 }
5600
5601 CreatureTemplate const* mount_info = GetCreatureTemplate(mount_entry);
5602 if (mount_info)
5603 {
5604 mount_id = mount_info->GetRandomValidModelId();
5605 if (!mount_id)
5606 {
5607 SF_LOG_ERROR("sql.sql", "No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry);
5608 return 0;
5609 }
5610 }
5611 }
5612
5613 // minfo is not actually used but the mount_id was updated
5615
5616 return mount_id;
5617}
5618
5620{
5621 uint32 oldMSTime = getMSTime();
5622
5623 GraveYardStore.clear(); // need for reload case
5624
5625 // 0 1 2
5626 QueryResult result = WorldDatabase.Query("SELECT id, ghost_zone, faction FROM game_graveyard_zone");
5627
5628 if (!result)
5629 {
5630 SF_LOG_INFO("server.loading", ">> Loaded 0 graveyard-zone links. DB table `game_graveyard_zone` is empty.");
5631 return;
5632 }
5633
5634 uint32 count = 0;
5635
5636 do
5637 {
5638 ++count;
5639
5640 Field* fields = result->Fetch();
5641
5642 uint32 safeLocId = fields[0].GetUInt32();
5643 uint32 zoneId = fields[1].GetUInt32();
5644 uint32 team = fields[2].GetUInt16();
5645
5646 WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId);
5647 if (!entry)
5648 {
5649 SF_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` has a record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.", safeLocId);
5650 continue;
5651 }
5652
5653 AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId);
5654 if (!areaEntry)
5655 {
5656 SF_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` has a record for not existing zone id (%u), skipped.", zoneId);
5657 continue;
5658 }
5659
5660 if (team != 0 && team != HORDE && team != ALLIANCE)
5661 {
5662 SF_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` has a record for non player faction (%u), skipped.", team);
5663 continue;
5664 }
5665
5666 if (!AddGraveYardLink(safeLocId, zoneId, team, false))
5667 SF_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` has a duplicate record for Graveyard (ID: %u) and Zone (ID: %u), skipped.", safeLocId, zoneId);
5668 } while (result->NextRow());
5669
5670 SF_LOG_INFO("server.loading", ">> Loaded %u graveyard-zone links in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
5671}
5672
5674{
5675 enum DefaultGraveyard
5676 {
5677 HORDE_GRAVEYARD = 10, // Crossroads
5678 ALLIANCE_GRAVEYARD = 4 // Westfall
5679 };
5680
5681 if (team == HORDE)
5682 return sWorldSafeLocsStore.LookupEntry(HORDE_GRAVEYARD);
5683 else if (team == ALLIANCE)
5684 return sWorldSafeLocsStore.LookupEntry(ALLIANCE_GRAVEYARD);
5685 else return NULL;
5686}
5687
5688WorldSafeLocsEntry const* ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
5689{
5690 // search for zone associated closest graveyard
5691 uint32 zoneId = sMapMgr->GetZoneId(MapId, x, y, z);
5692
5693 if (!zoneId)
5694 {
5695 if (z > -500)
5696 {
5697 SF_LOG_ERROR("misc", "ZoneId not found for map %u coords (%f, %f, %f)", MapId, x, y, z);
5698 return GetDefaultGraveYard(team);
5699 }
5700 }
5701
5702 // Simulate std. algorithm:
5703 // found some graveyard associated to (ghost_zone, ghost_map)
5704 //
5705 // if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map
5706 // then check faction
5707 // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated
5708 // then check faction
5709 uint32 lookupZoneId = zoneId;
5710 GraveYardMapBounds range = GraveYardStore.equal_range(lookupZoneId);
5711 if (range.first == range.second)
5712 {
5713 uint32 rootZoneId = Skyfire::AreaTable::GetRootZoneId(zoneId);
5714 if (rootZoneId && rootZoneId != zoneId)
5715 {
5716 lookupZoneId = rootZoneId;
5717 range = GraveYardStore.equal_range(lookupZoneId);
5718 }
5719 }
5720
5721 MapEntry const* map = sMapStore.LookupEntry(MapId);
5722
5723 // not need to check validity of map object; MapId _MUST_ be valid here
5724 if (range.first == range.second && !map->IsBattlegroundOrArena())
5725 {
5726 SF_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.", zoneId, team);
5727 return GetDefaultGraveYard(team);
5728 }
5729
5730 // at corpse map
5731 bool foundNear = false;
5732 float distNear = 10000;
5733 WorldSafeLocsEntry const* entryNear = NULL;
5734
5735 // at entrance map for corpse map
5736 bool foundEntr = false;
5737 float distEntr = 10000;
5738 WorldSafeLocsEntry const* entryEntr = NULL;
5739
5740 // some where other
5741 WorldSafeLocsEntry const* entryFar = NULL;
5742
5743 MapEntry const* mapEntry = sMapStore.LookupEntry(MapId);
5744
5745 for (; range.first != range.second; ++range.first)
5746 {
5747 GraveYardData const& data = range.first->second;
5748
5749 WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId);
5750 if (!entry)
5751 {
5752 SF_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.", data.safeLocId);
5753 continue;
5754 }
5755
5756 // skip enemy faction graveyard
5757 // team == 0 case can be at call from .neargrave
5758 if (data.team != 0 && team != 0 && data.team != team)
5759 continue;
5760
5761 // find now nearest graveyard at other map
5762 if (MapId != entry->map_id)
5763 {
5764 // if find graveyard at different map from where entrance placed (or no entrance data), use any first
5765 if (!mapEntry
5766 || mapEntry->entrance_map < 0
5767 || uint32(mapEntry->entrance_map) != entry->map_id
5768 || (mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0))
5769 {
5770 // not have any corrdinates for check distance anyway
5771 entryFar = entry;
5772 continue;
5773 }
5774
5775 // at entrance map calculate distance (2D);
5776 float dist2 = (entry->x - mapEntry->entrance_x) * (entry->x - mapEntry->entrance_x)
5777 + (entry->y - mapEntry->entrance_y) * (entry->y - mapEntry->entrance_y);
5778 if (foundEntr)
5779 {
5780 if (dist2 < distEntr)
5781 {
5782 distEntr = dist2;
5783 entryEntr = entry;
5784 }
5785 }
5786 else
5787 {
5788 foundEntr = true;
5789 distEntr = dist2;
5790 entryEntr = entry;
5791 }
5792 }
5793 // find now nearest graveyard at same map
5794 else
5795 {
5796 float dist2 = (entry->x - x) * (entry->x - x) + (entry->y - y) * (entry->y - y) + (entry->z - z) * (entry->z - z);
5797 if (foundNear)
5798 {
5799 if (dist2 < distNear)
5800 {
5801 distNear = dist2;
5802 entryNear = entry;
5803 }
5804 }
5805 else
5806 {
5807 foundNear = true;
5808 distNear = dist2;
5809 entryNear = entry;
5810 }
5811 }
5812 }
5813
5814 if (entryNear)
5815 return entryNear;
5816
5817 if (entryEntr)
5818 return entryEntr;
5819
5820 return entryFar;
5821}
5822
5824{
5825 auto findData = [this, id](uint32 lookupZoneId) -> GraveYardData const*
5826 {
5827 GraveYardMapBounds range = GraveYardStore.equal_range(lookupZoneId);
5828 for (; range.first != range.second; ++range.first)
5829 {
5830 GraveYardData const& data = range.first->second;
5831 if (data.safeLocId == id)
5832 return &data;
5833 }
5834
5835 return NULL;
5836 };
5837
5838 if (GraveYardData const* data = findData(zoneId))
5839 return data;
5840
5841 uint32 rootZoneId = Skyfire::AreaTable::GetRootZoneId(zoneId);
5842 if (rootZoneId && rootZoneId != zoneId)
5843 return findData(rootZoneId);
5844
5845 return NULL;
5846}
5847
5848bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool persist /*= true*/)
5849{
5850 if (FindGraveYardData(id, zoneId))
5851 return false;
5852
5853 // add link to loaded data
5854 GraveYardData data;
5855 data.safeLocId = id;
5856 data.team = team;
5857
5858 GraveYardStore.insert(GraveYardContainer::value_type(zoneId, data));
5859
5860 // add link to DB
5861 if (persist)
5862 {
5863 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GRAVEYARD_ZONE);
5864
5865 stmt->setUInt32(0, id);
5866 stmt->setUInt32(1, zoneId);
5867 stmt->setUInt16(2, uint16(team));
5868
5869 WorldDatabase.Execute(stmt);
5870 }
5871
5872 return true;
5873}
5874
5875void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool persist /*= false*/)
5876{
5877 GraveYardMapBoundsNonConst range = GraveYardStore.equal_range(zoneId);
5878 if (range.first == range.second)
5879 {
5880 //SF_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.", zoneId, team);
5881 return;
5882 }
5883
5884 bool found = false;
5885
5886
5887 for (; range.first != range.second; ++range.first)
5888 {
5889 GraveYardData& data = range.first->second;
5890
5891 // skip not matching safezone id
5892 if (data.safeLocId != id)
5893 continue;
5894
5895 // skip enemy faction graveyard at same map (normal area, city, or battleground)
5896 // team == 0 case can be at call from .neargrave
5897 if (data.team != 0 && team != 0 && data.team != team)
5898 continue;
5899
5900 found = true;
5901 break;
5902 }
5903
5904 // no match, return
5905 if (!found)
5906 return;
5907
5908 // remove from links
5909 GraveYardStore.erase(range.first);
5910
5911 // remove link from DB
5912 if (persist)
5913 {
5914 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GRAVEYARD_ZONE);
5915
5916 stmt->setUInt32(0, id);
5917 stmt->setUInt32(1, zoneId);
5918 stmt->setUInt16(2, uint16(team));
5919
5920 WorldDatabase.Execute(stmt);
5921 }
5922}
5923
5925{
5926 uint32 oldMSTime = getMSTime();
5927
5928 _areaTriggerStore.clear(); // need for reload case
5929
5930 // 0 1 2 3 4 5
5931 QueryResult result = WorldDatabase.Query("SELECT id, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
5932 if (!result)
5933 {
5934 SF_LOG_INFO("server.loading", ">> Loaded 0 area trigger teleport definitions. DB table `areatrigger_teleport` is empty.");
5935 return;
5936 }
5937
5938 uint32 count = 0;
5939
5940 do
5941 {
5942 Field* fields = result->Fetch();
5943
5944 ++count;
5945
5946 uint32 Trigger_ID = fields[0].GetUInt32();
5947
5949
5950 at.target_mapId = fields[1].GetUInt16();
5951 at.target_X = fields[2].GetFloat();
5952 at.target_Y = fields[3].GetFloat();
5953 at.target_Z = fields[4].GetFloat();
5954 at.target_Orientation = fields[5].GetFloat();
5955
5956 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
5957 if (!atEntry)
5958 {
5959 SF_LOG_ERROR("sql.sql", "Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.", Trigger_ID);
5960 continue;
5961 }
5962
5963 MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
5964 if (!mapEntry)
5965 {
5966 SF_LOG_ERROR("sql.sql", "Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.", Trigger_ID, at.target_mapId);
5967 continue;
5968 }
5969
5970 if (at.target_X == 0 && at.target_Y == 0 && at.target_Z == 0)
5971 {
5972 SF_LOG_ERROR("sql.sql", "Area trigger (ID:%u) target coordinates not provided.", Trigger_ID);
5973 continue;
5974 }
5975
5976 _areaTriggerStore[Trigger_ID] = at;
5977 } while (result->NextRow());
5978
5979 SF_LOG_INFO("server.loading", ">> Loaded %u area trigger teleport definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
5980}
5981
5983{
5984 uint32 oldMSTime = getMSTime();
5985
5986 if (!_accessRequirementStore.empty())
5987 {
5988 for (AccessRequirementContainer::iterator itr = _accessRequirementStore.begin(); itr != _accessRequirementStore.end(); ++itr)
5989 delete itr->second;
5990
5991 _accessRequirementStore.clear(); // need for reload case
5992 }
5993
5994 // 0 1 2 3 4 5 6 7 8 9 10
5995 QueryResult result = WorldDatabase.Query("SELECT mapid, difficulty, level_min, level_max, item, item2, quest_done_A, quest_done_H, completed_achievement, quest_failed_text, ilvl FROM access_requirement");
5996 if (!result)
5997 {
5998 SF_LOG_INFO("server.loading", ">> Loaded 0 access requirement definitions. DB table `access_requirement` is empty.");
5999 return;
6000 }
6001
6002 uint32 count = 0;
6003
6004 do
6005 {
6006 Field* fields = result->Fetch();
6007
6008 ++count;
6009
6010 uint32 mapid = fields[0].GetUInt32();
6011 uint8 difficulty = fields[1].GetUInt8();
6012 uint32 requirement_ID = MAKE_PAIR32(mapid, difficulty);
6013
6015
6016 ar->levelMin = fields[2].GetUInt8();
6017 ar->levelMax = fields[3].GetUInt8();
6018 ar->item = fields[4].GetUInt32();
6019 ar->item2 = fields[5].GetUInt32();
6020 ar->quest_A = fields[6].GetUInt32();
6021 ar->quest_H = fields[7].GetUInt32();
6022 ar->achievement = fields[8].GetUInt32();
6023 ar->questFailedText = fields[9].GetString();
6024 ar->iLvl = fields[10].GetUInt32();
6025
6026 if (ar->item)
6027 {
6028 ItemTemplate const* pProto = GetItemTemplate(ar->item);
6029 if (!pProto)
6030 {
6031 SF_LOG_ERROR("misc", "Key item %u does not exist for map %u difficulty %u, removing key requirement.", ar->item, mapid, difficulty);
6032 ar->item = 0;
6033 }
6034 }
6035
6036 if (ar->item2)
6037 {
6038 ItemTemplate const* pProto = GetItemTemplate(ar->item2);
6039 if (!pProto)
6040 {
6041 SF_LOG_ERROR("misc", "Second item %u does not exist for map %u difficulty %u, removing key requirement.", ar->item2, mapid, difficulty);
6042 ar->item2 = 0;
6043 }
6044 }
6045
6046 if (ar->quest_A)
6047 {
6048 if (!GetQuestTemplate(ar->quest_A))
6049 {
6050 SF_LOG_ERROR("sql.sql", "Required Alliance Quest %u not exist for map %u difficulty %u, remove quest done requirement.", ar->quest_A, mapid, difficulty);
6051 ar->quest_A = 0;
6052 }
6053 }
6054
6055 if (ar->quest_H)
6056 {
6057 if (!GetQuestTemplate(ar->quest_H))
6058 {
6059 SF_LOG_ERROR("sql.sql", "Required Horde Quest %u not exist for map %u difficulty %u, remove quest done requirement.", ar->quest_H, mapid, difficulty);
6060 ar->quest_H = 0;
6061 }
6062 }
6063
6064 if (ar->achievement)
6065 {
6066 if (!sAchievementMgr->GetAchievement(ar->achievement))
6067 {
6068 SF_LOG_ERROR("sql.sql", "Required Achievement %u not exist for map %u difficulty %u, remove quest done requirement.", ar->achievement, mapid, difficulty);
6069 ar->achievement = 0;
6070 }
6071 }
6072
6073 _accessRequirementStore[requirement_ID] = ar;
6074 } while (result->NextRow());
6075
6076 SF_LOG_INFO("server.loading", ">> Loaded %u access requirement definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6077}
6078
6079/*
6080 * Searches for the areatrigger which teleports players out of the given map with instance_template.parent field support
6081 */
6083{
6084 bool useParentDbValue = false;
6085 uint32 parentId = 0;
6086 const MapEntry* mapEntry = sMapStore.LookupEntry(Map);
6087 if (!mapEntry || mapEntry->entrance_map < 0)
6088 return NULL;
6089
6090 if (mapEntry->IsInstance())
6091 {
6092 const InstanceTemplate* iTemplate = sObjectMgr->GetInstanceTemplate(Map);
6093
6094 if (!iTemplate)
6095 return NULL;
6096
6097 parentId = iTemplate->Parent;
6098 useParentDbValue = true;
6099 }
6100
6101 uint32 entrance_map = uint32(mapEntry->entrance_map);
6102 for (AreaTriggerContainer::const_iterator itr = _areaTriggerStore.begin(); itr != _areaTriggerStore.end(); ++itr)
6103 if ((!useParentDbValue && itr->second.target_mapId == entrance_map) || (useParentDbValue && itr->second.target_mapId == parentId))
6104 {
6105 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
6106 if (atEntry && atEntry->mapid == Map)
6107 return &itr->second;
6108 }
6109 return NULL;
6110}
6111
6116{
6117 for (AreaTriggerContainer::const_iterator itr = _areaTriggerStore.begin(); itr != _areaTriggerStore.end(); ++itr)
6118 {
6119 if (itr->second.target_mapId == Map)
6120 {
6121 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
6122 if (atEntry)
6123 return &itr->second;
6124 }
6125 }
6126 return NULL;
6127}
6128
6130{
6131 QueryResult result = CharacterDatabase.Query("SELECT MAX(guid) FROM characters");
6132 if (result)
6133 _hiCharGuid = (*result)[0].GetUInt32() + 1;
6134
6135 result = WorldDatabase.Query("SELECT MAX(guid) FROM creature");
6136 if (result)
6137 _hiCreatureGuid = (*result)[0].GetUInt32() + 1;
6138
6139 result = CharacterDatabase.Query("SELECT MAX(guid) FROM item_instance");
6140 if (result)
6141 _hiItemGuid = (*result)[0].GetUInt32() + 1;
6142
6143 // Cleanup other tables from not existed guids ( >= _hiItemGuid)
6144 CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", _hiItemGuid); // One-time query
6145 CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", _hiItemGuid); // One-time query
6146 CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", _hiItemGuid); // One-time query
6147 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", _hiItemGuid); // One-time query
6148
6149 result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject");
6150 if (result)
6151 _hiGoGuid = (*result)[0].GetUInt32() + 1;
6152
6153 result = WorldDatabase.Query("SELECT MAX(guid) FROM transports");
6154 if (result)
6155 _hiMoTransGuid = (*result)[0].GetUInt32() + 1;
6156
6157 result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse");
6158 if (result)
6159 _auctionId = (*result)[0].GetUInt32() + 1;
6160
6161 result = CharacterDatabase.Query("SELECT MAX(id) FROM mail");
6162 if (result)
6163 _mailId = (*result)[0].GetUInt32() + 1;
6164
6165 result = CharacterDatabase.Query("SELECT MAX(corpseGuid) FROM corpse");
6166 if (result)
6167 _hiCorpseGuid = (*result)[0].GetUInt32() + 1;
6168
6169 result = CharacterDatabase.Query("SELECT MAX(setguid) FROM character_equipmentsets");
6170 if (result)
6171 _equipmentSetGuid = (*result)[0].GetUInt64() + 1;
6172
6173 result = CharacterDatabase.Query("SELECT MAX(guildId) FROM guild");
6174 if (result)
6175 sGuildMgr->SetNextGuildId((*result)[0].GetUInt32() + 1);
6176
6177 result = CharacterDatabase.Query("SELECT MAX(guid) FROM parties");
6178 if (result)
6179 sGroupMgr->SetGroupDbStoreSize((*result)[0].GetUInt32() + 1);
6180
6181 result = CharacterDatabase.Query("SELECT MAX(itemId) from character_void_storage");
6182 if (result)
6183 _voidItemId = (*result)[0].GetUInt64() + 1;
6184
6185 result = CharacterDatabase.Query("SELECT MAX(id) from account_battle_pet");
6186 if (result)
6187 m_battlePetId = (*result)[0].GetUInt64() + 1;
6188}
6189
6191{
6192 if (_auctionId >= 0xFFFFFFFE)
6193 {
6194 SF_LOG_ERROR("misc", "Auctions ids overflow!! Can't continue, shutting down server. ");
6196 }
6197 return _auctionId++;
6198}
6199
6201{
6202 if (_equipmentSetGuid >= uint64(0xFFFFFFFFFFFFFFFELL))
6203 {
6204 SF_LOG_ERROR("misc", "EquipmentSet guid overflow!! Can't continue, shutting down server. ");
6206 }
6207 return _equipmentSetGuid++;
6208}
6209
6211{
6212 if (_mailId >= 0xFFFFFFFE)
6213 {
6214 SF_LOG_ERROR("misc", "Mail ids overflow!! Can't continue, shutting down server. ");
6216 }
6217 return _mailId++;
6218}
6219
6221{
6222 switch (guidhigh)
6223 {
6224 case HIGHGUID_ITEM:
6225 {
6226 ASSERT(_hiItemGuid < 0xFFFFFFFE && "Item guid overflow!");
6227 return _hiItemGuid++;
6228 }
6229 case HIGHGUID_UNIT:
6230 {
6231 ASSERT(_hiCreatureGuid < 0x00FFFFFE && "Creature guid overflow!");
6232 return _hiCreatureGuid++;
6233 }
6234 case HIGHGUID_PET:
6235 {
6236 ASSERT(_hiPetGuid < 0x00FFFFFE && "Pet guid overflow!");
6237 return _hiPetGuid++;
6238 }
6239 case HIGHGUID_VEHICLE:
6240 {
6241 ASSERT(_hiVehicleGuid < 0x00FFFFFF && "Vehicle guid overflow!");
6242 return _hiVehicleGuid++;
6243 }
6244 case HIGHGUID_PLAYER:
6245 {
6246 ASSERT(_hiCharGuid < 0xFFFFFFFE && "Player guid overflow!");
6247 return _hiCharGuid++;
6248 }
6250 {
6251 ASSERT(_hiGoGuid < 0x00FFFFFE && "Gameobject guid overflow!");
6252 return _hiGoGuid++;
6253 }
6254 case HIGHGUID_CORPSE:
6255 {
6256 ASSERT(_hiCorpseGuid < 0xFFFFFFFE && "Corpse guid overflow!");
6257 return _hiCorpseGuid++;
6258 }
6260 {
6261 ASSERT(_hiAreaTriggerGuid < 0xFFFFFFFE && "AreaTrigger guid overflow!");
6262 return _hiAreaTriggerGuid++;
6263 }
6265 {
6266 ASSERT(_hiDoGuid < 0xFFFFFFFE && "DynamicObject guid overflow!");
6267 return _hiDoGuid++;
6268 }
6270 {
6271 ASSERT(_hiMoTransGuid < 0xFFFFFFFE && "MO Transport guid overflow!");
6272 return _hiMoTransGuid++;
6273 }
6274 default:
6275 ASSERT(false && "ObjectMgr::GenerateLowGuid - Unknown HIGHGUID type");
6276 return 0;
6277 }
6278}
6279
6281{
6282 uint32 oldMSTime = getMSTime();
6283
6284 _gameObjectLocaleStore.clear(); // need for reload case
6285
6286 QueryResult result = WorldDatabase.Query("SELECT entry, name_loc1, name_loc2, name_loc3, name_loc4, "
6287 "name_loc5, name_loc6, name_loc7, name_loc8, name_loc9, name_loc10, name_loc11, "
6288 "castbarcaption_loc1, castbarcaption_loc2, castbarcaption_loc3, castbarcaption_loc4, "
6289 "castbarcaption_loc5, castbarcaption_loc6, castbarcaption_loc7, castbarcaption_loc8, "
6290 "castbarcaption_loc9, castbarcaption_loc10, castbarcaption_loc11 FROM locales_gameobject");
6291
6292 if (!result)
6293 return;
6294
6295 do
6296 {
6297 Field* fields = result->Fetch();
6298
6299 uint32 entry = fields[0].GetUInt32();
6300
6302
6303 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
6304 AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.Name);
6305
6306 for (uint8 i = 1; i < TOTAL_LOCALES; ++i)
6307 AddLocaleString(fields[i + (TOTAL_LOCALES - 1)].GetString(), LocaleConstant(i), data.CastBarCaption);
6308 } while (result->NextRow());
6309
6310 SF_LOG_INFO("server.loading", ">> Loaded %lu gameobject locale strings in %u ms", (unsigned long)_gameObjectLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime));
6311}
6312
6313inline void CheckGOLockId(GameObjectTemplate const* goInfo, uint32 dataN, uint32 N)
6314{
6315 if (sLockStore.LookupEntry(dataN))
6316 return;
6317
6318 SF_LOG_ERROR("sql.sql", "Gameobject (Entry: %u GoType: %u) have data%d=%u but lock (Id: %u) not found.",
6319 goInfo->entry, goInfo->type, N, dataN, dataN);
6320}
6321
6322inline void CheckGOLinkedTrapId(GameObjectTemplate const* goInfo, uint32 dataN, uint32 N)
6323{
6324 if (GameObjectTemplate const* trapInfo = sObjectMgr->GetGameObjectTemplate(dataN))
6325 {
6326 if (trapInfo->type != GAMEOBJECT_TYPE_TRAP)
6327 SF_LOG_ERROR("sql.sql", "Gameobject (Entry: %u GoType: %u) have data%d=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
6328 goInfo->entry, goInfo->type, N, dataN, dataN, GAMEOBJECT_TYPE_TRAP);
6329 }
6330}
6331
6332inline void CheckGOSpellId(GameObjectTemplate const* goInfo, uint32 dataN, uint32 N)
6333{
6334 if (sSpellMgr->GetSpellInfo(dataN))
6335 return;
6336
6337 SF_LOG_ERROR("sql.sql", "Gameobject (Entry: %u GoType: %u) have data%d=%u but Spell (Entry %u) not exist.",
6338 goInfo->entry, goInfo->type, N, dataN, dataN);
6339}
6340
6341inline void CheckAndFixGOChairHeightId(GameObjectTemplate const* goInfo, uint32& dataN, uint32 N)
6342{
6344 return;
6345
6346 SF_LOG_ERROR("sql.sql", "Gameobject (Entry: %u GoType: %u) have data%d=%u but correct chair height in range 0..%i.",
6348
6349 // prevent client and server unexpected work
6350 dataN = 0;
6351}
6352
6354{
6355 // 0/1 correct values
6356 if (dataN <= 1)
6357 return;
6358
6359 SF_LOG_ERROR("sql.sql", "Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) noDamageImmune field value.", goTemplate->entry, goTemplate->type, N, dataN);
6360}
6361
6362inline void CheckGOConsumable(GameObjectTemplate const* goInfo, uint32 dataN, uint32 N)
6363{
6364 // 0/1 correct values
6365 if (dataN <= 1)
6366 return;
6367
6368 SF_LOG_ERROR("sql.sql", "Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) consumable field value.",
6369 goInfo->entry, goInfo->type, N, dataN);
6370}
6371
6373{
6374 uint32 oldMSTime = getMSTime();
6375
6376 // 0 1 2 3 4 5 6 7 8 9 10 11 12
6377 QueryResult result = WorldDatabase.Query("SELECT entry, type, displayId, name, IconName, castBarCaption, unk1, faction, flags, size, questItem1, questItem2, questItem3, "
6378 // 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
6379 "questItem4, questItem5, questItem6, data0, data1, data2, data3, data4, data5, data6, data7, data8, data9, data10, data11, data12, "
6380 // 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
6381 "data13, data14, data15, data16, data17, data18, data19, data20, data21, data22, data23, data24, data25, data26, data27, data28, "
6382 // 45 46 47 48 49 50
6383 "data29, data30, data31, unkInt32, AIName, ScriptName "
6384 "FROM gameobject_template");
6385
6386 if (!result)
6387 {
6388 SF_LOG_INFO("server.loading", ">> Loaded 0 gameobject definitions. DB table `gameobject_template` is empty.");
6389 return;
6390 }
6391
6392 _gameObjectTemplateStore.rehash(result->GetRowCount());
6393 uint32 count = 0;
6394 do
6395 {
6396 Field* fields = result->Fetch();
6397
6398 uint32 entry = fields[0].GetUInt32();
6399
6401
6402 got.entry = entry;
6403 got.type = uint32(fields[1].GetUInt8());
6404 got.displayId = fields[2].GetUInt32();
6405 got.name = fields[3].GetString();
6406 got.IconName = fields[4].GetString();
6407 got.castBarCaption = fields[5].GetString();
6408 got.unk1 = fields[6].GetString();
6409 got.faction = uint32(fields[7].GetUInt16());
6410 got.flags = fields[8].GetUInt32();
6411 got.size = fields[9].GetFloat();
6412
6413 for (uint8 i = 0; i < MAX_GAMEOBJECT_QUEST_ITEMS; ++i)
6414 got.questItems[i] = fields[10 + i].GetUInt32();
6415
6416 for (uint8 i = 0; i < MAX_GAMEOBJECT_DATA; ++i)
6417 got.raw.data[i] = fields[16 + i].GetUInt32();
6418
6419 got.unkInt32 = fields[48].GetInt32();
6420 got.AIName = fields[49].GetString();
6421 got.ScriptId = GetScriptId(fields[50].GetCString());
6422
6423 // Checks
6424
6425 switch (got.type)
6426 {
6427 case GAMEOBJECT_TYPE_DOOR: //0
6428 {
6429 if (got.door.lockId)
6430 CheckGOLockId(&got, got.door.lockId, 1);
6432 break;
6433 }
6434 case GAMEOBJECT_TYPE_BUTTON: //1
6435 {
6436 if (got.button.lockId)
6437 CheckGOLockId(&got, got.button.lockId, 1);
6439 break;
6440 }
6442 {
6443 if (got.questgiver.lockId)
6444 CheckGOLockId(&got, got.questgiver.lockId, 0);
6446 break;
6447 }
6448 case GAMEOBJECT_TYPE_CHEST: //3
6449 {
6450 if (got.chest.lockId)
6451 CheckGOLockId(&got, got.chest.lockId, 0);
6452
6453 CheckGOConsumable(&got, got.chest.consumable, 3);
6454
6455 if (got.chest.linkedTrapId) // linked trap
6457 break;
6458 }
6459 case GAMEOBJECT_TYPE_TRAP: //6
6460 {
6461 if (got.trap.lockId)
6462 CheckGOLockId(&got, got.trap.lockId, 0);
6463 break;
6464 }
6465 case GAMEOBJECT_TYPE_CHAIR: //7
6467 break;
6469 {
6470 if (got.spellFocus.focusId)
6471 {
6472 if (!sSpellFocusObjectStore.LookupEntry(got.spellFocus.focusId))
6473 SF_LOG_ERROR("sql.sql", "GameObject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.",
6474 entry, got.type, got.spellFocus.focusId, got.spellFocus.focusId);
6475 }
6476
6477 if (got.spellFocus.linkedTrapId) // linked trap
6479 break;
6480 }
6481 case GAMEOBJECT_TYPE_GOOBER: //10
6482 {
6483 if (got.goober.lockId)
6484 CheckGOLockId(&got, got.goober.lockId, 0);
6485
6486 CheckGOConsumable(&got, got.goober.consumable, 3);
6487
6488 if (got.goober.pageId) // pageId
6489 {
6490 if (!GetPageText(got.goober.pageId))
6491 SF_LOG_ERROR("sql.sql", "GameObject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.",
6492 entry, got.type, got.goober.pageId, got.goober.pageId);
6493 }
6495 if (got.goober.linkedTrapId) // linked trap
6497 break;
6498 }
6500 {
6501 if (got.areadamage.lockId)
6502 CheckGOLockId(&got, got.areadamage.lockId, 0);
6503 break;
6504 }
6505 case GAMEOBJECT_TYPE_CAMERA: //13
6506 {
6507 if (got.camera.lockId)
6508 CheckGOLockId(&got, got.camera.lockId, 0);
6509 break;
6510 }
6512 {
6513 if (got.moTransport.taxiPathId)
6514 {
6516 SF_LOG_ERROR("sql.sql", "GameObject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
6517 entry, got.type, got.moTransport.taxiPathId, got.moTransport.taxiPathId);
6518 }
6519 break;
6520 }
6522 break;
6524 {
6525 // always must have spell
6526 CheckGOSpellId(&got, got.spellcaster.spellId, 0);
6527 break;
6528 }
6529 case GAMEOBJECT_TYPE_FLAGSTAND: //24
6530 {
6531 if (got.flagstand.lockId)
6532 CheckGOLockId(&got, got.flagstand.lockId, 0);
6534 break;
6535 }
6537 {
6538 if (got.fishinghole.lockId)
6539 CheckGOLockId(&got, got.fishinghole.lockId, 4);
6540 break;
6541 }
6542 case GAMEOBJECT_TYPE_FLAGDROP: //26
6543 {
6544 if (got.flagdrop.lockId)
6545 CheckGOLockId(&got, got.flagdrop.lockId, 0);
6547 break;
6548 }
6551 break;
6552 }
6553
6554 ++count;
6555 } while (result->NextRow());
6556
6557 SF_LOG_INFO("server.loading", ">> Loaded %u game object templates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6558}
6559
6561{
6562 uint32 oldMSTime = getMSTime();
6563
6564 QueryResult result = WorldDatabase.Query("SELECT level, basexp FROM exploration_basexp");
6565
6566 if (!result)
6567 {
6568 SF_LOG_ERROR("server.loading", ">> Loaded 0 BaseXP definitions. DB table `exploration_basexp` is empty.");
6569 return;
6570 }
6571
6572 uint32 count = 0;
6573
6574 do
6575 {
6576 Field* fields = result->Fetch();
6577 uint8 level = fields[0].GetUInt8();
6578 uint32 basexp = fields[1].GetInt32();
6579 _baseXPTable[level] = basexp;
6580 ++count;
6581 } while (result->NextRow());
6582
6583 SF_LOG_INFO("server.loading", ">> Loaded %u BaseXP definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6584}
6585
6587{
6588 return _baseXPTable[level] ? _baseXPTable[level] : 0;
6589}
6590
6592{
6593 if (level < _playerXPperLevel.size())
6594 return _playerXPperLevel[level];
6595 return 0;
6596}
6597
6599{
6600 uint32 oldMSTime = getMSTime();
6601 // 0 1 2
6602 QueryResult result = WorldDatabase.Query("SELECT word, entry, half FROM pet_name_generation");
6603
6604 if (!result)
6605 {
6606 SF_LOG_INFO("server.loading", ">> Loaded 0 pet name parts. DB table `pet_name_generation` is empty!");
6607 return;
6608 }
6609
6610 uint32 count = 0;
6611
6612 do
6613 {
6614 Field* fields = result->Fetch();
6615 std::string word = fields[0].GetString();
6616 uint32 entry = fields[1].GetUInt32();
6617 bool half = fields[2].GetBool();
6618 if (half)
6619 _petHalfName1[entry].push_back(word);
6620 else
6621 _petHalfName0[entry].push_back(word);
6622 ++count;
6623 } while (result->NextRow());
6624
6625 SF_LOG_INFO("server.loading", ">> Loaded %u pet name parts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6626}
6627
6629{
6630 uint32 oldMSTime = getMSTime();
6631
6632 QueryResult result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet");
6633 if (result)
6634 {
6635 Field* fields = result->Fetch();
6636 _hiPetNumber = fields[0].GetUInt32() + 1;
6637 }
6638
6639 SF_LOG_INFO("server.loading", ">> Loaded the max pet number: %d in %u ms", _hiPetNumber - 1, GetMSTimeDiffToNow(oldMSTime));
6640}
6641
6643{
6644 StringVector& list0 = _petHalfName0[entry];
6645 StringVector& list1 = _petHalfName1[entry];
6646
6647 if (list0.empty() || list1.empty())
6648 {
6649 CreatureTemplate const* cinfo = GetCreatureTemplate(entry);
6650 if (!cinfo)
6651 return std::string();
6652
6653 char const* petname = GetPetName(cinfo->family, sWorld->GetDefaultDbcLocale());
6654 if (petname)
6655 return std::string(petname);
6656 else
6657 return cinfo->Name;
6658 }
6659
6660 return *(list0.begin() + std::rand() % list0.size()) + *(list1.begin() + std::rand() % list1.size());
6661}
6662
6664{
6665 if (_hiPetNumber >= 0xFFFFFFFE)
6666 {
6667 SF_LOG_ERROR("misc", "_hiPetNumber Id overflow!! Can't continue, shutting down server. ");
6669 }
6670 return ++_hiPetNumber;
6671}
6672
6674{
6675 if (_voidItemId >= uint64(0xFFFFFFFFFFFFFFFELL))
6676 {
6677 SF_LOG_ERROR("misc", "VoidStorageItem Id overflow!! Can't continue, shutting down server. ");
6679 }
6680 return ++_voidItemId;
6681}
6682
6684{
6685 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
6686 // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0
6687
6688 uint32 oldMSTime = getMSTime();
6689
6690 PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSES));
6691 if (!result)
6692 {
6693 SF_LOG_INFO("server.loading", ">> Loaded 0 corpses. DB table `corpse` is empty.");
6694 return;
6695 }
6696
6697 uint32 count = 0;
6698 do
6699 {
6700 Field* fields = result->Fetch();
6701 uint32 guid = fields[16].GetUInt32();
6702 CorpseType type = CorpseType(fields[12].GetUInt8());
6703 if (type >= CorpseType::MAX_CORPSE_TYPE)
6704 {
6705 SF_LOG_ERROR("misc", "Corpse (guid: %u) have wrong corpse type (%u), not loading.", guid, uint8(type));
6706 continue;
6707 }
6708
6709 Corpse* corpse = new Corpse(type);
6710 if (!corpse->LoadCorpseFromDB(guid, fields))
6711 {
6712 delete corpse;
6713 continue;
6714 }
6715
6716 sObjectAccessor->AddCorpse(corpse);
6717 ++count;
6718 } while (result->NextRow());
6719
6720 SF_LOG_INFO("server.loading", ">> Loaded %u corpses in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6721}
6722
6724{
6725 uint32 oldMSTime = getMSTime();
6726
6727 _repRewardRateStore.clear(); // for reload case
6728
6729 uint32 count = 0; // 0 1 2 3 4 5 6 7
6730 QueryResult result = WorldDatabase.Query("SELECT faction, quest_rate, quest_daily_rate, quest_weekly_rate, quest_monthly_rate, quest_repeatable_rate, creature_rate, spell_rate FROM reputation_reward_rate");
6731 if (!result)
6732 {
6733 SF_LOG_ERROR("server.loading", ">> Loaded `reputation_reward_rate`, table is empty!");
6734 return;
6735 }
6736
6737 do
6738 {
6739 Field* fields = result->Fetch();
6740
6741 uint32 factionId = fields[0].GetUInt32();
6742
6743 RepRewardRate repRate;
6744
6745 repRate.questRate = fields[1].GetFloat();
6746 repRate.questDailyRate = fields[2].GetFloat();
6747 repRate.questWeeklyRate = fields[3].GetFloat();
6748 repRate.questMonthlyRate = fields[4].GetFloat();
6749 repRate.questRepeatableRate = fields[5].GetFloat();
6750 repRate.creatureRate = fields[6].GetFloat();
6751 repRate.spellRate = fields[7].GetFloat();
6752
6753 FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId);
6754 if (!factionEntry)
6755 {
6756 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_reward_rate`", factionId);
6757 continue;
6758 }
6759
6760 if (repRate.questRate < 0.0f)
6761 {
6762 SF_LOG_ERROR("sql.sql", "Table reputation_reward_rate has quest_rate with invalid rate %f, skipping data for faction %u", repRate.questRate, factionId);
6763 continue;
6764 }
6765
6766 if (repRate.questDailyRate < 0.0f)
6767 {
6768 SF_LOG_ERROR("sql.sql", "Table reputation_reward_rate has quest_daily_rate with invalid rate %f, skipping data for faction %u", repRate.questDailyRate, factionId);
6769 continue;
6770 }
6771
6772 if (repRate.questWeeklyRate < 0.0f)
6773 {
6774 SF_LOG_ERROR("sql.sql", "Table reputation_reward_rate has quest_weekly_rate with invalid rate %f, skipping data for faction %u", repRate.questWeeklyRate, factionId);
6775 continue;
6776 }
6777
6778 if (repRate.questMonthlyRate < 0.0f)
6779 {
6780 SF_LOG_ERROR("sql.sql", "Table reputation_reward_rate has quest_monthly_rate with invalid rate %f, skipping data for faction %u", repRate.questMonthlyRate, factionId);
6781 continue;
6782 }
6783
6784 if (repRate.questRepeatableRate < 0.0f)
6785 {
6786 SF_LOG_ERROR("sql.sql", "Table reputation_reward_rate has quest_repeatable_rate with invalid rate %f, skipping data for faction %u", repRate.questRepeatableRate, factionId);
6787 continue;
6788 }
6789
6790 if (repRate.creatureRate < 0.0f)
6791 {
6792 SF_LOG_ERROR("sql.sql", "Table reputation_reward_rate has creature_rate with invalid rate %f, skipping data for faction %u", repRate.creatureRate, factionId);
6793 continue;
6794 }
6795
6796 if (repRate.spellRate < 0.0f)
6797 {
6798 SF_LOG_ERROR("sql.sql", "Table reputation_reward_rate has spell_rate with invalid rate %f, skipping data for faction %u", repRate.spellRate, factionId);
6799 continue;
6800 }
6801
6802 _repRewardRateStore[factionId] = repRate;
6803
6804 ++count;
6805 } while (result->NextRow());
6806
6807 SF_LOG_INFO("server.loading", ">> Loaded %u reputation_reward_rate in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6808}
6809
6811{
6812 uint32 oldMSTime = getMSTime();
6813
6814 // For reload case
6815 _repOnKillStore.clear();
6816
6817 uint32 count = 0;
6818
6819 // 0 1 2
6820 QueryResult result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2, "
6821 // 3 4 5 6 7 8 9
6822 "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent "
6823 "FROM creature_onkill_reputation");
6824
6825 if (!result)
6826 {
6827 SF_LOG_ERROR("server.loading", ">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty.");
6828 return;
6829 }
6830
6831 do
6832 {
6833 Field* fields = result->Fetch();
6834
6835 uint32 creature_id = fields[0].GetUInt32();
6836
6837 ReputationOnKillEntry repOnKill;
6838 repOnKill.RepFaction1 = fields[1].GetInt16();
6839 repOnKill.RepFaction2 = fields[2].GetInt16();
6840 repOnKill.IsTeamAward1 = fields[3].GetBool();
6841 repOnKill.ReputationMaxCap1 = fields[4].GetUInt8();
6842 repOnKill.RepValue1 = fields[5].GetInt32();
6843 repOnKill.IsTeamAward2 = fields[6].GetBool();
6844 repOnKill.ReputationMaxCap2 = fields[7].GetUInt8();
6845 repOnKill.RepValue2 = fields[8].GetInt32();
6846 repOnKill.TeamDependent = fields[9].GetUInt8();
6847
6848 if (!GetCreatureTemplate(creature_id))
6849 {
6850 SF_LOG_ERROR("sql.sql", "Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped", creature_id);
6851 continue;
6852 }
6853
6854 if (repOnKill.RepFaction1)
6855 {
6856 FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(repOnKill.RepFaction1);
6857 if (!factionEntry1)
6858 {
6859 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`", repOnKill.RepFaction1);
6860 continue;
6861 }
6862 }
6863
6864 if (repOnKill.RepFaction2)
6865 {
6866 FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(repOnKill.RepFaction2);
6867 if (!factionEntry2)
6868 {
6869 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`", repOnKill.RepFaction2);
6870 continue;
6871 }
6872 }
6873
6874 _repOnKillStore[creature_id] = repOnKill;
6875
6876 ++count;
6877 } while (result->NextRow());
6878
6879 SF_LOG_INFO("server.loading", ">> Loaded %u creature award reputation definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6880}
6881
6883{
6884 uint32 oldMSTime = getMSTime();
6885
6886 _repSpilloverTemplateStore.clear(); // for reload case
6887
6888 uint32 count = 0; // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
6889 QueryResult result = WorldDatabase.Query("SELECT faction, faction1, rate_1, rank_1, faction2, rate_2, rank_2, faction3, rate_3, rank_3, faction4, rate_4, rank_4, faction5, rate_5, rank_5 FROM reputation_spillover_template");
6890
6891 if (!result)
6892 {
6893 SF_LOG_INFO("server.loading", ">> Loaded `reputation_spillover_template`, table is empty.");
6894 return;
6895 }
6896
6897 do
6898 {
6899 Field* fields = result->Fetch();
6900
6901 uint32 factionId = fields[0].GetUInt16();
6902
6903 RepSpilloverTemplate repTemplate;
6904
6905 repTemplate.faction[0] = fields[1].GetUInt16();
6906 repTemplate.faction_rate[0] = fields[2].GetFloat();
6907 repTemplate.faction_rank[0] = fields[3].GetUInt8();
6908 repTemplate.faction[1] = fields[4].GetUInt16();
6909 repTemplate.faction_rate[1] = fields[5].GetFloat();
6910 repTemplate.faction_rank[1] = fields[6].GetUInt8();
6911 repTemplate.faction[2] = fields[7].GetUInt16();
6912 repTemplate.faction_rate[2] = fields[8].GetFloat();
6913 repTemplate.faction_rank[2] = fields[9].GetUInt8();
6914 repTemplate.faction[3] = fields[10].GetUInt16();
6915 repTemplate.faction_rate[3] = fields[11].GetFloat();
6916 repTemplate.faction_rank[3] = fields[12].GetUInt8();
6917 repTemplate.faction[4] = fields[13].GetUInt16();
6918 repTemplate.faction_rate[4] = fields[14].GetFloat();
6919 repTemplate.faction_rank[4] = fields[15].GetUInt8();
6920
6921 FactionEntry const* factionEntry = sFactionStore.LookupEntry(factionId);
6922
6923 if (!factionEntry)
6924 {
6925 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", factionId);
6926 continue;
6927 }
6928
6929 if (factionEntry->team == 0)
6930 {
6931 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u in `reputation_spillover_template` does not belong to any team, skipping", factionId);
6932 continue;
6933 }
6934
6935 for (uint32 i = 0; i < MAX_SPILLOVER_FACTIONS; ++i)
6936 {
6937 if (repTemplate.faction[i])
6938 {
6939 FactionEntry const* factionSpillover = sFactionStore.LookupEntry(repTemplate.faction[i]);
6940
6941 if (!factionSpillover)
6942 {
6943 SF_LOG_ERROR("sql.sql", "Spillover faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template` for faction %u, skipping", repTemplate.faction[i], factionId);
6944 continue;
6945 }
6946
6947 if (factionSpillover->reputationListID < 0)
6948 {
6949 SF_LOG_ERROR("sql.sql", "Spillover faction (faction.dbc) %u for faction %u in `reputation_spillover_template` can not be listed for client, and then useless, skipping", repTemplate.faction[i], factionId);
6950 continue;
6951 }
6952
6953 if (repTemplate.faction_rank[i] >= MAX_REPUTATION_RANK)
6954 {
6955 SF_LOG_ERROR("sql.sql", "Rank %u used in `reputation_spillover_template` for spillover faction %u is not valid, skipping", repTemplate.faction_rank[i], repTemplate.faction[i]);
6956 continue;
6957 }
6958 }
6959 }
6960
6961 FactionEntry const* factionEntry0 = sFactionStore.LookupEntry(repTemplate.faction[0]);
6962 if (repTemplate.faction[0] && !factionEntry0)
6963 {
6964 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[0]);
6965 continue;
6966 }
6967 FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(repTemplate.faction[1]);
6968 if (repTemplate.faction[1] && !factionEntry1)
6969 {
6970 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[1]);
6971 continue;
6972 }
6973 FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(repTemplate.faction[2]);
6974 if (repTemplate.faction[2] && !factionEntry2)
6975 {
6976 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[2]);
6977 continue;
6978 }
6979 FactionEntry const* factionEntry3 = sFactionStore.LookupEntry(repTemplate.faction[3]);
6980 if (repTemplate.faction[3] && !factionEntry3)
6981 {
6982 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[3]);
6983 continue;
6984 }
6985 FactionEntry const* factionEntry4 = sFactionStore.LookupEntry(repTemplate.faction[4]);
6986 if (repTemplate.faction[4] && !factionEntry4)
6987 {
6988 SF_LOG_ERROR("sql.sql", "Faction (faction.dbc) %u does not exist but is used in `reputation_spillover_template`", repTemplate.faction[4]);
6989 continue;
6990 }
6991
6992 _repSpilloverTemplateStore[factionId] = repTemplate;
6993
6994 ++count;
6995 } while (result->NextRow());
6996
6997 SF_LOG_INFO("server.loading", ">> Loaded %u reputation_spillover_template in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
6998}
6999
7001{
7002 uint32 oldMSTime = getMSTime();
7003
7004 _pointsOfInterestStore.clear(); // need for reload case
7005
7006 uint32 count = 0;
7007
7008 // 0 1 2 3 4 5 6
7009 QueryResult result = WorldDatabase.Query("SELECT entry, x, y, icon, flags, data, icon_name FROM points_of_interest");
7010
7011 if (!result)
7012 {
7013 SF_LOG_ERROR("server.loading", ">> Loaded 0 Points of Interest definitions. DB table `points_of_interest` is empty.");
7014 return;
7015 }
7016
7017 do
7018 {
7019 Field* fields = result->Fetch();
7020
7021 uint32 point_id = fields[0].GetUInt32();
7022
7023 PointOfInterest POI;
7024 POI.entry = point_id;
7025 POI.x = fields[1].GetFloat();
7026 POI.y = fields[2].GetFloat();
7027 POI.icon = fields[3].GetUInt32();
7028 POI.flags = fields[4].GetUInt32();
7029 POI.data = fields[5].GetUInt32();
7030 POI.icon_name = fields[6].GetString();
7031
7032 if (!Skyfire::IsValidMapCoord(POI.x, POI.y))
7033 {
7034 SF_LOG_ERROR("sql.sql", "Table `points_of_interest` (Entry: %u) have invalid coordinates (X: %f Y: %f), ignored.", point_id, POI.x, POI.y);
7035 continue;
7036 }
7037
7038 _pointsOfInterestStore[point_id] = POI;
7039
7040 ++count;
7041 } while (result->NextRow());
7042
7043 SF_LOG_INFO("server.loading", ">> Loaded %u Points of Interest definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
7044}
7045
7047{
7048 uint32 oldMSTime = getMSTime();
7049
7050 _questPOIStore.clear(); // need for reload case
7051
7052 uint32 count = 0;
7053
7054 // 0 1 2 3 4 5 6 7
7055 QueryResult result = WorldDatabase.Query("SELECT questId, id, objIndex, mapid, WorldMapAreaId, FloorId, unk3, unk4 FROM quest_poi order by questId");
7056
7057 if (!result)
7058 {
7059 SF_LOG_ERROR("server.loading", ">> Loaded 0 quest POI definitions. DB table `quest_poi` is empty.");
7060 return;
7061 }
7062
7063 // 0 1 2 3
7064 QueryResult points = WorldDatabase.Query("SELECT questId, id, x, y FROM quest_poi_points ORDER BY questId DESC, idx");
7065
7066 std::vector<std::vector<std::vector<QuestPOIPoint> > > POIs;
7067
7068 if (points)
7069 {
7070 // The first result should have the highest questId
7071 Field* fields = points->Fetch();
7072 uint32 questIdMax = fields[0].GetUInt32();
7073 POIs.resize(questIdMax + 1);
7074
7075 do
7076 {
7077 fields = points->Fetch();
7078
7079 uint32 questId = fields[0].GetUInt32();
7080 uint32 id = fields[1].GetUInt32();
7081 int32 x = fields[2].GetInt32();
7082 int32 y = fields[3].GetInt32();
7083
7084 if (POIs[questId].size() <= id + 1)
7085 POIs[questId].resize(id + 10);
7086
7087 QuestPOIPoint point(x, y);
7088 POIs[questId][id].push_back(point);
7089 } while (points->NextRow());
7090 }
7091
7092 do
7093 {
7094 Field* fields = result->Fetch();
7095
7096 uint32 questId = fields[0].GetUInt32();
7097 uint32 id = fields[1].GetUInt32();
7098 int32 objIndex = fields[2].GetInt32();
7099 uint32 mapId = fields[3].GetUInt32();
7100 uint32 WorldMapAreaId = fields[4].GetUInt32();
7101 uint32 FloorId = fields[5].GetUInt32();
7102 uint32 unk3 = fields[6].GetUInt32();
7103 uint32 unk4 = fields[7].GetUInt32();
7104
7105 QuestPOI POI(id, objIndex, mapId, WorldMapAreaId, FloorId, unk3, unk4);
7106 POI.points = POIs[questId][id];
7107
7108 _questPOIStore[questId].push_back(POI);
7109
7110 ++count;
7111 } while (result->NextRow());
7112
7113 SF_LOG_INFO("server.loading", ">> Loaded %u quest POI definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
7114}
7115
7117{
7118 uint32 oldMSTime = getMSTime();
7119
7120 _spellClickInfoStore.clear();
7121 // 0 1 2 3
7122 QueryResult result = WorldDatabase.Query("SELECT npc_entry, spell_id, cast_flags, user_type FROM npc_spellclick_spells");
7123
7124 if (!result)
7125 {
7126 SF_LOG_ERROR("server.loading", ">> Loaded 0 spellclick spells. DB table `npc_spellclick_spells` is empty.");
7127 return;
7128 }
7129
7130 uint32 count = 0;
7131
7132 do
7133 {
7134 Field* fields = result->Fetch();
7135
7136 uint32 npc_entry = fields[0].GetUInt32();
7137 CreatureTemplate const* cInfo = GetCreatureTemplate(npc_entry);
7138 if (!cInfo)
7139 {
7140 SF_LOG_ERROR("sql.sql", "Table npc_spellclick_spells references unknown creature_template %u. Skipping entry.", npc_entry);
7141 continue;
7142 }
7143
7144 uint32 spellid = fields[1].GetUInt32();
7145 SpellInfo const* spellinfo = sSpellMgr->GetSpellInfo(spellid);
7146 if (!spellinfo)
7147 {
7148 SF_LOG_ERROR("sql.sql", "Table npc_spellclick_spells references unknown spellid %u. Skipping entry.", spellid);
7149 continue;
7150 }
7151
7152 uint8 userType = fields[3].GetUInt16();
7153 if (userType >= SPELL_CLICK_USER_MAX)
7154 SF_LOG_ERROR("sql.sql", "Table npc_spellclick_spells references unknown user type %u. Skipping entry.", uint32(userType));
7155
7156 uint8 castFlags = fields[2].GetUInt8();
7157 SpellClickInfo info;
7158 info.spellId = spellid;
7159 info.castFlags = castFlags;
7160 info.userType = SpellClickUserTypes(userType);
7161 _spellClickInfoStore.insert(SpellClickInfoContainer::value_type(npc_entry, info));
7162
7163 ++count;
7164 } while (result->NextRow());
7165
7166 // all spellclick data loaded, now we check if there are creatures with NPC_FLAG_SPELLCLICK but with no data
7167 // NOTE: It *CAN* be the other way around: no spellclick flag but with spellclick data, in case of creature-only vehicle accessories
7168 CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates();
7169 for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr)
7170 {
7171 if ((itr->second.npcflag & UNIT_NPC_FLAG_SPELLCLICK) && _spellClickInfoStore.find(itr->second.Entry) == _spellClickInfoStore.end())
7172 {
7173 SF_LOG_ERROR("sql.sql", "npc_spellclick_spells: Creature template %u has UNIT_NPC_FLAG_SPELLCLICK but no data in spellclick table! Removing flag", itr->second.Entry);
7174 const_cast<CreatureTemplate*>(&itr->second)->npcflag &= ~UNIT_NPC_FLAG_SPELLCLICK;
7175 }
7176 }
7177
7178 SF_LOG_INFO("server.loading", ">> Loaded %u spellclick definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
7179}
7180
7182{
7183 // remove mapid*cellid -> guid_set map
7184 CreatureData const* data = GetCreatureData(guid);
7185 if (data)
7186 RemoveCreatureFromGrid(guid, data);
7187
7188 _creatureDataStore.erase(guid);
7189}
7190
7192{
7193 // remove mapid*cellid -> guid_set map
7194 GameObjectData const* data = GetGOData(guid);
7195 if (data)
7196 RemoveGameobjectFromGrid(guid, data);
7197
7198 _gameObjectDataStore.erase(guid);
7199}
7200
7201void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
7202{
7203 // corpses are always added to spawn mode 0 and they are spawned by their instance id
7204 CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(mapid, 0)][cellid];
7205 cell_guids.corpses[player_guid] = instance;
7206}
7207
7208void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
7209{
7210 // corpses are always added to spawn mode 0 and they are spawned by their instance id
7211 CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(mapid, 0)][cellid];
7212 cell_guids.corpses.erase(player_guid);
7213}
7214
7215void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map, std::string const& table, bool starter, bool go)
7216{
7217 uint32 oldMSTime = getMSTime();
7218
7219 map.clear(); // need for reload case
7220
7221 uint32 count = 0;
7222
7223 QueryResult result = WorldDatabase.PQuery("SELECT id, quest, pool_entry FROM %s qr LEFT JOIN pool_quest pq ON qr.quest = pq.entry", table.c_str());
7224
7225 if (!result)
7226 {
7227 SF_LOG_ERROR("server.loading", ">> Loaded 0 quest relations from `%s`, table is empty.", table.c_str());
7228 return;
7229 }
7230
7231 PooledQuestRelation* poolRelationMap = go ? &sPoolMgr->mQuestGORelation : &sPoolMgr->mQuestCreatureRelation;
7232 if (starter)
7233 poolRelationMap->clear();
7234
7235 do
7236 {
7237 uint32 id = result->Fetch()[0].GetUInt32();
7238 uint32 quest = result->Fetch()[1].GetUInt32();
7239 uint32 poolId = result->Fetch()[2].GetUInt32();
7240
7241 if (_questTemplates.find(quest) == _questTemplates.end())
7242 {
7243 SF_LOG_ERROR("sql.sql", "Table `%s`: Quest %u listed for entry %u does not exist.", table.c_str(), quest, id);
7244 continue;
7245 }
7246
7247 if (!poolId || !starter)
7248 map.insert(QuestRelations::value_type(id, quest));
7249 else if (starter)
7250 poolRelationMap->insert(PooledQuestRelation::value_type(quest, id));
7251
7252 ++count;
7253 } while (result->NextRow());
7254
7255 SF_LOG_INFO("server.loading", ">> Loaded %u quest relations from %s in %u ms", count, table.c_str(), GetMSTimeDiffToNow(oldMSTime));
7256}
7257
7259{
7260 LoadQuestRelationsHelper(_goQuestRelations, "gameobject_queststarter", true, true);
7261
7262 for (QuestRelations::iterator itr = _goQuestRelations.begin(); itr != _goQuestRelations.end(); ++itr)
7263 {
7264 GameObjectTemplate const* goInfo = GetGameObjectTemplate(itr->first);
7265 if (!goInfo)
7266 SF_LOG_ERROR("sql.sql", "Table `gameobject_queststarter` have data for not existed gameobject entry (%u) and existed quest %u", itr->first, itr->second);
7267 else if (goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
7268 SF_LOG_ERROR("sql.sql", "Table `gameobject_queststarter` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER", itr->first, itr->second);
7269 }
7270}
7271
7273{
7274 LoadQuestRelationsHelper(_goQuestInvolvedRelations, "gameobject_questender", false, true);
7275
7276 for (QuestRelations::iterator itr = _goQuestInvolvedRelations.begin(); itr != _goQuestInvolvedRelations.end(); ++itr)
7277 {
7278 GameObjectTemplate const* goInfo = GetGameObjectTemplate(itr->first);
7279 if (!goInfo)
7280 SF_LOG_ERROR("sql.sql", "Table `gameobject_questender` have data for not existed gameobject entry (%u) and existed quest %u", itr->first, itr->second);
7281 else if (goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
7282 SF_LOG_ERROR("sql.sql", "Table `gameobject_questender` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER", itr->first, itr->second);
7283 }
7284}
7285
7287{
7288 LoadQuestRelationsHelper(_creatureQuestRelations, "creature_queststarter", true, false);
7289
7290 for (QuestRelations::iterator itr = _creatureQuestRelations.begin(); itr != _creatureQuestRelations.end(); ++itr)
7291 {
7292 CreatureTemplate const* cInfo = GetCreatureTemplate(itr->first);
7293 if (!cInfo)
7294 SF_LOG_ERROR("sql.sql", "Table `creature_queststarter` have data for not existed creature entry (%u) and existed quest %u", itr->first, itr->second);
7295 else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
7296 SF_LOG_ERROR("sql.sql", "Table `creature_queststarter` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
7297 }
7298}
7299
7301{
7302 LoadQuestRelationsHelper(_creatureQuestInvolvedRelations, "creature_questender", false, false);
7303
7304 for (QuestRelations::iterator itr = _creatureQuestInvolvedRelations.begin(); itr != _creatureQuestInvolvedRelations.end(); ++itr)
7305 {
7306 CreatureTemplate const* cInfo = GetCreatureTemplate(itr->first);
7307 if (!cInfo)
7308 SF_LOG_ERROR("sql.sql", "Table `creature_questender` have data for not existed creature entry (%u) and existed quest %u", itr->first, itr->second);
7309 else if (!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
7310 SF_LOG_ERROR("sql.sql", "Table `creature_questender` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", itr->first, itr->second);
7311 }
7312}
7313
7315{
7316 uint32 oldMSTime = getMSTime();
7317
7318 _reservedNamesStore.clear(); // need for reload case
7319
7320 QueryResult result = CharacterDatabase.Query("SELECT name FROM reserved_name");
7321
7322 if (!result)
7323 {
7324 SF_LOG_INFO("server.loading", ">> Loaded 0 reserved player names. DB table `reserved_name` is empty!");
7325 return;
7326 }
7327
7328 uint32 count = 0;
7329
7330 Field* fields;
7331 do
7332 {
7333 fields = result->Fetch();
7334 std::string name = fields[0].GetString();
7335
7336 std::wstring wstr;
7337 if (!Utf8toWStr(name, wstr))
7338 {
7339 SF_LOG_ERROR("misc", "Table `reserved_name` have invalid name: %s", name.c_str());
7340 continue;
7341 }
7342
7343 wstrToLower(wstr);
7344
7345 _reservedNamesStore.insert(wstr);
7346 ++count;
7347 } while (result->NextRow());
7348
7349 SF_LOG_INFO("server.loading", ">> Loaded %u reserved player names in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
7350}
7351
7352bool ObjectMgr::IsReservedName(const std::string& name) const
7353{
7354 std::wstring wstr;
7355 if (!Utf8toWStr(name, wstr))
7356 return false;
7357
7358 wstrToLower(wstr);
7359
7360 return _reservedNamesStore.find(wstr) != _reservedNamesStore.end();
7361}
7362
7364{
7367 LT_CYRILLIC = 0x0002,
7369 LT_ANY = 0xFFFF
7370};
7371
7373{
7374 switch (sWorld->getIntConfig(WorldIntConfigs::CONFIG_REALM_ZONE))
7375 {
7376 case REALM_ZONE_UNKNOWN: // any language
7380 return LT_ANY;
7381 case REALM_ZONE_UNITED_STATES: // extended-Latin
7382 case REALM_ZONE_OCEANIC:
7384 case REALM_ZONE_ENGLISH:
7385 case REALM_ZONE_GERMAN:
7386 case REALM_ZONE_FRENCH:
7387 case REALM_ZONE_SPANISH:
7388 return LT_EXTENDEN_LATIN;
7389 case REALM_ZONE_KOREA: // East-Asian
7390 case REALM_ZONE_TAIWAN:
7391 case REALM_ZONE_CHINA:
7392 return LT_EAST_ASIA;
7393 case REALM_ZONE_RUSSIAN: // Cyrillic
7394 return LT_CYRILLIC;
7395 default:
7396 return create ? LT_BASIC_LATIN : LT_ANY; // basic-Latin at create, any at login
7397 }
7398}
7399
7400bool isValidString(const std::wstring& wstr, uint32 strictMask, bool numericOrSpace, bool create = false)
7401{
7402 if (strictMask == 0) // any language, ignore realm
7403 {
7404 if (isExtendedLatinString(wstr, numericOrSpace))
7405 return true;
7406 if (isCyrillicString(wstr, numericOrSpace))
7407 return true;
7408 if (isEastAsianString(wstr, numericOrSpace))
7409 return true;
7410 return false;
7411 }
7412
7413 if (strictMask & 0x2) // realm zone specific
7414 {
7416 if (lt & LT_EXTENDEN_LATIN)
7417 if (isExtendedLatinString(wstr, numericOrSpace))
7418 return true;
7419 if (lt & LT_CYRILLIC)
7420 if (isCyrillicString(wstr, numericOrSpace))
7421 return true;
7422 if (lt & LT_EAST_ASIA)
7423 if (isEastAsianString(wstr, numericOrSpace))
7424 return true;
7425 }
7426
7427 if (strictMask & 0x1) // basic Latin
7428 {
7429 if (isBasicLatinString(wstr, numericOrSpace))
7430 return true;
7431 }
7432
7433 return false;
7434}
7435
7436ResponseCodes ObjectMgr::CheckPlayerName(const std::string& name, bool create)
7437{
7438 std::wstring wname;
7439 if (!Utf8toWStr(name, wname))
7441
7442 if (wname.size() > MAX_PLAYER_NAME)
7444
7445 uint32 minName = sWorld->getIntConfig(WorldIntConfigs::CONFIG_MIN_PLAYER_NAME);
7446 if (wname.size() < minName)
7448
7449 uint32 strictMask = sWorld->getIntConfig(WorldIntConfigs::CONFIG_STRICT_PLAYER_NAMES);
7450 if (!isValidString(wname, strictMask, false, create))
7452
7453 wstrToLower(wname);
7454 for (size_t i = 2; i < wname.size(); ++i)
7455 if (wname[i] == wname[i - 1] && wname[i] == wname[i - 2])
7457
7459}
7460
7461bool ObjectMgr::IsValidCharterName(const std::string& name)
7462{
7463 std::wstring wname;
7464 if (!Utf8toWStr(name, wname))
7465 return false;
7466
7467 if (wname.size() > MAX_CHARTER_NAME)
7468 return false;
7469
7471 if (wname.size() < minName)
7472 return false;
7473
7475
7476 return isValidString(wname, strictMask, true);
7477}
7478
7480{
7481 std::wstring wname;
7482 if (!Utf8toWStr(name, wname))
7483 return PET_NAME_INVALID;
7484
7485 if (wname.size() > MAX_PET_NAME)
7486 return PET_NAME_TOO_LONG;
7487
7488 uint32 minName = sWorld->getIntConfig(WorldIntConfigs::CONFIG_MIN_PET_NAME);
7489 if (wname.size() < minName)
7490 return PET_NAME_TOO_SHORT;
7491
7492 uint32 strictMask = sWorld->getIntConfig(WorldIntConfigs::CONFIG_STRICT_PET_NAMES);
7493 if (!isValidString(wname, strictMask, false))
7495
7496 return PET_NAME_SUCCESS;
7497}
7498
7500{
7501 uint32 oldMSTime = getMSTime();
7502
7503 _gameObjectForQuestStore.clear(); // need for reload case
7504
7505 if (sObjectMgr->GetGameObjectTemplates()->empty())
7506 {
7507 SF_LOG_INFO("server.loading", ">> Loaded 0 GameObjects for quests");
7508 return;
7509 }
7510
7511 uint32 count = 0;
7512
7513 // collect GO entries for GO that must activated
7514 GameObjectTemplateContainer const* gotc = sObjectMgr->GetGameObjectTemplates();
7515 for (GameObjectTemplateContainer::const_iterator itr = gotc->begin(); itr != gotc->end(); ++itr)
7516 {
7517 switch (itr->second.type)
7518 {
7519 // scan GO chest with loot including quest items
7521 {
7522 uint32 loot_id = (itr->second.GetLootId());
7523
7524 // find quest loot for GO
7525 if (itr->second.chest.questId || LootTemplates_Gameobject.HaveQuestLootFor(loot_id))
7526 {
7527 _gameObjectForQuestStore.insert(itr->second.entry);
7528 ++count;
7529 }
7530 break;
7531 }
7533 {
7534 if (itr->second._generic.questID > 0) //quests objects
7535 {
7536 _gameObjectForQuestStore.insert(itr->second.entry);
7537 count++;
7538 }
7539 break;
7540 }
7542 {
7543 if (itr->second.goober.questId > 0) //quests objects
7544 {
7545 _gameObjectForQuestStore.insert(itr->second.entry);
7546 count++;
7547 }
7548 break;
7549 }
7550 default:
7551 break;
7552 }
7553 }
7554
7555 SF_LOG_INFO("server.loading", ">> Loaded %u GameObjects for quests in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
7556}
7557
7558bool ObjectMgr::LoadSkyFireStrings(const char* table, int32 min_value, int32 max_value)
7559{
7560 uint32 oldMSTime = getMSTime();
7561
7562 int32 start_value = min_value;
7563 int32 end_value = max_value;
7564 // some string can have negative indexes range
7565 if (start_value < 0)
7566 {
7567 if (end_value >= start_value)
7568 {
7569 SF_LOG_ERROR("sql.sql", "Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.", table, min_value, max_value);
7570 return false;
7571 }
7572
7573 // real range (max+1, min+1) exaple: (-10, -1000) -> -999...-10+1
7574 std::swap(start_value, end_value);
7575 ++start_value;
7576 ++end_value;
7577 }
7578 else
7579 {
7580 if (start_value >= end_value)
7581 {
7582 SF_LOG_ERROR("sql.sql", "Table '%s' attempt loaded with invalid range (%d - %d), strings not loaded.", table, min_value, max_value);
7583 return false;
7584 }
7585 }
7586
7587 // cleanup affected map part for reloading case
7588 for (SkyFireStringLocaleContainer::iterator itr = _SkyfireStringLocaleStore.begin(); itr != _SkyfireStringLocaleStore.end();)
7589 {
7590 if (itr->first >= start_value && itr->first < end_value)
7591 _SkyfireStringLocaleStore.erase(itr++);
7592 else
7593 ++itr;
7594 }
7595
7596 QueryResult result = WorldDatabase.PQuery("SELECT entry, content_default, content_loc1, content_loc2, content_loc3, content_loc4, content_loc5, content_loc6, content_loc7, content_loc8, content_loc9, content_loc10, content_loc11 FROM %s", table);
7597
7598 if (!result)
7599 {
7600 if (min_value == MIN_SKYFIRE_STRING_ID) // error only in case internal strings
7601 SF_LOG_ERROR("server.loading", ">> Loaded 0 skyfire strings. DB table `%s` is empty. Cannot continue.", table);
7602 else
7603 SF_LOG_INFO("server.loading", ">> Loaded 0 string templates. DB table `%s` is empty.", table);
7604
7605 return false;
7606 }
7607
7608 uint32 count = 0;
7609
7610 do
7611 {
7612 Field* fields = result->Fetch();
7613
7614 int32 entry = fields[0].GetInt32();
7615
7616 if (entry == 0)
7617 {
7618 SF_LOG_ERROR("sql.sql", "Table `%s` contain reserved entry 0, ignored.", table);
7619 continue;
7620 }
7621 else if (entry < start_value || entry >= end_value)
7622 {
7623 SF_LOG_ERROR("sql.sql", "Table `%s` contain entry %i out of allowed range (%d - %d), ignored.", table, entry, min_value, max_value);
7624 continue;
7625 }
7626
7628
7629 if (!data.Content.empty())
7630 {
7631 SF_LOG_ERROR("sql.sql", "Table `%s` contain data for already loaded entry %i (from another table?), ignored.", table, entry);
7632 continue;
7633 }
7634
7635 data.Content.resize(1);
7636 ++count;
7637
7638 for (uint8 i = 0; i < TOTAL_LOCALES; ++i)
7639 AddLocaleString(fields[i + 1].GetString(), LocaleConstant(i), data.Content);
7640 } while (result->NextRow());
7641
7642 if (min_value == MIN_SKYFIRE_STRING_ID)
7643 SF_LOG_INFO("server.loading", ">> Loaded %u Skyfire strings from table %s in %u ms", count, table, GetMSTimeDiffToNow(oldMSTime));
7644 else
7645 SF_LOG_INFO("server.loading", ">> Loaded %u string templates from %s in %u ms", count, table, GetMSTimeDiffToNow(oldMSTime));
7646
7647 return true;
7648}
7649
7650const char* ObjectMgr::GetSkyFireString(int32 entry, LocaleConstant locale_idx) const
7651{
7652 if (SkyFireStringLocale const* msl = GetSkyFireStringLocale(entry))
7653 {
7654 if (msl->Content.size() > size_t(locale_idx) && !msl->Content[locale_idx].empty())
7655 return msl->Content[locale_idx].c_str();
7656
7657 return msl->Content[DEFAULT_LOCALE].c_str();
7658 }
7659
7660 if (entry > 0)
7661 SF_LOG_ERROR("sql.sql", "Entry %i not found in `skyfire_string` table.", entry);
7662 else
7663 SF_LOG_ERROR("sql.sql", "Skyfire string entry %i not found in DB.", entry);
7664 return "<error>";
7665}
7666
7668{
7669 uint32 oldMSTime = getMSTime();
7670
7671 _fishingBaseForAreaStore.clear(); // for reload case
7672
7673 QueryResult result = WorldDatabase.Query("SELECT entry, skill FROM skill_fishing_base_level");
7674
7675 if (!result)
7676 {
7677 SF_LOG_ERROR("server.loading", ">> Loaded 0 areas for fishing base skill level. DB table `skill_fishing_base_level` is empty.");
7678 return;
7679 }
7680
7681 uint32 count = 0;
7682
7683 do
7684 {
7685 Field* fields = result->Fetch();
7686 uint32 entry = fields[0].GetUInt32();
7687 int32 skill = fields[1].GetInt16();
7688
7689 AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
7690 if (!fArea)
7691 {
7692 SF_LOG_ERROR("sql.sql", "AreaId %u defined in `skill_fishing_base_level` does not exist", entry);
7693 continue;
7694 }
7695
7696 _fishingBaseForAreaStore[entry] = skill;
7697 ++count;
7698 } while (result->NextRow());
7699
7700 SF_LOG_INFO("server.loading", ">> Loaded %u areas for fishing base skill level in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
7701}
7702
7703bool ObjectMgr::CheckDeclinedNames(const std::wstring& w_ownname, DeclinedName const& names)
7704{
7705 // get main part of the name
7706 std::wstring mainpart = GetMainPartOfName(w_ownname, 0);
7707 // prepare flags
7708 bool x = true;
7709 bool y = true;
7710
7711 // check declined names
7712 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
7713 {
7714 std::wstring wname;
7715 if (!Utf8toWStr(names.name[i], wname))
7716 return false;
7717
7718 if (mainpart != GetMainPartOfName(wname, i + 1))
7719 x = false;
7720
7721 if (w_ownname != wname)
7722 y = false;
7723 }
7724 return (x || y);
7725}
7726
7728{
7729 AreaTriggerScriptContainer::const_iterator i = _areaTriggerScriptStore.find(trigger_id);
7730 if (i != _areaTriggerScriptStore.end())
7731 return i->second;
7732 return 0;
7733}
7734
7739
7740// this allows calculating base reputations to offline players, just by race and class
7741int32 ObjectMgr::GetBaseReputationOf(FactionEntry const* factionEntry, uint8 race, uint8 playerClass)
7742{
7743 if (!factionEntry)
7744 return 0;
7745
7746 uint32 raceMask = (1 << (race - 1));
7747 uint32 classMask = (1 << (playerClass - 1));
7748
7749 for (int i = 0; i < 4; i++)
7750 {
7751 if ((!factionEntry->BaseRepClassMask[i] ||
7752 factionEntry->BaseRepClassMask[i] & classMask) &&
7753 (!factionEntry->BaseRepRaceMask[i] ||
7754 factionEntry->BaseRepRaceMask[i] & raceMask))
7755 return factionEntry->BaseRepValue[i];
7756 }
7757
7758 return 0;
7759}
7760
7762{
7763 switch (pSkill->categoryId)
7764 {
7766 return SKILL_RANGE_LANGUAGE;
7769 if (pSkill->id == SKILL_RUNEFORGING)
7770 return SKILL_RANGE_MONO;
7771 else
7772 return SKILL_RANGE_LEVEL;
7774 return SKILL_RANGE_MONO;
7777 // not set skills for professions and racial abilities
7778 if (IsProfessionSkill(pSkill->id))
7779 return SKILL_RANGE_RANK;
7780 else if (racial)
7781 return SKILL_RANGE_NONE;
7782 else
7783 return SKILL_RANGE_MONO;
7784 default:
7785 case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc
7786 case SKILL_CATEGORY_GENERIC: //only GENERIC(DND)
7787 return SKILL_RANGE_NONE;
7788 }
7789}
7790
7792{
7793 uint32 oldMSTime = getMSTime();
7794
7795 _gameTeleStore.clear(); // for reload case
7796
7797 // 0 1 2 3 4 5 6
7798 QueryResult result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele");
7799
7800 if (!result)
7801 {
7802 SF_LOG_ERROR("server.loading", ">> Loaded 0 GameTeleports. DB table `game_tele` is empty!");
7803 return;
7804 }
7805
7806 uint32 count = 0;
7807
7808 do
7809 {
7810 Field* fields = result->Fetch();
7811
7812 uint32 id = fields[0].GetUInt32();
7813
7814 GameTele gt;
7815
7816 gt.position_x = fields[1].GetFloat();
7817 gt.position_y = fields[2].GetFloat();
7818 gt.position_z = fields[3].GetFloat();
7819 gt.orientation = fields[4].GetFloat();
7820 gt.mapId = fields[5].GetUInt16();
7821 gt.name = fields[6].GetString();
7822
7824 {
7825 SF_LOG_ERROR("sql.sql", "Wrong position for id %u (name: %s) in `game_tele` table, ignoring.", id, gt.name.c_str());
7826 continue;
7827 }
7828
7829 if (!Utf8toWStr(gt.name, gt.wnameLow))
7830 {
7831 SF_LOG_ERROR("sql.sql", "Wrong UTF8 name for id %u in `game_tele` table, ignoring.", id);
7832 continue;
7833 }
7834
7836
7837 _gameTeleStore[id] = gt;
7838
7839 ++count;
7840 } while (result->NextRow());
7841
7842 SF_LOG_INFO("server.loading", ">> Loaded %u GameTeleports in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
7843}
7844
7845GameTele const* ObjectMgr::GetGameTele(const std::string& name) const
7846{
7847 // explicit name case
7848 std::wstring wname;
7849 if (!Utf8toWStr(name, wname))
7850 return NULL;
7851
7852 // converting string that we try to find to lower case
7853 wstrToLower(wname);
7854
7855 // Alternative first GameTele what contains wnameLow as substring in case no GameTele location found
7856 const GameTele* alt = NULL;
7857 for (GameTeleContainer::const_iterator itr = _gameTeleStore.begin(); itr != _gameTeleStore.end(); ++itr)
7858 {
7859 if (itr->second.wnameLow == wname)
7860 return &itr->second;
7861 else if (alt == NULL && itr->second.wnameLow.find(wname) != std::wstring::npos)
7862 alt = &itr->second;
7863 }
7864
7865 return alt;
7866}
7867
7868GameTele const* ObjectMgr::GetGameTeleExactName(const std::string& name) const
7869{
7870 // explicit name case
7871 std::wstring wname;
7872 if (!Utf8toWStr(name, wname))
7873 return NULL;
7874
7875 // converting string that we try to find to lower case
7876 wstrToLower(wname);
7877
7878 for (GameTeleContainer::const_iterator itr = _gameTeleStore.begin(); itr != _gameTeleStore.end(); ++itr)
7879 {
7880 if (itr->second.wnameLow == wname)
7881 return &itr->second;
7882 }
7883
7884 return NULL;
7885}
7886
7888{
7889 // find max id
7890 uint32 new_id = 0;
7891 for (GameTeleContainer::const_iterator itr = _gameTeleStore.begin(); itr != _gameTeleStore.end(); ++itr)
7892 if (itr->first > new_id)
7893 new_id = itr->first;
7894
7895 // use next
7896 ++new_id;
7897
7898 if (!Utf8toWStr(tele.name, tele.wnameLow))
7899 return false;
7900
7901 wstrToLower(tele.wnameLow);
7902
7903 _gameTeleStore[new_id] = tele;
7904
7905 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_GAME_TELE);
7906
7907 stmt->setUInt32(0, new_id);
7908 stmt->setFloat(1, tele.position_x);
7909 stmt->setFloat(2, tele.position_y);
7910 stmt->setFloat(3, tele.position_z);
7911 stmt->setFloat(4, tele.orientation);
7912 stmt->setUInt16(5, uint16(tele.mapId));
7913 stmt->setString(6, tele.name);
7914
7915 WorldDatabase.Execute(stmt);
7916
7917 return true;
7918}
7919
7920bool ObjectMgr::DeleteGameTele(const std::string& name)
7921{
7922 // explicit name case
7923 std::wstring wname;
7924 if (!Utf8toWStr(name, wname))
7925 return false;
7926
7927 // converting string that we try to find to lower case
7928 wstrToLower(wname);
7929
7930 for (GameTeleContainer::iterator itr = _gameTeleStore.begin(); itr != _gameTeleStore.end(); ++itr)
7931 {
7932 if (itr->second.wnameLow == wname)
7933 {
7934 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAME_TELE);
7935
7936 stmt->setString(0, itr->second.name);
7937
7938 WorldDatabase.Execute(stmt);
7939
7940 _gameTeleStore.erase(itr);
7941 return true;
7942 }
7943 }
7944
7945 return false;
7946}
7947
7949{
7950 uint32 oldMSTime = getMSTime();
7951
7952 _mailLevelRewardStore.clear(); // for reload case
7953
7954 // 0 1 2 3
7955 QueryResult result = WorldDatabase.Query("SELECT level, raceMask, mailTemplateId, senderEntry FROM mail_level_reward");
7956
7957 if (!result)
7958 {
7959 SF_LOG_ERROR("server.loading", ">> Loaded 0 level dependent mail rewards. DB table `mail_level_reward` is empty.");
7960 return;
7961 }
7962
7963 uint32 count = 0;
7964
7965 do
7966 {
7967 Field* fields = result->Fetch();
7968
7969 uint8 level = fields[0].GetUInt8();
7970 uint32 raceMask = fields[1].GetUInt32();
7971 uint32 mailTemplateId = fields[2].GetUInt32();
7972 uint32 senderEntry = fields[3].GetUInt32();
7973
7974 if (level > MAX_LEVEL)
7975 {
7976 SF_LOG_ERROR("sql.sql", "Table `mail_level_reward` have data for level %u that more supported by client (%u), ignoring.", level, MAX_LEVEL);
7977 continue;
7978 }
7979
7980 if (!(raceMask & RACEMASK_ALL_PLAYABLE))
7981 {
7982 SF_LOG_ERROR("sql.sql", "Table `mail_level_reward` have raceMask (%u) for level %u that not include any player races, ignoring.", raceMask, level);
7983 continue;
7984 }
7985
7986 if (!sMailTemplateStore.LookupEntry(mailTemplateId))
7987 {
7988 SF_LOG_ERROR("sql.sql", "Table `mail_level_reward` have invalid mailTemplateId (%u) for level %u that invalid not include any player races, ignoring.", mailTemplateId, level);
7989 continue;
7990 }
7991
7992 if (!GetCreatureTemplate(senderEntry))
7993 {
7994 SF_LOG_ERROR("sql.sql", "Table `mail_level_reward` have not existed sender creature entry (%u) for level %u that invalid not include any player races, ignoring.", senderEntry, level);
7995 continue;
7996 }
7997
7998 _mailLevelRewardStore[level].push_back(MailLevelReward(raceMask, mailTemplateId, senderEntry));
7999
8000 ++count;
8001 } while (result->NextRow());
8002
8003 SF_LOG_INFO("server.loading", ">> Loaded %u level dependent mail rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8004}
8005
8006void ObjectMgr::AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel)
8007{
8008 if (entry >= SKYFIRE_TRAINER_START_REF)
8009 return;
8010
8011 CreatureTemplate const* cInfo = GetCreatureTemplate(entry);
8012 if (!cInfo)
8013 {
8014 SF_LOG_ERROR("sql.sql", "Table `npc_trainer` contains entries for a non-existing creature template (Entry: %u), ignoring", entry);
8015 return;
8016 }
8017
8018 if (!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
8019 {
8020 SF_LOG_ERROR("sql.sql", "Table `npc_trainer` contains entries for a creature template (Entry: %u) without trainer flag, ignoring", entry);
8021 return;
8022 }
8023
8024 SpellInfo const* spellinfo = sSpellMgr->GetSpellInfo(spell);
8025 if (!spellinfo)
8026 {
8027 SF_LOG_ERROR("sql.sql", "Table `npc_trainer` contains an entry (Entry: %u) for a non-existing spell (Spell: %u), ignoring", entry, spell);
8028 return;
8029 }
8030
8031 if (!SpellMgr::IsSpellValid(spellinfo))
8032 {
8033 SF_LOG_ERROR("sql.sql", "Table `npc_trainer` contains an entry (Entry: %u) for a broken spell (Spell: %u), ignoring", entry, spell);
8034 return;
8035 }
8036
8037 if (GetTalentSpellCost(spell))
8038 {
8039 SF_LOG_ERROR("sql.sql", "Table `npc_trainer` contains an entry (Entry: %u) for a non-existing spell (Spell: %u) which is a talent, ignoring", entry, spell);
8040 return;
8041 }
8042
8044
8045 TrainerSpell& trainerSpell = data.spellList[spell];
8046 trainerSpell.spell = spell;
8047 trainerSpell.spellCost = spellCost;
8048 trainerSpell.reqSkill = reqSkill;
8049 trainerSpell.reqSkillValue = reqSkillValue;
8050 trainerSpell.reqLevel = reqLevel;
8051
8052 if (!trainerSpell.reqLevel)
8053 trainerSpell.reqLevel = spellinfo->SpellLevel;
8054
8055 // calculate learned spell for profession case when stored cast-spell
8056 trainerSpell.learnedSpell[0] = spell;
8057 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
8058 {
8059 if (spellinfo->Effects[i].Effect != SPELL_EFFECT_LEARN_SPELL)
8060 continue;
8061 if (trainerSpell.learnedSpell[0] == spell)
8062 trainerSpell.learnedSpell[0] = 0;
8063 // player must be able to cast spell on himself
8064 if (spellinfo->Effects[i].TargetA.GetTarget() != 0 && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ALLY
8065 && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_TARGET_ANY && spellinfo->Effects[i].TargetA.GetTarget() != TARGET_UNIT_CASTER)
8066 {
8067 SF_LOG_ERROR("sql.sql", "Table `npc_trainer` has spell %u for trainer entry %u with learn effect which has incorrect target type, ignoring learn effect!", spell, entry);
8068 continue;
8069 }
8070
8071 trainerSpell.learnedSpell[i] = spellinfo->Effects[i].TriggerSpell;
8072
8073 if (trainerSpell.learnedSpell[i])
8074 {
8075 SpellInfo const* learnedSpellInfo = sSpellMgr->GetSpellInfo(trainerSpell.learnedSpell[i]);
8076 if (learnedSpellInfo && learnedSpellInfo->IsProfession())
8077 data.trainerType = 2;
8078 }
8079 }
8080
8081 return;
8082}
8083
8085{
8086 uint32 oldMSTime = getMSTime();
8087
8088 // For reload case
8090
8091 QueryResult result = WorldDatabase.Query("SELECT b.entry, a.spell, a.spellcost, a.reqskill, a.reqskillvalue, a.reqlevel FROM npc_trainer AS a "
8092 "INNER JOIN npc_trainer AS b ON a.entry = -(b.spell) "
8093 "UNION SELECT * FROM npc_trainer WHERE spell > 0");
8094
8095 if (!result)
8096 {
8097 SF_LOG_ERROR("server.loading", ">> Loaded 0 Trainers. DB table `npc_trainer` is empty!");
8098
8099 return;
8100 }
8101
8102 uint32 count = 0;
8103
8104 do
8105 {
8106 Field* fields = result->Fetch();
8107
8108 uint32 entry = fields[0].GetUInt32();
8109 uint32 spell = fields[1].GetUInt32();
8110 uint32 spellCost = fields[2].GetUInt32();
8111 uint32 reqSkill = fields[3].GetUInt16();
8112 uint32 reqSkillValue = fields[4].GetUInt16();
8113 uint32 reqLevel = fields[5].GetUInt8();
8114
8115 AddSpellToTrainer(entry, spell, spellCost, reqSkill, reqSkillValue, reqLevel);
8116
8117 ++count;
8118 } while (result->NextRow());
8119
8120 SF_LOG_INFO("server.loading", ">> Loaded %d Trainers in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8121}
8122
8123int ObjectMgr::LoadReferenceVendor(int32 vendor, int32 item, uint8 type, std::set<uint32>* skip_vendors)
8124{
8125 // find all items from the reference vendor
8126 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_NPC_VENDOR_REF);
8127 stmt->setUInt32(0, uint32(item));
8128 stmt->setUInt8(1, type);
8129 PreparedQueryResult result = WorldDatabase.Query(stmt);
8130
8131 if (!result)
8132 return 0;
8133
8134 uint32 count = 0;
8135 do
8136 {
8137 Field* fields = result->Fetch();
8138
8139 int32 item_id = fields[0].GetInt32();
8140
8141 // if item is a negative, its a reference
8142 if (item_id < 0)
8143 count += LoadReferenceVendor(vendor, -item_id, type, skip_vendors);
8144 else
8145 {
8146 int32 maxcount = fields[1].GetUInt32();
8147 uint32 incrtime = fields[2].GetUInt32();
8148 uint32 ExtendedCost = fields[3].GetUInt32();
8149 uint8 type = fields[4].GetUInt8();
8150
8151 if (!IsVendorItemValid(vendor, item_id, maxcount, incrtime, ExtendedCost, type, NULL, skip_vendors))
8152 continue;
8153
8154 VendorItemData& vList = _cacheVendorItemStore[vendor];
8155
8156 vList.AddItem(item_id, maxcount, incrtime, ExtendedCost, type);
8157 ++count;
8158 }
8159 } while (result->NextRow());
8160
8161 return count;
8162}
8163
8165{
8166 uint32 oldMSTime = getMSTime();
8167
8168 // For reload case
8169 for (CacheVendorItemContainer::iterator itr = _cacheVendorItemStore.begin(); itr != _cacheVendorItemStore.end(); ++itr)
8170 itr->second.Clear();
8171 _cacheVendorItemStore.clear();
8172
8173 std::set<uint32> skip_vendors;
8174
8175 QueryResult result = WorldDatabase.Query("SELECT entry, item, maxcount, incrtime, ExtendedCost, type FROM npc_vendor ORDER BY entry, slot ASC");
8176 if (!result)
8177 {
8178 SF_LOG_ERROR("server.loading", ">> Loaded 0 Vendors. DB table `npc_vendor` is empty!");
8179 return;
8180 }
8181
8182 uint32 count = 0;
8183
8184 do
8185 {
8186 Field* fields = result->Fetch();
8187
8188 uint32 entry = fields[0].GetUInt32();
8189 int32 item_id = fields[1].GetInt32();
8190
8191 // if item is a negative, its a reference
8192 if (item_id < 0)
8193 count += LoadReferenceVendor(entry, -item_id, 0, &skip_vendors);
8194 else
8195 {
8196 uint32 maxcount = fields[2].GetUInt32();
8197 uint32 incrtime = fields[3].GetUInt32();
8198 uint32 ExtendedCost = fields[4].GetUInt32();
8199 uint8 type = fields[5].GetUInt8();
8200
8201 if (!IsVendorItemValid(entry, item_id, maxcount, incrtime, ExtendedCost, type, NULL, &skip_vendors))
8202 continue;
8203
8204 VendorItemData& vList = _cacheVendorItemStore[entry];
8205
8206 vList.AddItem(item_id, maxcount, incrtime, ExtendedCost, type);
8207 ++count;
8208 }
8209 } while (result->NextRow());
8210
8211 SF_LOG_INFO("server.loading", ">> Loaded %d Vendors in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8212}
8213
8215{
8216 uint32 oldMSTime = getMSTime();
8217
8218 _gossipMenusStore.clear();
8219
8220 QueryResult result = WorldDatabase.Query(
8221 "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'gossip_menu' AND LOWER(COLUMN_NAME) = 'menuid' LIMIT 1");
8222
8223 if (result)
8224 result = WorldDatabase.Query("SELECT MenuID, TextID FROM gossip_menu");
8225 else
8226 result = WorldDatabase.Query("SELECT entry, text_id FROM gossip_menu");
8227
8228 if (!result)
8229 {
8230 SF_LOG_ERROR("server.loading", ">> Loaded 0 gossip_menu entries. DB table `gossip_menu` is empty!");
8231 return;
8232 }
8233
8234 uint32 count = 0;
8235
8236 do
8237 {
8238 Field* fields = result->Fetch();
8239
8240 GossipMenus gMenu;
8241
8242 gMenu.entry = fields[0].GetUInt32();
8243 gMenu.text_id = fields[1].GetUInt32();
8244
8245 if (!GetGossipText(gMenu.text_id))
8246 {
8247 SF_LOG_ERROR("sql.sql", "Table gossip_menu entry %u are using non-existing text_id %u", gMenu.entry, gMenu.text_id);
8248 continue;
8249 }
8250
8251 _gossipMenusStore.insert(GossipMenusContainer::value_type(gMenu.entry, gMenu));
8252
8253 ++count;
8254 } while (result->NextRow());
8255
8256 SF_LOG_INFO("server.loading", ">> Loaded %u gossip_menu entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8257}
8258
8260{
8261 uint32 oldMSTime = getMSTime();
8262
8263 _gossipMenuItemsStore.clear();
8264
8266
8267 if (!result)
8268 {
8269 SF_LOG_ERROR("server.loading", ">> Loaded 0 gossip_menu_option entries. DB table `gossip_menu_option` is empty!");
8270 return;
8271 }
8272
8273 uint32 count = 0;
8274
8275 do
8276 {
8277 Field* fields = result->Fetch();
8278
8279 GossipMenuItems gMenuItem;
8280
8281 gMenuItem.MenuID = fields[0].GetUInt32();
8282 gMenuItem.OptionID = fields[1].GetUInt32();
8283 gMenuItem.OptionIcon = fields[2].GetUInt8();
8284 gMenuItem.OptionText = fields[3].GetString();
8285 gMenuItem.OptionBroadcastTextID = fields[4].GetUInt32();
8286 gMenuItem.OptionType = fields[5].GetUInt8();
8287 gMenuItem.OptionNpcflag = fields[6].GetUInt32();
8288 gMenuItem.ActionMenuID = fields[7].GetUInt32();
8289 gMenuItem.ActionPoiID = fields[8].GetUInt32();
8290 gMenuItem.BoxCoded = fields[9].GetBool();
8291 gMenuItem.BoxMoney = fields[10].GetUInt32();
8292 gMenuItem.BoxText = fields[11].GetString();
8293 gMenuItem.BoxBroadcastTextID = fields[12].GetUInt32();
8294
8295 if (gMenuItem.OptionIcon >= GOSSIP_ICON_MAX)
8296 {
8297 SF_LOG_ERROR("sql.sql", "Table gossip_menu_option for menu %u, id %u has unknown icon id %u. Replacing with GOSSIP_ICON_CHAT", gMenuItem.MenuID, gMenuItem.OptionID, gMenuItem.OptionIcon);
8298 gMenuItem.OptionIcon = GOSSIP_ICON_CHAT;
8299 }
8300
8301 if (gMenuItem.OptionType >= GOSSIP_OPTION_MAX)
8302 SF_LOG_ERROR("sql.sql", "Table gossip_menu_option for menu %u, id %u has unknown option id %u. Option will not be used", gMenuItem.MenuID, gMenuItem.OptionID, gMenuItem.OptionType);
8303
8304 if (gMenuItem.ActionPoiID && !GetPointOfInterest(gMenuItem.ActionPoiID))
8305 {
8306 SF_LOG_ERROR("sql.sql", "Table gossip_menu_option for menu %u, id %u use non-existing action_poi_id %u, ignoring", gMenuItem.MenuID, gMenuItem.OptionID, gMenuItem.ActionPoiID);
8307 gMenuItem.ActionPoiID = 0;
8308 }
8309
8310 _gossipMenuItemsStore.insert(GossipMenuItemsContainer::value_type(gMenuItem.MenuID, gMenuItem));
8311 ++count;
8312 } while (result->NextRow());
8313
8314 SF_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_option entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8315}
8316
8317void ObjectMgr::AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, uint8 type, bool persist /*= true*/)
8318{
8319 VendorItemData& vList = _cacheVendorItemStore[entry];
8320 vList.AddItem(item, maxcount, incrtime, extendedCost, type);
8321
8322 if (persist)
8323 {
8324 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_NPC_VENDOR);
8325
8326 stmt->setUInt32(0, entry);
8327 stmt->setUInt32(1, item);
8328 stmt->setUInt8(2, maxcount);
8329 stmt->setUInt32(3, incrtime);
8330 stmt->setUInt32(4, extendedCost);
8331 stmt->setUInt8(5, type);
8332
8333 WorldDatabase.Execute(stmt);
8334 }
8335}
8336
8337bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, uint8 type, bool persist /*= true*/)
8338{
8339 CacheVendorItemContainer::iterator iter = _cacheVendorItemStore.find(entry);
8340 if (iter == _cacheVendorItemStore.end())
8341 return false;
8342
8343 if (!iter->second.RemoveItem(item, type))
8344 return false;
8345
8346 if (persist)
8347 {
8348 PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_NPC_VENDOR);
8349
8350 stmt->setUInt32(0, entry);
8351 stmt->setUInt32(1, item);
8352 stmt->setUInt8(2, type);
8353
8354 WorldDatabase.Execute(stmt);
8355 }
8356
8357 return true;
8358}
8359
8360bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, uint8 type, Player* player, std::set<uint32>* skip_vendors, uint32 ORnpcflag) const
8361{
8362 CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(vendor_entry);
8363 if (!cInfo)
8364 {
8365 if (player)
8367 else
8368 SF_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` have data for not existed creature template (Entry: %u), ignore", vendor_entry);
8369 return false;
8370 }
8371
8372 if (!((cInfo->npcflag | ORnpcflag) & UNIT_NPC_FLAG_VENDOR))
8373 {
8374 if (!skip_vendors || skip_vendors->count(vendor_entry) == 0)
8375 {
8376 if (player)
8378 else
8379 SF_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry);
8380
8381 if (skip_vendors)
8382 skip_vendors->insert(vendor_entry);
8383 }
8384 return false;
8385 }
8386
8387 if ((type == ITEM_VENDOR_TYPE_ITEM && !sObjectMgr->GetItemTemplate(id)) ||
8388 (type == ITEM_VENDOR_TYPE_CURRENCY && !sCurrencyTypesStore.LookupEntry(id)))
8389 {
8390 if (player)
8392 else
8393 SF_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u, type %u), ignore", vendor_entry, id, type);
8394 return false;
8395 }
8396
8397 if (ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost))
8398 {
8399 if (player)
8401 else
8402 SF_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore", id, ExtendedCost, vendor_entry);
8403 return false;
8404 }
8405
8406 if (type == ITEM_VENDOR_TYPE_ITEM) // not applicable to currencies
8407 {
8408 if (maxcount > 0 && incrtime == 0)
8409 {
8410 if (player)
8411 ChatHandler(player->GetSession()).PSendSysMessage("MaxCount != 0 (%u) but IncrTime == 0", maxcount);
8412 else
8413 SF_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, id, vendor_entry);
8414 return false;
8415 }
8416 else if (maxcount == 0 && incrtime > 0)
8417 {
8418 if (player)
8419 ChatHandler(player->GetSession()).PSendSysMessage("MaxCount == 0 but IncrTime<>= 0");
8420 else
8421 SF_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", id, vendor_entry);
8422 return false;
8423 }
8424 }
8425
8426 VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry);
8427 if (!vItems)
8428 return true; // later checks for non-empty lists
8429
8430 if (vItems->FindItemCostPair(id, ExtendedCost, type))
8431 {
8432 if (player)
8433 ChatHandler(player->GetSession()).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST, id, ExtendedCost, type);
8434 else
8435 SF_LOG_ERROR("sql.sql", "Table `npc_vendor` has duplicate items %u (with extended cost %u, type %u) for vendor (Entry: %u), ignoring", id, ExtendedCost, type, vendor_entry);
8436 return false;
8437 }
8438
8439 if (type == ITEM_VENDOR_TYPE_CURRENCY && maxcount == 0)
8440 {
8441 SF_LOG_ERROR("sql.sql", "Table `(game_event_)npc_vendor` have Item (Entry: %u, type: %u) with missing maxcount for vendor (%u), ignore", id, type, vendor_entry);
8442 return false;
8443 }
8444
8445 return true;
8446}
8447
8449{
8450 uint32 oldMSTime = getMSTime();
8451
8452 _scriptNamesStore.push_back("");
8453 QueryResult result = WorldDatabase.Query(
8454 "SELECT DISTINCT(ScriptName) FROM achievement_criteria_data WHERE ScriptName <> '' AND type = 11 "
8455 "UNION "
8456 "SELECT DISTINCT(ScriptName) FROM battleground_template WHERE ScriptName <> '' "
8457 "UNION "
8458 "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' "
8459 "UNION "
8460 "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' "
8461 "UNION "
8462 "SELECT DISTINCT(ScriptName) FROM item_script_names WHERE ScriptName <> '' "
8463 "UNION "
8464 "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
8465 "UNION "
8466 "SELECT DISTINCT(ScriptName) FROM spell_script_names WHERE ScriptName <> '' "
8467 "UNION "
8468 "SELECT DISTINCT(ScriptName) FROM transports WHERE ScriptName <> '' "
8469 "UNION "
8470 "SELECT DISTINCT(ScriptName) FROM game_weather WHERE ScriptName <> '' "
8471 "UNION "
8472 "SELECT DISTINCT(ScriptName) FROM conditions WHERE ScriptName <> '' "
8473 "UNION "
8474 "SELECT DISTINCT(ScriptName) FROM outdoorpvp_template WHERE ScriptName <> '' "
8475 "UNION "
8476 "SELECT DISTINCT(ScriptName) FROM scene_template WHERE ScriptName <> '' "
8477 "UNION "
8478 "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
8479
8480 if (!result)
8481 {
8482 SF_LOG_ERROR("server.loading", ">> Loaded empty set of Script Names!");
8483 return;
8484 }
8485
8486 uint32 count = 1;
8487
8488 do
8489 {
8490 _scriptNamesStore.push_back((*result)[0].GetString());
8491 ++count;
8492 } while (result->NextRow());
8493
8494 std::sort(_scriptNamesStore.begin(), _scriptNamesStore.end());
8495 SF_LOG_INFO("server.loading", ">> Loaded %d Script Names in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8496}
8497
8499{
8500 // use binary search to find the script name in the sorted vector
8501 // assume "" is the first element
8502 if (!name)
8503 return 0;
8504
8505 ScriptNameContainer::const_iterator itr = std::lower_bound(_scriptNamesStore.begin(), _scriptNamesStore.end(), name);
8506 if (itr == _scriptNamesStore.end() || *itr != name)
8507 return 0;
8508
8509 return uint32(itr - _scriptNamesStore.begin());
8510}
8511
8512void ObjectMgr::CheckScripts(ScriptsType type, std::set<int32>& ids)
8513{
8514 ScriptMapMap* scripts = GetScriptsMapByType(type);
8515 if (!scripts)
8516 return;
8517
8518 for (ScriptMapMap::const_iterator itrMM = scripts->begin(); itrMM != scripts->end(); ++itrMM)
8519 {
8520 for (ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM)
8521 {
8522 switch (itrM->second.command)
8523 {
8525 {
8526 if (!GetSkyFireStringLocale(itrM->second.Talk.TextID))
8527 SF_LOG_ERROR("sql.sql", "Table `%s` references invalid text id %u from `db_script_string`, script id: %u.", GetScriptsTableNameByType(type).c_str(), itrM->second.Talk.TextID, itrMM->first);
8528
8529 if (ids.find(itrM->second.Talk.TextID) != ids.end())
8530 ids.erase(itrM->second.Talk.TextID);
8531 }
8532 default:
8533 break;
8534 }
8535 }
8536 }
8537}
8538
8540{
8542
8543 std::set<int32> ids;
8544
8547 ids.insert(i);
8548
8552
8553 for (std::set<int32>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr)
8554 SF_LOG_ERROR("sql.sql", "Table `db_script_string` has unused string id %u", *itr);
8555}
8556
8557bool LoadSkyFireStrings(const char* table, int32 start_value, int32 end_value)
8558{
8559 // MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values
8560 // start/end reversed for negative values
8561 if (start_value > MAX_DB_SCRIPT_STRING_ID || end_value >= start_value)
8562 {
8563 SF_LOG_ERROR("sql.sql", "Table '%s' load attempted with range (%d - %d) reserved by Skyfire, strings not loaded.", table, start_value, end_value + 1);
8564 return false;
8565 }
8566
8567 return sObjectMgr->LoadSkyFireStrings(table, start_value, end_value);
8568}
8569
8571{
8572 CreatureBaseStatsContainer::const_iterator it = _creatureBaseStatsStore.find(MAKE_PAIR16(level, unitClass));
8573
8574 if (it != _creatureBaseStatsStore.end())
8575 return &(it->second);
8576
8577 struct DefaultCreatureBaseStats : public CreatureBaseStats
8578 {
8579 DefaultCreatureBaseStats()
8580 {
8581 BaseArmor = 1;
8582 for (uint8 j = 0; j < MAX_CREATURE_BASE_HP; ++j)
8583 BaseHealth[j] = 1;
8584 BaseMana = 0;
8585 }
8586 };
8587 static const DefaultCreatureBaseStats def_stats;
8588 return &def_stats;
8589}
8590
8592{
8593 uint32 oldMSTime = getMSTime();
8594 // 0 1 2 3 7 8
8595 QueryResult result = WorldDatabase.Query("SELECT level, class, OldContentBaseHP, CurrentContentBaseHP, basemana, basearmor FROM creature_classlevelstats");
8596
8597 if (!result)
8598 {
8599 SF_LOG_INFO("server.loading", ">> Loaded 0 creature base stats. DB table `creature_classlevelstats` is empty.");
8600 return;
8601 }
8602
8603 uint32 count = 0;
8604 do
8605 {
8606 Field* fields = result->Fetch();
8607
8608 uint8 Level = fields[0].GetInt8();
8609 uint8 Class = fields[1].GetInt8();
8610
8611 CreatureBaseStats stats;
8612
8613 for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i)
8614 stats.BaseHealth[i] = fields[i + 2].GetUInt32();
8615
8616 stats.BaseMana = fields[4].GetUInt32();
8617 stats.BaseArmor = fields[5].GetUInt32();
8618
8619 if (!Class || ((1 << (Class - 1)) & CLASSMASK_ALL_CREATURES) == 0)
8620 SF_LOG_ERROR("sql.sql", "Creature base stats for level %u has invalid class %u", Level, Class);
8621
8622 for (uint8 i = 0; i < MAX_CREATURE_BASE_HP; ++i)
8623 {
8624 if (stats.BaseHealth[i] < 1)
8625 {
8626 SF_LOG_ERROR("sql.sql", "Creature base stats for class %u, level %u has invalid zero base HP[%u] - set to 1", Class, Level, i);
8627 stats.BaseHealth[i] = 1;
8628 }
8629 }
8630
8631 _creatureBaseStatsStore[MAKE_PAIR16(Level, Class)] = stats;
8632
8633 ++count;
8634 } while (result->NextRow());
8635
8636 CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates();
8637 for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr)
8638 {
8639 for (uint16 lvl = itr->second.minlevel; lvl <= itr->second.maxlevel; ++lvl)
8640 {
8641 if (_creatureBaseStatsStore.find(MAKE_PAIR16(lvl, itr->second.unit_class)) == _creatureBaseStatsStore.end())
8642 SF_LOG_ERROR("sql.sql", "Missing base stats for creature entry %u, class %u, level %u", itr->second.Entry, itr->second.unit_class, lvl);
8643 }
8644 }
8645
8646 SF_LOG_INFO("server.loading", ">> Loaded %u creature base stats in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8647}
8648
8650{
8651 uint32 oldMSTime = getMSTime();
8652
8653 QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_achievement");
8654
8655 if (!result)
8656 {
8657 SF_LOG_ERROR("server.loading", ">> Loaded 0 faction change achievement pairs. DB table `player_factionchange_achievement` is empty.");
8658 return;
8659 }
8660
8661 uint32 count = 0;
8662
8663 do
8664 {
8665 Field* fields = result->Fetch();
8666
8667 uint32 alliance = fields[0].GetUInt32();
8668 uint32 horde = fields[1].GetUInt32();
8669
8670 if (!sAchievementMgr->GetAchievement(alliance))
8671 SF_LOG_ERROR("sql.sql", "Achievement %u (alliance_id) referenced in `player_factionchange_achievement` does not exist, pair skipped!", alliance);
8672 else if (!sAchievementMgr->GetAchievement(horde))
8673 SF_LOG_ERROR("sql.sql", "Achievement %u (horde_id) referenced in `player_factionchange_achievement` does not exist, pair skipped!", horde);
8674 else
8675 FactionChangeAchievements[alliance] = horde;
8676
8677 ++count;
8678 } while (result->NextRow());
8679
8680 SF_LOG_INFO("server.loading", ">> Loaded %u faction change achievement pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8681}
8682
8684{
8685 uint32 oldMSTime = getMSTime();
8686
8687 QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_items");
8688
8689 if (!result)
8690 {
8691 SF_LOG_INFO("server.loading", ">> Loaded 0 faction change item pairs. DB table `player_factionchange_items` is empty.");
8692 return;
8693 }
8694
8695 uint32 count = 0;
8696
8697 do
8698 {
8699 Field* fields = result->Fetch();
8700
8701 uint32 alliance = fields[0].GetUInt32();
8702 uint32 horde = fields[1].GetUInt32();
8703
8704 if (!GetItemTemplate(alliance))
8705 SF_LOG_ERROR("sql.sql", "Item %u (alliance_id) referenced in `player_factionchange_items` does not exist, pair skipped!", alliance);
8706 else if (!GetItemTemplate(horde))
8707 SF_LOG_ERROR("sql.sql", "Item %u (horde_id) referenced in `player_factionchange_items` does not exist, pair skipped!", horde);
8708 else
8709 FactionChangeItems[alliance] = horde;
8710
8711 ++count;
8712 } while (result->NextRow());
8713
8714 SF_LOG_INFO("server.loading", ">> Loaded %u faction change item pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8715}
8716
8718{
8719 uint32 oldMSTime = getMSTime();
8720
8721 QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_quests");
8722
8723 if (!result)
8724 {
8725 SF_LOG_ERROR("server.loading", ">> Loaded 0 faction change quest pairs. DB table `player_factionchange_quests` is empty.");
8726 return;
8727 }
8728
8729 uint32 count = 0;
8730
8731 do
8732 {
8733 Field* fields = result->Fetch();
8734
8735 uint32 alliance = fields[0].GetUInt32();
8736 uint32 horde = fields[1].GetUInt32();
8737
8738 if (!sObjectMgr->GetQuestTemplate(alliance))
8739 SF_LOG_ERROR("sql.sql", "Quest %u (alliance_id) referenced in `player_factionchange_quests` does not exist, pair skipped!", alliance);
8740 else if (!sObjectMgr->GetQuestTemplate(horde))
8741 SF_LOG_ERROR("sql.sql", "Quest %u (horde_id) referenced in `player_factionchange_quests` does not exist, pair skipped!", horde);
8742 else
8743 FactionChangeQuests[alliance] = horde;
8744
8745 ++count;
8746 } while (result->NextRow());
8747
8748 SF_LOG_INFO("server.loading", ">> Loaded %u faction change quest pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8749}
8750
8752{
8753 uint32 oldMSTime = getMSTime();
8754
8755 QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_reputations");
8756
8757 if (!result)
8758 {
8759 SF_LOG_INFO("server.loading", ">> Loaded 0 faction change reputation pairs. DB table `player_factionchange_reputations` is empty.");
8760 return;
8761 }
8762
8763 uint32 count = 0;
8764
8765 do
8766 {
8767 Field* fields = result->Fetch();
8768
8769 uint32 alliance = fields[0].GetUInt32();
8770 uint32 horde = fields[1].GetUInt32();
8771
8772 if (!sFactionStore.LookupEntry(alliance))
8773 SF_LOG_ERROR("sql.sql", "Reputation %u (alliance_id) referenced in `player_factionchange_reputations` does not exist, pair skipped!", alliance);
8774 else if (!sFactionStore.LookupEntry(horde))
8775 SF_LOG_ERROR("sql.sql", "Reputation %u (horde_id) referenced in `player_factionchange_reputations` does not exist, pair skipped!", horde);
8776 else
8777 FactionChangeReputation[alliance] = horde;
8778
8779 ++count;
8780 } while (result->NextRow());
8781
8782 SF_LOG_INFO("server.loading", ">> Loaded %u faction change reputation pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8783}
8784
8786{
8787 uint32 oldMSTime = getMSTime();
8788
8789 QueryResult result = WorldDatabase.Query("SELECT entry, type, UNIX_TIMESTAMP(hotfixDate) FROM hotfix_data");
8790
8791 if (!result)
8792 {
8793 SF_LOG_INFO("server.loading", ">> Loaded 0 hotfix info entries. DB table `hotfix_data` is empty.");
8794 return;
8795 }
8796
8797 uint32 count = 0;
8798
8799 _hotfixData.reserve(result->GetRowCount());
8800
8801 do
8802 {
8803 Field* fields = result->Fetch();
8804
8805 HotfixInfo info;
8806 info.Entry = fields[0].GetUInt32();
8807 info.Type = fields[1].GetUInt32();
8808 info.Timestamp = fields[2].GetUInt64();
8809 _hotfixData.push_back(info);
8810
8811 ++count;
8812 } while (result->NextRow());
8813
8814 SF_LOG_INFO("server.loading", ">> Loaded %u hotfix info entries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8815}
8816
8818{
8819 uint32 oldMSTime = getMSTime();
8820
8821 QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_spells");
8822
8823 if (!result)
8824 {
8825 SF_LOG_ERROR("server.loading", ">> Loaded 0 faction change spell pairs. DB table `player_factionchange_spells` is empty.");
8826 return;
8827 }
8828
8829 uint32 count = 0;
8830
8831 do
8832 {
8833 Field* fields = result->Fetch();
8834
8835 uint32 alliance = fields[0].GetUInt32();
8836 uint32 horde = fields[1].GetUInt32();
8837
8838 if (!sSpellMgr->GetSpellInfo(alliance))
8839 SF_LOG_ERROR("sql.sql", "Spell %u (alliance_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", alliance);
8840 else if (!sSpellMgr->GetSpellInfo(horde))
8841 SF_LOG_ERROR("sql.sql", "Spell %u (horde_id) referenced in `player_factionchange_spells` does not exist, pair skipped!", horde);
8842 else
8843 FactionChangeSpells[alliance] = horde;
8844
8845 ++count;
8846 } while (result->NextRow());
8847
8848 SF_LOG_INFO("server.loading", ">> Loaded %u faction change spell pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8849}
8850
8852{
8853 uint32 oldMSTime = getMSTime();
8854
8855 QueryResult result = WorldDatabase.Query("SELECT alliance_id, horde_id FROM player_factionchange_titles");
8856
8857 if (!result)
8858 {
8859 SF_LOG_INFO("server.loading", ">> Loaded 0 faction change title pairs. DB table `player_factionchange_title` is empty.");
8860 return;
8861 }
8862
8863 uint32 count = 0;
8864
8865 do
8866 {
8867 Field* fields = result->Fetch();
8868
8869 uint32 alliance = fields[0].GetUInt32();
8870 uint32 horde = fields[1].GetUInt32();
8871
8872 if (!sCharTitlesStore.LookupEntry(alliance))
8873 SF_LOG_ERROR("sql.sql", "Title %u (alliance_id) referenced in `player_factionchange_title` does not exist, pair skipped!", alliance);
8874 else if (!sCharTitlesStore.LookupEntry(horde))
8875 SF_LOG_ERROR("sql.sql", "Title %u (horde_id) referenced in `player_factionchange_title` does not exist, pair skipped!", horde);
8876 else
8877 FactionChangeTitles[alliance] = horde;
8878
8879 ++count;
8880 } while (result->NextRow());
8881
8882 SF_LOG_INFO("server.loading", ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
8883}
8885{
8887
8888 uint32 oldMSTime = getMSTime();
8889
8890 // 0 1
8891 QueryResult result = WorldDatabase.Query("SELECT MapId, TerrainSwapMap FROM `terrain_swap_defaults`");
8892
8893 if (!result)
8894 {
8895 SF_LOG_INFO("server.loading", ">> Loaded 0 terrain swap defaults. DB table `terrain_swap_defaults` is empty.");
8896 return;
8897 }
8898
8899 uint32 count = 0;
8900 do
8901 {
8902 Field* fields = result->Fetch();
8903
8904 uint32 mapId = fields[0].GetUInt32();
8905
8906 MapEntry const* map = sMapStore.LookupEntry(mapId);
8907 if (!map)
8908 {
8909 SF_LOG_INFO("sql.sql", "Map %u defined in `terrain_swap_defaults` does not exist, skipped.", mapId);
8910 continue;
8911 }
8912
8913 uint32 terrainSwap = fields[1].GetUInt32();
8914
8915 map = sMapStore.LookupEntry(terrainSwap);
8916 if (!map)
8917 {
8918 SF_LOG_INFO("sql.sql", "TerrainSwapMap %u defined in `terrain_swap_defaults` does not exist, skipped.", terrainSwap);
8919 continue;
8920 }
8921 PhaseInfoStruct defaultSwap;
8922 defaultSwap.id = terrainSwap;
8923 _terrainMapDefaultStore[mapId].push_back(defaultSwap);
8924
8925 ++count;
8926 } while (result->NextRow());
8927
8928 SF_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
8929}
8930
8932{
8933 _terrainPhaseInfoStore.clear();
8934
8935 uint32 oldMSTime = getMSTime();
8936
8937 // 0 1
8938 QueryResult result = WorldDatabase.Query("SELECT Id, TerrainSwapMap FROM `terrain_phase_info`");
8939
8940 if (!result)
8941 {
8942 SF_LOG_INFO("server.loading", ">> Loaded 0 terrain phase infos. DB table `terrain_phase_info` is empty.");
8943 return;
8944 }
8945
8946 uint32 count = 0;
8947 do
8948 {
8949 Field* fields = result->Fetch();
8950
8951 uint32 phaseId = fields[0].GetUInt32();
8952
8953 PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId);
8954 if (!phase)
8955 {
8956 SF_LOG_INFO("sql.sql", "Phase %u defined in `terrain_phase_info` does not exist, skipped.", phaseId);
8957 continue;
8958 }
8959
8960 PhaseInfoStruct terrainSwap;
8961 terrainSwap.id = fields[1].GetUInt32();
8962 _terrainPhaseInfoStore[phaseId].push_back(terrainSwap);
8963
8964 ++count;
8965 } while (result->NextRow());
8966
8967 SF_LOG_INFO("server.loading", ">> Loaded %u terrain phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
8968}
8969
8971{
8972 _terrainWorldMapStore.clear();
8973
8974 uint32 oldMSTime = getMSTime();
8975
8976 // 0 1
8977 QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`");
8978
8979 if (!result)
8980 {
8981 SF_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty.");
8982 return;
8983 }
8984
8985 uint32 count = 0;
8986 do
8987 {
8988 Field* fields = result->Fetch();
8989
8990 uint32 mapId = fields[0].GetUInt32();
8991
8992 if (!sMapStore.LookupEntry(mapId))
8993 {
8994 SF_LOG_INFO("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId);
8995 continue;
8996 }
8997
8998 uint32 worldMapArea = fields[1].GetUInt32();
8999
9000 _terrainWorldMapStore[mapId].push_back(worldMapArea);
9001
9002 ++count;
9003 } while (result->NextRow());
9004
9005 SF_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9006}
9007
9009{
9010 _phases.clear();
9011
9012 uint32 oldMSTime = getMSTime();
9013
9014 // 0 1
9015 QueryResult result = WorldDatabase.Query("SELECT AreaId, PhaseId FROM `phase_area`");
9016
9017 if (!result)
9018 {
9019 SF_LOG_INFO("server.loading", ">> Loaded 0 phase areas. DB table `phase_area` is empty.");
9020 return;
9021 }
9022
9023 uint32 count = 0;
9024 do
9025 {
9026 Field* fields = result->Fetch();
9027
9028 PhaseInfoStruct phase;
9029 uint32 area = fields[0].GetUInt32();
9030 phase.id = fields[1].GetUInt32();
9031 _phases[area].push_back(phase);
9032
9033 ++count;
9034 } while (result->NextRow());
9035
9036 SF_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9037}
9038/*
9039void ObjectMgr::LoadSpellPhaseInfo()
9040{
9041 _SpellPhaseStore.clear();
9042
9043 uint32 oldMSTime = getMSTime();
9044
9045 // 0 1 2
9046 QueryResult result = WorldDatabase.Query("SELECT id, phasemask, terrainswapmap FROM `spell_phase`");
9047
9048 if (!result)
9049 {
9050 SF_LOG_INFO("server.loading", ">> Loaded 0 spell dbc infos. DB table `spell_phase` is empty.");
9051 return;
9052 }
9053
9054 uint32 count = 0;
9055 do
9056 {
9057 Field* fields = result->Fetch();
9058
9059 SpellPhaseInfo spellPhaseInfo;
9060 spellPhaseInfo.spellId = fields[0].GetUInt32();
9061
9062 SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellPhaseInfo.spellId);
9063 if (!spell)
9064 {
9065 SF_LOG_ERROR("sql.sql", "Spell %u defined in `spell_phase` does not exists, skipped.", spellPhaseInfo.spellId);
9066 continue;
9067 }
9068
9069 if (!spell->HasAura(SPELL_AURA_PHASE))
9070 {
9071 SF_LOG_ERROR("sql.sql", "Spell %u defined in `spell_phase` does not have aura effect type SPELL_AURA_PHASE, useless value.", spellPhaseInfo.spellId);
9072 continue;
9073 }
9074
9075 spellPhaseInfo.phasemask = fields[1].GetUInt32();
9076 spellPhaseInfo.terrainswapmap = fields[2].GetUInt32();
9077
9078 _SpellPhaseStore[spellPhaseInfo.spellId] = spellPhaseInfo;
9079
9080 ++count;
9081 }
9082 while (result->NextRow());
9083 SF_LOG_INFO("server.loading", ">> Loaded %u spell dbc infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9084}
9085*/
9087{
9088 GameObjectTemplateContainer::const_iterator itr = _gameObjectTemplateStore.find(entry);
9089 if (itr != _gameObjectTemplateStore.end())
9090 return &(itr->second);
9091
9092 return NULL;
9093}
9094
9096{
9097 CreatureTemplateContainer::const_iterator itr = _creatureTemplateStore.find(entry);
9098 if (itr != _creatureTemplateStore.end())
9099 return &(itr->second);
9100
9101 return NULL;
9102}
9103
9105{
9106 if (Creature* cre = veh->GetBase()->ToCreature())
9107 {
9108 // Give preference to GUID-based accessories
9109 VehicleAccessoryContainer::const_iterator itr = _vehicleAccessoryStore.find(cre->GetDBTableGUIDLow());
9110 if (itr != _vehicleAccessoryStore.end())
9111 return &itr->second;
9112 }
9113
9114 // Otherwise return entry-based
9115 VehicleAccessoryContainer::const_iterator itr = _vehicleTemplateAccessoryStore.find(veh->GetCreatureEntry());
9116 if (itr != _vehicleTemplateAccessoryStore.end())
9117 return &itr->second;
9118 return NULL;
9119}
9120
9122{
9123 if (race >= MAX_RACES)
9124 return NULL;
9125 if (class_ >= MAX_CLASSES)
9126 return NULL;
9127 PlayerInfo const* info = _playerInfo[race][class_];
9128 if (!info)
9129 return NULL;
9130 return info;
9131}
9132
9134{
9135 _researchDigsiteStore.clear();
9136
9137 uint32 oldMSTime = getMSTime();
9138
9139 // 0 1 2 3
9140 QueryResult result = WorldDatabase.Query("SELECT digsiteId, branchId, requiredSkillValue, requiredLevel FROM `research_digsite_data`");
9141
9142 if (!result)
9143 {
9144 SF_LOG_INFO("server.loading", ">> Loaded 0 research digsite infos. DB table `research_digsite_data` is empty.");
9145 return;
9146 }
9147
9148 uint32 count = 0;
9149 do
9150 {
9151 Field* fields = result->Fetch();
9152
9153 ResearchDigsiteInfo digsiteInfo;
9154 digsiteInfo.digsiteId = fields[0].GetUInt32();
9155
9156 ResearchSiteEntry const* siteEntry = sResearchSiteStore.LookupEntry(digsiteInfo.digsiteId);
9157 if (!siteEntry)
9158 {
9159 SF_LOG_ERROR("sql.sql", "Digsite %u defined in `research_digsite_data` does not exist in DBC, skipped.", digsiteInfo.digsiteId);
9160 continue;
9161 }
9162
9163 digsiteInfo.branchId = fields[1].GetUInt32();
9164 digsiteInfo.requiredSkillValue = fields[2].GetUInt32();
9165 digsiteInfo.requiredLevel = fields[3].GetUInt32();
9166 _researchDigsiteStore[siteEntry->MapId].push_back(digsiteInfo);
9167
9168 ++count;
9169 }
9170 while (result->NextRow());
9171 SF_LOG_INFO("server.loading", ">> Loaded %u research digsite infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9172}
9173
9175{
9176 _archaeologyFindStore.clear();
9177
9178 uint32 oldMSTime = getMSTime();
9179
9180 // 0 1 2 3 4 5
9181 QueryResult result = WorldDatabase.Query("SELECT guid, digsiteId, goEntry, position_x, position_y, position_z FROM `research_digsite_finds`");
9182
9183 if (!result)
9184 {
9185 SF_LOG_INFO("server.loading", ">> Loaded 0 archaeology find infos. DB table `research_digsite_finds` is empty.");
9186 return;
9187 }
9188
9189 uint32 count = 0;
9190 do
9191 {
9192 Field* fields = result->Fetch();
9193
9194 ArchaeologyFindInfo findInfo;
9195 findInfo.guid = fields[0].GetUInt32();
9196 uint32 digsiteId = fields[1].GetUInt32();
9197
9198 if (!sResearchSiteStore.LookupEntry(digsiteId))
9199 {
9200 SF_LOG_ERROR("sql.sql", "Digsite %u referenced in `research_digsite_finds` does not exist in DBC, skipped.", digsiteId);
9201 continue;
9202 }
9203
9204 findInfo.goEntry = fields[2].GetUInt32();
9205 if (!GetGameObjectTemplate(findInfo.goEntry))
9206 {
9207 SF_LOG_ERROR("sql.sql", "Table `research_digsite_finds` has archaeology find with non existing gameobject entry %u (Digsite Id: %u), skipped.", findInfo.goEntry, digsiteId);
9208 continue;
9209 }
9210
9211 findInfo.x = fields[3].GetFloat();
9212 findInfo.y = fields[4].GetFloat();
9213 findInfo.z = fields[5].GetFloat();
9214
9215 _archaeologyFindStore[digsiteId].push_back(findInfo);
9216
9217 ++count;
9218 }
9219 while (result->NextRow());
9220 SF_LOG_INFO("server.loading", ">> Loaded %u archaeology find infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9221}
9222
9224{
9226
9227 uint32 oldMSTime = getMSTime();
9228
9229 // 0 1 2
9230 QueryResult result = WorldDatabase.Query("SELECT projectId, requiredSkillValue, chance FROM `research_project_requirements`");
9231
9232 if (!result)
9233 {
9234 SF_LOG_INFO("server.loading", ">> Loaded 0 research project requirements. DB table `research_project_requirements` is empty.");
9235 return;
9236 }
9237
9238 uint32 count = 0;
9239 do
9240 {
9241 Field* fields = result->Fetch();
9242
9243 uint32 projectId = fields[0].GetUInt32();
9244 if (!sResearchProjectStore.LookupEntry(projectId))
9245 {
9246 SF_LOG_ERROR("sql.sql", "Research project %u referenced in `research_project_requirements` does not exist in DBC, skipped.", projectId);
9247 continue;
9248 }
9249
9250 ResearchProjectRequirements requirements;
9251 requirements.requiredSkillValue = fields[1].GetUInt32();
9252 requirements.chance = fields[2].GetFloat();
9253
9254 _researchProjectRequirementStore[projectId] = requirements;
9255
9256 ++count;
9257 }
9258 while (result->NextRow());
9259 SF_LOG_INFO("server.loading", ">> Loaded %u research project requirements in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9260}
9262{
9263 uint32 oldMSTime = getMSTime();
9264
9265 QueryResult result = WorldDatabase.Query("SELECT species, breed FROM `battle_pet_breed`");
9266 if (!result)
9267 {
9268 SF_LOG_ERROR("server.loading", ">> Loaded 0 Battle Pets breed definitions. DB table `battle_pet_breed` is empty.");
9269 return;
9270 }
9271
9272 uint32 count = 0;
9273 do
9274 {
9275 Field* fields = result->Fetch();
9276
9277 uint16 speciesId = fields[0].GetUInt16();
9278 uint8 breedId = fields[1].GetUInt8();
9279
9280 if (!sBattlePetSpeciesStore.HasRecord(speciesId))
9281 {
9282 SF_LOG_ERROR("sql.sql", "Battle Pet species %u defined in `battle_pet_breed` does not exists, skipped.", speciesId);
9283 continue;
9284 }
9285
9286 if (sBattlePetBreedSet.find(breedId) == sBattlePetBreedSet.end())
9287 {
9288 SF_LOG_ERROR("sql.sql", "Battle Pet breed %u defined in `battle_pet_breed` does not exists, skipped.", breedId);
9289 continue;
9290 }
9291
9293 sBattlePetBreedXSpeciesStore.insert(make_pair(speciesId, BattleBetBreedSet()));
9294
9295 sBattlePetBreedXSpeciesStore[speciesId].insert(breedId);
9296
9297 count++;
9298 } while (result->NextRow());
9299
9300 SF_LOG_INFO("server.loading", ">> Loaded %u Battle Pet breed definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9301}
9302
9304{
9305 uint32 oldMSTime = getMSTime();
9306
9307 QueryResult result = WorldDatabase.Query("SELECT species, quality FROM `battle_pet_quality`");
9308 if (!result)
9309 {
9310 SF_LOG_ERROR("server.loading", ">> Loaded 0 Battle Pets quality definitions. DB table `battle_pet_quality` is empty.");
9311 return;
9312 }
9313
9314 uint32 count = 0;
9315 do
9316 {
9317 Field* fields = result->Fetch();
9318
9319 uint16 speciesId = fields[0].GetUInt16();
9320 uint8 quality = fields[1].GetUInt8();
9321
9322 if (!sBattlePetSpeciesStore.HasRecord(speciesId))
9323 {
9324 SF_LOG_ERROR("sql.sql", "Battle Pet species %u defined in `battle_pet_quality` does not exists, skipped.", speciesId);
9325 continue;
9326 }
9327
9328 if (quality > ITEM_QUALITY_LEGENDARY)
9329 {
9330 SF_LOG_ERROR("sql.sql", "Battle Pet quality %u defined in `battle_pet_quality` is invalid, skipped.", quality);
9331 continue;
9332 }
9333
9335 sBattlePetQualityXSpeciesStore.insert(make_pair(speciesId, BattlePetQualitySet()));
9336
9337 sBattlePetQualityXSpeciesStore[speciesId].insert(quality);
9338
9339 count++;
9340 } while (result->NextRow());
9341
9342 SF_LOG_INFO("server.loading", ">> Loaded %u Battle Pet quality definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9343}
9344
9346{
9347 uint32 oldMSTime = getMSTime();
9348
9349 QueryResult result = WorldDatabase.Query("SELECT itemId, species FROM `battle_pet_item_to_species` ORDER BY itemId, species");
9350 if (!result)
9351 {
9352 SF_LOG_ERROR("server.loading", ">> Loaded 0 Battle Pet item to species definitions. DB table `battle_pet_item_to_species` is empty.");
9353 return;
9354 }
9355
9356 uint32 count = 0;
9357 do
9358 {
9359 Field* fields = result->Fetch();
9360
9361 uint32 itemId = fields[0].GetUInt32();
9362 uint16 speciesId = fields[1].GetUInt16();
9363
9364 if (!GetItemTemplate(itemId))
9365 {
9366 SF_LOG_ERROR("sql.sql", "Item id %u defined in `battle_pet_item_to_species` does not exist, skipped.", itemId);
9367 continue;
9368 }
9369
9370 if (!sBattlePetSpeciesStore.HasRecord(speciesId))
9371 {
9372 SF_LOG_ERROR("sql.sql", "Battle Pet species %u defined in `battle_pet_item_to_species` does not exist, skipped.", speciesId);
9373 continue;
9374 }
9375
9377 SF_LOG_DEBUG("sql.sql", "Battle Pet item %u already mapped to species %u, replacing with species %u.",
9378 itemId, sBattlePetItemXSpeciesStore[itemId], speciesId);
9379
9380 sBattlePetItemXSpeciesStore[itemId] = speciesId;
9381 ++count;
9382 } while (result->NextRow());
9383
9384 SF_LOG_INFO("server.loading", ">> Loaded %u Battle Pet item to species definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9385}
9386
9388{
9389 ASSERT(m_battlePetId < 0xFFFFFFFE && "Battle Pet id overflow!");
9390 return m_battlePetId++;
9391}
9392
9394{
9395 for (BattlePetBreedXSpeciesMap::const_iterator mapCitr = sBattlePetBreedXSpeciesStore.begin(); mapCitr != sBattlePetBreedXSpeciesStore.end(); ++mapCitr)
9396 {
9397 if (mapCitr->first == speciesId)
9398 {
9399 BattleBetBreedSet::iterator setItr(mapCitr->second.begin());
9400 std::advance(setItr, std::rand() % mapCitr->second.size());
9401
9402 return *setItr;
9403 }
9404 }
9405
9406 return 0;
9407}
9408
9410{
9411 for (BattlePetQualityXSpeciesMap::const_iterator mapCitr = sBattlePetQualityXSpeciesStore.begin(); mapCitr != sBattlePetQualityXSpeciesStore.end(); ++mapCitr)
9412 {
9413 if (mapCitr->first == speciesId)
9414 {
9415 BattlePetQualitySet::iterator setItr(mapCitr->second.begin());
9416 std::advance(setItr, std::rand() % mapCitr->second.size());
9417
9418 return *setItr;
9419 }
9420 }
9421
9422 return ITEM_QUALITY_NORMAL;
9423}
9424
9426{
9427 uint32 oldMSTime = getMSTime();
9428
9429 QueryResult result = WorldDatabase.Query("SELECT `questId`, `id`, `index`, `type`, `objectId`, `amount`, `flags`, `description` FROM `quest_objective` ORDER BY `questId` ASC");
9430 if (!result)
9431 {
9432 SF_LOG_ERROR("server.loading", ">> Loaded 0 Quest Objectives. DB table `quest_objective` is empty.");
9433 return;
9434 }
9435
9436 uint32 count = 0;
9437 do
9438 {
9439 Field* fields = result->Fetch();
9440
9441 uint32 questId = fields[0].GetUInt32();
9442 uint32 id = fields[1].GetUInt32();
9443 uint8 index = fields[2].GetUInt8();
9444 uint8 type = fields[3].GetUInt8();
9445 uint32 objectId = fields[4].GetUInt32();
9446 int32 amount = fields[5].GetInt32();
9447 uint32 flags = fields[6].GetUInt32();
9448 std::string description = fields[7].GetString();
9449
9450 if (_questTemplates.find(questId) == _questTemplates.end())
9451 {
9452 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant Quest Id %u! Skipping.", id, questId);
9453 continue;
9454 }
9455
9457 continue;
9458
9459 if (type >= QUEST_OBJECTIVE_TYPE_END)
9460 {
9461 SF_LOG_ERROR("sql.sql", "Quest Objective %u has invalid type %u! Skipping.", id, type);
9462 continue;
9463 }
9464
9465 Quest* quest = _questTemplates.find(questId)->second;
9466 switch (type)
9467 {
9471 {
9472 if (!GetCreatureTemplate(objectId))
9473 {
9474 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant Creature Id %u! Skipping.", id, objectId);
9475 continue;
9476 }
9477
9478 if (amount <= 0)
9479 {
9480 SF_LOG_ERROR("sql.sql", "Quest Objective %u has valid Creature Id %u but amount %u is invalid! Skipping.", id, objectId, amount);
9481 continue;
9482 }
9483
9484 break;
9485 }
9487 {
9488 if (!GetItemTemplate(objectId))
9489 {
9490 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant Item Id %u! Skipping.", id, objectId);
9491 continue;
9492 }
9493
9494 if (amount <= 0)
9495 {
9496 SF_LOG_ERROR("sql.sql", "Quest Objective %u has valid Item Id %u but amount %u is invalid! Skipping.", id, objectId, amount);
9497 continue;
9498 }
9499
9500 break;
9501 }
9503 {
9504 if (!GetGameObjectTemplate(objectId))
9505 {
9506 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant GameObject Id %u! Skipping.", id, objectId);
9507 continue;
9508 }
9509
9510 if (amount <= 0)
9511 {
9512 SF_LOG_ERROR("sql.sql", "Quest Objective %u has valid GameObject Id %u but amount %u is invalid! Skipping.", id, objectId, amount);
9513 continue;
9514 }
9515
9516 break;
9517 }
9519 {
9520 if (!sCurrencyTypesStore.LookupEntry(objectId))
9521 {
9522 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant Currency Id %u! Skipping.", id, objectId);
9523 continue;
9524 }
9525
9526 break;
9527 }
9529 {
9530 SpellInfo const* spell = sSpellMgr->GetSpellInfo(objectId);
9531 if (!spell)
9532 {
9533 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant Spell Id %u! Skipping.", id, objectId);
9534 continue;
9535 }
9536
9537 else if (!SpellMgr::IsSpellValid(spell))
9538 {
9539 SF_LOG_ERROR("sql.sql", "Quest Objective %u has invalid Spell Id %u! Skipping.", id, objectId);
9540 continue;
9541 }
9542
9543 if (amount <= 0)
9544 {
9545 SF_LOG_ERROR("sql.sql", "Quest Objective %u has valid Spell Id %u but amount %u is invalid! Skipping.", id, objectId, amount);
9546 continue;
9547 }
9548
9549 break;
9550 }
9553 {
9554 if (!sFactionStore.LookupEntry(objectId))
9555 {
9556 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant Faction Id %u! Skipping.", id, objectId);
9557 continue;
9558 }
9559
9560 break;
9561 }
9563 {
9564 if (quest->GetQuestObjectiveCountType(type) >= 1)
9565 {
9566 SF_LOG_ERROR("sql.sql", "Quest Objective %u is invalid, Quest %u already has the max amount of Quest Objective type %u! Skipping.", id, questId, type);
9567 continue;
9568 }
9569
9570 break;
9571 }
9573 {
9574 if (!sBattlePetSpeciesStore.HasRecord(objectId))
9575 {
9576 SF_LOG_ERROR("sql.sql", "Quest Objective %u has non existant Battle Pet Species %u! Skipping.", id, objectId);
9577 continue;
9578 }
9579
9581 {
9582 SF_LOG_ERROR("sql.sql", "Quest Objective %u has invalid Battle Pet Species %u, it doesn't have BATTLE_PET_FLAG_ELITE flag! Skipping.", id, objectId);
9583 continue;
9584 }
9585
9586 if (amount <= 0)
9587 {
9588 SF_LOG_ERROR("sql.sql", "Quest Objective %u has valid Item Id %u but amount %u is invalid! Skipping.", id, objectId, amount);
9589 continue;
9590 }
9591
9592 break;
9593 }
9595 {
9596 if (quest->GetQuestObjectiveCountType(type) >= 1)
9597 {
9598 SF_LOG_ERROR("sql.sql", "Quest Objective %u is invalid, Quest %u already has the max amount of Quest Objective type %u! Skipping.", id, questId, type);
9599 continue;
9600 }
9601
9602 if (amount <= 0)
9603 {
9604 SF_LOG_ERROR("sql.sql", "Quest Objective %u has invalid Pet Battle PvP win amount %u! Skipping.", id, amount);
9605 continue;
9606 }
9607
9608 break;
9609 }
9610 default:
9611 break;
9612 }
9613
9614 if (m_questObjectiveLookup.find(id) == m_questObjectiveLookup.end())
9615 m_questObjectiveLookup.insert(std::make_pair(id, questId));
9616
9617 quest->m_questObjectives.insert(new QuestObjective(id, index, type, objectId, amount, flags, description));
9618 quest->m_questObjecitveTypeCount[type]++;
9619
9620 count++;
9621 } while (result->NextRow());
9622
9623 SF_LOG_INFO("server.loading", ">> Loaded %u Quest Objectives in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9624}
9625
9627{
9628 uint32 oldMSTime = getMSTime();
9629
9630 QueryResult result = WorldDatabase.Query("SELECT `objectiveId`, `visualEffect` FROM `quest_objective_effects` ORDER BY `objectiveId` ASC");
9631 if (!result)
9632 {
9633 SF_LOG_ERROR("server.loading", ">> Loaded 0 Quest Objective visual effects. DB table `quest_objective_effects` is empty.");
9634 return;
9635 }
9636
9637 uint32 count = 0;
9638 do
9639 {
9640 Field* fields = result->Fetch();
9641
9642 uint32 objectiveId = fields[0].GetUInt32();
9643 uint32 visualEffect = fields[1].GetUInt32();
9644
9645 if (!QuestObjectiveExists(objectiveId))
9646 {
9647 SF_LOG_ERROR("sql.sql", "Visual effect %u has non existant Quest Objective Id %u! Skipping.", visualEffect, objectiveId);
9648 continue;
9649 }
9650
9651 Quest const* quest = GetQuestTemplate(GetQuestObjectiveQuestId(objectiveId));
9652 if (!quest)
9653 continue;
9654
9655 QuestObjective* questObjective = const_cast<QuestObjective*>(quest->GetQuestObjective(objectiveId));
9656 if (!questObjective)
9657 {
9658 SF_LOG_ERROR("sql.sql", "Visual effect %u has non existant Quest Objective %u for Quest %u! Skipping.", visualEffect, objectiveId, quest->GetQuestId());
9659 continue;
9660 }
9661
9662 questObjective->VisualEffects.push_back(visualEffect);
9663
9664 count++;
9665 } while (result->NextRow());
9666
9667 SF_LOG_INFO("server.loading", ">> Loaded %u Quest Objective visual effects in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9668}
9669
9671{
9672 uint32 oldMSTime = getMSTime();
9673
9674 QueryResult result = WorldDatabase.Query("SELECT `id`, `locale`, `description` FROM `locales_quest_objective` ORDER BY `id` ASC");
9675 if (!result)
9676 {
9677 SF_LOG_ERROR("server.loading", ">> Loaded 0 Quest Objective locale descriptions. DB table `locales_quest_objective` is empty.");
9678 return;
9679 }
9680
9681 uint32 count = 0;
9682 do
9683 {
9684 Field* fields = result->Fetch();
9685
9686 uint32 objectiveId = fields[0].GetUInt32();
9687 uint8 locale = fields[1].GetUInt8();
9688 std::string description = fields[2].GetString();
9689
9690 if (!QuestObjectiveExists(objectiveId))
9691 {
9692 SF_LOG_ERROR("sql.sql", "Quest Objective locale %u has invalid Quest Objective %u! Skipping.", locale, objectiveId);
9693 continue;
9694 }
9695
9696 if (locale >= TOTAL_LOCALES)
9697 {
9698 SF_LOG_ERROR("sql.sql", "Locale Id %u for Quest Objective %u is invalid! Skipping.", locale, objectiveId);
9699 continue;
9700 }
9701
9702 AddLocaleString(description, (LocaleConstant)locale, m_questObjectiveLocaleStore[objectiveId].Description);
9703 } while (result->NextRow());
9704
9705 SF_LOG_INFO("server.loading", ">> Loaded %u Quest Objective visual effects in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9706}
9707
9709{
9710 QuestObjectiveLocaleContainer::const_iterator citr = m_questObjectiveLocaleStore.find(objectiveId);
9711 if (citr == m_questObjectiveLocaleStore.end())
9712 return NULL;
9713
9714 return &citr->second;
9715}
9716
9718{
9719 if (m_questObjectiveLookup.find(objectiveId) == m_questObjectiveLookup.end())
9720 return false;
9721
9722 return true;
9723}
9724
9726{
9727 QuestObjectiveLookupMap::const_iterator citr = m_questObjectiveLookup.find(objectiveId);
9728 if (citr == m_questObjectiveLookup.end())
9729 return 0;
9730
9731 return citr->second;
9732}
9733
9735{
9736 uint32 oldMSTime = getMSTime();
9737 _sceneTemplateStore.clear();
9738
9739 QueryResult templates = WorldDatabase.Query("SELECT SceneId, Flags, ScriptPackageID, ScriptName FROM scene_template");
9740 if (!templates)
9741 {
9742 SF_LOG_INFO("server.loading", ">> Loaded 0 scene templates. DB table `scene_template` is empty.");
9743 return;
9744 }
9745
9746 uint32 count = 0;
9747
9748 do
9749 {
9750 Field* fields = templates->Fetch();
9751 uint32 sceneId = fields[0].GetUInt32();
9752 SceneTemplate& sceneTemplate = _sceneTemplateStore[sceneId];
9753 sceneTemplate.SceneId = sceneId;
9754 sceneTemplate.PlaybackFlags = fields[1].GetUInt32();
9755 sceneTemplate.ScenePackageId = fields[2].GetUInt32();
9756 sceneTemplate.ScriptId = sObjectMgr->GetScriptId(fields[3].GetCString());
9757 } while (templates->NextRow());
9758
9759 SF_LOG_INFO("server.loading", ">> Loaded %u scene templates in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
9760}
9761
9763{
9764 SceneTemplateContainer::const_iterator citr = _sceneTemplateStore.find(sceneId);
9765 if (citr == _sceneTemplateStore.end())
9766 return NULL;
9767
9768 return &citr->second;
9769}
#define sAchievementMgr
const AuthHandler table[]
bool BattlePetSpeciesFlagsAllowWildCapture(uint32 flags)
@ CHAR_UPD_ITEM_OWNER
@ CHAR_DEL_EMPTY_EXPIRED_MAIL
@ CHAR_DEL_ITEM_INSTANCE
@ CHAR_SEL_GUID_BY_NAME
@ CHAR_UPD_MAIL_RETURNED
@ CHAR_SEL_EXPIRED_MAIL
@ CHAR_SEL_ACCOUNT_BY_NAME
@ CHAR_SEL_ACCOUNT_BY_GUID
@ CHAR_SEL_EXPIRED_MAIL_ITEMS
@ CHAR_SEL_CORPSES
@ CHAR_DEL_MAIL_BY_ID
@ CHAR_SEL_CHAR_RACE
@ CHAR_SEL_CHARACTER_NAME
@ CHAR_UPD_MAIL_ITEM_RECEIVER
LocaleConstant GetLocaleByName(const std::string &name)
Definition Common.cpp:23
const uint8 TOTAL_LOCALES
Definition Common.h:153
LocaleConstant
Definition Common.h:138
#define DEFAULT_LOCALE
Definition Common.h:154
#define MAX_LOCALES
Definition Common.h:156
@ DAY
Definition Common.h:121
std::vector< std::string > StringVector
Definition Common.h:163
CorpseType
Definition Corpse.h:15
@ MAX_CORPSE_TYPE
Definition Corpse.h:19
#define MAX_KILL_CREDIT
Definition Creature.h:54
@ CREATURE_FLAG_EXTRA_DUNGEON_BOSS
Definition Creature.h:44
@ CREATURE_FLAG_EXTRA_INSTANCE_BIND
Definition Creature.h:29
UNORDERED_MAP< uint32, CreatureTemplate > CreatureTemplateContainer
Definition Creature.h:187
#define MAX_CREATURE_QUEST_ITEMS
Definition Creature.h:57
@ CHAT_TYPE_BOSS_WHISPER
Definition Creature.h:310
@ CHAT_TYPE_WHISPER
Definition Creature.h:309
#define MAX_EQUIPMENT_ITEMS
Definition Creature.h:59
@ INHABIT_ANYWHERE
Definition Creature.h:299
#define CREATURE_FLAG_EXTRA_DB_ALLOWED
Definition Creature.h:47
@ BATTLE_PET_FLAG_ELITE
Definition DB2Enums.h:22
DB2Storage< ItemEntry > sItemStore(Itemfmt, &DB2Utilities::HasItemEntry, &DB2Utilities::WriteItemDbReply)
bool BattlePetSpeciesHasFlag(uint16 speciesId, uint16 flag)
DB2Storage< ItemExtendedCostEntry > sItemExtendedCostStore(ItemExtendedCostEntryfmt)
BattlePetItemXSpeciesStore sBattlePetItemXSpeciesStore
Definition DB2Stores.cpp:48
DB2Storage< ItemSparseEntry > sItemSparseStore(ItemSparsefmt, &DB2Utilities::HasItemSparseEntry, &DB2Utilities::WriteItemSparseDbReply)
DB2Storage< ItemCurrencyCostEntry > sItemCurrencyCostStore(ItemCurrencyCostfmt)
DB2Storage< BattlePetSpeciesEntry > sBattlePetSpeciesStore(BattlePetSpeciesfmt)
BattlePetBreedSet sBattlePetBreedSet
Definition DB2Stores.cpp:47
@ DEFAULT_MAX_LEVEL
Definition DBCEnums.h:16
@ MAX_LEVEL
Definition DBCEnums.h:20
@ STRONG_MAX_LEVEL
Definition DBCEnums.h:24
DifficultyID
Definition DBCEnums.h:330
@ DIFFICULTY_NONE
Definition DBCEnums.h:331
DBCStorage< CharTitlesEntry > sCharTitlesStore(CharTitlesEntryfmt)
DBCStorage< ResearchSiteEntry > sResearchSiteStore(ResearchSitefmt)
DBCStorage< FactionEntry > sFactionStore(FactionEntryfmt)
DBCStorage< WorldSafeLocsEntry > sWorldSafeLocsStore(WorldSafeLocsEntryfmt)
TaxiPathSetBySource sTaxiPathSetBySource
DBCStorage< MailTemplateEntry > sMailTemplateStore(MailTemplateEntryfmt)
DBCStorage< VehicleEntry > sVehicleStore(VehicleEntryfmt)
TaxiMask sTaxiNodesMask
DBCStorage< GtOCTBaseHPByClassEntry > sGtOCTBaseHPByClassStore(GtOCTBaseHPByClassfmt)
DBCStorage< CharStartOutfitEntry > sCharStartOutfitStore(CharStartOutfitEntryfmt)
DBCStorage< LockEntry > sLockStore(LockEntryfmt)
MapDifficulty const * GetMapDifficultyData(uint32 mapId, DifficultyID difficulty)
TaxiPathNodesByPath sTaxiPathNodesByPath
DBCStorage< ItemDamageEntry > sItemDamageOneHandCasterStore(ItemDamagefmt)
DBCStorage< CreatureSpellDataEntry > sCreatureSpellDataStore(CreatureSpellDatafmt)
DBCStorage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore(CreatureDisplayInfofmt)
DBCStorage< ChrRacesEntry > sChrRacesStore(ChrRacesEntryfmt)
uint32 GetTalentSpellCost(uint32 spellId)
DBCStorage< GameObjectDisplayInfoEntry > sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt)
DBCStorage< ItemDamageEntry > sItemDamageRangedStore(ItemDamagefmt)
DBCStorage< ItemDamageEntry > sItemDamageAmmoStore(ItemDamagefmt)
DBCStorage< AreaTriggerEntry > sAreaTriggerStore(AreaTriggerEntryfmt)
DBCStorage< ItemDisenchantLootEntry > sItemDisenchantLootStore(ItemDisenchantLootfmt)
DBCStorage< ResearchProjectEntry > sResearchProjectStore(ResearchProjectfmt)
DBCStorage< SoundEntriesEntry > sSoundEntriesStore(SoundEntriesfmt)
DBCStorage< ItemDamageEntry > sItemDamageWandStore(ItemDamagefmt)
DBCStorage< QuestSortEntry > sQuestSortStore(QuestSortEntryfmt)
std::set< uint32 > const & GetPhasesForGroup(uint32 group)
DBCStorage< DungeonEncounterEntry > sDungeonEncounterStore(DungeonEncounterfmt)
DBCStorage< SkillLineEntry > sSkillLineStore(SkillLinefmt)
DBCStorage< PhaseEntry > sPhaseStore(PhaseEntryfmt)
DBCStorage< CreatureFamilyEntry > sCreatureFamilyStore(CreatureFamilyfmt)
DBCStorage< FactionTemplateEntry > sFactionTemplateStore(FactionTemplateEntryfmt)
DBCStorage< ItemDamageEntry > sItemDamageThrownStore(ItemDamagefmt)
DBCStorage< GtOCTBaseMPByClassEntry > sGtOCTBaseMPByClassStore(GtOCTBaseMPByClassfmt)
DBCStorage< TaxiNodesEntry > sTaxiNodesStore(TaxiNodesEntryfmt)
DBCStorage< SpellFocusObjectEntry > sSpellFocusObjectStore(SpellFocusObjectfmt)
char const * GetPetName(uint32 petfamily, uint32)
DBCStorage< ItemDamageEntry > sItemDamageOneHandStore(ItemDamagefmt)
DBCStorage< ItemDamageEntry > sItemDamageTwoHandStore(ItemDamagefmt)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
CharStartOutfitEntry const * GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender)
DBCStorage< CreatureTypeEntry > sCreatureTypeStore(CreatureTypefmt)
AreaTableEntry const * GetAreaEntryByAreaID(uint32 area_id)
DBCStorage< ChrClassesEntry > sChrClassesStore(ChrClassesEntryfmt)
DBCStorage< CurrencyTypesEntry > sCurrencyTypesStore(CurrencyTypesfmt)
DBCStorage< EmotesEntry > sEmotesStore(EmotesEntryfmt)
DBCStorage< ItemDamageEntry > sItemDamageTwoHandCasterStore(ItemDamagefmt)
std::map< uint32, TaxiPathBySourceAndDestination > TaxiPathSetForSource
#define GT_MAX_LEVEL
#define MAX_SPELL_EFFECTS
#define MAX_OUTFIT_ITEMS
std::int32_t int32
Definition Define.h:73
#define UI64FMTD
Definition Define.h:64
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::int8_t int8
Definition Define.h:75
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
std::int16_t int16
Definition Define.h:74
@ DISABLE_TYPE_QUEST
Definition DisableMgr.h:16
#define ASSERT
Definition Errors.h:29
UNORDERED_MAP< uint32, GameObjectTemplate > GameObjectTemplateContainer
Definition GameObject.h:529
#define MAX_GAMEOBJECT_QUEST_ITEMS
Definition GameObject.h:20
GOState
Definition GameObject.h:575
@ GO_STATE_TRANSPORT_ACTIVE
Definition GameObject.h:580
@ GO_STATE_ACTIVE
Definition GameObject.h:576
@ GO_STATE_READY
Definition GameObject.h:577
@ GO_STATE_TRANSPORT_STOPPED
Definition GameObject.h:581
@ GO_STATE_ACTIVE_ALTERNATIVE
Definition GameObject.h:578
@ GOSSIP_ICON_CHAT
Definition GossipDef.h:46
@ GOSSIP_ICON_MAX
Definition GossipDef.h:67
@ GOSSIP_OPTION_MAX
Definition GossipDef.h:41
CoordPair< TOTAL_NUMBER_OF_CELLS_PER_MAP > CellCoord
#define sGroupMgr
Definition GroupMgr.h:44
#define sGuildMgr
Definition GuildMgr.h:53
@ ITEM_SUBCLASS_WEAPON_CROSSBOW
@ ITEM_SUBCLASS_WEAPON_GUN
@ ITEM_SUBCLASS_WEAPON_BOW
@ ITEM_SUBCLASS_WEAPON_WAND
@ ITEM_SUBCLASS_WEAPON_THROWN
@ INVTYPE_ROBE
@ INVTYPE_HOLDABLE
@ INVTYPE_RANGED
@ INVTYPE_THROWN
@ INVTYPE_RANGEDRIGHT
@ INVTYPE_WEAPON
@ INVTYPE_WEAPONMAINHAND
@ INVTYPE_WEAPONOFFHAND
@ INVTYPE_2HWEAPON
@ INVTYPE_AMMO
@ INVTYPE_SHIELD
@ ITEM_PROTO_FLAG_CONJURED
@ ITEM_PROTO_FLAG_UNK6
@ ITEM_FLAGS_EXTRA_CASTER_WEAPON
#define MAX_INVTYPE
#define MAX_ITEM_PROTO_SOCKETS
#define MAX_ITEM_PROTO_SPELLS
@ BIND_QUEST_ITEM
@ ITEM_CLASS_ARMOR
@ ITEM_CLASS_WEAPON
@ ITEM_VENDOR_TYPE_ITEM
@ ITEM_VENDOR_TYPE_CURRENCY
#define MAX_ITEM_SUBCLASS_WEAPON
#define MAX_ITEM_PROTO_STATS
#define sLFGMgr
Definition LFGMgr.h:518
@ LANG_ITEM_ALREADY_IN_LIST
Definition Language.h:210
@ LANG_COMMAND_VENDORSELECTION
Definition Language.h:285
@ LANG_ITEM_NOT_FOUND
Definition Language.h:207
@ LANG_EXTENDED_COST_NOT_EXIST
Definition Language.h:338
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
LootStore LootTemplates_Gameobject("gameobject_loot_template", "gameobject entry", true)
@ MAIL_CHECK_MASK_COD_PAYMENT
This mail was copied. Do not allow making a copy of items in mail.
Definition Mail.h:38
@ MAIL_CHECK_MASK_RETURNED
Definition Mail.h:36
std::vector< MailItemInfo > MailItemInfoVec
Definition Mail.h:153
@ MAIL_NORMAL
Definition Mail.h:24
#define sMapMgr
Definition MapManager.h:145
@ MAX_DB_MOTION_TYPE
@ IDLE_MOTION_TYPE
@ WAYPOINT_MOTION_TYPE
@ RANDOM_MOTION_TYPE
#define MAX_GOSSIP_TEXT_OPTIONS
Definition NPCHandler.h:27
#define MAX_GOSSIP_TEXT_EMOTES
Definition NPCHandler.h:16
#define DEFAULT_VISIBILITY_DISTANCE
Definition Object.h:25
TempSummonType
Definition Object.h:67
@ TEMPSUMMON_MANUAL_DESPAWN
Definition Object.h:75
#define INTERACTION_DISTANCE
Definition Object.h:21
#define DEFAULT_COMBAT_REACH
Definition Object.h:30
#define sObjectAccessor
uint32 GUID_LOPART(uint64 x)
uint32 MAKE_PAIR32(uint16 l, uint16 h)
HighGuid
@ HIGHGUID_PET
@ HIGHGUID_AREATRIGGER
@ HIGHGUID_DYNAMICOBJECT
@ HIGHGUID_GAMEOBJECT
@ HIGHGUID_CORPSE
@ HIGHGUID_PLAYER
@ HIGHGUID_MO_TRANSPORT
@ HIGHGUID_UNIT
@ HIGHGUID_ITEM
@ HIGHGUID_VEHICLE
uint64 MAKE_NEW_GUID(uint32 l, uint32 e, uint32 h)
uint16 MAKE_PAIR16(uint8 l, uint8 h)
LanguageDesc lang_description[LANGUAGES_COUNT]
void CheckAndFixGOChairHeightId(GameObjectTemplate const *goInfo, uint32 &dataN, uint32 N)
bool LoadSkyFireStrings(const char *table, int32 start_value, int32 end_value)
static LanguageType GetRealmLanguageType(bool create)
void CheckGONoDamageImmuneId(GameObjectTemplate *goTemplate, uint32 dataN, uint32 N)
void CheckGOSpellId(GameObjectTemplate const *goInfo, uint32 dataN, uint32 N)
ScriptMapMap * GetScriptsMapByType(ScriptsType type)
ScriptMapMap sSpellScripts
Definition ObjectMgr.cpp:50
std::string GetScriptCommandName(ScriptCommands command)
bool isValidString(const std::wstring &wstr, uint32 strictMask, bool numericOrSpace, bool create=false)
uint32 FillMaxDurability(uint32 itemClass, uint32 itemSubClass, uint32 inventoryType, uint32 quality, uint32 itemLevel)
void FillItemDamageFields(float *minDamage, float *maxDamage, float *dps, uint32 itemLevel, uint32 itemClass, uint32 itemSubClass, uint32 quality, uint32 delay, float statScalingFactor, uint32 inventoryType, uint32 flags2)
SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
ScriptMapMap sEventScripts
Definition ObjectMgr.cpp:51
void CheckGOConsumable(GameObjectTemplate const *goInfo, uint32 dataN, uint32 N)
void CheckGOLinkedTrapId(GameObjectTemplate const *goInfo, uint32 dataN, uint32 N)
void CheckGOLockId(GameObjectTemplate const *goInfo, uint32 dataN, uint32 N)
LanguageDesc const * GetLanguageDescByID(Language lang)
std::string GetScriptsTableNameByType(ScriptsType type)
Definition ObjectMgr.cpp:88
ScriptMapMap sWaypointScripts
Definition ObjectMgr.cpp:52
LanguageType
@ LT_ANY
@ LT_EXTENDEN_LATIN
@ LT_EAST_ASIA
@ LT_BASIC_LATIN
@ LT_CYRILLIC
bool normalizePlayerName(std::string &name)
void FillDisenchantFields(uint32 *disenchantID, uint32 *requiredDisenchantSkill, ItemTemplate const &itemTemplate)
EncounterCreditType
Definition ObjectMgr.h:638
std::pair< GraveYardContainer::const_iterator, GraveYardContainer::const_iterator > GraveYardMapBounds
Definition ObjectMgr.h:603
#define MAX_PLAYER_NAME
Definition ObjectMgr.h:620
#define SKYFIRE_TRAINER_START_REF
Definition ObjectMgr.h:433
std::pair< GraveYardContainer::iterator, GraveYardContainer::iterator > GraveYardMapBoundsNonConst
Definition ObjectMgr.h:604
std::multimap< uint32, ScriptInfo > ScriptMap
Definition ObjectMgr.h:379
#define MAX_CHARTER_NAME
Definition ObjectMgr.h:623
std::pair< SpellScriptsContainer::iterator, SpellScriptsContainer::iterator > SpellScriptsBounds
Definition ObjectMgr.h:382
ScriptMapMap * GetScriptsMapByType(ScriptsType type)
ScriptCommands
Definition ObjectMgr.h:84
@ SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT
Definition ObjectMgr.h:106
@ SCRIPT_COMMAND_KILL_CREDIT
Definition ObjectMgr.h:93
@ SCRIPT_COMMAND_QUEST_EXPLORED
Definition ObjectMgr.h:92
@ SCRIPT_COMMAND_TELEPORT_TO
Definition ObjectMgr.h:91
@ SCRIPT_COMMAND_RESPAWN_GAMEOBJECT
Definition ObjectMgr.h:94
@ SCRIPT_COMMAND_FLAG_SET
Definition ObjectMgr.h:89
@ SCRIPT_COMMAND_MOVE_TO
Definition ObjectMgr.h:88
@ SCRIPT_COMMAND_ACTIVATE_OBJECT
Definition ObjectMgr.h:98
@ SCRIPT_COMMAND_PLAY_SOUND
Definition ObjectMgr.h:101
@ SCRIPT_COMMAND_OPEN_DOOR
Definition ObjectMgr.h:96
@ SCRIPT_COMMAND_FIELD_SET
Definition ObjectMgr.h:87
@ SCRIPT_COMMAND_LOAD_PATH
Definition ObjectMgr.h:105
@ SCRIPT_COMMAND_TEMP_SUMMON_CREATURE
Definition ObjectMgr.h:95
@ SCRIPT_COMMAND_REMOVE_AURA
Definition ObjectMgr.h:99
@ SCRIPT_COMMAND_DESPAWN_SELF
Definition ObjectMgr.h:103
@ SCRIPT_COMMAND_CLOSE_DOOR
Definition ObjectMgr.h:97
@ SCRIPT_COMMAND_CAST_SPELL
Definition ObjectMgr.h:100
@ SCRIPT_COMMAND_PLAYMOVIE
Definition ObjectMgr.h:114
@ SCRIPT_COMMAND_CLOSE_GOSSIP
Definition ObjectMgr.h:113
@ SCRIPT_COMMAND_FLAG_REMOVE
Definition ObjectMgr.h:90
@ SCRIPT_COMMAND_CREATE_ITEM
Definition ObjectMgr.h:102
@ SCRIPT_COMMAND_ORIENTATION
Definition ObjectMgr.h:110
ScriptMapMap sSpellScripts
Definition ObjectMgr.cpp:50
std::string GetScriptCommandName(ScriptCommands command)
#define MIN_DB_SCRIPT_STRING_ID
Definition ObjectMgr.h:427
#define MAX_DB_SCRIPT_STRING_ID
Definition ObjectMgr.h:428
#define sObjectMgr
Definition ObjectMgr.h:1617
ScriptMapMap sEventScripts
Definition ObjectMgr.cpp:51
#define MIN_SKYFIRE_STRING_ID
Definition ObjectMgr.h:425
std::map< uint32, ScriptMap > ScriptMapMap
Definition ObjectMgr.h:380
std::string GetScriptsTableNameByType(ScriptsType type)
Definition ObjectMgr.cpp:88
ScriptMapMap sWaypointScripts
Definition ObjectMgr.cpp:52
ScriptsType
Definition ObjectMgr.h:152
std::multimap< uint32, uint32 > QuestRelations
Definition ObjectMgr.h:455
std::list< DungeonEncounter const * > DungeonEncounterList
Definition ObjectMgr.h:654
#define MAX_PET_NAME
Definition ObjectMgr.h:622
SkillRangeType
Definition ObjectMgr.h:610
@ SKILL_RANGE_MONO
Definition ObjectMgr.h:613
@ SKILL_RANGE_NONE
Definition ObjectMgr.h:615
@ SKILL_RANGE_LANGUAGE
Definition ObjectMgr.h:611
@ SKILL_RANGE_RANK
Definition ObjectMgr.h:614
@ SKILL_RANGE_LEVEL
Definition ObjectMgr.h:612
#define sPoolMgr
Definition PoolMgr.h:154
std::multimap< uint32, uint32 > PooledQuestRelation
Definition PoolMgr.h:88
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
Definition QueryResult.h:94
Skyfire::AutoPtr< ResultSet, Skyfire::Mutex > QueryResult
Definition QueryResult.h:48
#define QUEST_REWARDS_COUNT
Definition QuestDef.h:26
@ QUEST_OBJECTIVE_TYPE_FACTION_REP2
Definition QuestDef.h:200
@ QUEST_OBJECTIVE_TYPE_PET_BATTLE_PVP
Definition QuestDef.h:206
@ QUEST_OBJECTIVE_TYPE_CURRENCY
Definition QuestDef.h:197
@ QUEST_OBJECTIVE_TYPE_ITEM
Definition QuestDef.h:194
@ QUEST_OBJECTIVE_TYPE_NPC
Definition QuestDef.h:193
@ QUEST_OBJECTIVE_TYPE_NPC_INTERACT
Definition QuestDef.h:196
@ QUEST_OBJECTIVE_TYPE_PET_BATTLE_ELITE
Definition QuestDef.h:205
@ QUEST_OBJECTIVE_TYPE_SPELL
Definition QuestDef.h:198
@ QUEST_OBJECTIVE_TYPE_PET_BATTLE_TAMER
Definition QuestDef.h:204
@ QUEST_OBJECTIVE_TYPE_END
Definition QuestDef.h:207
@ QUEST_OBJECTIVE_TYPE_FACTION_REP
Definition QuestDef.h:199
@ QUEST_OBJECTIVE_TYPE_MONEY
Definition QuestDef.h:201
@ QUEST_OBJECTIVE_TYPE_GO
Definition QuestDef.h:195
#define QUEST_REWARD_CURRENCY_COUNT
Definition QuestDef.h:30
@ QUEST_FLAGS_DAILY
Definition QuestDef.h:127
@ QUEST_FLAGS_WEEKLY
Definition QuestDef.h:130
@ QUEST_FLAGS_TRACKING_EVENT
Definition QuestDef.h:125
#define QUEST_REPUTATIONS_COUNT
Definition QuestDef.h:28
#define QUEST_SOURCE_ITEM_IDS_COUNT
Definition QuestDef.h:24
#define QUEST_REWARD_CHOICES_COUNT
Definition QuestDef.h:25
@ QUEST_SPECIAL_FLAGS_TIMED
Definition QuestDef.h:187
@ QUEST_SPECIAL_FLAGS_REPEATABLE
Definition QuestDef.h:174
@ QUEST_SPECIAL_FLAGS_DB_ALLOWED
Definition QuestDef.h:182
@ QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT
Definition QuestDef.h:175
@ QUEST_SPECIAL_FLAGS_MONTHLY
Definition QuestDef.h:178
#define sScriptMgr
Definition ScriptMgr.h:764
@ GAMEOBJECT_TYPE_CAMERA
@ GAMEOBJECT_TYPE_CAPTURE_POINT
@ GAMEOBJECT_TYPE_BUTTON
@ GAMEOBJECT_TYPE_SPELL_FOCUS
@ GAMEOBJECT_TYPE_MO_TRANSPORT
@ GAMEOBJECT_TYPE_TRANSPORT
@ GAMEOBJECT_TYPE_SUMMONING_RITUAL
@ GAMEOBJECT_TYPE_TRAP
@ GAMEOBJECT_TYPE_GENERIC
@ GAMEOBJECT_TYPE_CHEST
@ GAMEOBJECT_TYPE_FISHINGHOLE
@ GAMEOBJECT_TYPE_FLAGDROP
@ GAMEOBJECT_TYPE_QUESTGIVER
@ GAMEOBJECT_TYPE_SPELLCASTER
@ GAMEOBJECT_TYPE_FLAGSTAND
@ GAMEOBJECT_TYPE_CHAIR
@ GAMEOBJECT_TYPE_AREADAMAGE
@ GAMEOBJECT_TYPE_GOOBER
@ GAMEOBJECT_TYPE_FISHINGNODE
@ GAMEOBJECT_TYPE_BARBER_CHAIR
@ GAMEOBJECT_TYPE_DOOR
#define MAX_STATS
#define MAX_CREATURE_BASE_HP
#define MAX_REPUTATION_RANK
@ SPELL_SCHOOL_NORMAL
@ SPELL_SCHOOL_HOLY
#define LANGUAGES_COUNT
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_SCRIPT_EFFECT
@ SPELL_EFFECT_SEND_EVENT
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_QUEST_COMPLETE
uint32 SkillByQuestSort(int32 QuestSort)
Language
@ LANG_GNOMISH_BINARY
@ LANG_PANDAREN_ALLIANCE
@ LANG_PANDAREN_NEUTRAL
@ LANG_PANDAREN_HORDE
@ SKILL_CATEGORY_WEAPON
@ SKILL_CATEGORY_ARMOR
@ SKILL_CATEGORY_ATTRIBUTES
@ SKILL_CATEGORY_SECONDARY
@ SKILL_CATEGORY_LANGUAGES
@ SKILL_CATEGORY_PROFESSION
@ SKILL_CATEGORY_CLASS
@ SKILL_CATEGORY_GENERIC
@ GENDER_MALE
@ GENDER_NONE
@ TARGET_UNIT_TARGET_ALLY
@ TARGET_UNIT_TARGET_ANY
@ TARGET_UNIT_CASTER
@ CREATURE_FAMILY_HORSE_CUSTOM
ResponseCodes
@ UNIT_CLASS_WARRIOR
#define MAX_RACES
@ CREATURE_TYPE_HUMANOID
@ ITEM_QUALITY_UNCOMMON
@ ITEM_QUALITY_NORMAL
@ ITEM_QUALITY_LEGENDARY
@ ITEM_QUALITY_ARTIFACT
@ ITEM_QUALITY_EPIC
@ CLASS_HUNTER
@ CLASS_DRUID
@ CLASS_SHAMAN
@ CLASS_MONK
@ CLASS_PRIEST
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_DEATH_KNIGHT
@ CLASS_PALADIN
@ CLASS_ROGUE
#define MAX_ITEM_QUALITY
SpellClickUserTypes
@ SPELL_CLICK_USER_PARTY
@ SPELL_CLICK_USER_RAID
@ SPELL_CLICK_USER_MAX
@ SPELL_CLICK_USER_FRIEND
#define MAX_GAMEOBJECT_DATA
@ ALLIANCE
@ HORDE
#define MAX_CLASSES
@ RACE_PANDAREN_NEUTRAL
@ RACE_DRAENEI
@ RACE_BLOODELF
@ RACE_HUMAN
@ RACE_PANDAREN_ALLIANCE
@ RACE_PANDAREN_HORDE
#define CLASSMASK_ALL_PLAYABLE
#define CURRENT_CONTENT_EXP
@ STAT_SPIRIT
@ STAT_INTELLECT
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
#define MAX_SPELL_SCHOOL
PetNameInvalidReason
@ PET_NAME_INVALID
@ PET_NAME_SUCCESS
@ PET_NAME_MIXED_LANGUAGES
@ PET_NAME_TOO_SHORT
@ PET_NAME_TOO_LONG
#define RACEMASK_ALL_PLAYABLE
#define CLASSMASK_ALL_CREATURES
#define MAX_TRAINER_TYPE
@ SKILL_LANG_GNOMISH
@ SKILL_LANG_COMMON
@ SKILL_LANG_PANDAREN_NEUTRAL
@ SKILL_LANG_DRAENEI
@ SKILL_LANG_ORCISH
@ SKILL_LANG_TROLL
@ SKILL_LANG_GUTTERSPEAK
@ SKILL_LANG_OLD_TONGUE
@ SKILL_LANG_TAURAHE
@ SKILL_LANG_PANDAREN_ALLIANCE
@ SKILL_LANG_TITAN
@ SKILL_LANG_DARNASSIAN
@ SKILL_LANG_DEMON_TONGUE
@ SKILL_LANG_DWARVEN
@ SKILL_LANG_THALASSIAN
@ SKILL_RUNEFORGING
@ SKILL_LANG_PANDAREN_HORDE
@ SKILL_LANG_DRACONIC
@ SKILL_LANG_WORGEN
@ SKILL_LANG_GOBLIN
#define MAX_SPILLOVER_FACTIONS
@ SPELL_AURA_CONTROL_VEHICLE
bool IsProfessionSkill(uint32 skill)
Definition SpellMgr.h:570
#define sSpellMgr
Definition SpellMgr.h:744
SummonerType
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:22
uint32 getMSTime()
Definition Timer.h:12
#define sTransportMgr
@ UNIT_NPC_FLAG_WILDPET_CAPTURABLE
Definition Unit.h:716
@ UNIT_NPC_FLAG_VENDOR
Definition Unit.h:694
@ UNIT_NPC_FLAG_GOSSIP
Definition Unit.h:687
@ UNIT_NPC_FLAG_QUESTGIVER
Definition Unit.h:688
@ UNIT_NPC_FLAG_SPELLCLICK
Definition Unit.h:711
@ UNIT_NPC_FLAG_TRAINER
Definition Unit.h:691
#define BASE_ATTACK_TIME
Definition Unit.h:157
@ UNIT_STAND_STATE_SIT_HIGH_CHAIR
Definition Unit.h:168
@ UNIT_STAND_STATE_SIT_LOW_CHAIR
Definition Unit.h:166
#define MAX_DECLINED_NAME_CASES
Definition Unit.h:1098
#define CREATURE_MAX_SPELLS
Definition Unit.h:272
bool WStrToUtf8(wchar_t *wstr, size_t size, std::string &utf8str)
Definition Util.cpp:348
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition Util.cpp:305
std::wstring GetMainPartOfName(std::wstring wname, uint32 declension)
Definition Util.cpp:396
bool isBasicLatinString(const std::wstring &wstr, bool numericOrSpace)
Definition Util.h:226
bool isCyrillicString(const std::wstring &wstr, bool numericOrSpace)
Definition Util.h:242
bool isExtendedLatinString(const std::wstring &wstr, bool numericOrSpace)
Definition Util.h:234
bool isEastAsianString(const std::wstring &wstr, bool numericOrSpace)
Definition Util.h:250
void wstrToLower(std::wstring &str)
Definition Util.h:314
wchar_t wcharToUpper(wchar_t wchar)
Definition Util.h:258
std::vector< VehicleAccessory > VehicleAccessoryList
@ WORLD_SEL_WAYPOINT_DATA_ACTION
@ WORLD_DEL_GAME_TELE
@ WORLD_INS_GRAVEYARD_ZONE
@ WORLD_SEL_NPC_VENDOR_REF
@ WORLD_INS_GAME_TELE
@ WORLD_REP_CREATURE_LINKED_RESPAWN
@ WORLD_DEL_NPC_VENDOR
@ WORLD_INS_NPC_VENDOR
@ WORLD_DEL_GRAVEYARD_ZONE
@ WORLD_DEL_CRELINKED_RESPAWN
virtual void _Register()
virtual void _Init(std::string const *scriptname, uint32 spellId)
bool _Validate(SpellInfo const *entry)
void PSendSysMessage(const char *format,...) ATTR_PRINTF(2
Definition Chat.cpp:221
virtual void SendSysMessage(const char *str)
Definition Chat.cpp:153
bool LoadCorpseFromDB(uint32 guid, Field *fields)
Definition Corpse.cpp:140
bool LoadCreatureFromDB(uint32 guid, Map *map, bool addToMap=true)
static float _GetDamageMod(int32 Rank)
T const * LookupEntry(uint32 id) const
Definition DBCStore.h:71
Definition Field.h:16
uint8 GetUInt8() const
Definition Field.h:26
std::string GetString() const
Definition Field.h:228
int8 GetInt8() const
Definition Field.h:44
uint64 GetUInt64() const
Definition Field.h:141
int16 GetInt16() const
Definition Field.h:87
uint16 GetUInt16() const
Definition Field.h:69
char const * GetCString() const
Definition Field.h:213
float GetFloat() const
Definition Field.h:177
bool GetBool() const
Definition Field.h:21
uint32 GetUInt32() const
Definition Field.h:105
int32 GetInt32() const
Definition Field.h:123
bool LoadGameObjectFromDB(uint32 guid, Map *map, bool addToMap=true)
static uint32 GetSpecialPrice(ItemTemplate const *proto, uint32 minimumPrice=10000)
Definition Item.cpp:1425
Definition Map.h:238
bool Instanceable() const
Definition Map.h:367
bool IsGridLoaded(float x, float y) const
Definition Map.h:283
static bool IsValidMapCoord(uint32 mapid, float x, float y)
Definition MapManager.h:75
static bool IsValidMAP(uint32 mapid, bool startUp)
static Player * FindPlayer(uint64)
Player * ToPlayer()
Definition Object.h:204
Creature * ToCreature()
Definition Object.h:207
ItemTemplate const * GetItemTemplate(uint32 entry)
uint64 GetPlayerGUIDByName(std::string const &name) const
uint32 _hiAreaTriggerGuid
Definition ObjectMgr.h:1465
CharacterConversionMap FactionChangeAchievements
Definition ObjectMgr.h:1359
std::set< uint32 > _difficultyEntries[4 - 1]
Definition ObjectMgr.h:1600
void LoadResearchDigsiteInfo()
uint32 GenerateLowGuid(HighGuid guidhigh)
TempSummonDataContainer _tempSummonDataStore
Stores temp summon data grouped by summoner's entry, summoner's type and group id.
Definition ObjectMgr.h:1582
std::set< uint8 > BattlePetQualitySet
Definition ObjectMgr.h:1532
QuestRelations _creatureQuestInvolvedRelations
Definition ObjectMgr.h:1502
PetLevelInfo const * GetPetLevelInfo(uint32 creature_id, uint8 level) const
PlayerInfo * _playerInfo[MAX_RACES][MAX_CLASSES]
Definition ObjectMgr.h:1554
VehicleAccessoryList const * GetVehicleAccessoryList(Vehicle *veh) const
bool LoadSkyFireStrings()
Definition ObjectMgr.h:976
VehicleAccessoryContainer _vehicleAccessoryStore
Definition ObjectMgr.h:1518
ResearchDigsiteContainer _researchDigsiteStore
Definition ObjectMgr.h:1612
QuestObjectiveLocale const * GetQuestObjectiveLocale(uint32 objectiveId) const
WorldSafeLocsEntry const * GetDefaultGraveYard(uint32 team)
uint32 GetXPForLevel(uint8 level) const
BattlePetQualityXSpeciesMap sBattlePetQualityXSpeciesStore
Definition ObjectMgr.h:1536
CreatureBaseStats const * GetCreatureBaseStats(uint8 level, uint8 unitClass)
GameTele const * GetGameTeleExactName(std::string const &name) const
WorldSafeLocsEntry const * GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
bool AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool persist=true)
uint32 GetAreaTriggerScriptId(uint32 trigger_id)
void LoadReputationOnKill()
PointOfInterest const * GetPointOfInterest(uint32 id) const
Definition ObjectMgr.h:882
void LoadEventScripts()
void LoadGameObjectTemplate()
void LoadFactionChangeSpells()
TavernRestAreaContainer _tavernRestAreaStore
Definition ObjectMgr.h:1480
void RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool persist=false)
void LoadFactionChangeItems()
void LoadAreaTriggerTeleports()
SceneTemplateContainer _sceneTemplateStore
Definition ObjectMgr.h:1597
void LoadNpcTextLocales()
GameTeleContainer _gameTeleStore
Definition ObjectMgr.h:1509
void LoadPageTextLocales()
uint32 GetPlayerAccountIdByGUID(uint64 guid) const
HalfNameContainer _petHalfName1
Definition ObjectMgr.h:1567
GossipTextContainer _gossipTextStore
Definition ObjectMgr.h:1482
void LoadInstanceTemplate()
void LoadScriptNames()
HotfixData _hotfixData
Definition ObjectMgr.h:1610
void LoadItemScriptNames()
uint32 GetTaxiMountDisplayId(uint32 id, uint32 team, bool allowed_alt_team=false)
void LoadSpellScripts()
SpellScriptsContainer _spellScriptsStore
Definition ObjectMgr.h:1515
void LoadPlayerCreateCastSpellsData()
CreatureDataContainer _creatureDataStore
Definition ObjectMgr.h:1570
void LoadPageTexts()
void ValidateSpellScripts()
uint32 _hiCreatureGuid
Definition ObjectMgr.h:1458
void LoadGraveyardOrientations()
void LoadCreatureQuestEnders()
QuestRelations _goQuestRelations
Definition ObjectMgr.h:1498
CreatureBaseStatsContainer _creatureBaseStatsStore
Definition ObjectMgr.h:1546
void RemoveCreatureFromGrid(uint32 guid, CreatureData const *data)
void LoadSceneTemplates()
void LoadGameobjectQuestEnders()
SkyFireStringLocaleContainer _SkyfireStringLocaleStore
Definition ObjectMgr.h:1589
void LoadCreatureLocales()
uint32 _hiPetGuid
Definition ObjectMgr.h:1459
ScriptNameContainer _scriptNamesStore
Definition ObjectMgr.h:1511
GameObjectTemplate const * GetGameObjectTemplate(uint32 entry)
TavernAreaTriggerContainer _tavernAreaTriggerStore
Definition ObjectMgr.h:1479
void LoadCreatureClassLevelStats()
PlayerInfo const * GetPlayerInfo(uint32 race, uint32 class_) const
int LoadReferenceVendor(int32 vendor, int32 item, uint8 type, std::set< uint32 > *skip_vendors)
void LoadCreatureTemplates()
GossipText const * GetGossipText(uint32 Text_ID) const
CacheTrainerSpellContainer _cacheTrainerSpellStore
Definition ObjectMgr.h:1595
PageTextLocaleContainer _pageTextLocaleStore
Definition ObjectMgr.h:1588
GameObjectData const * GetGOData(uint32 guid) const
Definition ObjectMgr.h:1234
EquipmentInfoContainer _equipmentInfoStore
Definition ObjectMgr.h:1575
void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
uint32 _hiVehicleGuid
Definition ObjectMgr.h:1460
AccessRequirementContainer _accessRequirementStore
Definition ObjectMgr.h:1485
void LoadQuestAreaTriggers()
uint32 GetScriptId(const char *name)
CreatureAddon const * GetCreatureAddon(uint32 lowguid)
CreatureAddonContainer _creatureTemplateAddonStore
Definition ObjectMgr.h:1574
CreatureTemplateContainer _creatureTemplateStore
Definition ObjectMgr.h:1571
bool AddGameTele(GameTele &data)
static bool CheckDeclinedNames(const std::wstring &w_ownname, DeclinedName const &names)
const char * GetScriptName(uint32 id) const
Definition ObjectMgr.h:1322
void LoadFactionChangeAchievements()
static PetNameInvalidReason CheckPetName(std::string const &name)
static void AddLocaleString(std::string const &s, LocaleConstant locale, StringVector &data)
static uint32 ChooseDisplayId(CreatureTemplate const *cinfo, CreatureData const *data=NULL)
TerrainPhaseInfo _terrainMapDefaultStore
Definition ObjectMgr.h:1526
CharacterConversionMap FactionChangeReputation
Definition ObjectMgr.h:1362
uint64 BattlePetGetNewId()
SpellScriptsBounds GetSpellScriptsBounds(uint32 spellId)
ExclusiveQuestGroups mExclusiveQuestGroups
Definition ObjectMgr.h:1127
void AddGameobjectToGrid(uint32 guid, GameObjectData const *data)
void LoadBattlePetBreedData()
void LoadFactionChangeReputations()
uint32 _mailId
Definition ObjectMgr.h:1452
static ResponseCodes CheckPlayerName(std::string const &name, bool create=false)
void LoadPetNumber()
void AddCreatureToGrid(uint32 guid, CreatureData const *data)
GameObjectTemplateContainer _gameObjectTemplateStore
Definition ObjectMgr.h:1580
void LoadReputationSpilloverTemplate()
uint32 GetPlayerAccountIdByPlayerName(std::string const &name) const
void LoadExplorationBaseXP()
void LoadFishingBaseSkillLevel()
std::set< uint32 > _hasDifficultyEntries[4 - 1]
Definition ObjectMgr.h:1601
uint8 BattlePetGetRandomQuality(uint32 speciesId) const
void LoadPetLevelInfo()
uint64 GenerateVoidStorageItemId()
void GetPlayerClassLevelInfo(uint32 class_, uint8 level, uint32 &baseHP, uint32 &baseMana) const
void LoadArchaeologyFindInfo()
void GetPlayerLevelInfo(uint32 race, uint32 class_, uint8 level, PlayerLevelInfo *info) const
bool GetPlayerNameByGUID(uint64 guid, std::string &name) const
PhaseInfo _phases
Definition ObjectMgr.h:1528
EquipmentInfo const * GetEquipmentInfo(uint32 entry, int8 &id)
void LoadLinkedRespawn()
void LoadEquipmentTemplates()
void LoadGossipMenu()
bool QuestObjectiveExists(uint32 objectiveId) const
void DeleteCreatureData(uint32 guid)
void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const *data)
ItemTemplateContainer _itemTemplateStore
Definition ObjectMgr.h:1584
GameObjectDataContainer _gameObjectDataStore
Definition ObjectMgr.h:1578
void LoadGraveyardZones()
uint32 GeneratePetNumber()
GossipMenusContainer _gossipMenusStore
Definition ObjectMgr.h:1492
uint32 GetQuestObjectiveQuestId(uint32 objectiveId) const
uint32 GetNearestTaxiNode(float x, float y, float z, uint32 mapid, uint32 team)
void LoadTerrainWorldMaps()
void LoadPlayerInfo()
void LoadGossipMenuItemsLocales()
VehicleAccessoryContainer _vehicleTemplateAccessoryStore
Definition ObjectMgr.h:1517
void LoadQuests()
CreatureLocaleContainer _creatureLocaleStore
Definition ObjectMgr.h:1577
void CheckCreatureTemplate(CreatureTemplate const *cInfo)
TerrainPhaseInfo _terrainPhaseInfoStore
Definition ObjectMgr.h:1525
void LoadHotfixData()
SkyFireStringLocale const * GetSkyFireStringLocale(int32 entry) const
Definition ObjectMgr.h:1243
void LoadPlayerCreateItemsData()
uint8 BattlePetGetRandomBreed(uint32 speciesId) const
void LoadGameTele()
PointOfInterestLocaleContainer _pointOfInterestLocaleStore
Definition ObjectMgr.h:1591
InstanceTemplateContainer _instanceTemplateStore
Definition ObjectMgr.h:1523
void DeleteGOData(uint32 guid)
void LoadTerrainSwapDefaults()
void LoadQuestLocales()
void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel)
QuestRelations _goQuestInvolvedRelations
Definition ObjectMgr.h:1499
void LoadNPCSpellClickSpells()
void LoadCorpses()
QuestAreaTriggerContainer _questAreaTriggerStore
Definition ObjectMgr.h:1478
CreatureData & NewOrExistCreatureData(uint32 guid)
Definition ObjectMgr.h:1176
void LoadQuestObjectiveLocales()
FishingBaseSkillContainer _fishingBaseForAreaStore
Definition ObjectMgr.h:1563
AreaTriggerContainer _areaTriggerStore
Definition ObjectMgr.h:1483
uint32 _hiCharGuid
Definition ObjectMgr.h:1457
@ CREATURE_TO_CREATURE
Definition ObjectMgr.h:1605
uint32 _hiItemGuid
Definition ObjectMgr.h:1461
uint32 AddGOData(uint32 entry, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay=0, float rotation0=0, float rotation1=0, float rotation2=0, float rotation3=0)
void LoadAccessRequirements()
MapObjectGuids _mapObjectGuidsStore
Definition ObjectMgr.h:1569
CreatureAddonContainer _creatureAddonStore
Definition ObjectMgr.h:1573
ArchaeologyFindContainer _archaeologyFindStore
Definition ObjectMgr.h:1613
bool IsValidPlayerCreateClass(uint32 currentClass)
GraveyardOrientationContainer _graveyardOrientations
Definition ObjectMgr.h:1598
PetLevelInfoContainer _petInfoStore
Definition ObjectMgr.h:1550
GameObjectForQuestContainer _gameObjectForQuestStore
Definition ObjectMgr.h:1481
MailLevelRewardContainer _mailLevelRewardStore
Definition ObjectMgr.h:1544
AreaTriggerStruct const * GetGoBackTrigger(uint32 Map) const
void LoadVehicleTemplateAccessories()
Player * GetPlayerByLowGUID(uint32 lowguid) const
NpcTextLocaleContainer _npcTextLocaleStore
Definition ObjectMgr.h:1587
VendorItemData const * GetNpcVendorItemList(uint32 entry) const
Definition ObjectMgr.h:1298
HalfNameContainer _petHalfName0
Definition ObjectMgr.h:1566
void LoadGameObjectLocales()
void LoadAreaPhases()
ResearchProjectRequirementContainer _researchProjectRequirementStore
Definition ObjectMgr.h:1614
void LoadTempSummons()
void PlayerCreateInfoAddItemHelper(uint32 race_, uint32 class_, uint32 itemId, int32 count)
PageText const * GetPageText(uint32 pageEntry)
uint32 _hiCorpseGuid
Definition ObjectMgr.h:1464
void LoadCreatureTemplateAddons()
void LoadItemTemplates()
bool RemoveVendorItem(uint32 entry, uint32 item, uint8 type, bool persist=true)
QuestMap _questTemplates
Definition ObjectMgr.h:1469
CharacterConversionMap FactionChangeSpells
Definition ObjectMgr.h:1363
uint32 GetBaseXP(uint8 level)
bool IsValidPlayerCreateRace(uint32 currentRace)
void LoadPetNames()
CharacterConversionMap FactionChangeItems
Definition ObjectMgr.h:1360
void LoadBattlePetItemToSpeciesData()
uint32 _hiMoTransGuid
Definition ObjectMgr.h:1466
GossipMenuItemsLocaleContainer _gossipMenuItemsLocaleStore
Definition ObjectMgr.h:1590
CreatureModelInfo const * GetCreatureModelInfo(uint32 modelId)
BaseXPContainer _baseXPTable
Definition ObjectMgr.h:1560
void LoadQuestPOI()
void LoadTavernAreaTriggers()
void LoadReputationRewardRate()
AreaTriggerScriptContainer _areaTriggerScriptStore
Definition ObjectMgr.h:1484
QuestRelations _creatureQuestRelations
Definition ObjectMgr.h:1501
QuestLocaleContainer _questLocaleStore
Definition ObjectMgr.h:1586
std::set< uint8 > BattleBetBreedSet
Definition ObjectMgr.h:1530
uint32 _hiGoGuid
Definition ObjectMgr.h:1462
SceneTemplate const * GetSceneTemplate(uint32 sceneId) const
Quest const * GetQuestTemplate(uint32 quest_id) const
Definition ObjectMgr.h:794
void LoadPlayerCreateLevelStatsData()
DungeonEncounterContainer _dungeonEncounterStore
Definition ObjectMgr.h:1486
BattlePetBreedXSpeciesMap sBattlePetBreedXSpeciesStore
Definition ObjectMgr.h:1535
void LoadGameobjectQuestStarters()
void LoadScripts(ScriptsType type)
void LoadGossipText()
RepOnKillContainer _repOnKillStore
Definition ObjectMgr.h:1489
void LoadGameObjectForQuests()
AreaTriggerStruct const * GetMapEntranceTrigger(uint32 Map) const
void LoadFactionChangeTitles()
QuestObjectiveLocaleContainer m_questObjectiveLocaleStore
Definition ObjectMgr.h:1592
void LoadQuestObjectives()
CreatureModelInfo const * GetCreatureModelRandomGender(uint32 *displayID)
int32 GetBaseReputationOf(FactionEntry const *factionEntry, uint8 race, uint8 playerClass)
uint64 _equipmentSetGuid
Definition ObjectMgr.h:1450
RepSpilloverTemplateContainer _repSpilloverTemplateStore
Definition ObjectMgr.h:1490
uint32 GetPlayerTeamByGUID(uint64 guid) const
void LoadAreaTriggerScripts()
void ReturnOrDeleteOldMails(bool serverUp)
bool IsReservedName(std::string const &name) const
void LoadTerrainPhaseInfo()
static bool IsValidCharterName(std::string const &name)
void LoadItemLocales()
void LoadWaypointScripts()
CreatureModelContainer _creatureModelStore
Definition ObjectMgr.h:1572
bool DeleteGameTele(std::string const &name)
LinkedRespawnContainer _linkedRespawnStore
Definition ObjectMgr.h:1576
CreatureAddon const * GetCreatureTemplateAddon(uint32 entry)
uint64 GenerateEquipmentSetGuid()
GameObjectData & NewGOData(uint32 guid)
Definition ObjectMgr.h:1240
GraveYardContainer GraveYardStore
Definition ObjectMgr.h:1350
bool SetCreatureLinkedRespawn(uint32 guid, uint32 linkedGuid)
void LoadPlayerCreateActionData()
uint32 _auctionId
Definition ObjectMgr.h:1449
uint32 _hiDoGuid
Definition ObjectMgr.h:1463
void GetTaxiPath(uint32 source, uint32 destination, uint32 &path, uint32 &cost)
static void ChooseCreatureFlags(CreatureTemplate const *cinfo, uint32 &npcflag, uint32 &unit_flags, uint32 &dynamicflags, CreatureData const *data=NULL)
void LoadInstanceEncounters()
InstanceTemplate const * GetInstanceTemplate(uint32 mapId)
TerrainUIPhaseInfo _terrainWorldMapStore
Definition ObjectMgr.h:1527
uint32 m_battlePetId
Definition ObjectMgr.h:1467
GameObjectLocaleContainer _gameObjectLocaleStore
Definition ObjectMgr.h:1579
uint32 _itemTextId
Definition ObjectMgr.h:1451
void LoadBattlePetQualityData()
void LoadCreatureQuestStarters()
const char * GetSkyFireString(int32 entry, LocaleConstant locale_idx) const
GameTele const * GetGameTele(uint32 id) const
Definition ObjectMgr.h:1277
void CheckScripts(ScriptsType type, std::set< int32 > &ids)
void LoadItemTemplateAddon()
PlayerXPperLevel _playerXPperLevel
Definition ObjectMgr.h:1557
CacheVendorItemContainer _cacheVendorItemStore
Definition ObjectMgr.h:1594
void LoadSpellScriptNames()
void LoadMailLevelRewards()
void AddVendorItem(uint32 entry, uint32 item, int32 maxcount, uint32 incrtime, uint32 extendedCost, uint8 type, bool persist=true)
void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo *plinfo) const
void LoadDbScriptStrings()
PointOfInterestContainer _pointsOfInterestStore
Definition ObjectMgr.h:1494
uint32 _hiPetNumber
Definition ObjectMgr.h:1453
void LoadGameobjects()
CreatureData const * GetCreatureData(uint32 guid) const
Definition ObjectMgr.h:1170
void LoadPointsOfInterest()
void LoadFactionChangeQuests()
RepRewardRateContainer _repRewardRateStore
Definition ObjectMgr.h:1488
TavernRestArea const * GetTavernRestAreaAtPosition(uint32 mapId, float x, float y, float z) const
CharacterConversionMap FactionChangeTitles
Definition ObjectMgr.h:1364
uint32 GenerateAuctionID()
void LoadPlayerCreateSpellsData()
std::string GeneratePetName(uint32 entry)
GraveYardData const * FindGraveYardData(uint32 id, uint32 zone)
void LoadPointOfInterestLocales()
void LoadQuestObjectiveVisualEffects()
bool IsInTavernRestArea(TavernRestArea const &restArea, uint32 mapId, float x, float y, float z, float padding=0.0f) const
PageTextContainer _pageTextStore
Definition ObjectMgr.h:1522
bool MoveCreData(uint32 guid, uint32 map, const Position &pos)
bool IsTavernAreaTrigger(uint32 Trigger_ID) const
Definition ObjectMgr.h:810
void LoadGossipMenuItems()
void LoadResearchProjectRequirements()
uint32 GenerateMailID()
ItemLocaleContainer _itemLocaleStore
Definition ObjectMgr.h:1585
void LoadVehicleAccessories()
bool IsVendorItemValid(uint32 vendor_entry, uint32 id, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type, Player *player=NULL, std::set< uint32 > *skip_vendors=NULL, uint32 ORnpcflag=0) const
void LoadVendors()
void LoadCreatureModelInfo()
void SetHighestGuids()
CharacterConversionMap FactionChangeQuests
Definition ObjectMgr.h:1361
void LoadReservedPlayersNames()
QuestPOIContainer _questPOIStore
Definition ObjectMgr.h:1496
CreatureTemplate const * GetCreatureTemplate(uint32 entry)
SpellClickInfoContainer _spellClickInfoStore
Definition ObjectMgr.h:1513
ReservedNamesContainer _reservedNamesStore
Definition ObjectMgr.h:1507
uint32 AddCreData(uint32 entry, uint32 team, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay=0)
void LoadPlayerCreateXpData()
GossipMenuItemsContainer _gossipMenuItemsStore
Definition ObjectMgr.h:1493
uint64 _voidItemId
Definition ObjectMgr.h:1454
void LoadQuestRelationsHelper(QuestRelations &map, std::string const &table, bool starter, bool go)
void LoadCreatureAddons()
void LoadCreatures()
QuestObjectiveLookupMap m_questObjectiveLookup
Definition ObjectMgr.h:1470
void LoadTrainerSpell()
TavernRestArea const * GetTavernRestArea(uint32 triggerId) const
WorldSession * GetSession() const
Definition Player.h:2417
static uint32 TeamForRace(uint8 race)
Definition Player.cpp:7072
bool m_mailsLoaded
Definition Player.h:1927
void setFloat(const uint8 index, const float value)
void setString(const uint8 index, const std::string &value)
void setUInt16(const uint8 index, const uint16 value)
void setUInt64(const uint8 index, const uint64 value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt8(const uint8 index, const uint8 value)
bool HasSpecialFlag(uint32 flag) const
Definition QuestDef.h:266
uint32 RewardMailDelay
Definition QuestDef.h:439
uint32 MinLevel
Definition QuestDef.h:399
uint32 RewardCurrencyCount[QUEST_REWARD_CURRENCY_COUNT]
Definition QuestDef.h:364
uint32 LimitTime
Definition QuestDef.h:412
uint32 RequiredMaxRepFaction
Definition QuestDef.h:409
int32 RewardSpellCast
Definition QuestDef.h:437
uint32 SourceSpellid
Definition QuestDef.h:424
uint32 RequiredMinRepFaction
Definition QuestDef.h:407
int32 ZoneOrSort
Definition QuestDef.h:398
int32 NextQuestId
Definition QuestDef.h:419
void SetSpecialFlag(uint32 flag)
Definition QuestDef.h:267
uint32 RequiredSourceItemId[QUEST_SOURCE_ITEM_IDS_COUNT]
Definition QuestDef.h:349
uint32 GetCharTitleId() const
Definition QuestDef.h:291
uint32 RewardTitleId
Definition QuestDef.h:414
uint8 GetQuestObjectiveCountType(uint8 type) const
Definition QuestDef.cpp:320
uint32 RewardItemIdCount[QUEST_REWARDS_COUNT]
Definition QuestDef.h:354
uint32 RewardChoiceItemId[QUEST_REWARD_CHOICES_COUNT]
Definition QuestDef.h:351
uint32 RewardMailTemplateId
Definition QuestDef.h:438
uint32 SoundTurnIn
Definition QuestDef.h:458
uint32 RequiredRaces
Definition QuestDef.h:404
int32 GetNextQuestId() const
Definition QuestDef.h:288
int32 RewardFactionValueIdOverride[QUEST_REPUTATIONS_COUNT]
Definition QuestDef.h:357
ObjectiveTypeCountVec m_questObjecitveTypeCount
Definition QuestDef.h:392
uint32 RequiredSkillPoints
Definition QuestDef.h:406
uint32 SourceItemId
Definition QuestDef.h:423
uint32 RewardChoiceItemCount[QUEST_REWARD_CHOICES_COUNT]
Definition QuestDef.h:352
int32 GetPrevQuestId() const
Definition QuestDef.h:287
uint32 GetQuestId() const
Definition QuestDef.h:270
int32 RequiredMaxRepValue
Definition QuestDef.h:410
uint32 RequiredClasses
Definition QuestDef.h:403
uint32 RequiredSourceItemCount[QUEST_SOURCE_ITEM_IDS_COUNT]
Definition QuestDef.h:350
QuestObjectiveSet m_questObjectives
Definition QuestDef.h:378
uint32 Flags
Definition QuestDef.h:413
uint32 NextQuestIdChain
Definition QuestDef.h:421
PrevQuests prevQuests
Definition QuestDef.h:373
uint32 RewardCurrencyId[QUEST_REWARD_CURRENCY_COUNT]
Definition QuestDef.h:363
int32 PrevQuestId
Definition QuestDef.h:418
uint32 RewardSkillId
Definition QuestDef.h:448
uint32 RewardFactionId[QUEST_REPUTATIONS_COUNT]
Definition QuestDef.h:355
uint32 RewardSpell
Definition QuestDef.h:436
uint32 SoundAccept
Definition QuestDef.h:457
int32 ExclusiveGroup
Definition QuestDef.h:420
uint32 RequiredSkillId
Definition QuestDef.h:405
int32 RewardFactionValueId[QUEST_REPUTATIONS_COUNT]
Definition QuestDef.h:356
uint32 RewardItemId[QUEST_REWARDS_COUNT]
Definition QuestDef.h:353
uint32 GetQuestMethod() const
Definition QuestDef.h:271
uint32 RewardSkillPoints
Definition QuestDef.h:449
int32 RequiredMinRepValue
Definition QuestDef.h:408
uint32 SpecialFlags
Definition QuestDef.h:463
QuestObjective const * GetQuestObjective(uint32 objectiveId) const
Definition QuestDef.cpp:293
static const int32 Reputation_Cap
uint32 TriggerSpell
Definition SpellInfo.h:108
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:102
SpellEffectInfo Effects[MAX_SPELL_EFFECTS]
Definition SpellInfo.h:255
uint32 SpellLevel
Definition SpellInfo.h:206
SpellInfo const * GetFirstRankSpell() const
uint32 Id
Definition SpellInfo.h:160
bool IsRanked() const
SpellInfo const * GetNextRankSpell() const
bool IsProfession() const
bool HasAura(AuraType aura) const
static bool IsSpellValid(SpellInfo const *spellInfo, Player *player=NULL, bool msg=true)
Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book,...
Definition SpellMgr.cpp:319
bool _Validate(SpellInfo const *entry)
Unit * GetSummoner() const
size_type size() const
Definition Util.h:46
StorageType::const_iterator const_iterator
Definition Util.h:35
const_iterator end() const
Definition Util.h:44
const_iterator begin() const
Definition Util.h:43
Definition Unit.h:1367
TempSummon * ToTempSummon()
Definition Unit.h:2821
bool IsSummon() const
Definition Unit.h:1503
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:7253
bool IsFriendlyTo(Unit const *unit) const
Definition Unit.cpp:2283
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:7234
Unit * GetBase() const
May be called from scripts.
Definition Vehicle.h:38
uint32 GetCreatureEntry() const
Definition Vehicle.h:40
static void StopNow(uint8 exitcode)
Definition World.h:674
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
WorldDatabaseWorkerPool WorldDatabase
Accessor to the world database.
Definition Main.cpp:40
#define sWorld
Definition World.h:910
@ CONFIG_REALM_ZONE
Definition World.h:209
@ CONFIG_MIN_PET_NAME
Definition World.h:215
@ CONFIG_MAX_PLAYER_LEVEL
Definition World.h:224
@ CONFIG_STRICT_PET_NAMES
Definition World.h:212
@ CONFIG_MIN_CHARTER_NAME
Definition World.h:214
@ CONFIG_STRICT_PLAYER_NAMES
Definition World.h:210
@ CONFIG_MIN_PLAYER_NAME
Definition World.h:213
@ CONFIG_STRICT_CHARTER_NAMES
Definition World.h:211
@ CONFIG_START_ALL_SPELLS
Definition World.h:135
@ REALM_ZONE_TEST_SERVER
Definition World.h:497
@ REALM_ZONE_LATIN_AMERICA
Definition World.h:475
@ REALM_ZONE_SPANISH
Definition World.h:482
@ REALM_ZONE_OCEANIC
Definition World.h:474
@ REALM_ZONE_KOREA
Definition World.h:477
@ REALM_ZONE_UNKNOWN
Definition World.h:471
@ REALM_ZONE_UNITED_STATES
Definition World.h:473
@ REALM_ZONE_ENGLISH
Definition World.h:479
@ REALM_ZONE_FRENCH
Definition World.h:481
@ REALM_ZONE_QA_SERVER
Definition World.h:499
@ REALM_ZONE_CHINA
Definition World.h:487
@ REALM_ZONE_RUSSIAN
Definition World.h:483
@ REALM_ZONE_DEVELOPMENT
Definition World.h:472
@ REALM_ZONE_TAIWAN
Definition World.h:485
@ REALM_ZONE_GERMAN
Definition World.h:480
@ ERROR_EXIT_CODE
Definition World.h:65
bool IsDisabledFor(DisableType type, uint32 entry, Unit const *unit, uint8 flags)
void LogMissingAnimationData(uint32, uint32, uint32)
void LogRegisteredSpawn(LegacyTransportSpawnDiagnostic const &)
uint32 GetAllowedSpawnMask(uint32 dbEntry, uint32 mapId, uint32 spawnMask)
char const * GetGossipMenuOptionLocaleLoadQuery()
char const * GetGossipMenuOptionLoadQuery()
uint32 GetRootZoneId(uint32 areaId)
bool HasInnAreaBounds(InnAreaBounds const &bounds)
bool IsInsideInnArea(InnAreaBounds const &bounds, uint32 mapId, float x, float y, float z, float padding)
bool LocalTime(time_t const &time, tm &result)
Definition TimeUtils.h:57
bool IsValidMapCoord(float c)
CellCoord ComputeCellCoord(float x, float y)
int32 ItemStatValue
int32 ItemStatUnk2
uint32 ItemStatType
int32 ItemStatUnk1
uint32 Content
uint32 Color
int32 SpellCharges
uint32 SpellTrigger
int32 SpellCategoryCooldown
int32 SpellCooldown
uint32 SpellCategory
int32 SpellId
std::string questFailedText
Definition Player.h:950
uint32 achievement
Definition Player.h:949
uint32 mapid
float target_Orientation
Definition ObjectMgr.h:410
uint32 Flags
uint32 NpcId
CellGuidSet gameobjects
Definition ObjectMgr.h:418
CellGuidSet creatures
Definition ObjectMgr.h:417
CellCorpseSet corpses
Definition ObjectMgr.h:419
int32 ItemId[MAX_OUTFIT_ITEMS]
uint32 model_f
uint32 model_m
uint32 GetId() const
std::vector< uint32 > auras
Definition Creature.h:330
uint32 mount
Definition Creature.h:326
uint32 emote
Definition Creature.h:329
uint32 path_id
Definition Creature.h:325
uint32 bytes1
Definition Creature.h:327
uint32 bytes2
Definition Creature.h:328
uint32 BaseHealth[MAX_CREATURE_BASE_HP]
Definition Creature.h:199
uint32 GenerateMana(CreatureTemplate const *info) const
Definition Creature.h:207
uint32 GenerateHealth(CreatureTemplate const *info) const
Definition Creature.cpp:122
uint32 spawntimesecs
Definition Creature.h:270
uint32 dynamicflags
Definition Creature.h:279
uint32 phaseid
Definition Creature.h:262
uint32 id
Definition Creature.h:260
uint32 npcflag
Definition Creature.h:277
uint32 displayid
Definition Creature.h:264
uint8 movementType
Definition Creature.h:275
uint32 phaseGroup
Definition Creature.h:263
uint32 unit_flags
Definition Creature.h:278
uint32 spawnMask
Definition Creature.h:276
float spawndist
Definition Creature.h:271
uint32 curhealth
Definition Creature.h:273
float orientation
Definition Creature.h:269
uint32 curmana
Definition Creature.h:274
int8 equipmentId
Definition Creature.h:265
uint32 currentwaypoint
Definition Creature.h:272
uint16 mapid
Definition Creature.h:261
float scale
StringVector Name
Definition Creature.h:228
StringVector SubName
Definition Creature.h:229
uint32 modelid_other_gender
Definition Creature.h:288
float bounding_radius
Definition Creature.h:285
uint32 unit_flags
Definition Creature.h:94
uint32 trainer_class
Definition Creature.h:99
uint32 trainer_race
Definition Creature.h:100
uint32 Modelid4
Definition Creature.h:70
float dmg_multiplier
Definition Creature.h:90
uint32 Modelid1
Definition Creature.h:67
std::string SubName
Definition Creature.h:72
uint32 SkinLootId
Definition Creature.h:109
uint32 Modelid2
Definition Creature.h:68
uint32 MechanicImmuneMask
Definition Creature.h:128
std::string Name
Definition Creature.h:71
int32 resistance[MAX_SPELL_SCHOOL]
Definition Creature.h:110
uint32 DifficultyEntry[4 - 1]
Definition Creature.h:65
uint32 faction_A
Definition Creature.h:79
uint32 pickpocketLootId
Definition Creature.h:108
uint32 KillCredit[MAX_KILL_CREDIT]
Definition Creature.h:66
uint32 InhabitType
Definition Creature.h:118
uint32 MovementType
Definition Creature.h:117
uint32 flags_extra
Definition Creature.h:129
uint32 expansionUnknown
Definition Creature.h:78
uint32 type_flags
Definition Creature.h:105
uint32 attackpower
Definition Creature.h:89
uint32 unit_flags2
Definition Creature.h:95
uint32 dmgschool
Definition Creature.h:88
uint32 rangeattacktime
Definition Creature.h:92
uint32 expansion
Definition Creature.h:77
uint32 trainer_type
Definition Creature.h:98
uint32 rangedattackpower
Definition Creature.h:103
uint32 GossipMenuId
Definition Creature.h:74
uint32 spells[CREATURE_MAX_SPELLS]
Definition Creature.h:111
uint32 unit_class
Definition Creature.h:93
uint32 baseattacktime
Definition Creature.h:91
uint32 faction_H
Definition Creature.h:80
std::string AIName
Definition Creature.h:116
uint32 questItems[MAX_CREATURE_QUEST_ITEMS]
Definition Creature.h:125
uint32 type_flags2
Definition Creature.h:106
uint32 Modelid3
Definition Creature.h:69
uint32 GetRandomValidModelId() const
Definition Creature.cpp:79
uint32 dynamicflags
Definition Creature.h:96
uint32 movementId
Definition Creature.h:126
uint32 PetSpellDataId
Definition Creature.h:112
std::string IconName
Definition Creature.h:73
std::string name[MAX_DECLINED_NAME_CASES]
Definition Unit.h:1102
uint32 mapId
int32 difficulty
char * encounterName
uint32 ItemEntry[MAX_EQUIPMENT_ITEMS]
Definition Creature.h:245
int32 BaseRepValue[4]
uint32 team
uint32 BaseRepRaceMask[4]
uint32 BaseRepClassMask[4]
int32 reputationListID
uint32 phaseGroup
Definition GameObject.h:593
int32 spawntimesecs
Definition GameObject.h:602
uint32 animprogress
Definition GameObject.h:603
GOState go_state
Definition GameObject.h:604
StringVector CastBarCaption
Definition GameObject.h:570
StringVector Name
Definition GameObject.h:569
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@114312050106372302366137106154036240136321221160 barberChair
uint32 questItems[MAX_GAMEOBJECT_QUEST_ITEMS]
Definition GameObject.h:35
uint32 data[MAX_GAMEOBJECT_DATA]
Definition GameObject.h:385
std::string AIName
Definition GameObject.h:389
std::string unk1
Definition GameObject.h:31
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@076042223047135343272115231235004103107103052206 raw
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@253305212064111242104116123236360243075266147175 flagstand
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@152130076372303155010023156377005036224346144151 camera
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@154136051106040324176270267211357174344063050360 chest
bool IsDespawnAtAction() const
Definition GameObject.h:393
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@076241013146174060203322361030304357327036335177 spellFocus
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@334327144355150311317234223372371064337023010042 trap
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@316034272062200025205312222263007157266267301257 chair
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@243266127071011160240350104214013054067132104252 fishinghole
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@110054372326320106132141070072073073207136033072 areadamage
std::string name
Definition GameObject.h:28
std::string castBarCaption
Definition GameObject.h:30
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@315077355127077256043020131262337362171234125061 spellcaster
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@041347154150020206261150105351300331163012356113 flagdrop
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@030154355127376377116310314155367165157323234200 door
std::string IconName
Definition GameObject.h:29
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@316212233253022127367165230227137227160036113140 moTransport
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@336001126101306307066053364273045317014372227110 questgiver
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@336060043160212225074214221232260020127013174055 goober
struct GameObjectTemplate::@046065176235271051340241126110345143267101032070::@035305233304037036156142147071371001131016202245 button
float position_y
Definition ObjectMgr.h:127
float orientation
Definition ObjectMgr.h:129
float position_x
Definition ObjectMgr.h:126
uint32 mapId
Definition ObjectMgr.h:130
std::string name
Definition ObjectMgr.h:131
float position_z
Definition ObjectMgr.h:128
std::wstring wnameLow
Definition ObjectMgr.h:132
uint32 BoxBroadcastTextID
Definition ObjectMgr.h:540
std::string OptionText
Definition ObjectMgr.h:531
uint32 ActionMenuID
Definition ObjectMgr.h:535
uint32 ActionPoiID
Definition ObjectMgr.h:536
uint32 OptionNpcflag
Definition ObjectMgr.h:534
std::string BoxText
Definition ObjectMgr.h:539
uint32 OptionType
Definition ObjectMgr.h:533
uint32 OptionBroadcastTextID
Definition ObjectMgr.h:532
StringVector BoxText
Definition Creature.h:235
StringVector OptionText
Definition Creature.h:234
uint32 entry
Definition ObjectMgr.h:546
uint32 text_id
Definition ObjectMgr.h:547
GossipTextOption Options[MAX_GOSSIP_TEXT_OPTIONS]
Definition NPCHandler.h:31
std::string Text_0
Definition NPCHandler.h:20
QEmote Emotes[MAX_GOSSIP_TEXT_EMOTES]
Definition NPCHandler.h:24
std::string Text_1
Definition NPCHandler.h:21
uint32 safeLocId
Definition ObjectMgr.h:597
float ratio
float ratio
uint32 Timestamp
Definition ObjectMgr.h:661
uint32 Entry
Definition ObjectMgr.h:662
uint32 Type
Definition ObjectMgr.h:660
bool AllowMount
Definition Map.h:221
uint32 Parent
Definition Map.h:219
uint32 ScriptId
Definition Map.h:220
float DPS[7]
uint32 RequiredDisenchantSkill
uint32 Id
uint32 ItemQuality
uint32 MaxItemLevel
uint32 ItemClass
uint32 MinItemLevel
uint32 InventoryType
uint32 Class
uint32 DisplayId
int32 SoundOverrideSubclass
uint32 SubClass
StringVector Name
StringVector Description
int32 ItemStatUnk1[MAX_ITEM_PROTO_STATS]
uint32 RandomSuffix
uint32 ContainerSlots
uint32 DamageType
int32 AllowableRace
int32 CurrencySubstitutionCount
uint32 RequiredReputationRank
uint32 Stackable
float Unk430_1
int32 RequiredLevel
LocalizedString * Description
uint32 RequiredReputationFaction
uint32 Flags3
uint32 ScalingStatDistribution
uint32 BuyPrice
int32 SpellId[MAX_ITEM_PROTO_SPELLS]
int32 SpellTrigger[MAX_ITEM_PROTO_SPELLS]
uint32 Sheath
uint32 MaxCount
uint32 BuyCount
uint32 HolidayId
uint32 Flags
uint32 ItemStatValue[MAX_ITEM_PROTO_STATS]
uint32 RequiredHonorRank
float StatScalingFactor
int32 CurrencySubstitutionId
LocalizedString * Name
float Unk430_2
uint32 ItemLevel
int32 SpellCooldown[MAX_ITEM_PROTO_SPELLS]
uint32 Map
int32 SpellCategoryCooldown[MAX_ITEM_PROTO_SPELLS]
uint32 ItemSet
uint32 InventoryType
uint32 Area
uint32 Bonding
uint32 RequiredSpell
uint32 RequiredSkill
uint32 BagFamily
float ArmorDamageModifier
uint32 Content[MAX_ITEM_PROTO_SOCKETS]
uint32 GemProperties
uint32 RequiredCityRank
uint32 Quality
int32 AllowableClass
int32 ItemStatUnk2[MAX_ITEM_PROTO_STATS]
uint32 Delay
int32 ItemStatType[MAX_ITEM_PROTO_STATS]
uint32 RequiredSkillRank
uint32 Duration
uint32 ItemLimitCategory
uint32 LockID
uint32 Color[MAX_ITEM_PROTO_SOCKETS]
uint32 PageMaterial
int32 SpellCategory[MAX_ITEM_PROTO_SPELLS]
int32 Material
uint32 LanguageID
int32 SocketBonus
uint32 StartQuest
uint32 SellPrice
uint32 RandomProperty
uint32 PageText
uint32 TotemCategory
int32 SpellCharges[MAX_ITEM_PROTO_SPELLS]
float RangedModRange
uint32 Flags2
uint32 DisenchantID
uint32 RequiredCityRank
uint32 RequiredSkill
uint32 RequiredSpell
std::string Description
uint32 AllowableClass
uint32 RequiredSkillRank
uint32 RequiredHonorRank
float ArmorDamageModifier
_Spell Spells[MAX_ITEM_PROTO_SPELLS]
uint32 RequiredDisenchantSkill
uint32 TotemCategory
uint32 MinMoneyLoot
uint32 MaxMoneyLoot
float StatScalingFactor
uint32 PageMaterial
uint32 RequiredLevel
std::string Name1
uint32 GemProperties
uint32 CurrencySubstitutionCount
uint32 RequiredReputationRank
uint32 ContainerSlots
uint32 DisplayInfoID
uint32 AllowableRace
uint32 RequiredReputationFaction
uint32 ItemLimitCategory
uint32 ScalingStatDistribution
_ItemStat ItemStat[MAX_ITEM_PROTO_STATS]
uint32 MaxDurability
uint32 InventoryType
uint32 CurrencySubstitutionId
int32 SoundOverrideSubclass
_Socket Socket[MAX_ITEM_PROTO_SOCKETS]
char const * Str[TOTAL_LOCALES]
Definition Common.h:173
Definition Mail.h:156
uint8 messageType
Definition Mail.h:161
uint32 messageID
Definition Mail.h:160
uint64 COD
Definition Mail.h:173
time_t expire_time
Definition Mail.h:170
uint32 sender
Definition Mail.h:164
uint32 receiver
Definition Mail.h:165
std::vector< MailItemInfo > items
Definition Mail.h:168
time_t deliver_time
Definition Mail.h:171
uint32 checked
Definition Mail.h:174
uint16 mailTemplateId
Definition Mail.h:163
uint32 item_guid
Definition Mail.h:150
uint32 item_template
Definition Mail.h:151
float entrance_y
int32 entrance_map
bool IsInstance() const
bool IsBattlegroundOrArena() const
float entrance_x
bool Instanceable() const
std::vector< StringVector > Text_0
Definition NPCHandler.h:43
std::vector< StringVector > Text_1
Definition NPCHandler.h:44
uint16 NextPage
Definition ObjectMgr.h:52
std::string Text
Definition ObjectMgr.h:51
StringVector Text
Definition NPCHandler.h:36
uint16 health
Definition ObjectMgr.h:465
uint16 armor
Definition ObjectMgr.h:467
uint16 stats[MAX_STATS]
Definition ObjectMgr.h:464
uint16 mana
Definition ObjectMgr.h:466
float orientation
Definition Player.h:430
uint16 displayId_m
Definition Player.h:431
float positionX
Definition Player.h:427
uint32 areaId
Definition Player.h:426
float positionY
Definition Player.h:428
PlayerLevelInfo * levelInfo
Definition Player.h:438
float positionZ
Definition Player.h:429
uint32 mapId
Definition Player.h:425
uint16 displayId_f
Definition Player.h:432
uint16 stats[MAX_STATS]
Definition Player.h:402
std::string icon_name
Definition ObjectMgr.h:523
StringVector IconName
Definition Creature.h:240
float GetPositionZ() const
Definition Object.h:330
float GetOrientation() const
Definition Object.h:331
float GetPositionX() const
Definition Object.h:328
float GetPositionY() const
Definition Object.h:329
void Relocate(float x, float y)
Definition Object.h:302
uint32 _Emote
Definition NPCHandler.h:12
uint32 _Delay
Definition NPCHandler.h:13
StringVector QuestTurnTargetName
Definition QuestDef.h:223
StringVector OfferRewardText
Definition QuestDef.h:215
StringVector RequestItemsText
Definition QuestDef.h:216
StringVector CompletedText
Definition QuestDef.h:218
StringVector QuestTurnTextWindow
Definition QuestDef.h:222
StringVector QuestGiverTextWindow
Definition QuestDef.h:220
StringVector Details
Definition QuestDef.h:213
StringVector QuestGiverTargetName
Definition QuestDef.h:221
StringVector Title
Definition QuestDef.h:212
StringVector EndText
Definition QuestDef.h:217
StringVector Objectives
Definition QuestDef.h:214
VisualEffectVec VisualEffects
Definition QuestDef.h:246
std::vector< QuestPOIPoint > points
Definition ObjectMgr.h:576
float questMonthlyRate
Definition ObjectMgr.h:489
float questWeeklyRate
Definition ObjectMgr.h:488
float questDailyRate
Definition ObjectMgr.h:487
float questRepeatableRate
Definition ObjectMgr.h:490
float spellRate
Definition ObjectMgr.h:492
float questRate
Definition ObjectMgr.h:486
float creatureRate
Definition ObjectMgr.h:491
uint32 faction_rank[MAX_SPILLOVER_FACTIONS]
Definition ObjectMgr.h:512
uint32 faction[MAX_SPILLOVER_FACTIONS]
Definition ObjectMgr.h:510
float faction_rate[MAX_SPILLOVER_FACTIONS]
Definition ObjectMgr.h:511
Definition ObjectMgr.h:496
bool IsTeamAward2
Definition ObjectMgr.h:504
bool IsTeamAward1
Definition ObjectMgr.h:503
uint32 ReputationMaxCap1
Definition ObjectMgr.h:499
uint32 RepFaction1
Definition ObjectMgr.h:497
uint32 RepFaction2
Definition ObjectMgr.h:498
bool TeamDependent
Definition ObjectMgr.h:505
int32 RepValue1
Definition ObjectMgr.h:500
uint32 ReputationMaxCap2
Definition ObjectMgr.h:501
int32 RepValue2
Definition ObjectMgr.h:502
uint32 requiredSkillValue
Definition ObjectMgr.h:672
uint32 MapId
uint32 SceneId
Definition ObjectMgr.h:587
uint32 PlaybackFlags
Definition ObjectMgr.h:588
uint32 ScriptId
Definition ObjectMgr.h:590
uint32 ScenePackageId
Definition ObjectMgr.h:589
float Orientation
Definition ObjectMgr.h:252
uint32 Flags
Definition ObjectMgr.h:209
ScriptsType type
Definition ObjectMgr.h:193
uint32 QuestID
Definition ObjectMgr.h:257
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@235213206037260262323130355352141154322352336256 KillCredit
int32 TextID
Definition ObjectMgr.h:210
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@323144237034231264254170147314213276360375006374 RespawnGameobject
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@366202063362232017203072231044323334343276266221 CreateItem
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@215362176107272335311131263361174353005102016155 QuestExplored
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@060313056375165064134111275066130320355250202151 TempSummonCreature
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@051127012334050237002325262055013174250146206153 ToggleDoor
float DestX
Definition ObjectMgr.h:231
uint32 ItemEntry
Definition ObjectMgr.h:317
uint32 ChatType
Definition ObjectMgr.h:208
uint32 id
Definition ObjectMgr.h:194
uint32 delay
Definition ObjectMgr.h:195
float fData[4]
Definition ObjectMgr.h:203
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@056312253106117114176351200255000030100172357051 Raw
float PosY
Definition ObjectMgr.h:280
ScriptCommands command
Definition ObjectMgr.h:196
float DestY
Definition ObjectMgr.h:232
uint32 MapID
Definition ObjectMgr.h:245
uint32 nData[3]
Definition ObjectMgr.h:202
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@310207036336307321205127162152160034150247215165 RemoveAura
float PosZ
Definition ObjectMgr.h:281
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@340160313205203126365171223166355241073242151073 CastSpell
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@044166240220270000271314363001357235305117106163 Emote
float PosX
Definition ObjectMgr.h:279
uint32 Distance
Definition ObjectMgr.h:258
uint32 SpellID
Definition ObjectMgr.h:296
std::string GetDebugInfo() const
float DestZ
Definition ObjectMgr.h:233
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@203261325337225075157146047106312017011372377163 TeleportTo
struct ScriptInfo::@073000116166017043214113002234263016340307140354::@264374040335366155120321054324331165306344366303 Talk
uint32 GOGuid
Definition ObjectMgr.h:269
uint32 CreatureEntry
Definition ObjectMgr.h:263
uint32 Amount
Definition ObjectMgr.h:318
uint32 EmoteID
Definition ObjectMgr.h:215
uint32 id
int32 categoryId
StringVector Content
Definition ObjectMgr.h:437
bool IsFitToRequirements(Unit const *clicker, Unit const *clickee) const
SpellClickUserTypes userType
Definition ObjectMgr.h:395
float BoxOrientation
Definition ObjectMgr.h:148
uint32 TriggerId
Definition ObjectMgr.h:139
float z
uint32 map_id
float x
float y
uint32 MountCreatureID[2]
uint32 arrivalEventID
uint32 departureEventID
Stores data for temp summons.
TempSummonType type
Summon type, see TempSummonType for available types.
uint32 time
Despawn time, usable only with certain temp summon types.
uint32 entry
Entry of summoned creature.
Position pos
Position, where should be creature spawned.
Key for storing temp summon data in TempSummonDataContainer.
Definition ObjectMgr.h:57
TrainerSpellMap spellList
Definition Creature.h:413
uint32 trainerType
Definition Creature.h:414
uint32 reqSkillValue
Definition Creature.h:398
uint32 spellCost
Definition Creature.h:396
uint32 reqSkill
Definition Creature.h:397
uint32 reqLevel
Definition Creature.h:399
uint32 learnedSpell[MAX_SPELL_EFFECTS]
Definition Creature.h:400
uint32 spell
Definition Creature.h:395
VendorItem const * FindItemCostPair(uint32 item_id, uint32 extendedCost, uint8 type) const
Definition Creature.cpp:71
void AddItem(uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost, uint8 type)
Definition Creature.h:365
float x
float z
float y
uint32 map_id