From a9af7f2b1cb39cd47ac0f20307ac35ed6c759dbe Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Mon, 5 Oct 2009 02:04:33 +0400 Subject: [PATCH] Use reset time for normal/heroic from new DBC. Improve basic support for raid difficalties. --- src/game/AchievementMgr.cpp | 6 +-- src/game/AchievementMgr.h | 4 +- src/game/CalendarHandler.cpp | 2 +- src/game/DBCStores.cpp | 29 +++++++++-- src/game/DBCStores.h | 3 ++ src/game/DBCStructure.h | 21 +++++--- src/game/DBCfmt.h | 1 + src/game/Group.cpp | 95 ++++++++++++++++++++++++++---------- src/game/Group.h | 23 +++++---- src/game/InstanceSaveMgr.cpp | 31 +++++++----- src/game/InstanceSaveMgr.h | 10 ++-- src/game/Level1.cpp | 9 ++-- src/game/Level3.cpp | 14 +++--- src/game/Map.cpp | 8 +-- src/game/Map.h | 2 +- src/game/MapInstanced.cpp | 12 +++-- src/game/MapInstanced.h | 2 +- src/game/MapManager.cpp | 10 +++- src/game/MiscHandler.cpp | 56 +++++++++++++-------- src/game/MovementHandler.cpp | 17 +++++-- src/game/ObjectMgr.cpp | 33 +++++++++---- src/game/Player.cpp | 73 +++++++++++++++++---------- src/game/Player.h | 31 ++++++------ src/game/SharedDefines.h | 21 ++++---- 24 files changed, 340 insertions(+), 173 deletions(-) diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 2b816aa53..b21bb0571 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -196,10 +196,10 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) } return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: - if (difficalty.difficalty >= TOTAL_DUNGEON_DIFFICULTIES) + if (difficulty.difficulty >= MAX_DIFFICULTY) { sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY (%u) have wrong difficulty in value1 (%u), ignore.", - criteria->ID, criteria->requiredType,dataType,difficalty.difficalty); + criteria->ID, criteria->requiredType,dataType,difficulty.difficulty); return false; } return true; @@ -294,7 +294,7 @@ bool AchievementCriteriaData::Meets(Player const* source, Unit const* target, ui case ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED: return false; // always fail case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: - return source->GetMap()->GetSpawnMode()==difficalty.difficalty; + return source->GetMap()->GetSpawnMode()==difficulty.difficulty; case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT: return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index d0b0b90a5..eedd74700 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -125,8 +125,8 @@ struct AchievementCriteriaData // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12 struct { - uint32 difficalty; - } difficalty; + uint32 difficulty; + } difficulty; // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13 struct { diff --git a/src/game/CalendarHandler.cpp b/src/game/CalendarHandler.cpp index c5287a767..84c4c5aab 100644 --- a/src/game/CalendarHandler.cpp +++ b/src/game/CalendarHandler.cpp @@ -44,7 +44,7 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket &recv_data) size_t p_counter = data.wpos(); data << uint32(counter); // instance save count - for(int i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(int i = 0; i < MAX_DIFFICULTY; ++i) { for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr) { diff --git a/src/game/DBCStores.cpp b/src/game/DBCStores.cpp index 9050a1b52..62782159b 100644 --- a/src/game/DBCStores.cpp +++ b/src/game/DBCStores.cpp @@ -96,6 +96,12 @@ DBCStorage sLockStore(LockEntryfmt); DBCStorage sMailTemplateStore(MailTemplateEntryfmt); DBCStorage sMapStore(MapEntryfmt); + +// DBC used only for initialization sMapDifficultyMap at startup. +DBCStorage sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading +typedef std::map MapDifficultyMap; +MapDifficultyMap sMapDifficultyMap; + DBCStorage sMovieStore(MovieEntryfmt); DBCStorage sQuestSortStore(QuestSortEntryfmt); @@ -129,7 +135,7 @@ TalentSpellPosMap sTalentSpellPosMap; DBCStorage sTalentTabStore(TalentTabEntryfmt); // store absolute bit position for first rank for talent inspect -static uint32 sTalentTabPages[12/*MAX_CLASSES*/][3]; +static uint32 sTalentTabPages[MAX_CLASSES][3]; DBCStorage sTaxiNodesStore(TaxiNodesEntryfmt); TaxiMask sTaxiNodesMask; @@ -139,10 +145,10 @@ TaxiMask sOldContinentsNodesMask; TaxiPathSetBySource sTaxiPathSetBySource; DBCStorage sTaxiPathStore(TaxiPathEntryfmt); -// DBC used only for initialization sTaxiPathSetBySource at startup. +// DBC used only for initialization sTaxiPathNodeStore at startup. TaxiPathNodesByPath sTaxiPathNodesByPath; - static DBCStorage sTaxiPathNodeStore(TaxiPathNodeEntryfmt); + DBCStorage sTotemCategoryStore(TotemCategoryEntryfmt); DBCStorage sVehicleStore(VehicleEntryfmt); DBCStorage sVehicleSeatStore(VehicleSeatEntryfmt); @@ -200,7 +206,7 @@ void LoadDBCStores(const std::string& dataPath) { std::string dbcPath = dataPath+"dbc/"; - const uint32 DBCFilesCount = 79; + const uint32 DBCFilesCount = 80; barGoLink bar( DBCFilesCount ); @@ -232,7 +238,6 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBarberShopStyleStore, dbcPath,"BarberShopStyle.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharStartOutfitStore, dbcPath,"CharStartOutfit.dbc"); - LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChatChannelsStore, dbcPath,"ChatChannels.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.dbc"); @@ -290,6 +295,14 @@ void LoadDBCStores(const std::string& dataPath) LoadDBC(availableDbcLocales,bar,bad_dbc_files,sLockStore, dbcPath,"Lock.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapStore, dbcPath,"Map.dbc"); + + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMapDifficultyStore, dbcPath,"MapDifficulty.dbc"); + // fill data + for(uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i) + if(MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i)) + sMapDifficultyMap[MAKE_PAIR32(entry->MapId,entry->Difficulty)] = MapDifficulty(entry->resetTime,entry->maxPlayers); + sMapDifficultyStore.Clear(); + LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMovieStore, dbcPath,"Movie.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sRandomPropertiesPointsStore, dbcPath,"RandPropPoints.dbc"); @@ -659,6 +672,12 @@ void Map2ZoneCoordinates(float& x,float& y,uint32 zone) std::swap(x,y); // client have map coords swapped } +MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty) +{ + MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId,difficulty)); + return itr != sMapDifficultyMap.end() ? &itr->second : NULL; +} + uint32 const* GetTalentTabPages(uint32 cls) { return sTalentTabPages[cls]; diff --git a/src/game/DBCStores.h b/src/game/DBCStores.h index b41a3c94e..4a4761620 100644 --- a/src/game/DBCStores.h +++ b/src/game/DBCStores.h @@ -54,6 +54,8 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT void Zone2MapCoordinates(float& x,float& y,uint32 zone); void Map2ZoneCoordinates(float& x,float& y,uint32 zone); +MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty); + uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls); extern DBCStorage sAchievementStore; @@ -109,6 +111,7 @@ extern DBCStorage sItemSetStore; extern DBCStorage sLockStore; extern DBCStorage sMailTemplateStore; extern DBCStorage sMapStore; +//extern DBCStorage sMapDifficultyStore; -- use GetMapDifficultyData insteed extern DBCStorage sMovieStore; extern DBCStorage sQuestSortStore; extern DBCStorage sRandomPropertiesPointsStore; diff --git a/src/game/DBCStructure.h b/src/game/DBCStructure.h index 2f0c82aa4..ce364eba9 100644 --- a/src/game/DBCStructure.h +++ b/src/game/DBCStructure.h @@ -1105,8 +1105,6 @@ struct MapEntry bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; } bool IsBattleArena() const { return map_type == MAP_ARENA; } bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || map_type == MAP_ARENA; } - bool SupportsHeroicMode() const { return true; } - bool HasResetTime() const { return true; } bool IsMountAllowed() const { @@ -1125,14 +1123,14 @@ struct MapEntry struct MapDifficultyEntry { - uint32 Id; // 0 + //uint32 Id; // 0 uint32 MapId; // 1 - uint32 Difficulty; // 2 - char* areaTriggerText[16]; // 3-18 text showed when transfer to map failed (missing requirements) - uint32 textFlags; // 19 + uint32 Difficulty; // 2 (for arenas: arena slot) + //char* areaTriggerText[16]; // 3-18 text showed when transfer to map failed (missing requirements) + //uint32 textFlags; // 19 uint32 resetTime; // 20 uint32 maxPlayers; // 21 - char* difficultyString; // 22 + //char* difficultyString; // 22 }; struct MovieEntry @@ -1769,6 +1767,15 @@ struct WorldSafeLocsEntry #endif // Structures not used for casting to loaded DBC data and not required then packing +struct MapDifficulty +{ + MapDifficulty() : resetTime(0), maxPlayers(0) {} + MapDifficulty(uint32 _resetTime, uint32 _maxPlayers) : resetTime(_resetTime), maxPlayers(_maxPlayers) {} + + uint32 resetTime; + uint32 maxPlayers; +}; + struct TalentSpellPos { TalentSpellPos() : talent_id(0), rank(0) {} diff --git a/src/game/DBCfmt.h b/src/game/DBCfmt.h index 3a5c2e5cf..32c18ecfa 100644 --- a/src/game/DBCfmt.h +++ b/src/game/DBCfmt.h @@ -73,6 +73,7 @@ const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiii const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const char MapEntryfmt[]="nxixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxixx"; +const char MapDifficultyEntryfmt[]="diixxxxxxxxxxxxxxxxxiix"; const char MovieEntryfmt[]="nxx"; const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx"; const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii"; diff --git a/src/game/Group.cpp b/src/game/Group.cpp index f9b616fcd..7edee6eb1 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -69,7 +69,7 @@ Group::~Group() // it is undefined whether objectmgr (which stores the groups) or instancesavemgr // will be unloaded first so we must be prepared for both cases // this may unload some instance saves - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) for(BoundInstancesMap::iterator itr2 = m_boundInstances[i].begin(); itr2 != m_boundInstances[i].end(); ++itr2) itr2->second.save->RemoveGroup(this); @@ -112,7 +112,7 @@ bool Group::Create(const uint64 &guid, const char * name) CharacterDatabase.PExecute("INSERT INTO groups (leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid,difficulty,raiddifficulty) " "VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','" UI64FMTD "','%u','%u','%u')", GUID_LOPART(m_leaderGuid), GUID_LOPART(m_mainTank), GUID_LOPART(m_mainAssistant), uint32(m_lootMethod), - GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], isRaidGroup(), m_dungeonDifficulty, m_raidDifficulty); + GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], isRaidGroup(), uint32(m_dungeonDifficulty), m_raidDifficulty); } if(!AddMember(guid, name)) @@ -152,8 +152,16 @@ bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool if (m_groupType == GROUPTYPE_RAID) _initRaidSubGroupsCounter(); - m_dungeonDifficulty = (*result)[14].GetUInt8(); - m_raidDifficulty = (*result)[15].GetUInt8(); + uint32 diff = (*result)[14].GetUInt8(); + if (diff >= MAX_DUNGEON_DIFFICULTY) + diff = DUNGEON_DIFFICULTY_NORMAL; + m_dungeonDifficulty = Difficulty(diff); + + uint32 r_diff = (*result)[15].GetUInt8(); + if (r_diff >= MAX_RAID_DIFFICULTY) + r_diff = RAID_DIFFICULTY_10MAN_NORMAL; + m_raidDifficulty = Difficulty(r_diff); + m_mainTank = (*result)[0].GetUInt64(); m_mainAssistant = (*result)[1].GetUInt64(); m_lootMethod = (LootMethod)(*result)[2].GetUInt8(); @@ -295,12 +303,21 @@ bool Group::AddMember(const uint64 &guid, const char* name) { // reset the new member's instances, unless he is currently in one of them // including raid/heroic instances that they are not permanently bound to! - player->ResetInstances(INSTANCE_RESET_GROUP_JOIN); + player->ResetInstances(INSTANCE_RESET_GROUP_JOIN,false); + player->ResetInstances(INSTANCE_RESET_GROUP_JOIN,true); - if(player->getLevel() >= LEVELREQUIREMENT_HEROIC && player->GetDungeonDifficulty() != GetDungeonDifficulty() ) + if (player->getLevel() >= LEVELREQUIREMENT_HEROIC) { - player->SetDungeonDifficulty(m_dungeonDifficulty); - player->SendDungeonDifficulty(true); + if (player->GetDungeonDifficulty() != GetDungeonDifficulty()) + { + player->SetDungeonDifficulty(GetDungeonDifficulty()); + player->SendDungeonDifficulty(true); + } + if (player->GetRaidDifficulty() != GetRaidDifficulty()) + { + player->SetRaidDifficulty(GetRaidDifficulty()); + player->SendRaidDifficulty(true); + } } } player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); @@ -443,7 +460,8 @@ void Group::Disband(bool hideDestroy) CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); CharacterDatabase.CommitTransaction(); - ResetInstances(INSTANCE_RESET_GROUP_DISBAND, NULL); + ResetInstances(INSTANCE_RESET_GROUP_DISBAND, false, NULL); + ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL); } m_leaderGuid = 0; @@ -1079,7 +1097,7 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u else player->SetGroup(this, group); // if the same group invites the player back, cancel the homebind timer - InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDungeonDifficulty()); + InstanceGroupBind *bind = GetBoundInstance(player); if(bind && bind->save->GetInstanceId() == player->GetInstanceId()) player->m_InstanceValid = true; } @@ -1165,7 +1183,7 @@ void Group::_setLeader(const uint64 &guid) Player *player = objmgr.GetPlayer(slot->guid); if(player) { - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();) { @@ -1452,10 +1470,11 @@ void Roll::targetObjectBuildLink() getTarget()->addLootValidatorRef(this); } -void Group::SetDungeonDifficulty(uint8 difficulty) +void Group::SetDungeonDifficulty(Difficulty difficulty) { m_dungeonDifficulty = difficulty; - if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE leaderGuid ='%u'", m_dungeonDifficulty, GUID_LOPART(m_leaderGuid)); + if(!isBGGroup()) + CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE leaderGuid ='%u'", m_dungeonDifficulty, GUID_LOPART(m_leaderGuid)); for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -1467,10 +1486,11 @@ void Group::SetDungeonDifficulty(uint8 difficulty) } } -void Group::SetRaidDifficulty(uint8 difficulty) +void Group::SetRaidDifficulty(Difficulty difficulty) { m_raidDifficulty = difficulty; - if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET raiddifficulty = %u WHERE leaderGuid ='%u'", m_raidDifficulty, GUID_LOPART(m_leaderGuid)); + if(!isBGGroup()) + CharacterDatabase.PExecute("UPDATE groups SET raiddifficulty = %u WHERE leaderGuid ='%u'", m_raidDifficulty, GUID_LOPART(m_leaderGuid)); for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { @@ -1493,7 +1513,7 @@ bool Group::InCombatToInstance(uint32 instanceId) return false; } -void Group::ResetInstances(uint8 method, Player* SendMsgTo) +void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo) { if(isBGGroup()) return; @@ -1501,13 +1521,13 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND // we assume that when the difficulty changes, all instances that can be reset will be - uint8 dif = GetDungeonDifficulty(); + Difficulty diff = GetDifficulty(isRaid); - for(BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();) + for(BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end();) { InstanceSave *p = itr->second.save; const MapEntry *entry = sMapStore.LookupEntry(itr->first); - if(!entry || (!p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND)) + if(!entry || entry->IsRaid() != isRaid || !p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND) { ++itr; continue; @@ -1516,7 +1536,7 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) if(method == INSTANCE_RESET_ALL) { // the "reset all instances" method can only reset normal maps - if(dif == DUNGEON_DIFFICULTY_HEROIC || entry->map_type == MAP_RAID) + if (entry->map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC) { ++itr; continue; @@ -1541,8 +1561,8 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) if(p->CanReset()) p->DeleteFromDB(); else CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId()); // i don't know for sure if hash_map iterators - m_boundInstances[dif].erase(itr); - itr = m_boundInstances[dif].begin(); + m_boundInstances[diff].erase(itr); + itr = m_boundInstances[diff].begin(); // this unloads the instance save unless online players are bound to it // (eg. permanent binds or GM solo binds) p->RemoveGroup(this); @@ -1552,11 +1572,19 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo) } } -InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty) +InstanceGroupBind* Group::GetBoundInstance(Player* player) { + uint32 mapid = player->GetMapId(); + MapEntry const* mapEntry = sMapStore.LookupEntry(mapid); + if(!mapEntry) + return NULL; + + Difficulty difficulty = player->GetDifficulty(mapEntry->IsRaid()); + // some instances only have one difficulty - const MapEntry* entry = sMapStore.LookupEntry(mapid); - if(!entry || !entry->SupportsHeroicMode()) difficulty = DUNGEON_DIFFICULTY_NORMAL; + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty); + if(!mapDiff) + difficulty = DUNGEON_DIFFICULTY_NORMAL; BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); if(itr != m_boundInstances[difficulty].end()) @@ -1565,6 +1593,23 @@ InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty) return NULL; } +InstanceGroupBind* Group::GetBoundInstance(Map* aMap) +{ + // Currently spawn numbering not different from map difficulty + Difficulty difficulty = Difficulty(aMap->GetSpawnMode()); + + // some instances only have one difficulty + MapDifficulty const* mapDiff = GetMapDifficultyData(aMap->GetId(),difficulty); + if(!mapDiff) + return NULL; + + BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(aMap->GetId()); + if(itr != m_boundInstances[difficulty].end()) + return &itr->second; + else + return NULL; +} + InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load) { if(save && !isBGGroup()) diff --git a/src/game/Group.h b/src/game/Group.h index f6837e410..3b852fa8e 100644 --- a/src/game/Group.h +++ b/src/game/Group.h @@ -279,13 +279,15 @@ class MANGOS_DLL_SPEC Group } void SetTargetIcon(uint8 id, uint64 guid); - void SetDungeonDifficulty(uint8 difficulty); - uint8 GetDungeonDifficulty() { return m_dungeonDifficulty; } - void SetRaidDifficulty(uint8 difficulty); - uint8 GetRaidDifficulty() { return m_raidDifficulty; } + + Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; } + Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; } + Difficulty GetRaidDifficulty() const { return m_raidDifficulty; } + void SetDungeonDifficulty(Difficulty difficulty); + void SetRaidDifficulty(Difficulty difficulty); uint16 InInstance(); bool InCombatToInstance(uint32 instanceId); - void ResetInstances(uint8 method, Player* SendMsgTo); + void ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo); // -no description- //void SendInit(WorldSession *session); @@ -329,8 +331,9 @@ class MANGOS_DLL_SPEC Group InstanceGroupBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); - InstanceGroupBind* GetBoundInstance(uint32 mapid, uint8 difficulty); - BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } + InstanceGroupBind* GetBoundInstance(Player* player); + InstanceGroupBind* GetBoundInstance(Map* aMap); + BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } protected: bool _addMember(const uint64 &guid, const char* name, bool isAssistant=false); @@ -399,15 +402,15 @@ class MANGOS_DLL_SPEC Group uint64 m_mainTank; uint64 m_mainAssistant; GroupType m_groupType; - uint8 m_dungeonDifficulty; - uint8 m_raidDifficulty; + Difficulty m_dungeonDifficulty; + Difficulty m_raidDifficulty; BattleGround* m_bgGroup; uint64 m_targetIcons[TARGETICONCOUNT]; LootMethod m_lootMethod; ItemQualities m_lootThreshold; uint64 m_looterGuid; Rolls RollId; - BoundInstancesMap m_boundInstances[TOTAL_DUNGEON_DIFFICULTIES]; + BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]; uint8* m_subGroupsCounts; }; #endif diff --git a/src/game/InstanceSaveMgr.cpp b/src/game/InstanceSaveMgr.cpp index b52f74504..2db0c49d4 100644 --- a/src/game/InstanceSaveMgr.cpp +++ b/src/game/InstanceSaveMgr.cpp @@ -72,15 +72,27 @@ InstanceSaveManager::~InstanceSaveManager() - adding instance into manager - called from InstanceMap::Add, _LoadBoundInstances, LoadGroups */ -InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, uint8 difficulty, time_t resetTime, bool canReset, bool load) +InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load) { - InstanceSave *save = GetInstanceSave(instanceId); - if(save) return save; + if(InstanceSave *old_save = GetInstanceSave(instanceId)) + return old_save; const MapEntry* entry = sMapStore.LookupEntry(mapId); - if(!entry || instanceId == 0) + if (!entry) { - sLog.outError("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d!", mapId, instanceId); + sLog.outError("InstanceSaveManager::AddInstanceSave: wrong mapid = %d!", mapId, instanceId); + return NULL; + } + + if (instanceId == 0) + { + sLog.outError("InstanceSaveManager::AddInstanceSave: mapid = %d, wrong instanceid = %d!", mapId, instanceId); + return NULL; + } + + if (difficulty >= (entry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) + { + sLog.outError("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d, wrong dificalty %u!", mapId, instanceId, difficulty); return NULL; } @@ -100,7 +112,7 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance sLog.outDebug("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId); - save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset); + InstanceSave *save = new InstanceSave(mapId, instanceId, difficulty, resetTime, canReset); if(!load) save->SaveToDB(); m_instanceSaveById[instanceId] = save; @@ -136,7 +148,7 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId) } } -InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, uint8 difficulty, time_t resetTime, bool canReset) +InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset) : m_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId), m_difficulty(difficulty), m_canReset(canReset) { @@ -446,10 +458,7 @@ void InstanceSaveManager::LoadResetTimes() for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) { InstanceTemplate const* temp = objmgr.GetInstanceTemplate(i); - if(!temp) continue; - // only raid/heroic maps have a global reset time - const MapEntry* entry = sMapStore.LookupEntry(temp->map); - if(!entry || !entry->HasResetTime()) + if(!temp || temp->reset_delay == 0) continue; uint32 period = temp->reset_delay * DAY; diff --git a/src/game/InstanceSaveMgr.h b/src/game/InstanceSaveMgr.h index 5f573313a..f1d08e8f2 100644 --- a/src/game/InstanceSaveMgr.h +++ b/src/game/InstanceSaveMgr.h @@ -47,7 +47,7 @@ class InstanceSave - any new instance is being generated - the first time a player bound to InstanceId logs in - when a group bound to the instance is loaded */ - InstanceSave(uint16 MapId, uint32 InstanceId, uint8 difficulty, time_t resetTime, bool canReset); + InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset); /* Unloaded when m_playerList and m_groupList become empty or when the instance is reset */ @@ -92,7 +92,7 @@ class InstanceSave /* currently it is possible to omit this information from this structure but that would depend on a lot of things that can easily change in future */ - uint8 GetDifficulty() { return m_difficulty; } + Difficulty GetDifficulty() { return m_difficulty; } typedef std::list PlayerListType; typedef std::list GroupListType; @@ -105,8 +105,8 @@ class InstanceSave GroupListType m_groupList; time_t m_resetTime; uint32 m_instanceid; - uint16 m_mapid; - uint8 m_difficulty; + uint32 m_mapid; + Difficulty m_difficulty; bool m_canReset; }; @@ -143,7 +143,7 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::SingletonGetBoundInstance(target->GetMapId(), target->GetDungeonDifficulty()); + InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDifficulty(cMap->IsRaid())); if (!pBind) { Group *group = _player->GetGroup(); // if no bind exists, create a solo bind - InstanceGroupBind *gBind = group ? group->GetBoundInstance(target->GetMapId(), target->GetDungeonDifficulty()) : NULL; + InstanceGroupBind *gBind = group ? group->GetBoundInstance(target) : NULL; // if no bind exists, create a solo bind if (!gBind) if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(target->GetInstanceId())) _player->BindToInstance(save, !save->CanReset()); } - _player->SetDungeonDifficulty(target->GetDungeonDifficulty()); + if(cMap->IsRaid()) + _player->SetRaidDifficulty(target->GetRaidDifficulty()); + else + _player->SetDungeonDifficulty(target->GetDungeonDifficulty()); } PSendSysMessage(LANG_APPEARING_AT, chrNameLink.c_str()); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index ec69567c0..623f70631 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -5912,9 +5912,9 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) Player* player = getSelectedPlayer(); if (!player) player = m_session->GetPlayer(); uint32 counter = 0; - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) { - Player::BoundInstancesMap &binds = player->GetBoundInstances(i); + Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); for(Player::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) { InstanceSave *save = itr->second.save; @@ -5928,9 +5928,9 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/) Group *group = player->GetGroup(); if(group) { - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) { - Group::BoundInstancesMap &binds = group->GetBoundInstances(i); + Group::BoundInstancesMap &binds = group->GetBoundInstances(Difficulty(i)); for(Group::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr) { InstanceSave *save = itr->second.save; @@ -5956,9 +5956,9 @@ bool ChatHandler::HandleInstanceUnbindCommand(const char* args) Player* player = getSelectedPlayer(); if (!player) player = m_session->GetPlayer(); uint32 counter = 0; - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) { - Player::BoundInstancesMap &binds = player->GetBoundInstances(i); + Player::BoundInstancesMap &binds = player->GetBoundInstances(Difficulty(i)); for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();) { if(itr->first != player->GetMapId()) @@ -5966,7 +5966,7 @@ bool ChatHandler::HandleInstanceUnbindCommand(const char* args) InstanceSave *save = itr->second.save; std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); PSendSysMessage("unbinding map: %d inst: %d perm: %s diff: %s canReset: %s TTR: %s", itr->first, save->GetInstanceId(), itr->second.perm ? "yes" : "no", save->GetDifficulty() == DUNGEON_DIFFICULTY_NORMAL ? "normal" : "heroic", save->CanReset() ? "yes" : "no", timeleft.c_str()); - player->UnbindInstance(itr, i); + player->UnbindInstance(itr, Difficulty(i)); counter++; } else diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 35dd3d744..7e4fdfba9 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -2334,11 +2334,11 @@ bool InstanceMap::Add(Player *player) if(!mapSave) { sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId()); - mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), GetSpawnMode(), 0, true); + mapSave = sInstanceSaveManager.AddInstanceSave(GetId(), GetInstanceId(), Difficulty(GetSpawnMode()), 0, true); } // check for existing instance binds - InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetSpawnMode()); + InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), Difficulty(GetSpawnMode())); if(playerBind && playerBind->perm) { // cannot enter other instances if bound permanently @@ -2354,7 +2354,7 @@ bool InstanceMap::Add(Player *player) if(pGroup) { // solo saves should be reset when entering a group - InstanceGroupBind *groupBind = pGroup->GetBoundInstance(GetId(), GetSpawnMode()); + InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this); if(playerBind) { sLog.outError("InstanceMap::Add: player %s(%d) is being put in instance %d,%d,%d,%d,%d,%d but he is in group %d and is bound to instance %d,%d,%d,%d,%d,%d!", player->GetName(), player->GetGUIDLow(), mapSave->GetMapId(), mapSave->GetInstanceId(), mapSave->GetDifficulty(), mapSave->GetPlayerCount(), mapSave->GetGroupCount(), mapSave->CanReset(), GUID_LOPART(pGroup->GetLeaderGUID()), playerBind->save->GetMapId(), playerBind->save->GetInstanceId(), playerBind->save->GetDifficulty(), playerBind->save->GetPlayerCount(), playerBind->save->GetGroupCount(), playerBind->save->CanReset()); @@ -2573,7 +2573,7 @@ void InstanceMap::UnloadAll(bool pForce) void InstanceMap::SendResetWarnings(uint32 timeLeft) const { for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) - itr->getSource()->SendInstanceResetWarning(GetId(), itr->getSource()->GetDungeonDifficulty(), timeLeft); + itr->getSource()->SendInstanceResetWarning(GetId(), itr->getSource()->GetDifficulty(IsRaid()), timeLeft); } void InstanceMap::SetResetSchedule(bool on) diff --git a/src/game/Map.h b/src/game/Map.h index d4a01bc62..6fe6fdf3b 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -365,7 +365,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable bool IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); } bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } - bool IsHeroic() const { return i_spawnMode == DUNGEON_DIFFICULTY_HEROIC; } + bool IsHeroic() const { return IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; } bool IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); } bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } diff --git a/src/game/MapInstanced.cpp b/src/game/MapInstanced.cpp index 85bd15da1..0aa985ffe 100644 --- a/src/game/MapInstanced.cpp +++ b/src/game/MapInstanced.cpp @@ -139,7 +139,7 @@ Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) } else { - InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDungeonDifficulty()); + InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty(IsRaid())); InstanceSave *pSave = pBind ? pBind->save : NULL; // the player's permanent player bind is taken into consideration first @@ -149,7 +149,7 @@ Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) InstanceGroupBind *groupBind = NULL; Group *group = player->GetGroup(); // use the player's difficulty setting (it may not be the same as the group's) - if(group && (groupBind = group->GetBoundInstance(GetId(), player->GetDungeonDifficulty()))) + if(group && (groupBind = group->GetBoundInstance(this))) pSave = groupBind->save; } @@ -167,14 +167,14 @@ Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player) // if no instanceId via group members or instance saves is found // the instance will be created for the first time NewInstanceId = MapManager::Instance().GenerateInstanceId(); - map = CreateInstance(NewInstanceId, NULL, player->GetDungeonDifficulty()); + map = CreateInstance(NewInstanceId, NULL, player->GetDifficulty(IsRaid())); } } return map; } -InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty) +InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty) { // load/create a map Guard guard(*this); @@ -194,7 +194,9 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, } // some instances only have one difficulty - if (entry && !entry->SupportsHeroicMode()) difficulty = DUNGEON_DIFFICULTY_NORMAL; + MapDifficulty const* mapDiff = GetMapDifficultyData(GetId(),difficulty); + if (!mapDiff) + difficulty = DUNGEON_DIFFICULTY_NORMAL; sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal"); diff --git a/src/game/MapInstanced.h b/src/game/MapInstanced.h index 5e8183bac..baa78eeb6 100644 --- a/src/game/MapInstanced.h +++ b/src/game/MapInstanced.h @@ -61,7 +61,7 @@ class MANGOS_DLL_DECL MapInstanced : public Map private: - InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty); + InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty); BattleGroundMap* CreateBattleGroundMap(uint32 InstanceId, BattleGround* bg); InstancedMaps m_InstancedMaps; diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index f98011e34..624e3b884 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -182,10 +182,16 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player) } //The player has a heroic mode and tries to enter into instance which has no a heroic mode - if (!entry->SupportsHeroicMode() && player->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC) + MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID,player->GetDifficulty(entry->map_type == MAP_RAID)); + if (!mapDiff) { + bool isHeroicTargetMap = entry->map_type == MAP_RAID + ? (player->GetRaidDifficulty() >= RAID_DIFFICULTY_10MAN_HEROIC) + : (player->GetDungeonDifficulty() >= DUNGEON_DIFFICULTY_HEROIC); + //Send aborted message - player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, DUNGEON_DIFFICULTY_HEROIC); + // FIX ME: what about absent normal/heroic mode with specific players limit... + player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, isHeroicTargetMap ? DUNGEON_DIFFICULTY_HEROIC : DUNGEON_DIFFICULTY_NORMAL); return false; } diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index 5cccd4ea0..776277d2a 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -809,8 +809,16 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1)) missingItem = at->requiredItem2; + MapEntry const* mapEntry = sMapStore.LookupEntry(at->target_mapId); + if(!mapEntry) + return; + + bool isHeroicTargetMap = mapEntry->IsRaid() + ? (GetPlayer()->GetRaidDifficulty() >= RAID_DIFFICULTY_10MAN_HEROIC) + : (GetPlayer()->GetDungeonDifficulty() >= DUNGEON_DIFFICULTY_HEROIC); + uint32 missingKey = 0; - if(GetPlayer()->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC) + if(isHeroicTargetMap) { if(at->heroicKey) { @@ -823,7 +831,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) } uint32 missingQuest = 0; - if(GetPlayer()->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC) + if(isHeroicTargetMap) { if (at->requiredQuestHeroic && !GetPlayer()->GetQuestRewardStatus(at->requiredQuestHeroic)) missingQuest = at->requiredQuestHeroic; @@ -840,7 +848,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data) if(missingItem) SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1); else if(missingKey) - GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, DUNGEON_DIFFICULTY_HEROIC); + GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, isHeroicTargetMap ? DUNGEON_DIFFICULTY_HEROIC : DUNGEON_DIFFICULTY_NORMAL); else if(missingQuest) SendAreaTriggerMessage(at->requiredFailedText.c_str()); else if(missingLevel) @@ -1383,10 +1391,16 @@ void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ ) if(Group *pGroup = _player->GetGroup()) { if(pGroup->IsLeader(_player->GetGUID())) - pGroup->ResetInstances(INSTANCE_RESET_ALL, _player); + { + pGroup->ResetInstances(INSTANCE_RESET_ALL, false, _player); + pGroup->ResetInstances(INSTANCE_RESET_ALL, true,_player); + } } else - _player->ResetInstances(INSTANCE_RESET_ALL); + { + _player->ResetInstances(INSTANCE_RESET_ALL, false); + _player->ResetInstances(INSTANCE_RESET_ALL, true); + } } void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data ) @@ -1396,15 +1410,15 @@ void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data ) uint32 mode; recv_data >> mode; - if(mode == _player->GetDungeonDifficulty()) - return; - - if(mode > DUNGEON_DIFFICULTY_HEROIC) + if(mode >= MAX_DUNGEON_DIFFICULTY) { sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); return; } + if(Difficulty(mode) == _player->GetDungeonDifficulty()) + return; + // cannot reset while in an instance Map *map = _player->GetMap(); if(map && map->IsDungeon()) @@ -1422,14 +1436,14 @@ void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data ) { // the difficulty is set even if the instances can't be reset //_player->SendDungeonDifficulty(true); - pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player); - pGroup->SetDungeonDifficulty(mode); + pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player); + pGroup->SetDungeonDifficulty(Difficulty(mode)); } } else { - _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY); - _player->SetDungeonDifficulty(mode); + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false); + _player->SetDungeonDifficulty(Difficulty(mode)); } } @@ -1440,15 +1454,15 @@ void WorldSession::HandleSetRaidDifficultyOpcode( WorldPacket & recv_data ) uint32 mode; recv_data >> mode; - if(mode == _player->GetRaidDifficulty()) - return; - - if(mode > RAID_DIFFICULTY_25MAN_HEROIC) + if(mode >= MAX_RAID_DIFFICULTY) { sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); return; } + if(RaidDifficulties(mode) == _player->GetRaidDifficulty()) + return; + // cannot reset while in an instance Map *map = _player->GetMap(); if(map && map->IsDungeon()) @@ -1466,14 +1480,14 @@ void WorldSession::HandleSetRaidDifficultyOpcode( WorldPacket & recv_data ) { // the difficulty is set even if the instances can't be reset //_player->SendDungeonDifficulty(true); - pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player); - pGroup->SetRaidDifficulty(mode); + pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player); + pGroup->SetRaidDifficulty(Difficulty(mode)); } } else { - _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY); - _player->SetRaidDifficulty(mode); + _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true); + _player->SetRaidDifficulty(Difficulty(mode)); } } diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 5ad057fe2..3d10973c6 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -137,10 +137,21 @@ void WorldSession::HandleMoveWorldportAckOpcode() } } - if((mEntry->IsRaid() || (mEntry->IsNonRaidDungeon() && mEntry->SupportsHeroicMode() && GetPlayer()->IsHeroicDungeon())) && mInstance) + if (mInstance) { - uint32 timeleft = sInstanceSaveManager.GetResetTimeFor(GetPlayer()->GetMapId()) - time(NULL); - GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), GetPlayer()->GetDungeonDifficulty(), timeleft); + if(mEntry->IsRaid()) + { + uint32 timeleft = sInstanceSaveManager.GetResetTimeFor(GetPlayer()->GetMapId()) - time(NULL); + GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), GetPlayer()->GetRaidDifficulty(), timeleft); + } + else if(mEntry->IsNonRaidDungeon() && GetPlayer()->GetDungeonDifficulty() > DUNGEON_DIFFICULTY_NORMAL) + { + if(MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID,GetPlayer()->GetDungeonDifficulty())) + { + uint32 timeleft = sInstanceSaveManager.GetResetTimeFor(GetPlayer()->GetMapId()) - time(NULL); + GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), GetPlayer()->GetDungeonDifficulty(), timeleft); + } + } } // mount allow check diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp index 8a37a0085..6791db917 100644 --- a/src/game/ObjectMgr.cpp +++ b/src/game/ObjectMgr.cpp @@ -3148,7 +3148,14 @@ void ObjectMgr::LoadGroups() continue; } - InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true); + uint32 diff = fields[4].GetUInt8(); + if(diff >= (mapEntry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY)) + { + sLog.outErrorDb("Wrong dungeon difficulty use in group_instance table: %d", diff); + diff = 0; // default for both difficaly types + } + + InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapEntry->MapID, fields[2].GetUInt32(), Difficulty(diff), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true); group->BindToInstance(save, fields[3].GetBool(), true); }while( result->NextRow() ); delete result; @@ -4477,15 +4484,15 @@ void ObjectMgr::LoadInstanceTemplate() for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) { InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i); - if(!temp) continue; + if(!temp) + continue; + const MapEntry* entry = sMapStore.LookupEntry(temp->map); if(!entry) { sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); continue; } - else if(!entry->HasResetTime()) - continue; //FIXME: now exist heroic instance, normal/heroic raid instances // entry->resetTimeHeroic store reset time for both heroic mode instance (raid and non-raid) @@ -4494,16 +4501,24 @@ void ObjectMgr::LoadInstanceTemplate() // but at some point wee need implement reset time dependent from raid instance mode if(temp->reset_delay == 0) { + MapDifficulty const* mapDiffNorm = GetMapDifficultyData(temp->map,DUNGEON_DIFFICULTY_NORMAL); + MapDifficulty const* mapDiffHeroic = GetMapDifficultyData(temp->map,DUNGEON_DIFFICULTY_HEROIC); + + // no reset time + if ((!mapDiffNorm || mapDiffNorm->resetTime == 0) && + (!mapDiffHeroic || mapDiffHeroic->resetTime == 0)) + continue; + // use defaults from the DBC - /*if(entry->resetTimeHeroic) // for both raid and non raids, read above + if(mapDiffHeroic && mapDiffHeroic->resetTime) // for both raid and non raids, read above { - temp->reset_delay = entry->resetTimeHeroic / DAY; + temp->reset_delay = mapDiffHeroic->resetTime / DAY; } - else if (entry->resetTimeRaid && entry->map_type == MAP_RAID) + else if (mapDiffNorm && mapDiffNorm->resetTime && entry->map_type == MAP_RAID) // for normal raid only { - temp->reset_delay = entry->resetTimeRaid / DAY; - }*/ + temp->reset_delay = mapDiffNorm->resetTime / DAY; + } } // the reset_delay must be at least one day diff --git a/src/game/Player.cpp b/src/game/Player.cpp index d10779d2c..185551340 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -509,7 +509,7 @@ Player::~Player () delete ItemSetEff[x]; // clean up player-instance binds, may unload some instance saves - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) itr->second.save->RemovePlayer(this); @@ -14182,7 +14182,11 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) uint32 transGUID = fields[31].GetUInt32(); Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat()); SetLocationMapId(fields[16].GetUInt32()); - SetDungeonDifficulty(fields[39].GetUInt32()); // may be changed in _LoadGroup + + uint32 difficulty = fields[39].GetUInt32(); + if(difficulty >= MAX_DUNGEON_DIFFICULTY) + difficulty = DUNGEON_DIFFICULTY_NORMAL; + SetDungeonDifficulty(Difficulty(difficulty)); // may be changed in _LoadGroup _LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP)); @@ -15281,19 +15285,20 @@ void Player::_LoadSpells(QueryResult *result) void Player::_LoadGroup(QueryResult *result) { //QueryResult *result = CharacterDatabase.PQuery("SELECT leaderGuid FROM group_member WHERE memberGuid='%u'", GetGUIDLow()); - if(result) + if (result) { uint64 leaderGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); delete result; - Group* group = objmgr.GetGroupByLeader(leaderGuid); - if(group) + + if (Group* group = objmgr.GetGroupByLeader(leaderGuid)) { uint8 subgroup = group->GetMemberGroup(GetGUID()); SetGroup(group, subgroup); - if(getLevel() >= LEVELREQUIREMENT_HEROIC) + if (getLevel() >= LEVELREQUIREMENT_HEROIC) { // the group leader may change the instance difficulty while the player is offline SetDungeonDifficulty(group->GetDungeonDifficulty()); + SetRaidDifficulty(group->GetRaidDifficulty()); } } } @@ -15301,7 +15306,7 @@ void Player::_LoadGroup(QueryResult *result) void Player::_LoadBoundInstances(QueryResult *result) { - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) m_boundInstances[i].clear(); Group *group = GetGroup(); @@ -15316,6 +15321,7 @@ void Player::_LoadBoundInstances(QueryResult *result) uint32 mapId = fields[2].GetUInt32(); uint32 instanceId = fields[0].GetUInt32(); uint8 difficulty = fields[3].GetUInt8(); + time_t resetTime = (time_t)fields[4].GetUInt64(); // the resettime for normal instances is only saved when the InstanceSave is unloaded // so the value read from the DB may be wrong here but only if the InstanceSave is loaded @@ -15329,6 +15335,21 @@ void Player::_LoadBoundInstances(QueryResult *result) continue; } + if(difficulty >= MAX_DIFFICULTY) + { + sLog.outError("_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); + continue; + } + + MapDifficulty const* mapDiff = GetMapDifficultyData(mapId,Difficulty(difficulty)); + if(!mapDiff) + { + sLog.outError("_LoadBoundInstances: player %s(%d) has bind to not existed difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId); + CharacterDatabase.PExecute("DELETE FROM character_instance WHERE guid = '%d' AND instance = '%d'", GetGUIDLow(), instanceId); + continue; + } + if(!perm && group) { sLog.outError("_LoadBoundInstances: player %s(%d) is in group %d but has a non-permanent character bind to map %d,%d,%d", GetName(), GetGUIDLow(), GUID_LOPART(group->GetLeaderGUID()), mapId, instanceId, difficulty); @@ -15337,18 +15358,19 @@ void Player::_LoadBoundInstances(QueryResult *result) } // since non permanent binds are always solo bind, they can always be reset - InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, difficulty, resetTime, !perm, true); + InstanceSave *save = sInstanceSaveManager.AddInstanceSave(mapId, instanceId, Difficulty(difficulty), resetTime, !perm, true); if(save) BindToInstance(save, perm, true); } while(result->NextRow()); delete result; } } -InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) +InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty) { // some instances only have one difficulty - const MapEntry* entry = sMapStore.LookupEntry(mapid); - if(!entry || !entry->SupportsHeroicMode()) difficulty = DUNGEON_DIFFICULTY_NORMAL; + MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty); + if(!mapDiff) + return NULL; BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); if(itr != m_boundInstances[difficulty].end()) @@ -15357,13 +15379,13 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) return NULL; } -void Player::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload) +void Player::UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload) { BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); UnbindInstance(itr, difficulty, unload); } -void Player::UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload) +void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload) { if(itr != m_boundInstances[difficulty].end()) { @@ -15415,7 +15437,7 @@ void Player::SendRaidInfo() time_t now = time(NULL); - for(int i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(int i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::const_iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -15444,7 +15466,7 @@ void Player::SendSavedInstances() bool hasBeenSaved = false; WorldPacket data; - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::const_iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -15464,7 +15486,7 @@ void Player::SendSavedInstances() if(!hasBeenSaved) return; - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::const_iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) { @@ -15492,7 +15514,7 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player if(player) { - for(uint8 i = 0; i < TOTAL_DUNGEON_DIFFICULTIES; ++i) + for(uint8 i = 0; i < MAX_DIFFICULTY; ++i) { for (BoundInstancesMap::iterator itr = player->m_boundInstances[i].begin(); itr != player->m_boundInstances[i].end();) { @@ -15501,7 +15523,8 @@ void Player::ConvertInstancesToGroup(Player *player, Group *group, uint64 player // permanent binds are not removed if(!itr->second.perm) { - player->UnbindInstance(itr, i, true); // increments itr + // increments itr in call + player->UnbindInstance(itr, Difficulty(i), true); has_solo = true; } else @@ -16209,18 +16232,18 @@ void Player::SendResetFailedNotify(uint32 mapid) } /// Reset all solo instances and optionally send a message on success for each -void Player::ResetInstances(uint8 method) +void Player::ResetInstances(uint8 method, bool isRaid) { // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_JOIN // we assume that when the difficulty changes, all instances that can be reset will be - uint8 dif = GetDungeonDifficulty(); + Difficulty diff = GetDifficulty(isRaid); - for (BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();) + for (BoundInstancesMap::iterator itr = m_boundInstances[diff].begin(); itr != m_boundInstances[diff].end();) { InstanceSave *p = itr->second.save; const MapEntry *entry = sMapStore.LookupEntry(itr->first); - if(!entry || !p->CanReset()) + if(!entry || entry->IsRaid() != isRaid || !p->CanReset()) { ++itr; continue; @@ -16229,7 +16252,7 @@ void Player::ResetInstances(uint8 method) if(method == INSTANCE_RESET_ALL) { // the "reset all instances" method can only reset normal maps - if(dif == DUNGEON_DIFFICULTY_HEROIC || entry->map_type == MAP_RAID) + if(entry->map_type == MAP_RAID || diff == DUNGEON_DIFFICULTY_HEROIC) { ++itr; continue; @@ -16246,7 +16269,7 @@ void Player::ResetInstances(uint8 method) SendResetInstanceSuccess(p->GetMapId()); p->DeleteFromDB(); - m_boundInstances[dif].erase(itr++); + m_boundInstances[diff].erase(itr++); // the following should remove the instance save from the manager and delete it as well p->RemovePlayer(this); @@ -18325,7 +18348,7 @@ void Player::SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg) GetSession()->SendPacket(&data); } -void Player::SendInstanceResetWarning( uint32 mapid, uint32 difficulty, uint32 time ) +void Player::SendInstanceResetWarning( uint32 mapid, Difficulty difficulty, uint32 time ) { // type of warning, based on the time remaining until reset uint32 type; diff --git a/src/game/Player.h b/src/game/Player.h index 41d852f85..20835baf1 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -704,6 +704,9 @@ enum TransferAbortReason TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1 TRANSFER_ABORT_NOT_FOUND2 = 0x0C, // 3.1 TRANSFER_ABORT_NOT_FOUND3 = 0x0D, // 3.1 + TRANSFER_ABORT_NOT_FOUND4 = 0x0E, // 3.2 + TRANSFER_ABORT_REALM_ONLY = 0x0F, // All players on party must be from the same realm. + TRANSFER_ABORT_MAP_NOT_ALLOWED = 0x10, // Map can't be entered at this time. }; enum InstanceResetWarningType @@ -1039,7 +1042,7 @@ class MANGOS_DLL_SPEC Player : public Unit void SendInitialPacketsBeforeAddToMap(); void SendInitialPacketsAfterAddToMap(); void SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg = 0); - void SendInstanceResetWarning(uint32 mapid, uint32 difficulty, uint32 time); + void SendInstanceResetWarning(uint32 mapid, Difficulty difficulty, uint32 time); Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask); bool CanInteractWithNPCs(bool alive = true) const; @@ -1673,11 +1676,11 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } static void LeaveAllArenaTeams(uint64 guid); - void SetDungeonDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } - uint8 GetDungeonDifficulty() { return m_dungeonDifficulty; } - bool IsHeroicDungeon() { return m_dungeonDifficulty == DUNGEON_DIFFICULTY_HEROIC; } - void SetRaidDifficulty(uint32 raid_difficulty) { m_raidDifficulty = raid_difficulty; } - uint8 GetRaidDifficulty() { return m_raidDifficulty; } + Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; } + Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; } + Difficulty GetRaidDifficulty() const { return m_raidDifficulty; } + void SetDungeonDifficulty(Difficulty dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } + void SetRaidDifficulty(Difficulty raid_difficulty) { m_raidDifficulty = raid_difficulty; } bool UpdateSkill(uint32 skill_id, uint32 step); bool UpdateSkillPro(uint16 SkillId, int32 Chance, uint32 step); @@ -1765,7 +1768,7 @@ class MANGOS_DLL_SPEC Player : public Unit void SendDungeonDifficulty(bool IsInGroup); void SendRaidDifficulty(bool IsInGroup); - void ResetInstances(uint8 method); + void ResetInstances(uint8 method, bool isRaid); void SendResetInstanceSuccess(uint32 MapId); void SendResetInstanceFailed(uint32 reason, uint32 MapId); void SendResetFailedNotify(uint32 mapid); @@ -2183,11 +2186,11 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_HomebindTimer; bool m_InstanceValid; // permanent binds and solo binds by difficulty - BoundInstancesMap m_boundInstances[TOTAL_DUNGEON_DIFFICULTIES]; - InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty); - BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } - void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); - void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false); + BoundInstancesMap m_boundInstances[MAX_DIFFICULTY]; + InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty); + BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; } + void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload = false); + void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false); InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); void SendRaidInfo(); void SendSavedInstances(); @@ -2339,8 +2342,8 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_nextSave; time_t m_speakTime; uint32 m_speakCount; - uint32 m_dungeonDifficulty; - uint32 m_raidDifficulty; + Difficulty m_dungeonDifficulty; + Difficulty m_raidDifficulty; uint32 m_atLoginFlags; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 011ed6f2d..282791706 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -2408,20 +2408,23 @@ enum DiminishingGroup DIMINISHING_LIMITONLY }; -enum DungeonDifficulties +enum Difficulty { - DUNGEON_DIFFICULTY_NORMAL = 0, - DUNGEON_DIFFICULTY_HEROIC = 1, - TOTAL_DUNGEON_DIFFICULTIES + DUNGEON_DIFFICULTY_NORMAL = 0, + DUNGEON_DIFFICULTY_HEROIC = 1, + + RAID_DIFFICULTY_10MAN_NORMAL = 0, + RAID_DIFFICULTY_25MAN_NORMAL = 1, + RAID_DIFFICULTY_10MAN_HEROIC = 2, + RAID_DIFFICULTY_25MAN_HEROIC = 3, }; +#define MAX_DUNGEON_DIFFICULTY 2 +#define MAX_RAID_DIFFICULTY 4 +#define MAX_DIFFICULTY 4 + enum RaidDifficulties { - RAID_DIFFICULTY_10MAN_NORMAL = 0, - RAID_DIFFICULTY_10MAN_HEROIC = 1, - RAID_DIFFICULTY_25MAN_NORMAL = 2, - RAID_DIFFICULTY_25MAN_HEROIC = 3, - TOTAL_RAID_DIFFICULTIES }; enum SummonType