diff options
Diffstat (limited to 'src/game/ObjectMgr.cpp')
-rw-r--r-- | src/game/ObjectMgr.cpp | 180 |
1 files changed, 120 insertions, 60 deletions
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index cbf445ebc6b..ec300715f86 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -178,6 +178,9 @@ ObjectMgr::~ObjectMgr() for (CachePlayerInfoMap::iterator itr = m_mPlayerInfoMap.begin(); itr != m_mPlayerInfoMap.end(); ++itr) delete itr->second; + for (ArenaTeamMap::iterator itr = mArenaTeamMap.begin(); itr != mArenaTeamMap.end(); ++itr) + delete itr->second; + for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr) itr->second.Clear(); @@ -635,7 +638,7 @@ void ObjectMgr::LoadCreatureTemplates() // used later for scale CreatureDisplayInfoEntry const* displayScaleEntry = NULL; - + if (cInfo->DisplayID_A[0]) { CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(cInfo->DisplayID_A[0]); @@ -703,6 +706,18 @@ void ObjectMgr::LoadCreatureTemplates() if (!displayScaleEntry) sLog.outErrorDb("Creature (Entry: %u) not has any existed display id in DisplayID_A/DisplayID_A2/DisplayID_H/DisplayID_H2", cInfo->Entry); + for(int k = 0; k < MAX_KILL_CREDIT; ++k) + { + if(cInfo->KillCredit[k]) + { + if(!GetCreatureTemplate(cInfo->KillCredit[k])) + { + sLog.outErrorDb("Creature (Entry: %u) has not existed creature entry in `KillCredit%d` (%u)",cInfo->Entry,k+1,cInfo->KillCredit[k]); + const_cast<CreatureInfo*>(cInfo)->KillCredit[k] = 0; + } + } + } + if (cInfo->unit_class && ((1 << (cInfo->unit_class-1)) & CLASSMASK_ALL_CREATURES) == 0) sLog.outErrorDb("Creature (Entry: %u) has invalid unit_class(%u) for creature_template", cInfo->Entry, cInfo->unit_class); @@ -786,7 +801,7 @@ void ObjectMgr::LoadCreatureTemplates() const_cast<CreatureInfo*>(cInfo)->scale = 1.0f; } - //const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank); + const_cast<CreatureInfo*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank); } } @@ -865,17 +880,17 @@ void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* endAura.effect_idx = 0; } -void ObjectMgr::LoadCreatureAddons() +void ObjectMgr::LoadCreatureAddons(SQLStorage& creatureaddons, char const* entryName, char const* comment) { - sCreatureInfoAddonStorage.Load(); + creatureaddons.Load(); - sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount ); + sLog.outString(">> Loaded %u %s", creatureaddons.RecordCount, comment); sLog.outString(); // check data correctness and convert 'auras' - for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) + for(uint32 i = 1; i < creatureaddons.MaxEntry; ++i) { - CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i); + CreatureDataAddon const* addon = creatureaddons.LookupEntry<CreatureDataAddon>(i); if(!addon) continue; @@ -883,49 +898,41 @@ void ObjectMgr::LoadCreatureAddons() { if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) { - sLog.outErrorDb("Creature (Entry %u) have invalid displayInfoId for mount (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->mount); + sLog.outErrorDb("Creature (%s %u) have invalid displayInfoId for mount (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->mount, creatureaddons.GetTableName()); const_cast<CreatureDataAddon*>(addon)->mount = 0; } } if (!sEmotesStore.LookupEntry(addon->emote)) - sLog.outErrorDb("Creature (Entry %u) have invalid emote (%u) defined in `creature_template_addon`.",addon->guidOrEntry, addon->emote); + sLog.outErrorDb("Creature (%s %u) have invalid emote (%u) defined in `%s`.", entryName, addon->guidOrEntry, addon->emote, creatureaddons.GetTableName()); - ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_template_addon", "Entry"); + /*if (addon->move_flags & (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)) + { + sLog.outErrorDb("Creature (%s %u) movement flags mask defined in `%s` include forbidden flags (" I32FMT ") that can crash client, cleanup at load.", entryName, addon->guidOrEntry, creatureaddons.GetTableName(), (MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4)); + const_cast<CreatureDataAddon*>(addon)->move_flags &= ~(MONSTER_MOVE_UNK1|MONSTER_MOVE_UNK4); + }*/ - if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry)) - sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry); + ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), creatureaddons.GetTableName(), entryName); } +} - sCreatureDataAddonStorage.Load(); - - sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount ); - sLog.outString(); - - // check data correctness and convert 'auras' - for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) - { - CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i); - if(!addon) - continue; - - if (addon->mount) - { - if (!sCreatureDisplayInfoStore.LookupEntry(addon->mount)) - { - sLog.outErrorDb("Creature (GUID %u) have invalid displayInfoId for mount (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->mount); - const_cast<CreatureDataAddon*>(addon)->mount = 0; - } - } +void ObjectMgr::LoadCreatureAddons() +{ + LoadCreatureAddons(sCreatureInfoAddonStorage,"Entry","creature template addons"); - if (!sEmotesStore.LookupEntry(addon->emote)) - sLog.outErrorDb("Creature (GUID %u) have invalid emote (%u) defined in `creature_addon`.",addon->guidOrEntry, addon->emote); + // check entry ids + for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i) + if(CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i)) + if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry)) + sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `%s`",addon->guidOrEntry, sCreatureInfoAddonStorage.GetTableName()); - ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_addon", "GUIDLow"); + LoadCreatureAddons(sCreatureDataAddonStorage,"GUID","creature addons"); - if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end()) - sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); - } + // check entry ids + for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i) + if(CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i)) + if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end()) + sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry); } EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry) @@ -1533,6 +1540,12 @@ void ObjectMgr::LoadGameobjects() data.rotation2 = fields[ 9].GetFloat(); data.rotation3 = fields[10].GetFloat(); data.spawntimesecs = fields[11].GetInt32(); + + if (data.spawntimesecs==0 && gInfo->IsDespawnAtAction()) + { + sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with `spawntimesecs` (0) value, but gameobejct marked as despawnable at action.",guid,data.id); + } + data.animprogress = fields[12].GetUInt32(); data.ArtKit = 0; @@ -2035,6 +2048,12 @@ void ObjectMgr::LoadItemPrototypes() const_cast<ItemPrototype*>(proto)->Stackable = 1000; } + if(proto->ContainerSlots > MAX_BAG_SIZE) + { + sLog.outErrorDb("Item (Entry: %u) has too large value in ContainerSlots (%u), replace by hardcoded limit (%u).",i,proto->ContainerSlots,MAX_BAG_SIZE); + const_cast<ItemPrototype*>(proto)->ContainerSlots = MAX_BAG_SIZE; + } + if(proto->StatsCount > MAX_ITEM_PROTO_STATS) { sLog.outErrorDb("Item (Entry: %u) has too large value in statscount (%u), replace by hardcoded limit (%u).",i,proto->StatsCount,MAX_ITEM_PROTO_STATS); @@ -2706,8 +2725,8 @@ void ObjectMgr::LoadPlayerInfo() // Load playercreate actions { - // 0 1 2 3 4 5 - QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action"); + // 0 1 2 3 4 + QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type FROM playercreateinfo_action"); uint32 count = 0; @@ -2742,10 +2761,7 @@ void ObjectMgr::LoadPlayerInfo() } PlayerInfo* pInfo = &playerInfo[current_race][current_class]; - pInfo->action[0].push_back(fields[2].GetUInt16()); - pInfo->action[1].push_back(fields[3].GetUInt16()); - pInfo->action[2].push_back(fields[4].GetUInt16()); - pInfo->action[3].push_back(fields[5].GetUInt16()); + pInfo->action.push_back(PlayerCreateInfoAction(fields[2].GetUInt8(),fields[3].GetUInt32(),fields[4].GetUInt8())); bar.step(); ++count; @@ -3901,13 +3917,20 @@ void ObjectMgr::LoadQuests() qinfo->RewSpell = 0; // no spell reward will display for this quest } - else if(!SpellMgr::IsSpellValid(spellInfo)) + if(!SpellMgr::IsSpellValid(spellInfo)) { - sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.", + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest will not have a spell reward.", qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); qinfo->RewSpell = 0; // no spell reward will display for this quest } + if(GetTalentSpellCost(qinfo->RewSpell)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell); + qinfo->RewSpell = 0; // no spell reward will display for this quest + continue; + } } if(qinfo->RewSpellCast) @@ -3921,13 +3944,20 @@ void ObjectMgr::LoadQuests() qinfo->RewSpellCast = 0; // no spell will be casted on player } - else if(!SpellMgr::IsSpellValid(spellInfo)) + if(!SpellMgr::IsSpellValid(spellInfo)) { - sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.", + sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest will not have a spell reward.", qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); qinfo->RewSpellCast = 0; // no spell will be casted on player } + if(GetTalentSpellCost(qinfo->RewSpellCast)) + { + sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is talent, quest will not have a spell reward.", + qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast); + qinfo->RewSpellCast = 0; // no spell will be casted on player + continue; + } } if(qinfo->RewMailTemplateId) @@ -6131,6 +6161,16 @@ inline void CheckGONoDamageImmuneId(GameObjectInfo const* goInfo,uint32 dataN,ui goInfo->id,goInfo->type,N,dataN); } +inline void CheckGOConsumable(GameObjectInfo const* goInfo,uint32 dataN,uint32 N) +{ + // 0/1 correct values + if (dataN <= 1) + return; + + sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data%d=%u but expected boolean (0/1) consumable field value.", + goInfo->id,goInfo->type,N,dataN); +} + void ObjectMgr::LoadGameobjectInfo() { SQLGameObjectLoader loader; @@ -6173,6 +6213,8 @@ void ObjectMgr::LoadGameobjectInfo() if (goInfo->chest.lockId) CheckGOLockId(goInfo,goInfo->chest.lockId,0); + CheckGOConsumable(goInfo,goInfo->chest.consumable,3); + if (goInfo->chest.linkedTrapId) // linked trap CheckGOLinkedTrapId(goInfo,goInfo->chest.linkedTrapId,7); break; @@ -6208,6 +6250,8 @@ void ObjectMgr::LoadGameobjectInfo() if (goInfo->goober.lockId) CheckGOLockId(goInfo,goInfo->goober.lockId,0); + CheckGOConsumable(goInfo,goInfo->goober.consumable,3); + if (goInfo->goober.pageId) // pageId { if (!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId)) @@ -7054,18 +7098,24 @@ bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bo return false; } -bool ObjectMgr::IsValidName( const std::string& name, bool create ) +uint8 ObjectMgr::CheckPlayerName( const std::string& name, bool create ) { std::wstring wname; if(!Utf8toWStr(name,wname)) - return false; + return CHAR_NAME_INVALID_CHARACTER; - if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME) - return false; + if(wname.size() > MAX_PLAYER_NAME) + return CHAR_NAME_TOO_LONG; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_PLAYER_NAME); + if(wname.size() < minName) + return CHAR_NAME_TOO_SHORT; uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES); + if(!isValidString(wname,strictMask,false,create)) + return CHAR_NAME_MIXED_LANGUAGES; - return isValidString(wname,strictMask,false,create); + return CHAR_NAME_SUCCESS; } bool ObjectMgr::IsValidCharterName( const std::string& name ) @@ -7074,7 +7124,11 @@ bool ObjectMgr::IsValidCharterName( const std::string& name ) if(!Utf8toWStr(name,wname)) return false; - if(wname.size() < 1) + if(wname.size() > MAX_CHARTER_NAME) + return false; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_CHARTER_NAME); + if(wname.size() < minName) return false; uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES); @@ -7082,18 +7136,24 @@ bool ObjectMgr::IsValidCharterName( const std::string& name ) return isValidString(wname,strictMask,true); } -bool ObjectMgr::IsValidPetName( const std::string& name ) +PetNameInvalidReason ObjectMgr::CheckPetName( const std::string& name ) { std::wstring wname; if(!Utf8toWStr(name,wname)) - return false; + return PET_NAME_INVALID; - if(wname.size() < 1) - return false; + if(wname.size() > MAX_PET_NAME) + return PET_NAME_TOO_LONG; + + uint32 minName = sWorld.getConfig(CONFIG_MIN_PET_NAME); + if(wname.size() < minName) + return PET_NAME_TOO_SHORT; uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES); + if(!isValidString(wname,strictMask,false)) + return PET_NAME_MIXED_LANGUAGES; - return isValidString(wname,strictMask,false); + return PET_NAME_SUCCESS; } int ObjectMgr::GetIndexForLocale( LocaleConstant loc ) @@ -7158,7 +7218,7 @@ void ObjectMgr::LoadGameObjectForQuests() // scan GO chest with loot including quest items case GAMEOBJECT_TYPE_CHEST: { - uint32 loot_id = GameObject::GetLootId(goInfo); + uint32 loot_id = goInfo->GetLootId(); // find quest loot for GO if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id)) |