Use reset time for normal/heroic from new DBC. Improve basic support for raid difficalties.

This commit is contained in:
VladimirMangos 2009-10-05 02:04:33 +04:00
parent 9850551751
commit a9af7f2b1c
24 changed files with 340 additions and 173 deletions

View file

@ -196,10 +196,10 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
} }
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: 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.", 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 false;
} }
return true; return true;
@ -294,7 +294,7 @@ bool AchievementCriteriaData::Meets(Player const* source, Unit const* target, ui
case ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED: case ACHIEVEMENT_CRITERIA_DATA_TYPE_DISABLED:
return false; // always fail return false; // always fail
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY: 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: case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT:
return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount; return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM: case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM:

View file

@ -125,8 +125,8 @@ struct AchievementCriteriaData
// ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12 // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY = 12
struct struct
{ {
uint32 difficalty; uint32 difficulty;
} difficalty; } difficulty;
// ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13 // ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT = 13
struct struct
{ {

View file

@ -44,7 +44,7 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket &recv_data)
size_t p_counter = data.wpos(); size_t p_counter = data.wpos();
data << uint32(counter); // instance save count 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) for (Player::BoundInstancesMap::const_iterator itr = _player->m_boundInstances[i].begin(); itr != _player->m_boundInstances[i].end(); ++itr)
{ {

View file

@ -96,6 +96,12 @@ DBCStorage <LockEntry> sLockStore(LockEntryfmt);
DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt); DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt);
DBCStorage <MapEntry> sMapStore(MapEntryfmt); DBCStorage <MapEntry> sMapStore(MapEntryfmt);
// DBC used only for initialization sMapDifficultyMap at startup.
DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading
typedef std::map<uint32/*pair32(map,diff)*/,MapDifficulty> MapDifficultyMap;
MapDifficultyMap sMapDifficultyMap;
DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt); DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt);
DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt); DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt);
@ -129,7 +135,7 @@ TalentSpellPosMap sTalentSpellPosMap;
DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt); DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
// store absolute bit position for first rank for talent inspect // store absolute bit position for first rank for talent inspect
static uint32 sTalentTabPages[12/*MAX_CLASSES*/][3]; static uint32 sTalentTabPages[MAX_CLASSES][3];
DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt); DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
TaxiMask sTaxiNodesMask; TaxiMask sTaxiNodesMask;
@ -139,10 +145,10 @@ TaxiMask sOldContinentsNodesMask;
TaxiPathSetBySource sTaxiPathSetBySource; TaxiPathSetBySource sTaxiPathSetBySource;
DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt); DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt);
// DBC used only for initialization sTaxiPathSetBySource at startup. // DBC used only for initialization sTaxiPathNodeStore at startup.
TaxiPathNodesByPath sTaxiPathNodesByPath; TaxiPathNodesByPath sTaxiPathNodesByPath;
static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt); static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt); DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt); DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt); DBCStorage <VehicleSeatEntry> sVehicleSeatStore(VehicleSeatEntryfmt);
@ -200,7 +206,7 @@ void LoadDBCStores(const std::string& dataPath)
{ {
std::string dbcPath = dataPath+"dbc/"; std::string dbcPath = dataPath+"dbc/";
const uint32 DBCFilesCount = 79; const uint32 DBCFilesCount = 80;
barGoLink bar( DBCFilesCount ); 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,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBarberShopStyleStore, dbcPath,"BarberShopStyle.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,sCharStartOutfitStore, dbcPath,"CharStartOutfit.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.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,sChatChannelsStore, dbcPath,"ChatChannels.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.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,sLockStore, dbcPath,"Lock.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sMailTemplateStore, dbcPath,"MailTemplate.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,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,sMovieStore, dbcPath,"Movie.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc"); LoadDBC(availableDbcLocales,bar,bad_dbc_files,sQuestSortStore, dbcPath,"QuestSort.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sRandomPropertiesPointsStore, dbcPath,"RandPropPoints.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 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) uint32 const* GetTalentTabPages(uint32 cls)
{ {
return sTalentTabPages[cls]; return sTalentTabPages[cls];

View file

@ -54,6 +54,8 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT
void Zone2MapCoordinates(float& x,float& y,uint32 zone); void Zone2MapCoordinates(float& x,float& y,uint32 zone);
void Map2ZoneCoordinates(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); uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls);
extern DBCStorage <AchievementEntry> sAchievementStore; extern DBCStorage <AchievementEntry> sAchievementStore;
@ -109,6 +111,7 @@ extern DBCStorage <ItemSetEntry> sItemSetStore;
extern DBCStorage <LockEntry> sLockStore; extern DBCStorage <LockEntry> sLockStore;
extern DBCStorage <MailTemplateEntry> sMailTemplateStore; extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
extern DBCStorage <MapEntry> sMapStore; extern DBCStorage <MapEntry> sMapStore;
//extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed
extern DBCStorage <MovieEntry> sMovieStore; extern DBCStorage <MovieEntry> sMovieStore;
extern DBCStorage <QuestSortEntry> sQuestSortStore; extern DBCStorage <QuestSortEntry> sQuestSortStore;
extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore; extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore;

View file

@ -1105,8 +1105,6 @@ struct MapEntry
bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; } bool IsBattleGround() const { return map_type == MAP_BATTLEGROUND; }
bool IsBattleArena() const { return map_type == MAP_ARENA; } bool IsBattleArena() const { return map_type == MAP_ARENA; }
bool IsBattleGroundOrArena() const { return map_type == MAP_BATTLEGROUND || 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 bool IsMountAllowed() const
{ {
@ -1125,14 +1123,14 @@ struct MapEntry
struct MapDifficultyEntry struct MapDifficultyEntry
{ {
uint32 Id; // 0 //uint32 Id; // 0
uint32 MapId; // 1 uint32 MapId; // 1
uint32 Difficulty; // 2 uint32 Difficulty; // 2 (for arenas: arena slot)
char* areaTriggerText[16]; // 3-18 text showed when transfer to map failed (missing requirements) //char* areaTriggerText[16]; // 3-18 text showed when transfer to map failed (missing requirements)
uint32 textFlags; // 19 //uint32 textFlags; // 19
uint32 resetTime; // 20 uint32 resetTime; // 20
uint32 maxPlayers; // 21 uint32 maxPlayers; // 21
char* difficultyString; // 22 //char* difficultyString; // 22
}; };
struct MovieEntry struct MovieEntry
@ -1769,6 +1767,15 @@ struct WorldSafeLocsEntry
#endif #endif
// Structures not used for casting to loaded DBC data and not required then packing // 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 struct TalentSpellPos
{ {
TalentSpellPos() : talent_id(0), rank(0) {} TalentSpellPos() : talent_id(0), rank(0) {}

View file

@ -73,6 +73,7 @@ const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiii
const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx"; const char LockEntryfmt[]="niiiiiiiiiiiiiiiiiiiiiiiixxxxxxxx";
const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const char MailTemplateEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char MapEntryfmt[]="nxixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxixx"; const char MapEntryfmt[]="nxixssssssssssssssssxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixiffxixx";
const char MapDifficultyEntryfmt[]="diixxxxxxxxxxxxxxxxxiix";
const char MovieEntryfmt[]="nxx"; const char MovieEntryfmt[]="nxx";
const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx"; const char QuestSortEntryfmt[]="nxxxxxxxxxxxxxxxxx";
const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii"; const char RandomPropertiesPointsfmt[]="niiiiiiiiiiiiiii";

View file

@ -69,7 +69,7 @@ Group::~Group()
// it is undefined whether objectmgr (which stores the groups) or instancesavemgr // it is undefined whether objectmgr (which stores the groups) or instancesavemgr
// will be unloaded first so we must be prepared for both cases // will be unloaded first so we must be prepared for both cases
// this may unload some instance saves // 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) for(BoundInstancesMap::iterator itr2 = m_boundInstances[i].begin(); itr2 != m_boundInstances[i].end(); ++itr2)
itr2->second.save->RemoveGroup(this); 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) " 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')", "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_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)) if(!AddMember(guid, name))
@ -152,8 +152,16 @@ bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool
if (m_groupType == GROUPTYPE_RAID) if (m_groupType == GROUPTYPE_RAID)
_initRaidSubGroupsCounter(); _initRaidSubGroupsCounter();
m_dungeonDifficulty = (*result)[14].GetUInt8(); uint32 diff = (*result)[14].GetUInt8();
m_raidDifficulty = (*result)[15].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_mainTank = (*result)[0].GetUInt64();
m_mainAssistant = (*result)[1].GetUInt64(); m_mainAssistant = (*result)[1].GetUInt64();
m_lootMethod = (LootMethod)(*result)[2].GetUInt8(); m_lootMethod = (LootMethod)(*result)[2].GetUInt8();
@ -295,13 +303,22 @@ bool Group::AddMember(const uint64 &guid, const char* name)
{ {
// reset the new member's instances, unless he is currently in one of them // 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! // 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); if (player->GetDungeonDifficulty() != GetDungeonDifficulty())
{
player->SetDungeonDifficulty(GetDungeonDifficulty());
player->SendDungeonDifficulty(true); player->SendDungeonDifficulty(true);
} }
if (player->GetRaidDifficulty() != GetRaidDifficulty())
{
player->SetRaidDifficulty(GetRaidDifficulty());
player->SendRaidDifficulty(true);
}
}
} }
player->SetGroupUpdateFlag(GROUP_UPDATE_FULL); player->SetGroupUpdateFlag(GROUP_UPDATE_FULL);
UpdatePlayerOutOfRange(player); UpdatePlayerOutOfRange(player);
@ -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 groups WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid)); CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
CharacterDatabase.CommitTransaction(); 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; m_leaderGuid = 0;
@ -1079,7 +1097,7 @@ bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, u
else else
player->SetGroup(this, group); player->SetGroup(this, group);
// if the same group invites the player back, cancel the homebind timer // 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()) if(bind && bind->save->GetInstanceId() == player->GetInstanceId())
player->m_InstanceValid = true; player->m_InstanceValid = true;
} }
@ -1165,7 +1183,7 @@ void Group::_setLeader(const uint64 &guid)
Player *player = objmgr.GetPlayer(slot->guid); Player *player = objmgr.GetPlayer(slot->guid);
if(player) 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();) for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();)
{ {
@ -1452,10 +1470,11 @@ void Roll::targetObjectBuildLink()
getTarget()->addLootValidatorRef(this); getTarget()->addLootValidatorRef(this);
} }
void Group::SetDungeonDifficulty(uint8 difficulty) void Group::SetDungeonDifficulty(Difficulty difficulty)
{ {
m_dungeonDifficulty = 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()) 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; 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()) for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
{ {
@ -1493,7 +1513,7 @@ bool Group::InCombatToInstance(uint32 instanceId)
return false; return false;
} }
void Group::ResetInstances(uint8 method, Player* SendMsgTo) void Group::ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo)
{ {
if(isBGGroup()) if(isBGGroup())
return; 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 // 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 // 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; InstanceSave *p = itr->second.save;
const MapEntry *entry = sMapStore.LookupEntry(itr->first); 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; ++itr;
continue; continue;
@ -1516,7 +1536,7 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo)
if(method == INSTANCE_RESET_ALL) if(method == INSTANCE_RESET_ALL)
{ {
// the "reset all instances" method can only reset normal maps // 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; ++itr;
continue; continue;
@ -1541,8 +1561,8 @@ void Group::ResetInstances(uint8 method, Player* SendMsgTo)
if(p->CanReset()) p->DeleteFromDB(); if(p->CanReset()) p->DeleteFromDB();
else CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId()); else CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId());
// i don't know for sure if hash_map iterators // i don't know for sure if hash_map iterators
m_boundInstances[dif].erase(itr); m_boundInstances[diff].erase(itr);
itr = m_boundInstances[dif].begin(); itr = m_boundInstances[diff].begin();
// this unloads the instance save unless online players are bound to it // this unloads the instance save unless online players are bound to it
// (eg. permanent binds or GM solo binds) // (eg. permanent binds or GM solo binds)
p->RemoveGroup(this); 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 // some instances only have one difficulty
const MapEntry* entry = sMapStore.LookupEntry(mapid); MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
if(!entry || !entry->SupportsHeroicMode()) difficulty = DUNGEON_DIFFICULTY_NORMAL; if(!mapDiff)
difficulty = DUNGEON_DIFFICULTY_NORMAL;
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
if(itr != m_boundInstances[difficulty].end()) if(itr != m_boundInstances[difficulty].end())
@ -1565,6 +1593,23 @@ InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty)
return NULL; 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) InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load)
{ {
if(save && !isBGGroup()) if(save && !isBGGroup())

View file

@ -279,13 +279,15 @@ class MANGOS_DLL_SPEC Group
} }
void SetTargetIcon(uint8 id, uint64 guid); void SetTargetIcon(uint8 id, uint64 guid);
void SetDungeonDifficulty(uint8 difficulty);
uint8 GetDungeonDifficulty() { return m_dungeonDifficulty; } Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; }
void SetRaidDifficulty(uint8 difficulty); Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; }
uint8 GetRaidDifficulty() { return m_raidDifficulty; } Difficulty GetRaidDifficulty() const { return m_raidDifficulty; }
void SetDungeonDifficulty(Difficulty difficulty);
void SetRaidDifficulty(Difficulty difficulty);
uint16 InInstance(); uint16 InInstance();
bool InCombatToInstance(uint32 instanceId); bool InCombatToInstance(uint32 instanceId);
void ResetInstances(uint8 method, Player* SendMsgTo); void ResetInstances(uint8 method, bool isRaid, Player* SendMsgTo);
// -no description- // -no description-
//void SendInit(WorldSession *session); //void SendInit(WorldSession *session);
@ -329,8 +331,9 @@ class MANGOS_DLL_SPEC Group
InstanceGroupBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); InstanceGroupBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false);
InstanceGroupBind* GetBoundInstance(uint32 mapid, uint8 difficulty); InstanceGroupBind* GetBoundInstance(Player* player);
BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } InstanceGroupBind* GetBoundInstance(Map* aMap);
BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; }
protected: protected:
bool _addMember(const uint64 &guid, const char* name, bool isAssistant=false); 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_mainTank;
uint64 m_mainAssistant; uint64 m_mainAssistant;
GroupType m_groupType; GroupType m_groupType;
uint8 m_dungeonDifficulty; Difficulty m_dungeonDifficulty;
uint8 m_raidDifficulty; Difficulty m_raidDifficulty;
BattleGround* m_bgGroup; BattleGround* m_bgGroup;
uint64 m_targetIcons[TARGETICONCOUNT]; uint64 m_targetIcons[TARGETICONCOUNT];
LootMethod m_lootMethod; LootMethod m_lootMethod;
ItemQualities m_lootThreshold; ItemQualities m_lootThreshold;
uint64 m_looterGuid; uint64 m_looterGuid;
Rolls RollId; Rolls RollId;
BoundInstancesMap m_boundInstances[TOTAL_DUNGEON_DIFFICULTIES]; BoundInstancesMap m_boundInstances[MAX_DIFFICULTY];
uint8* m_subGroupsCounts; uint8* m_subGroupsCounts;
}; };
#endif #endif

View file

@ -72,15 +72,27 @@ InstanceSaveManager::~InstanceSaveManager()
- adding instance into manager - adding instance into manager
- called from InstanceMap::Add, _LoadBoundInstances, LoadGroups - 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(InstanceSave *old_save = GetInstanceSave(instanceId))
if(save) return save; return old_save;
const MapEntry* entry = sMapStore.LookupEntry(mapId); 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; return NULL;
} }
@ -100,7 +112,7 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance
sLog.outDebug("InstanceSaveManager::AddInstanceSave: mapid = %d, instanceid = %d", mapId, instanceId); 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(); if(!load) save->SaveToDB();
m_instanceSaveById[instanceId] = save; 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_resetTime(resetTime), m_instanceid(InstanceId), m_mapid(MapId),
m_difficulty(difficulty), m_canReset(canReset) m_difficulty(difficulty), m_canReset(canReset)
{ {
@ -446,10 +458,7 @@ void InstanceSaveManager::LoadResetTimes()
for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
{ {
InstanceTemplate const* temp = objmgr.GetInstanceTemplate(i); InstanceTemplate const* temp = objmgr.GetInstanceTemplate(i);
if(!temp) continue; if(!temp || temp->reset_delay == 0)
// only raid/heroic maps have a global reset time
const MapEntry* entry = sMapStore.LookupEntry(temp->map);
if(!entry || !entry->HasResetTime())
continue; continue;
uint32 period = temp->reset_delay * DAY; uint32 period = temp->reset_delay * DAY;

View file

@ -47,7 +47,7 @@ class InstanceSave
- any new instance is being generated - any new instance is being generated
- the first time a player bound to InstanceId logs in - the first time a player bound to InstanceId logs in
- when a group bound to the instance is loaded */ - 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 /* Unloaded when m_playerList and m_groupList become empty
or when the instance is reset */ or when the instance is reset */
@ -92,7 +92,7 @@ class InstanceSave
/* currently it is possible to omit this information from this structure /* 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 */ 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<Player*> PlayerListType; typedef std::list<Player*> PlayerListType;
typedef std::list<Group*> GroupListType; typedef std::list<Group*> GroupListType;
@ -105,8 +105,8 @@ class InstanceSave
GroupListType m_groupList; GroupListType m_groupList;
time_t m_resetTime; time_t m_resetTime;
uint32 m_instanceid; uint32 m_instanceid;
uint16 m_mapid; uint32 m_mapid;
uint8 m_difficulty; Difficulty m_difficulty;
bool m_canReset; bool m_canReset;
}; };
@ -143,7 +143,7 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
void Update(); void Update();
InstanceSave* AddInstanceSave(uint32 mapId, uint32 instanceId, uint8 difficulty, time_t resetTime, bool canReset, bool load = false); InstanceSave* AddInstanceSave(uint32 mapId, uint32 instanceId, Difficulty difficulty, time_t resetTime, bool canReset, bool load = false);
void RemoveInstanceSave(uint32 InstanceId); void RemoveInstanceSave(uint32 InstanceId);
static void DeleteInstanceFromDB(uint32 instanceid); static void DeleteInstanceFromDB(uint32 instanceid);

View file

@ -537,18 +537,21 @@ bool ChatHandler::HandleGonameCommand(const char* args)
// if the player or the player's group is bound to another instance // if the player or the player's group is bound to another instance
// the player will not be bound to another one // the player will not be bound to another one
InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDungeonDifficulty()); InstancePlayerBind *pBind = _player->GetBoundInstance(target->GetMapId(), target->GetDifficulty(cMap->IsRaid()));
if (!pBind) if (!pBind)
{ {
Group *group = _player->GetGroup(); Group *group = _player->GetGroup();
// if no bind exists, create a solo bind // 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 no bind exists, create a solo bind
if (!gBind) if (!gBind)
if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(target->GetInstanceId())) if (InstanceSave *save = sInstanceSaveManager.GetInstanceSave(target->GetInstanceId()))
_player->BindToInstance(save, !save->CanReset()); _player->BindToInstance(save, !save->CanReset());
} }
if(cMap->IsRaid())
_player->SetRaidDifficulty(target->GetRaidDifficulty());
else
_player->SetDungeonDifficulty(target->GetDungeonDifficulty()); _player->SetDungeonDifficulty(target->GetDungeonDifficulty());
} }

View file

@ -5912,9 +5912,9 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/)
Player* player = getSelectedPlayer(); Player* player = getSelectedPlayer();
if (!player) player = m_session->GetPlayer(); if (!player) player = m_session->GetPlayer();
uint32 counter = 0; 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) for(Player::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr)
{ {
InstanceSave *save = itr->second.save; InstanceSave *save = itr->second.save;
@ -5928,9 +5928,9 @@ bool ChatHandler::HandleInstanceListBindsCommand(const char* /*args*/)
Group *group = player->GetGroup(); Group *group = player->GetGroup();
if(group) 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) for(Group::BoundInstancesMap::const_iterator itr = binds.begin(); itr != binds.end(); ++itr)
{ {
InstanceSave *save = itr->second.save; InstanceSave *save = itr->second.save;
@ -5956,9 +5956,9 @@ bool ChatHandler::HandleInstanceUnbindCommand(const char* args)
Player* player = getSelectedPlayer(); Player* player = getSelectedPlayer();
if (!player) player = m_session->GetPlayer(); if (!player) player = m_session->GetPlayer();
uint32 counter = 0; 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();) for(Player::BoundInstancesMap::iterator itr = binds.begin(); itr != binds.end();)
{ {
if(itr->first != player->GetMapId()) if(itr->first != player->GetMapId())
@ -5966,7 +5966,7 @@ bool ChatHandler::HandleInstanceUnbindCommand(const char* args)
InstanceSave *save = itr->second.save; InstanceSave *save = itr->second.save;
std::string timeleft = GetTimeString(save->GetResetTime() - time(NULL)); 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()); 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++; counter++;
} }
else else

View file

@ -2334,11 +2334,11 @@ bool InstanceMap::Add(Player *player)
if(!mapSave) if(!mapSave)
{ {
sLog.outDetail("InstanceMap::Add: creating instance save for map %d spawnmode %d with instance id %d", GetId(), GetSpawnMode(), GetInstanceId()); 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 // check for existing instance binds
InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), GetSpawnMode()); InstancePlayerBind *playerBind = player->GetBoundInstance(GetId(), Difficulty(GetSpawnMode()));
if(playerBind && playerBind->perm) if(playerBind && playerBind->perm)
{ {
// cannot enter other instances if bound permanently // cannot enter other instances if bound permanently
@ -2354,7 +2354,7 @@ bool InstanceMap::Add(Player *player)
if(pGroup) if(pGroup)
{ {
// solo saves should be reset when entering a group // solo saves should be reset when entering a group
InstanceGroupBind *groupBind = pGroup->GetBoundInstance(GetId(), GetSpawnMode()); InstanceGroupBind *groupBind = pGroup->GetBoundInstance(this);
if(playerBind) 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()); 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 void InstanceMap::SendResetWarnings(uint32 timeLeft) const
{ {
for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) 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) void InstanceMap::SetResetSchedule(bool on)

View file

@ -365,7 +365,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
// NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable // 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 IsDungeon() const { return i_mapEntry && i_mapEntry->IsDungeon(); }
bool IsRaid() const { return i_mapEntry && i_mapEntry->IsRaid(); } 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 IsBattleGround() const { return i_mapEntry && i_mapEntry->IsBattleGround(); }
bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); } bool IsBattleArena() const { return i_mapEntry && i_mapEntry->IsBattleArena(); }
bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); } bool IsBattleGroundOrArena() const { return i_mapEntry && i_mapEntry->IsBattleGroundOrArena(); }

View file

@ -139,7 +139,7 @@ Map* MapInstanced::CreateInstance(const uint32 mapId, Player * player)
} }
else else
{ {
InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDungeonDifficulty()); InstancePlayerBind *pBind = player->GetBoundInstance(GetId(), player->GetDifficulty(IsRaid()));
InstanceSave *pSave = pBind ? pBind->save : NULL; InstanceSave *pSave = pBind ? pBind->save : NULL;
// the player's permanent player bind is taken into consideration first // 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; InstanceGroupBind *groupBind = NULL;
Group *group = player->GetGroup(); Group *group = player->GetGroup();
// use the player's difficulty setting (it may not be the same as the group's) // 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; 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 // if no instanceId via group members or instance saves is found
// the instance will be created for the first time // the instance will be created for the first time
NewInstanceId = MapManager::Instance().GenerateInstanceId(); NewInstanceId = MapManager::Instance().GenerateInstanceId();
map = CreateInstance(NewInstanceId, NULL, player->GetDungeonDifficulty()); map = CreateInstance(NewInstanceId, NULL, player->GetDifficulty(IsRaid()));
} }
} }
return map; return map;
} }
InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty) InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty)
{ {
// load/create a map // load/create a map
Guard guard(*this); Guard guard(*this);
@ -194,7 +194,9 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave *save,
} }
// some instances only have one difficulty // 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"); sLog.outDebug("MapInstanced::CreateInstance: %s map instance %d for %d created with difficulty %s", save?"":"new ", InstanceId, GetId(), difficulty?"heroic":"normal");

View file

@ -61,7 +61,7 @@ class MANGOS_DLL_DECL MapInstanced : public Map
private: private:
InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, uint8 difficulty); InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave *save, Difficulty difficulty);
BattleGroundMap* CreateBattleGroundMap(uint32 InstanceId, BattleGround* bg); BattleGroundMap* CreateBattleGroundMap(uint32 InstanceId, BattleGround* bg);
InstancedMaps m_InstancedMaps; InstancedMaps m_InstancedMaps;

View file

@ -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 //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 //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; return false;
} }

View file

@ -809,8 +809,16 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1)) else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1))
missingItem = at->requiredItem2; 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; uint32 missingKey = 0;
if(GetPlayer()->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC) if(isHeroicTargetMap)
{ {
if(at->heroicKey) if(at->heroicKey)
{ {
@ -823,7 +831,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
} }
uint32 missingQuest = 0; uint32 missingQuest = 0;
if(GetPlayer()->GetDungeonDifficulty() == DUNGEON_DIFFICULTY_HEROIC) if(isHeroicTargetMap)
{ {
if (at->requiredQuestHeroic && !GetPlayer()->GetQuestRewardStatus(at->requiredQuestHeroic)) if (at->requiredQuestHeroic && !GetPlayer()->GetQuestRewardStatus(at->requiredQuestHeroic))
missingQuest = at->requiredQuestHeroic; missingQuest = at->requiredQuestHeroic;
@ -840,7 +848,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
if(missingItem) if(missingItem)
SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1); SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1);
else if(missingKey) 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) else if(missingQuest)
SendAreaTriggerMessage(at->requiredFailedText.c_str()); SendAreaTriggerMessage(at->requiredFailedText.c_str());
else if(missingLevel) else if(missingLevel)
@ -1383,10 +1391,16 @@ void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ )
if(Group *pGroup = _player->GetGroup()) if(Group *pGroup = _player->GetGroup())
{ {
if(pGroup->IsLeader(_player->GetGUID())) 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 else
_player->ResetInstances(INSTANCE_RESET_ALL); {
_player->ResetInstances(INSTANCE_RESET_ALL, false);
_player->ResetInstances(INSTANCE_RESET_ALL, true);
}
} }
void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data ) void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data )
@ -1396,15 +1410,15 @@ void WorldSession::HandleSetDungeonDifficultyOpcode( WorldPacket & recv_data )
uint32 mode; uint32 mode;
recv_data >> mode; recv_data >> mode;
if(mode == _player->GetDungeonDifficulty()) if(mode >= MAX_DUNGEON_DIFFICULTY)
return;
if(mode > DUNGEON_DIFFICULTY_HEROIC)
{ {
sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); sLog.outError("WorldSession::HandleSetDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
return; return;
} }
if(Difficulty(mode) == _player->GetDungeonDifficulty())
return;
// cannot reset while in an instance // cannot reset while in an instance
Map *map = _player->GetMap(); Map *map = _player->GetMap();
if(map && map->IsDungeon()) 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 // the difficulty is set even if the instances can't be reset
//_player->SendDungeonDifficulty(true); //_player->SendDungeonDifficulty(true);
pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player); pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false, _player);
pGroup->SetDungeonDifficulty(mode); pGroup->SetDungeonDifficulty(Difficulty(mode));
} }
} }
else else
{ {
_player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY); _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, false);
_player->SetDungeonDifficulty(mode); _player->SetDungeonDifficulty(Difficulty(mode));
} }
} }
@ -1440,15 +1454,15 @@ void WorldSession::HandleSetRaidDifficultyOpcode( WorldPacket & recv_data )
uint32 mode; uint32 mode;
recv_data >> mode; recv_data >> mode;
if(mode == _player->GetRaidDifficulty()) if(mode >= MAX_RAID_DIFFICULTY)
return;
if(mode > RAID_DIFFICULTY_25MAN_HEROIC)
{ {
sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode); sLog.outError("WorldSession::HandleSetRaidDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
return; return;
} }
if(RaidDifficulties(mode) == _player->GetRaidDifficulty())
return;
// cannot reset while in an instance // cannot reset while in an instance
Map *map = _player->GetMap(); Map *map = _player->GetMap();
if(map && map->IsDungeon()) 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 // the difficulty is set even if the instances can't be reset
//_player->SendDungeonDifficulty(true); //_player->SendDungeonDifficulty(true);
pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player); pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true, _player);
pGroup->SetRaidDifficulty(mode); pGroup->SetRaidDifficulty(Difficulty(mode));
} }
} }
else else
{ {
_player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY); _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, true);
_player->SetRaidDifficulty(mode); _player->SetRaidDifficulty(Difficulty(mode));
} }
} }

View file

@ -137,11 +137,22 @@ void WorldSession::HandleMoveWorldportAckOpcode()
} }
} }
if((mEntry->IsRaid() || (mEntry->IsNonRaidDungeon() && mEntry->SupportsHeroicMode() && GetPlayer()->IsHeroicDungeon())) && mInstance) if (mInstance)
{
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); uint32 timeleft = sInstanceSaveManager.GetResetTimeFor(GetPlayer()->GetMapId()) - time(NULL);
GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), GetPlayer()->GetDungeonDifficulty(), timeleft); GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), GetPlayer()->GetDungeonDifficulty(), timeleft);
} }
}
}
// mount allow check // mount allow check
if(!mEntry->IsMountAllowed()) if(!mEntry->IsMountAllowed())

View file

@ -3148,7 +3148,14 @@ void ObjectMgr::LoadGroups()
continue; 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); group->BindToInstance(save, fields[3].GetBool(), true);
}while( result->NextRow() ); }while( result->NextRow() );
delete result; delete result;
@ -4477,15 +4484,15 @@ void ObjectMgr::LoadInstanceTemplate()
for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++) for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
{ {
InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i); InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i);
if(!temp) continue; if(!temp)
continue;
const MapEntry* entry = sMapStore.LookupEntry(temp->map); const MapEntry* entry = sMapStore.LookupEntry(temp->map);
if(!entry) if(!entry)
{ {
sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map); sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map);
continue; continue;
} }
else if(!entry->HasResetTime())
continue;
//FIXME: now exist heroic instance, normal/heroic raid instances //FIXME: now exist heroic instance, normal/heroic raid instances
// entry->resetTimeHeroic store reset time for both heroic mode instance (raid and non-raid) // 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 // but at some point wee need implement reset time dependent from raid instance mode
if(temp->reset_delay == 0) 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 // 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 // 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 // the reset_delay must be at least one day

View file

@ -509,7 +509,7 @@ Player::~Player ()
delete ItemSetEff[x]; delete ItemSetEff[x];
// clean up player-instance binds, may unload some instance saves // 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) for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
itr->second.save->RemovePlayer(this); itr->second.save->RemovePlayer(this);
@ -14182,7 +14182,11 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
uint32 transGUID = fields[31].GetUInt32(); uint32 transGUID = fields[31].GetUInt32();
Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat()); Relocate(fields[13].GetFloat(),fields[14].GetFloat(),fields[15].GetFloat(),fields[17].GetFloat());
SetLocationMapId(fields[16].GetUInt32()); 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)); _LoadGroup(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGROUP));
@ -15285,8 +15289,8 @@ void Player::_LoadGroup(QueryResult *result)
{ {
uint64 leaderGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER); uint64 leaderGuid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
delete result; delete result;
Group* group = objmgr.GetGroupByLeader(leaderGuid);
if(group) if (Group* group = objmgr.GetGroupByLeader(leaderGuid))
{ {
uint8 subgroup = group->GetMemberGroup(GetGUID()); uint8 subgroup = group->GetMemberGroup(GetGUID());
SetGroup(group, subgroup); SetGroup(group, subgroup);
@ -15294,6 +15298,7 @@ void Player::_LoadGroup(QueryResult *result)
{ {
// the group leader may change the instance difficulty while the player is offline // the group leader may change the instance difficulty while the player is offline
SetDungeonDifficulty(group->GetDungeonDifficulty()); SetDungeonDifficulty(group->GetDungeonDifficulty());
SetRaidDifficulty(group->GetRaidDifficulty());
} }
} }
} }
@ -15301,7 +15306,7 @@ void Player::_LoadGroup(QueryResult *result)
void Player::_LoadBoundInstances(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(); m_boundInstances[i].clear();
Group *group = GetGroup(); Group *group = GetGroup();
@ -15316,6 +15321,7 @@ void Player::_LoadBoundInstances(QueryResult *result)
uint32 mapId = fields[2].GetUInt32(); uint32 mapId = fields[2].GetUInt32();
uint32 instanceId = fields[0].GetUInt32(); uint32 instanceId = fields[0].GetUInt32();
uint8 difficulty = fields[3].GetUInt8(); uint8 difficulty = fields[3].GetUInt8();
time_t resetTime = (time_t)fields[4].GetUInt64(); time_t resetTime = (time_t)fields[4].GetUInt64();
// the resettime for normal instances is only saved when the InstanceSave is unloaded // 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 // 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; 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) 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); 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 // 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); if(save) BindToInstance(save, perm, true);
} while(result->NextRow()); } while(result->NextRow());
delete result; delete result;
} }
} }
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty) InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty)
{ {
// some instances only have one difficulty // some instances only have one difficulty
const MapEntry* entry = sMapStore.LookupEntry(mapid); MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
if(!entry || !entry->SupportsHeroicMode()) difficulty = DUNGEON_DIFFICULTY_NORMAL; if(!mapDiff)
return NULL;
BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid); BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
if(itr != m_boundInstances[difficulty].end()) if(itr != m_boundInstances[difficulty].end())
@ -15357,13 +15379,13 @@ InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, uint8 difficulty)
return NULL; 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); BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
UnbindInstance(itr, difficulty, unload); 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()) if(itr != m_boundInstances[difficulty].end())
{ {
@ -15415,7 +15437,7 @@ void Player::SendRaidInfo()
time_t now = time(NULL); 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) 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; bool hasBeenSaved = false;
WorldPacket data; 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) for (BoundInstancesMap::const_iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
{ {
@ -15464,7 +15486,7 @@ void Player::SendSavedInstances()
if(!hasBeenSaved) if(!hasBeenSaved)
return; 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) 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) 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();) 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 // permanent binds are not removed
if(!itr->second.perm) if(!itr->second.perm)
{ {
player->UnbindInstance(itr, i, true); // increments itr // increments itr in call
player->UnbindInstance(itr, Difficulty(i), true);
has_solo = true; has_solo = true;
} }
else else
@ -16209,18 +16232,18 @@ void Player::SendResetFailedNotify(uint32 mapid)
} }
/// Reset all solo instances and optionally send a message on success for each /// 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 // 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 // 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; InstanceSave *p = itr->second.save;
const MapEntry *entry = sMapStore.LookupEntry(itr->first); const MapEntry *entry = sMapStore.LookupEntry(itr->first);
if(!entry || !p->CanReset()) if(!entry || entry->IsRaid() != isRaid || !p->CanReset())
{ {
++itr; ++itr;
continue; continue;
@ -16229,7 +16252,7 @@ void Player::ResetInstances(uint8 method)
if(method == INSTANCE_RESET_ALL) if(method == INSTANCE_RESET_ALL)
{ {
// the "reset all instances" method can only reset normal maps // 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; ++itr;
continue; continue;
@ -16246,7 +16269,7 @@ void Player::ResetInstances(uint8 method)
SendResetInstanceSuccess(p->GetMapId()); SendResetInstanceSuccess(p->GetMapId());
p->DeleteFromDB(); 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 // the following should remove the instance save from the manager and delete it as well
p->RemovePlayer(this); p->RemovePlayer(this);
@ -18325,7 +18348,7 @@ void Player::SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg)
GetSession()->SendPacket(&data); 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 // type of warning, based on the time remaining until reset
uint32 type; uint32 type;

View file

@ -704,6 +704,9 @@ enum TransferAbortReason
TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1 TRANSFER_ABORT_NEED_GROUP = 0x0B, // 3.1
TRANSFER_ABORT_NOT_FOUND2 = 0x0C, // 3.1 TRANSFER_ABORT_NOT_FOUND2 = 0x0C, // 3.1
TRANSFER_ABORT_NOT_FOUND3 = 0x0D, // 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 enum InstanceResetWarningType
@ -1039,7 +1042,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void SendInitialPacketsBeforeAddToMap(); void SendInitialPacketsBeforeAddToMap();
void SendInitialPacketsAfterAddToMap(); void SendInitialPacketsAfterAddToMap();
void SendTransferAborted(uint32 mapid, uint8 reason, uint8 arg = 0); 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); Creature* GetNPCIfCanInteractWith(uint64 guid, uint32 npcflagmask);
bool CanInteractWithNPCs(bool alive = true) const; bool CanInteractWithNPCs(bool alive = true) const;
@ -1673,11 +1676,11 @@ class MANGOS_DLL_SPEC Player : public Unit
uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; } uint32 GetArenaTeamIdInvited() { return m_ArenaTeamIdInvited; }
static void LeaveAllArenaTeams(uint64 guid); static void LeaveAllArenaTeams(uint64 guid);
void SetDungeonDifficulty(uint32 dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; } Difficulty GetDifficulty(bool isRaid) const { return isRaid ? m_raidDifficulty : m_dungeonDifficulty; }
uint8 GetDungeonDifficulty() { return m_dungeonDifficulty; } Difficulty GetDungeonDifficulty() const { return m_dungeonDifficulty; }
bool IsHeroicDungeon() { return m_dungeonDifficulty == DUNGEON_DIFFICULTY_HEROIC; } Difficulty GetRaidDifficulty() const { return m_raidDifficulty; }
void SetRaidDifficulty(uint32 raid_difficulty) { m_raidDifficulty = raid_difficulty; } void SetDungeonDifficulty(Difficulty dungeon_difficulty) { m_dungeonDifficulty = dungeon_difficulty; }
uint8 GetRaidDifficulty() { return m_raidDifficulty; } void SetRaidDifficulty(Difficulty raid_difficulty) { m_raidDifficulty = raid_difficulty; }
bool UpdateSkill(uint32 skill_id, uint32 step); bool UpdateSkill(uint32 skill_id, uint32 step);
bool UpdateSkillPro(uint16 SkillId, int32 Chance, 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 SendDungeonDifficulty(bool IsInGroup);
void SendRaidDifficulty(bool IsInGroup); void SendRaidDifficulty(bool IsInGroup);
void ResetInstances(uint8 method); void ResetInstances(uint8 method, bool isRaid);
void SendResetInstanceSuccess(uint32 MapId); void SendResetInstanceSuccess(uint32 MapId);
void SendResetInstanceFailed(uint32 reason, uint32 MapId); void SendResetInstanceFailed(uint32 reason, uint32 MapId);
void SendResetFailedNotify(uint32 mapid); void SendResetFailedNotify(uint32 mapid);
@ -2183,11 +2186,11 @@ class MANGOS_DLL_SPEC Player : public Unit
uint32 m_HomebindTimer; uint32 m_HomebindTimer;
bool m_InstanceValid; bool m_InstanceValid;
// permanent binds and solo binds by difficulty // permanent binds and solo binds by difficulty
BoundInstancesMap m_boundInstances[TOTAL_DUNGEON_DIFFICULTIES]; BoundInstancesMap m_boundInstances[MAX_DIFFICULTY];
InstancePlayerBind* GetBoundInstance(uint32 mapid, uint8 difficulty); InstancePlayerBind* GetBoundInstance(uint32 mapid, Difficulty difficulty);
BoundInstancesMap& GetBoundInstances(uint8 difficulty) { return m_boundInstances[difficulty]; } BoundInstancesMap& GetBoundInstances(Difficulty difficulty) { return m_boundInstances[difficulty]; }
void UnbindInstance(uint32 mapid, uint8 difficulty, bool unload = false); void UnbindInstance(uint32 mapid, Difficulty difficulty, bool unload = false);
void UnbindInstance(BoundInstancesMap::iterator &itr, uint8 difficulty, bool unload = false); void UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficulty, bool unload = false);
InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false); InstancePlayerBind* BindToInstance(InstanceSave *save, bool permanent, bool load = false);
void SendRaidInfo(); void SendRaidInfo();
void SendSavedInstances(); void SendSavedInstances();
@ -2339,8 +2342,8 @@ class MANGOS_DLL_SPEC Player : public Unit
uint32 m_nextSave; uint32 m_nextSave;
time_t m_speakTime; time_t m_speakTime;
uint32 m_speakCount; uint32 m_speakCount;
uint32 m_dungeonDifficulty; Difficulty m_dungeonDifficulty;
uint32 m_raidDifficulty; Difficulty m_raidDifficulty;
uint32 m_atLoginFlags; uint32 m_atLoginFlags;

View file

@ -2408,20 +2408,23 @@ enum DiminishingGroup
DIMINISHING_LIMITONLY DIMINISHING_LIMITONLY
}; };
enum DungeonDifficulties enum Difficulty
{ {
DUNGEON_DIFFICULTY_NORMAL = 0, DUNGEON_DIFFICULTY_NORMAL = 0,
DUNGEON_DIFFICULTY_HEROIC = 1, DUNGEON_DIFFICULTY_HEROIC = 1,
TOTAL_DUNGEON_DIFFICULTIES
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 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 enum SummonType