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;
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:

View file

@ -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
{

View file

@ -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)
{

View file

@ -96,6 +96,12 @@ DBCStorage <LockEntry> sLockStore(LockEntryfmt);
DBCStorage <MailTemplateEntry> sMailTemplateStore(MailTemplateEntryfmt);
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 <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt);
@ -129,7 +135,7 @@ TalentSpellPosMap sTalentSpellPosMap;
DBCStorage <TalentTabEntry> 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 <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
TaxiMask sTaxiNodesMask;
@ -139,10 +145,10 @@ TaxiMask sOldContinentsNodesMask;
TaxiPathSetBySource sTaxiPathSetBySource;
DBCStorage <TaxiPathEntry> sTaxiPathStore(TaxiPathEntryfmt);
// DBC used only for initialization sTaxiPathSetBySource at startup.
// DBC used only for initialization sTaxiPathNodeStore at startup.
TaxiPathNodesByPath sTaxiPathNodesByPath;
static DBCStorage <TaxiPathNodeEntry> sTaxiPathNodeStore(TaxiPathNodeEntryfmt);
DBCStorage <TotemCategoryEntry> sTotemCategoryStore(TotemCategoryEntryfmt);
DBCStorage <VehicleEntry> sVehicleStore(VehicleEntryfmt);
DBCStorage <VehicleSeatEntry> 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];

View file

@ -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 <AchievementEntry> sAchievementStore;
@ -109,6 +111,7 @@ extern DBCStorage <ItemSetEntry> sItemSetStore;
extern DBCStorage <LockEntry> sLockStore;
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
extern DBCStorage <MapEntry> sMapStore;
//extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed
extern DBCStorage <MovieEntry> sMovieStore;
extern DBCStorage <QuestSortEntry> sQuestSortStore;
extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore;

View file

@ -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) {}

View file

@ -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";

View file

@ -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())

View file

@ -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

View file

@ -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;

View file

@ -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<Player*> PlayerListType;
typedef std::list<Group*> 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::Singleton<InstanceSav
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);
static void DeleteInstanceFromDB(uint32 instanceid);

View file

@ -537,19 +537,22 @@ bool ChatHandler::HandleGonameCommand(const char* args)
// if the player or the player's group is bound to another instance
// 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)
{
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());

View file

@ -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

View file

@ -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)

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
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(); }

View file

@ -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");

View file

@ -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;

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
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;
}

View file

@ -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));
}
}

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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