[8828] Independent instance reset time for different difficulties.

* Store reset time for map/difficulty pairs.
* Use DBC data for reset time and max players instead `instance_template` fields (dropped)
  for each existed map/difficulty pair.
* Fix some "heroic" related checks in spells/etc.
This commit is contained in:
VladimirMangos 2009-11-18 09:58:10 +03:00
parent 70fb82b262
commit 37ba6623bb
19 changed files with 149 additions and 124 deletions

View file

@ -21,7 +21,7 @@
DROP TABLE IF EXISTS `character_db_version`;
CREATE TABLE `character_db_version` (
`required_8721_01_characters_guild` bit(1) default NULL
`required_8828_01_characters_instance_reset` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
--
@ -1170,8 +1170,9 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `instance_reset`;
CREATE TABLE `instance_reset` (
`mapid` int(11) unsigned NOT NULL default '0',
`difficulty` tinyint(1) unsigned NOT NULL default '0',
`resettime` bigint(40) NOT NULL default '0',
PRIMARY KEY (`mapid`)
PRIMARY KEY (`mapid`,`difficulty`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--

View file

@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_8818_01_mangos_mangos_string` bit(1) default NULL
`required_8828_02_mangos_instance_template` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@ -1904,9 +1904,6 @@ CREATE TABLE `instance_template` (
`parent` int(10) unsigned NOT NULL,
`levelMin` tinyint(3) unsigned NOT NULL default '0',
`levelMax` tinyint(3) unsigned NOT NULL default '0',
`maxPlayers` tinyint(3) unsigned NOT NULL default '0',
`maxPlayersHeroic` tinyint(3) unsigned NOT NULL default '0',
`reset_delay` int(10) unsigned NOT NULL default '0',
`startLocX` float default NULL,
`startLocY` float default NULL,
`startLocZ` float default NULL,

View file

@ -0,0 +1,6 @@
ALTER TABLE character_db_version CHANGE COLUMN required_8721_01_characters_guild required_8828_01_characters_instance_reset bit;
ALTER TABLE instance_reset
ADD COLUMN difficulty tinyint(1) unsigned NOT NULL default '0' AFTER mapid,
DROP PRIMARY KEY,
ADD PRIMARY KEY (`mapid`,`difficulty`);

View file

@ -0,0 +1,6 @@
ALTER TABLE db_version CHANGE COLUMN required_8818_01_mangos_mangos_string required_8828_02_mangos_instance_template bit;
ALTER TABLE instance_template
DROP COLUMN maxPlayers,
DROP COLUMN maxPlayersHeroic,
DROP COLUMN reset_delay;

View file

@ -158,6 +158,8 @@ pkgdata_DATA = \
8803_02_mangos_playercreateinfo_action.sql \
8815_01_mangos_mangos_string.sql \
8818_01_mangos_mangos_string.sql \
8828_01_characters_instance_reset.sql \
8828_02_mangos_instance_template.sql \
README
## Additional files to include when running 'make dist'
@ -296,4 +298,6 @@ EXTRA_DIST = \
8803_02_mangos_playercreateinfo_action.sql \
8815_01_mangos_mangos_string.sql \
8818_01_mangos_mangos_string.sql \
8828_01_characters_instance_reset.sql \
8828_02_mangos_instance_template.sql \
README

View file

@ -234,6 +234,8 @@ enum AreaFlags
enum Difficulty
{
DIFFICULTY_DEFAULT = 0,
DUNGEON_DIFFICULTY_NORMAL = 0,
DUNGEON_DIFFICULTY_HEROIC = 1,
@ -249,7 +251,7 @@ enum Difficulty
enum SpawnMask
{
SPAWNMASK_CONTINENT = 1, // any any maps without spawn modes
SPAWNMASK_CONTINENT = (1 << DIFFICULTY_DEFAULT),// any any maps without spawn modes
SPAWNMASK_DUNGEON_NORMAL = (1 << DUNGEON_DIFFICULTY_NORMAL),
SPAWNMASK_DUNGEON_HEROIC = (1 << DUNGEON_DIFFICULTY_HEROIC),

View file

@ -100,7 +100,6 @@ 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);

View file

@ -55,6 +55,7 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT
void Zone2MapCoordinates(float& x,float& y,uint32 zone);
void Map2ZoneCoordinates(float& x,float& y,uint32 zone);
typedef std::map<uint32/*pair32(map,diff)*/,MapDifficulty> MapDifficultyMap;
MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty);
uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls);
@ -113,6 +114,7 @@ extern DBCStorage <LockEntry> sLockStore;
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
extern DBCStorage <MapEntry> sMapStore;
//extern DBCStorage <MapDifficultyEntry> sMapDifficultyStore; -- use GetMapDifficultyData insteed
extern MapDifficultyMap sMapDifficultyMap;
extern DBCStorage <MovieEntry> sMovieStore;
extern DBCStorage <QuestSortEntry> sQuestSortStore;
extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore;

View file

@ -100,13 +100,13 @@ InstanceSave* InstanceSaveManager::AddInstanceSave(uint32 mapId, uint32 instance
{
// initialize reset time
// for normal instances if no creatures are killed the instance will reset in two hours
if(entry->map_type == MAP_RAID || difficulty == DUNGEON_DIFFICULTY_HEROIC)
resetTime = GetResetTimeFor(mapId);
if(entry->map_type == MAP_RAID || difficulty > DUNGEON_DIFFICULTY_NORMAL)
resetTime = GetResetTimeFor(mapId,difficulty);
else
{
resetTime = time(NULL) + 2 * HOUR;
// normally this will be removed soon after in InstanceMap::Add, prevent error
ScheduleReset(true, resetTime, InstResetEvent(0, mapId, instanceId));
ScheduleReset(true, resetTime, InstResetEvent(0, mapId, difficulty, instanceId));
}
}
@ -378,18 +378,26 @@ void InstanceSaveManager::LoadResetTimes()
// get the current reset times for normal instances (these may need to be updated)
// these are only kept in memory for InstanceSaves that are loaded later
// resettime = 0 in the DB for raid/heroic instances so those are skipped
typedef std::map<uint32, std::pair<uint32, time_t> > ResetTimeMapType;
ResetTimeMapType InstResetTime;
QueryResult *result = CharacterDatabase.Query("SELECT id, map, resettime FROM instance WHERE resettime > 0");
typedef std::pair<uint32 /*PAIR32(map,difficulty)*/, time_t> ResetTimeMapDiffType;
typedef std::map<uint32, ResetTimeMapDiffType> InstResetTimeMapDiffType;
InstResetTimeMapDiffType instResetTime;
// index instance ids by map/difficulty pairs for fast reset warning send
typedef std::multimap<uint32 /*PAIR32(map,difficulty)*/, uint32 /*instanceid*/ > ResetTimeMapDiffInstances;
ResetTimeMapDiffInstances mapDiffResetInstances;
QueryResult *result = CharacterDatabase.Query("SELECT id, map, difficulty, resettime FROM instance WHERE resettime > 0");
if( result )
{
do
{
if(time_t resettime = time_t((*result)[2].GetUInt64()))
if(time_t resettime = time_t((*result)[3].GetUInt64()))
{
uint32 id = (*result)[0].GetUInt32();
uint32 mapid = (*result)[1].GetUInt32();
InstResetTime[id] = std::pair<uint32, uint64>(mapid, resettime);
uint32 difficulty = (*result)[2].GetUInt32();
instResetTime[id] = ResetTimeMapDiffType(MAKE_PAIR32(mapid,difficulty), resettime);
mapDiffResetInstances.insert(ResetTimeMapDiffInstances::value_type(MAKE_PAIR32(mapid,difficulty),id));
}
}
while (result->NextRow());
@ -404,8 +412,8 @@ void InstanceSaveManager::LoadResetTimes()
Field *fields = result->Fetch();
uint32 instance = fields[1].GetUInt32();
time_t resettime = time_t(fields[0].GetUInt64() + 2 * HOUR);
ResetTimeMapType::iterator itr = InstResetTime.find(instance);
if(itr != InstResetTime.end() && itr->second.second != resettime)
InstResetTimeMapDiffType::iterator itr = instResetTime.find(instance);
if(itr != instResetTime.end() && itr->second.second != resettime)
{
CharacterDatabase.DirectPExecute("UPDATE instance SET resettime = '"UI64FMTD"' WHERE id = '%u'", uint64(resettime), instance);
itr->second.second = resettime;
@ -416,59 +424,65 @@ void InstanceSaveManager::LoadResetTimes()
}
// schedule the reset times
for(ResetTimeMapType::iterator itr = InstResetTime.begin(); itr != InstResetTime.end(); ++itr)
for(InstResetTimeMapDiffType::iterator itr = instResetTime.begin(); itr != instResetTime.end(); ++itr)
if(itr->second.second > now)
ScheduleReset(true, itr->second.second, InstResetEvent(0, itr->second.first, itr->first));
ScheduleReset(true, itr->second.second, InstResetEvent(0, PAIR32_LOPART(itr->second.first),Difficulty(PAIR32_HIPART(itr->second.first)),itr->first));
}
// load the global respawn times for raid/heroic instances
uint32 diff = sWorld.getConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR;
m_resetTimeByMapId.resize(sMapStore.GetNumRows()+1);
result = CharacterDatabase.Query("SELECT mapid, resettime FROM instance_reset");
result = CharacterDatabase.Query("SELECT mapid, difficulty, resettime FROM instance_reset");
if(result)
{
do
{
Field *fields = result->Fetch();
uint32 mapid = fields[0].GetUInt32();
if(!ObjectMgr::GetInstanceTemplate(mapid))
Difficulty difficulty = Difficulty(fields[1].GetUInt32());
uint64 oldresettime = fields[2].GetUInt64();
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
if(!mapDiff)
{
sLog.outError("InstanceSaveManager::LoadResetTimes: invalid mapid %u in instance_reset!", mapid);
CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u'", mapid);
sLog.outError("InstanceSaveManager::LoadResetTimes: invalid mapid(%u)/difficulty(%u) pair in instance_reset!", mapid, difficulty);
CharacterDatabase.DirectPExecute("DELETE FROM instance_reset WHERE mapid = '%u' AND difficulty = '%u'", mapid,difficulty);
continue;
}
// update the reset time if the hour in the configs changes
uint64 oldresettime = fields[1].GetUInt64();
uint64 newresettime = (oldresettime / DAY) * DAY + diff;
if(oldresettime != newresettime)
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u'", newresettime, mapid);
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty = '%u'", newresettime, mapid, difficulty);
m_resetTimeByMapId[mapid] = newresettime;
SetResetTimeFor(mapid,difficulty,newresettime);
} while(result->NextRow());
delete result;
}
// clean expired instances, references to them will be deleted in CleanupInstances
// must be done before calculating new reset times
_DelHelper(CharacterDatabase, "id, map, difficulty", "instance", "LEFT JOIN instance_reset ON mapid = map WHERE (instance.resettime < '"UI64FMTD"' AND instance.resettime > '0') OR (NOT instance_reset.resettime IS NULL AND instance_reset.resettime < '"UI64FMTD"')", (uint64)now, (uint64)now);
_DelHelper(CharacterDatabase, "id, map, instance.difficulty", "instance", "LEFT JOIN instance_reset ON mapid = map AND instance.difficulty = instance_reset.difficulty WHERE (instance.resettime < '"UI64FMTD"' AND instance.resettime > '0') OR (NOT instance_reset.resettime IS NULL AND instance_reset.resettime < '"UI64FMTD"')", (uint64)now, (uint64)now);
// calculate new global reset times for expired instances and those that have never been reset yet
// add the global reset times to the priority queue
for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
for(MapDifficultyMap::const_iterator itr = sMapDifficultyMap.begin(); itr != sMapDifficultyMap.end(); ++itr)
{
InstanceTemplate const* temp = ObjectMgr::GetInstanceTemplate(i);
if(!temp || temp->reset_delay == 0)
uint32 map_diff_pair = itr->first;
uint32 mapid = PAIR32_LOPART(map_diff_pair);
Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair));
MapDifficulty const* mapDiff = &itr->second;
if (!mapDiff->resetTime)
continue;
uint32 period = temp->reset_delay * DAY;
assert(period != 0);
time_t t = m_resetTimeByMapId[temp->map];
// the reset_delay must be at least one day
uint32 period = (mapDiff->resetTime / DAY * sWorld.getRate(RATE_INSTANCE_RESET_TIME)) * DAY;
time_t t = GetResetTimeFor(mapid,difficulty);
if(!t)
{
// initialize the reset time
t = today + period + diff;
CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u','"UI64FMTD"')", i, (uint64)t);
CharacterDatabase.DirectPExecute("INSERT INTO instance_reset VALUES ('%u','%u','"UI64FMTD"')", mapid, difficulty, (uint64)t);
}
if(t < now)
@ -477,17 +491,23 @@ void InstanceSaveManager::LoadResetTimes()
// calculate the next reset time
t = (t / DAY) * DAY;
t += ((today - t) / period + 1) * period + diff;
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u'", (uint64)t, i);
CharacterDatabase.DirectPExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%u' AND difficulty= '%u'", (uint64)t, mapid, difficulty);
}
m_resetTimeByMapId[temp->map] = t;
SetResetTimeFor(mapid,difficulty,t);
// schedule the global reset/warning
uint8 type = 1;
static int tim[4] = {3600, 900, 300, 60};
for(; type < 4; type++)
if(t - tim[type-1] > now) break;
ScheduleReset(true, t - tim[type-1], InstResetEvent(type, i));
if(t - tim[type-1] > now)
break;
for(ResetTimeMapDiffInstances::const_iterator in_itr = mapDiffResetInstances.lower_bound(map_diff_pair);
in_itr != mapDiffResetInstances.upper_bound(map_diff_pair); ++in_itr)
{
ScheduleReset(true, t - tim[type-1], InstResetEvent(type, mapid, difficulty, in_itr->second));
}
}
}
@ -528,8 +548,8 @@ void InstanceSaveManager::Update()
else
{
// global reset/warning for a certain map
time_t resetTime = GetResetTimeFor(event.mapid);
_ResetOrWarnAll(event.mapid, event.type != 4, resetTime - now);
time_t resetTime = GetResetTimeFor(event.mapid,event.difficulty);
_ResetOrWarnAll(event.mapid, event.difficulty, event.type != 4, resetTime - now);
if(event.type != 4)
{
// schedule the next warning/reset
@ -580,29 +600,28 @@ void InstanceSaveManager::_ResetInstance(uint32 mapid, uint32 instanceId)
else sObjectMgr.DeleteRespawnTimeForInstance(instanceId); // even if map is not loaded
}
void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeLeft)
void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeLeft)
{
// global reset for all instances of the given map
// note: this isn't fast but it's meant to be executed very rarely
Map const *map = sMapMgr.CreateBaseMap(mapid);
if(!map->Instanceable())
MapEntry const *mapEntry = sMapStore.LookupEntry(mapid);
if (!mapEntry->Instanceable())
return;
uint64 now = (uint64)time(NULL);
if (!warn)
{
// this is called one minute before the reset time
InstanceTemplate const* temp = ObjectMgr::GetInstanceTemplate(mapid);
if(!temp || !temp->reset_delay)
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid,difficulty);
if (!mapDiff || !mapDiff->resetTime)
{
sLog.outError("InstanceSaveManager::ResetOrWarnAll: no instance template or reset delay for map %d", mapid);
sLog.outError("InstanceSaveManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
return;
}
// remove all binds to instances of the given map
for(InstanceSaveHashMap::iterator itr = m_instanceSaveById.begin(); itr != m_instanceSaveById.end();)
{
if(itr->second->GetMapId() == mapid)
if (itr->second->GetMapId() == mapid && itr->second->GetDifficulty() == difficulty)
_ResetSave(itr);
else
++itr;
@ -617,12 +636,14 @@ void InstanceSaveManager::_ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeLe
// calculate the next reset time
uint32 diff = sWorld.getConfig(CONFIG_INSTANCE_RESET_TIME_HOUR) * HOUR;
uint32 period = temp->reset_delay * DAY;
uint32 period = mapDiff->resetTime * DAY;
uint64 next_reset = ((now + timeLeft + MINUTE) / DAY * DAY) + period + diff;
// update it in the DB
CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%d'", next_reset, mapid);
CharacterDatabase.PExecute("UPDATE instance_reset SET resettime = '"UI64FMTD"' WHERE mapid = '%d' AND difficulty = '%d'", next_reset, mapid, difficulty);
}
// note: this isn't fast but it's meant to be executed very rarely
Map const *map = sMapMgr.CreateBaseMap(mapid); // _not_ include difficulty
MapInstanced::InstancedMaps &instMaps = ((MapInstanced*)map)->GetInstancedMaps();
MapInstanced::InstancedMaps::iterator mitr;
for(mitr = instMaps.begin(); mitr != instMaps.end(); ++mitr)

View file

@ -118,28 +118,39 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
InstanceSaveManager();
~InstanceSaveManager();
typedef std::map<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveMap;
typedef UNORDERED_MAP<uint32 /*InstanceId*/, InstanceSave*> InstanceSaveHashMap;
typedef std::map<uint32 /*mapId*/, InstanceSaveMap> InstanceSaveMapMap;
typedef UNORDERED_MAP<uint32 /*mapId*/, InstanceSaveHashMap> InstanceSaveMapMap;
/* resetTime is a global propery of each (raid/heroic) map
all instances of that map reset at the same time */
struct InstResetEvent
{
uint8 type;
Difficulty difficulty:8;
uint16 mapid;
uint16 instanceId;
InstResetEvent(uint8 t = 0, uint16 m = 0, uint16 i = 0) : type(t), mapid(m), instanceId(i) {}
InstResetEvent() : type(0), difficulty(DUNGEON_DIFFICULTY_NORMAL), mapid(0), instanceId(0) {}
InstResetEvent(uint8 t, uint32 _mapid, Difficulty d, uint16 _instanceid)
: type(t), difficulty(d), mapid(_mapid), instanceId(_instanceid) {}
bool operator == (const InstResetEvent& e) { return e.instanceId == instanceId; }
};
typedef std::multimap<time_t /*resetTime*/, InstResetEvent> ResetTimeQueue;
typedef std::vector<time_t /*resetTime*/> ResetTimeVector;
typedef UNORDERED_MAP<uint32 /*PAIR32(map,difficulty)*/,time_t /*resetTime*/> ResetTimeByMapDifficultyMap;
void CleanupInstances();
void PackInstances();
void LoadResetTimes();
time_t GetResetTimeFor(uint32 mapid) { return m_resetTimeByMapId[mapid]; }
time_t GetResetTimeFor(uint32 mapid, Difficulty d) const
{
ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid,d));
return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0;
}
void SetResetTimeFor(uint32 mapid, Difficulty d, time_t t)
{
m_resetTimeByMapDifficulty[MAKE_PAIR32(mapid,d)] = t;
}
void ScheduleReset(bool add, time_t time, InstResetEvent event);
void Update();
@ -156,7 +167,7 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
uint32 GetNumBoundGroupsTotal();
private:
void _ResetOrWarnAll(uint32 mapid, bool warn, uint32 timeleft);
void _ResetOrWarnAll(uint32 mapid, Difficulty difficulty, bool warn, uint32 timeleft);
void _ResetInstance(uint32 mapid, uint32 instanceId);
void _ResetSave(InstanceSaveHashMap::iterator &itr);
void _DelHelper(DatabaseType &db, const char *fields, const char *table, const char *queryTail,...);
@ -164,8 +175,8 @@ class MANGOS_DLL_DECL InstanceSaveManager : public MaNGOS::Singleton<InstanceSav
bool lock_instLists;
// fast lookup by instance id
InstanceSaveHashMap m_instanceSaveById;
// fast lookup for reset times
ResetTimeVector m_resetTimeByMapId;
// fast lookup for reset times (always use existed functions for access/set)
ResetTimeByMapDifficultyMap m_resetTimeByMapDifficulty;
ResetTimeQueue m_resetTimeQueue;
};

View file

@ -2610,22 +2610,32 @@ void InstanceMap::SetResetSchedule(bool on)
// only for normal instances
// the reset time is only scheduled when there are no payers inside
// it is assumed that the reset time will rarely (if ever) change while the reset is scheduled
if(IsDungeon() && !HavePlayers() && !IsRaid() && !IsHeroic())
if(IsDungeon() && !HavePlayers() && !IsRaidOrHeroicDungeon())
{
InstanceSave *save = sInstanceSaveMgr.GetInstanceSave(GetInstanceId());
if(!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId());
else sInstanceSaveMgr.ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), GetInstanceId()));
else sInstanceSaveMgr.ScheduleReset(on, save->GetResetTime(), InstanceSaveManager::InstResetEvent(0, GetId(), Difficulty(GetSpawnMode()), GetInstanceId()));
}
}
MapDifficulty const* InstanceMap::GetMapDifficulty() const
{
return GetMapDifficultyData(GetId(),GetDifficulty());
}
uint32 InstanceMap::GetMaxPlayers() const
{
InstanceTemplate const* iTemplate = ObjectMgr::GetInstanceTemplate(GetId());
if(!iTemplate)
return 0;
return IsHeroic() ? iTemplate->maxPlayersHeroic : iTemplate->maxPlayers;
MapDifficulty const* mapDiff = GetMapDifficulty();
return mapDiff ? mapDiff->maxPlayers : 0;
}
uint32 InstanceMap::GetMaxResetDelay() const
{
MapDifficulty const* mapDiff = GetMapDifficulty();
return mapDiff ? mapDiff->resetTime : 0;
}
/* ******* Battleground Instance Maps ******* */
BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId, Map* _parent, uint8 spawnMode)
@ -3560,4 +3570,3 @@ uint32 Map::GenerateLocalLowGuid(HighGuid guidhigh)
ASSERT(0);
return 0;
}

View file

@ -227,9 +227,6 @@ struct InstanceTemplate
uint32 parent;
uint32 levelMin;
uint32 levelMax;
uint32 maxPlayers;
uint32 maxPlayersHeroic;
uint32 reset_delay; // FIX ME: now exist normal/heroic raids with possible different time of reset.
float startLocX;
float startLocY;
float startLocZ;
@ -373,7 +370,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 IsRaid() ? i_spawnMode >= RAID_DIFFICULTY_10MAN_HEROIC : i_spawnMode >= DUNGEON_DIFFICULTY_HEROIC; }
bool IsRaidOrHeroicDungeon() const { return IsRaid() || i_spawnMode > DUNGEON_DIFFICULTY_NORMAL; }
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(); }
@ -599,7 +596,12 @@ class MANGOS_DLL_SPEC InstanceMap : public Map
bool CanEnter(Player* player);
void SendResetWarnings(uint32 timeLeft) const;
void SetResetSchedule(bool on);
// have meaning only for instanced map (that have set real difficulty)
Difficulty GetDifficulty() const { return Difficulty(GetSpawnMode()); }
uint32 GetMaxPlayers() const;
uint32 GetMaxResetDelay() const;
MapDifficulty const* GetMapDifficulty() const;
virtual void InitVisibilityDistance();
private:

View file

@ -141,20 +141,13 @@ void WorldSession::HandleMoveWorldportAckOpcode()
}
}
if (mInstance)
if (mInstance && mEntry->IsDungeon())
{
if(mEntry->IsRaid())
Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid());
if (uint32 timeReset = sInstanceSaveMgr.GetResetTimeFor(GetPlayer()->GetMapId(),diff))
{
uint32 timeleft = sInstanceSaveMgr.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 = sInstanceSaveMgr.GetResetTimeFor(GetPlayer()->GetMapId()) - time(NULL);
GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), GetPlayer()->GetDungeonDifficulty(), timeleft);
}
uint32 timeleft = timeReset - time(NULL);
GetPlayer()->SendInstanceResetWarning(GetPlayer()->GetMapId(), diff, timeleft);
}
}

View file

@ -4593,42 +4593,14 @@ void ObjectMgr::LoadInstanceTemplate()
if(!temp)
continue;
const MapEntry* entry = sMapStore.LookupEntry(temp->map);
if(!entry)
{
if(!MapManager::IsValidMAP(temp->map))
sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map);
continue;
}
//FIXME: now exist heroic instance, normal/heroic raid instances
// entry->resetTimeHeroic store reset time for both heroic mode instance (raid and non-raid)
// entry->resetTimeRaid store reset time for normal raid only
// for current state entry->resetTimeRaid == entry->resetTimeHeroic in case raid instances with heroic mode.
// but at some point wee need implement reset time dependent from raid instance mode
if(temp->reset_delay == 0)
if(!MapManager::IsValidMapCoord(temp->parent,temp->startLocX,temp->startLocY,temp->startLocZ,temp->startLocO))
{
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(mapDiffHeroic && mapDiffHeroic->resetTime) // for both raid and non raids, read above
{
temp->reset_delay = mapDiffHeroic->resetTime / DAY;
sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad parent entrance coordinates for map id %d template!", temp->map);
temp->parent = 0; // will have wrong continent 0 parent, at least existed
}
else if (mapDiffNorm && mapDiffNorm->resetTime && entry->map_type == MAP_RAID)
// for normal raid only
{
temp->reset_delay = mapDiffNorm->resetTime / DAY;
}
}
// the reset_delay must be at least one day
temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME)));
}
sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount );

View file

@ -2319,7 +2319,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
{
if (m_target->GetMap()->IsDungeon())
{
uint32 spellId = m_target->GetMap()->IsHeroic() ? 46163 : 44190;
uint32 spellId = ((InstanceMap*)m_target->GetMap())->GetDifficulty() == DIFFICULTY_DEFAULT ? 44190 : 46163;
m_target->CastSpell(m_target, spellId, true, NULL, this);
}

View file

@ -683,7 +683,7 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if(m->IsDungeon() && creditedPlayer)
{
if(m->IsRaid() || m->IsHeroic())
if (m->IsRaidOrHeroicDungeon())
{
if(cVictim->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer);

View file

@ -36,8 +36,8 @@ const char GameObjectInfodstfmt[]="iiissssiifiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
const char ItemPrototypesrcfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiisiiii";
const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffiffiiiiiiiiiifiiifiiiiiifiiiiiifiiiiiifiiiiiifiiiisiiiiiiiiiiiiiiiiiiiiiiiiifiiiiiiii";
const char PageTextfmt[]="isi";
const char InstanceTemplatesrcfmt[]="iiiiiiiffffs";
const char InstanceTemplatedstfmt[]="iiiiiiiffffi";
const char InstanceTemplatesrcfmt[]="iiiiffffs";
const char InstanceTemplatedstfmt[]="iiiiffffi";
SQLStorage sCreatureStorage(CreatureInfosrcfmt, CreatureInfodstfmt, "entry","creature_template");
SQLStorage sCreatureDataAddonStorage(CreatureDataAddonInfofmt,"guid","creature_addon");

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "8827"
#define REVISION_NR "8828"
#endif // __REVISION_NR_H__

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_8721_01_characters_guild"
#define REVISION_DB_MANGOS "required_8818_01_mangos_mangos_string"
#define REVISION_DB_CHARACTERS "required_8828_01_characters_instance_reset"
#define REVISION_DB_MANGOS "required_8828_02_mangos_instance_template"
#define REVISION_DB_REALMD "required_8728_01_realmd_account"
#endif // __REVISION_SQL_H__