mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 10:37:03 +00:00
[12195] Improve AreaTrigger teleport requirement checks
Implement AreaLockStatus concept by rsa Also drop basicly unneeded `areatrigger_teleport`.required_failed_text field. This concept is still in testing phase, please feedback results of some glitches that might exist! TODO: Use Player::GetAreaLockStatus or GetAreaTriggerLockStatus for other "CanEnter" checks as well. Signed-off-by: Schmoozerd <schmoozerd@scriptdev2.com>
This commit is contained in:
parent
7901613472
commit
9022705faf
22 changed files with 304 additions and 162 deletions
|
|
@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
|
||||||
`version` varchar(120) default NULL,
|
`version` varchar(120) default NULL,
|
||||||
`creature_ai_version` varchar(120) default NULL,
|
`creature_ai_version` varchar(120) default NULL,
|
||||||
`cache_id` int(10) default '0',
|
`cache_id` int(10) default '0',
|
||||||
`required_12186_01_mangos_item_template` bit(1) default NULL
|
`required_12195_02_mangos_mangos_string"` bit(1) default NULL
|
||||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
@ -141,7 +141,6 @@ CREATE TABLE `areatrigger_teleport` (
|
||||||
`heroic_key2` mediumint(8) unsigned NOT NULL default '0',
|
`heroic_key2` mediumint(8) unsigned NOT NULL default '0',
|
||||||
`required_quest_done` int(11) unsigned NOT NULL default '0',
|
`required_quest_done` int(11) unsigned NOT NULL default '0',
|
||||||
`required_quest_done_heroic` int(11) unsigned NOT NULL default '0',
|
`required_quest_done_heroic` int(11) unsigned NOT NULL default '0',
|
||||||
`required_failed_text` text,
|
|
||||||
`target_map` smallint(5) unsigned NOT NULL default '0',
|
`target_map` smallint(5) unsigned NOT NULL default '0',
|
||||||
`target_position_x` float NOT NULL default '0',
|
`target_position_x` float NOT NULL default '0',
|
||||||
`target_position_y` float NOT NULL default '0',
|
`target_position_y` float NOT NULL default '0',
|
||||||
|
|
@ -4039,6 +4038,7 @@ INSERT INTO `mangos_string` VALUES
|
||||||
(815,'Initiate',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
(815,'Initiate',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
||||||
(816,'Your body is too exhausted to travel to the Spectral Realm.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
(816,'Your body is too exhausted to travel to the Spectral Realm.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
||||||
(817,'Warning: You\'ve entered a no-fly zone and are about to be dismounted!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
(817,'Warning: You\'ve entered a no-fly zone and are about to be dismounted!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
||||||
|
(818,'You can\'t enter Black Morass until you rescue Thrall from Durnholde Keep.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
||||||
(1000,'Exiting daemon...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
(1000,'Exiting daemon...',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
||||||
(1001,'Account deleted: %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
(1001,'Account deleted: %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
||||||
(1002,'Account %s NOT deleted (probably sql file format was updated)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
(1002,'Account %s NOT deleted (probably sql file format was updated)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
|
||||||
|
|
|
||||||
3
sql/updates/12195_01_mangos_areatrigger_teleport.sql
Normal file
3
sql/updates/12195_01_mangos_areatrigger_teleport.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE db_version CHANGE COLUMN required_12186_01_mangos_item_template required_12195_01_mangos_areatrigger_teleport bit;
|
||||||
|
|
||||||
|
ALTER TABLE areatrigger_teleport DROP COLUMN required_failed_text;
|
||||||
5
sql/updates/12195_02_mangos_mangos_string.sql
Normal file
5
sql/updates/12195_02_mangos_mangos_string.sql
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
ALTER TABLE db_version CHANGE COLUMN required_12195_01_mangos_areatrigger_teleport required_12195_02_mangos_mangos_string bit;
|
||||||
|
|
||||||
|
DELETE FROM mangos_string WHERE entry=818;
|
||||||
|
INSERT INTO mangos_string VALUES
|
||||||
|
(818,'You can\'t enter Black Morass until you rescue Thrall from Durnholde Keep.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||||
|
|
@ -140,7 +140,6 @@ 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
|
DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading
|
||||||
MapDifficultyMap sMapDifficultyMap;
|
MapDifficultyMap sMapDifficultyMap;
|
||||||
|
|
||||||
|
|
@ -540,8 +539,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||||
// fill data
|
// fill data
|
||||||
for(uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i)
|
for(uint32 i = 1; i < sMapDifficultyStore.GetNumRows(); ++i)
|
||||||
if(MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i))
|
if(MapDifficultyEntry const* entry = sMapDifficultyStore.LookupEntry(i))
|
||||||
sMapDifficultyMap[MAKE_PAIR32(entry->MapId,entry->Difficulty)] = MapDifficulty(entry->resetTime,entry->maxPlayers);
|
sMapDifficultyMap[MAKE_PAIR32(entry->MapId, entry->Difficulty)] = entry;
|
||||||
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,sNumTalentsAtLevelStore, dbcPath,"NumTalentsAtLevel.dbc");
|
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sNumTalentsAtLevelStore, dbcPath,"NumTalentsAtLevel.dbc");
|
||||||
|
|
@ -1024,10 +1022,10 @@ bool Map2ZoneCoordinates(float& x,float& y,uint32 zone)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
|
MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty)
|
||||||
{
|
{
|
||||||
MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId,difficulty));
|
MapDifficultyMap::const_iterator itr = sMapDifficultyMap.find(MAKE_PAIR32(mapId,difficulty));
|
||||||
return itr != sMapDifficultyMap.end() ? &itr->second : NULL;
|
return itr != sMapDifficultyMap.end() ? itr->second : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PvPDifficultyEntry const* GetBattlegroundBracketByLevel( uint32 mapid, uint32 level )
|
PvPDifficultyEntry const* GetBattlegroundBracketByLevel( uint32 mapid, uint32 level )
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ bool IsTotemCategoryCompatiableWith(uint32 itemTotemCategoryId, uint32 requiredT
|
||||||
bool Zone2MapCoordinates(float& x,float& y,uint32 zone);
|
bool Zone2MapCoordinates(float& x,float& y,uint32 zone);
|
||||||
bool Map2ZoneCoordinates(float& x,float& y,uint32 zone);
|
bool Map2ZoneCoordinates(float& x,float& y,uint32 zone);
|
||||||
|
|
||||||
typedef std::map<uint32/*pair32(map,diff)*/,MapDifficulty> MapDifficultyMap;
|
typedef std::map<uint32/*pair32(map,diff)*/, MapDifficultyEntry const*> MapDifficultyMap;
|
||||||
MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty);
|
MapDifficultyEntry const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty);
|
||||||
|
|
||||||
// natural order for difficulties up-down iteration
|
// natural order for difficulties up-down iteration
|
||||||
// difficulties for dungeons/battleground ordered in normal way
|
// difficulties for dungeons/battleground ordered in normal way
|
||||||
|
|
|
||||||
|
|
@ -2411,15 +2411,6 @@ typedef std::set<uint32> PetFamilySpellsSet;
|
||||||
typedef std::map<uint32,PetFamilySpellsSet > PetFamilySpellsStore;
|
typedef std::map<uint32,PetFamilySpellsSet > PetFamilySpellsStore;
|
||||||
|
|
||||||
// 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; // in secs, 0 if no fixed reset time
|
|
||||||
uint32 maxPlayers; // some heroic dungeons have 0 when expect same value as in normal dificulty case
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TalentSpellPos
|
struct TalentSpellPos
|
||||||
{
|
{
|
||||||
TalentSpellPos() : talent_id(0), rank(0) {}
|
TalentSpellPos() : talent_id(0), rank(0) {}
|
||||||
|
|
|
||||||
|
|
@ -1780,7 +1780,7 @@ InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, Player* player)
|
||||||
Difficulty difficulty = player->GetDifficulty(mapEntry->IsRaid());
|
Difficulty difficulty = player->GetDifficulty(mapEntry->IsRaid());
|
||||||
|
|
||||||
// some instances only have one difficulty
|
// some instances only have one difficulty
|
||||||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
||||||
if (!mapDiff)
|
if (!mapDiff)
|
||||||
difficulty = DUNGEON_DIFFICULTY_NORMAL;
|
difficulty = DUNGEON_DIFFICULTY_NORMAL;
|
||||||
|
|
||||||
|
|
@ -1794,7 +1794,7 @@ InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, Player* player)
|
||||||
InstanceGroupBind* Group::GetBoundInstance(Map* aMap, Difficulty difficulty)
|
InstanceGroupBind* Group::GetBoundInstance(Map* aMap, Difficulty difficulty)
|
||||||
{
|
{
|
||||||
// some instances only have one difficulty
|
// some instances only have one difficulty
|
||||||
MapDifficulty const* mapDiff = GetMapDifficultyData(aMap->GetId(), difficulty);
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(aMap->GetId(), difficulty);
|
||||||
if (!mapDiff)
|
if (!mapDiff)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -809,7 +809,8 @@ enum MangosStrings
|
||||||
LANG_GUILD_INITIATE = 815,
|
LANG_GUILD_INITIATE = 815,
|
||||||
LANG_FAIL_ENTER_SPECTRAL_REALM = 816,
|
LANG_FAIL_ENTER_SPECTRAL_REALM = 816,
|
||||||
LANG_NO_FLY_ZONE = 817,
|
LANG_NO_FLY_ZONE = 817,
|
||||||
// Room for in-game strings 818-999 not used
|
LANG_TELEREQ_QUEST_BLACK_MORASS = 818,
|
||||||
|
// Room for in-game strings 819-999 not used
|
||||||
|
|
||||||
// Level 4 (CLI only commands)
|
// Level 4 (CLI only commands)
|
||||||
LANG_COMMAND_EXIT = 1000,
|
LANG_COMMAND_EXIT = 1000,
|
||||||
|
|
|
||||||
|
|
@ -824,21 +824,21 @@ void Map::UnloadAll(bool pForce)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MapDifficulty const* Map::GetMapDifficulty() const
|
MapDifficultyEntry const* Map::GetMapDifficulty() const
|
||||||
{
|
{
|
||||||
return GetMapDifficultyData(GetId(), GetDifficulty());
|
return GetMapDifficultyData(GetId(), GetDifficulty());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Map::GetMaxPlayers() const
|
uint32 Map::GetMaxPlayers() const
|
||||||
{
|
{
|
||||||
if (MapDifficulty const* mapDiff = GetMapDifficulty())
|
if (MapDifficultyEntry const* mapDiff = GetMapDifficulty())
|
||||||
{
|
{
|
||||||
if (mapDiff->maxPlayers || IsRegularDifficulty()) // Normal case (expect that regular difficulty always have correct maxplayers)
|
if (mapDiff->maxPlayers || IsRegularDifficulty()) // Normal case (expect that regular difficulty always have correct maxplayers)
|
||||||
return mapDiff->maxPlayers;
|
return mapDiff->maxPlayers;
|
||||||
else // DBC have 0 maxplayers for heroic instances with expansion < 2
|
else // DBC have 0 maxplayers for heroic instances with expansion < 2
|
||||||
{
|
{
|
||||||
// The heroic entry exists, so we don't have to check anything, simply return normal max players
|
// The heroic entry exists, so we don't have to check anything, simply return normal max players
|
||||||
MapDifficulty const* normalDiff = GetMapDifficultyData(i_id, REGULAR_DIFFICULTY);
|
MapDifficultyEntry const* normalDiff = GetMapDifficultyData(i_id, REGULAR_DIFFICULTY);
|
||||||
return normalDiff ? normalDiff->maxPlayers : 0;
|
return normalDiff ? normalDiff->maxPlayers : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>
|
||||||
bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; }
|
bool IsRegularDifficulty() const { return GetDifficulty() == REGULAR_DIFFICULTY; }
|
||||||
uint32 GetMaxPlayers() const; // dependent from map difficulty
|
uint32 GetMaxPlayers() const; // dependent from map difficulty
|
||||||
uint32 GetMaxResetDelay() const; // dependent from map difficulty
|
uint32 GetMaxResetDelay() const; // dependent from map difficulty
|
||||||
MapDifficulty const* GetMapDifficulty() const; // dependent from map difficulty
|
MapDifficultyEntry const* GetMapDifficulty() const; // dependent from map difficulty
|
||||||
|
|
||||||
bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); }
|
bool Instanceable() const { return i_mapEntry && i_mapEntry->Instanceable(); }
|
||||||
// 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
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ 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
|
||||||
MapDifficulty const* mapDiff = GetMapDifficultyData(entry->MapID, player->GetDifficulty(entry->map_type == MAP_RAID));
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(entry->MapID, player->GetDifficulty(entry->map_type == MAP_RAID));
|
||||||
if (!mapDiff)
|
if (!mapDiff)
|
||||||
{
|
{
|
||||||
bool isRegularTargetMap = player->GetDifficulty(entry->IsRaid()) == REGULAR_DIFFICULTY;
|
bool isRegularTargetMap = player->GetDifficulty(entry->IsRaid()) == REGULAR_DIFFICULTY;
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ bool BattleGroundPersistentState::CanBeUnload() const
|
||||||
|
|
||||||
//== DungeonResetScheduler functions ======================
|
//== DungeonResetScheduler functions ======================
|
||||||
|
|
||||||
uint32 DungeonResetScheduler::GetMaxResetTimeFor(MapDifficulty const* mapDiff)
|
uint32 DungeonResetScheduler::GetMaxResetTimeFor(MapDifficultyEntry const* mapDiff)
|
||||||
{
|
{
|
||||||
if (!mapDiff || !mapDiff->resetTime)
|
if (!mapDiff || !mapDiff->resetTime)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -332,7 +332,7 @@ uint32 DungeonResetScheduler::GetMaxResetTimeFor(MapDifficulty const* mapDiff)
|
||||||
return delay;
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t DungeonResetScheduler::CalculateNextResetTime(MapDifficulty const* mapDiff, time_t prevResetTime)
|
time_t DungeonResetScheduler::CalculateNextResetTime(MapDifficultyEntry const* mapDiff, time_t prevResetTime)
|
||||||
{
|
{
|
||||||
uint32 diff = sWorld.getConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR) * HOUR;
|
uint32 diff = sWorld.getConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR) * HOUR;
|
||||||
uint32 period = GetMaxResetTimeFor(mapDiff);
|
uint32 period = GetMaxResetTimeFor(mapDiff);
|
||||||
|
|
@ -450,7 +450,7 @@ void DungeonResetScheduler::LoadResetTimes()
|
||||||
uint32 map_diff_pair = itr->first;
|
uint32 map_diff_pair = itr->first;
|
||||||
uint32 mapid = PAIR32_LOPART(map_diff_pair);
|
uint32 mapid = PAIR32_LOPART(map_diff_pair);
|
||||||
Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair));
|
Difficulty difficulty = Difficulty(PAIR32_HIPART(map_diff_pair));
|
||||||
MapDifficulty const* mapDiff = &itr->second;
|
MapDifficultyEntry const* mapDiff = itr->second;
|
||||||
|
|
||||||
// skip mapDiff without global reset time
|
// skip mapDiff without global reset time
|
||||||
if (!mapDiff->resetTime)
|
if (!mapDiff->resetTime)
|
||||||
|
|
@ -552,7 +552,7 @@ void DungeonResetScheduler::Update()
|
||||||
{
|
{
|
||||||
// re-schedule the next/new global reset/warning
|
// re-schedule the next/new global reset/warning
|
||||||
// calculate the next reset time
|
// calculate the next reset time
|
||||||
MapDifficulty const* mapDiff = GetMapDifficultyData(event.mapid, event.difficulty);
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(event.mapid, event.difficulty);
|
||||||
MANGOS_ASSERT(mapDiff);
|
MANGOS_ASSERT(mapDiff);
|
||||||
|
|
||||||
time_t next_reset = DungeonResetScheduler::CalculateNextResetTime(mapDiff, resetTime);
|
time_t next_reset = DungeonResetScheduler::CalculateNextResetTime(mapDiff, resetTime);
|
||||||
|
|
@ -857,7 +857,7 @@ void MapPersistentStateManager::_ResetOrWarnAll(uint32 mapid, Difficulty difficu
|
||||||
|
|
||||||
if (!warn)
|
if (!warn)
|
||||||
{
|
{
|
||||||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
||||||
if (!mapDiff || !mapDiff->resetTime)
|
if (!mapDiff || !mapDiff->resetTime)
|
||||||
{
|
{
|
||||||
sLog.outError("MapPersistentStateManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
|
sLog.outError("MapPersistentStateManager::ResetOrWarnAll: not valid difficulty or no reset delay for map %d", mapid);
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
struct InstanceTemplate;
|
struct InstanceTemplate;
|
||||||
struct MapEntry;
|
struct MapEntry;
|
||||||
struct MapDifficulty;
|
struct MapDifficultyEntry;
|
||||||
struct GameObjectData;
|
struct GameObjectData;
|
||||||
struct CreatureData;
|
struct CreatureData;
|
||||||
|
|
||||||
|
|
@ -304,8 +304,8 @@ class DungeonResetScheduler
|
||||||
return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0;
|
return itr != m_resetTimeByMapDifficulty.end() ? itr->second : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32 GetMaxResetTimeFor(MapDifficulty const* mapDiff);
|
static uint32 GetMaxResetTimeFor(MapDifficultyEntry const* mapDiff);
|
||||||
static time_t CalculateNextResetTime(MapDifficulty const* mapDiff, time_t prevResetTime);
|
static time_t CalculateNextResetTime(MapDifficultyEntry const* mapDiff, time_t prevResetTime);
|
||||||
public: // modifiers
|
public: // modifiers
|
||||||
void SetResetTimeFor(uint32 mapid, Difficulty d, time_t t)
|
void SetResetTimeFor(uint32 mapid, Difficulty d, time_t t)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -688,42 +688,42 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||||
|
|
||||||
recv_data >> Trigger_ID;
|
recv_data >> Trigger_ID;
|
||||||
DEBUG_LOG("Trigger ID: %u", Trigger_ID);
|
DEBUG_LOG("Trigger ID: %u", Trigger_ID);
|
||||||
|
Player* player = GetPlayer();
|
||||||
|
|
||||||
if (GetPlayer()->IsTaxiFlying())
|
if (player->IsTaxiFlying())
|
||||||
{
|
{
|
||||||
DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID: %u", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), Trigger_ID);
|
DEBUG_LOG("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
|
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
|
||||||
if (!atEntry)
|
if (!atEntry)
|
||||||
{
|
{
|
||||||
DEBUG_LOG("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID: %u", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), Trigger_ID);
|
DEBUG_LOG("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delta is safe radius
|
// delta is safe radius
|
||||||
const float delta = 5.0f;
|
const float delta = 5.0f;
|
||||||
// check if player in the range of areatrigger
|
|
||||||
Player* pl = GetPlayer();
|
|
||||||
|
|
||||||
if (!IsPointInAreaTriggerZone(atEntry, pl->GetMapId(), pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), delta))
|
// check if player in the range of areatrigger
|
||||||
|
if (!IsPointInAreaTriggerZone(atEntry, player->GetMapId(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), delta))
|
||||||
{
|
{
|
||||||
DEBUG_LOG("Player '%s' (GUID: %u) too far, ignore Area Trigger ID: %u", pl->GetName(), pl->GetGUIDLow(), Trigger_ID);
|
DEBUG_LOG("Player '%s' (GUID: %u) too far, ignore Area Trigger ID: %u", player->GetName(), player->GetGUIDLow(), Trigger_ID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sScriptMgr.OnAreaTrigger(pl, atEntry))
|
if (sScriptMgr.OnAreaTrigger(player, atEntry))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 quest_id = sObjectMgr.GetQuestForAreaTrigger(Trigger_ID);
|
uint32 quest_id = sObjectMgr.GetQuestForAreaTrigger(Trigger_ID);
|
||||||
if (quest_id && pl->isAlive() && pl->IsActiveQuest(quest_id))
|
if (quest_id && player->isAlive() && player->IsActiveQuest(quest_id))
|
||||||
{
|
{
|
||||||
Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id);
|
Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id);
|
||||||
if (pQuest)
|
if (pQuest)
|
||||||
{
|
{
|
||||||
if (pl->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
|
if (player->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
|
||||||
pl->AreaExploredOrEventHappens(quest_id);
|
player->AreaExploredOrEventHappens(quest_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -731,19 +731,19 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||||
if (sObjectMgr.IsTavernAreaTrigger(Trigger_ID))
|
if (sObjectMgr.IsTavernAreaTrigger(Trigger_ID))
|
||||||
{
|
{
|
||||||
// set resting flag we are in the inn
|
// set resting flag we are in the inn
|
||||||
if (pl->GetRestType() != REST_TYPE_IN_CITY)
|
if (player->GetRestType() != REST_TYPE_IN_CITY)
|
||||||
pl->SetRestType(REST_TYPE_IN_TAVERN, Trigger_ID);
|
player->SetRestType(REST_TYPE_IN_TAVERN, Trigger_ID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BattleGround* bg = pl->GetBattleGround())
|
if (BattleGround* bg = player->GetBattleGround())
|
||||||
{
|
{
|
||||||
bg->HandleAreaTrigger(pl, Trigger_ID);
|
bg->HandleAreaTrigger(player, Trigger_ID);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(pl->GetCachedZoneId()))
|
else if (OutdoorPvP* outdoorPvP = sOutdoorPvPMgr.GetScript(player->GetCachedZoneId()))
|
||||||
{
|
{
|
||||||
if (outdoorPvP->HandleAreaTrigger(pl, Trigger_ID))
|
if (outdoorPvP->HandleAreaTrigger(player, Trigger_ID))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -756,111 +756,103 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||||
if (!targetMapEntry)
|
if (!targetMapEntry)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!pl->isGameMaster())
|
// ghost resurrected at enter attempt to dungeon with corpse (including fail enter cases)
|
||||||
|
if (!player->isAlive() && targetMapEntry->IsDungeon())
|
||||||
{
|
{
|
||||||
// ghost resurrected at enter attempt to dungeon with corpse (including fail enter cases)
|
int32 corpseMapId = 0;
|
||||||
if (!pl->isAlive() && targetMapEntry->IsDungeon())
|
if (Corpse* corpse = player->GetCorpse())
|
||||||
|
corpseMapId = corpse->GetMapId();
|
||||||
|
|
||||||
|
// check back way from corpse to entrance
|
||||||
|
uint32 instance_map = corpseMapId;
|
||||||
|
do
|
||||||
{
|
{
|
||||||
int32 corpseMapId = 0;
|
// most often fast case
|
||||||
if (Corpse* corpse = pl->GetCorpse())
|
if (instance_map == targetMapEntry->MapID)
|
||||||
corpseMapId = corpse->GetMapId();
|
break;
|
||||||
|
|
||||||
// check back way from corpse to entrance
|
InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(instance_map);
|
||||||
uint32 instance_map = corpseMapId;
|
instance_map = instance ? instance->parent : 0;
|
||||||
do
|
|
||||||
{
|
|
||||||
// most often fast case
|
|
||||||
if (instance_map == targetMapEntry->MapID)
|
|
||||||
break;
|
|
||||||
|
|
||||||
InstanceTemplate const* instance = ObjectMgr::GetInstanceTemplate(instance_map);
|
|
||||||
instance_map = instance ? instance->parent : 0;
|
|
||||||
}
|
|
||||||
while (instance_map);
|
|
||||||
|
|
||||||
// corpse not in dungeon or some linked deep dungeons
|
|
||||||
if (!instance_map)
|
|
||||||
{
|
|
||||||
WorldPacket data(SMSG_AREA_TRIGGER_NO_CORPSE);
|
|
||||||
pl->GetSession()->SendPacket(&data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// need find areatrigger to inner dungeon for landing point
|
|
||||||
if (at->target_mapId != corpseMapId)
|
|
||||||
{
|
|
||||||
if (AreaTrigger const* corpseAt = sObjectMgr.GetMapEntranceTrigger(corpseMapId))
|
|
||||||
{
|
|
||||||
at = corpseAt;
|
|
||||||
targetMapEntry = sMapStore.LookupEntry(at->target_mapId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we can resurrect player, and then check teleport requirements
|
|
||||||
pl->ResurrectPlayer(0.5f);
|
|
||||||
pl->SpawnCorpseBones();
|
|
||||||
}
|
}
|
||||||
|
while (instance_map);
|
||||||
|
|
||||||
// check trigger requirements
|
// corpse not in dungeon or some linked deep dungeons
|
||||||
bool missingItem = false;
|
if (!instance_map)
|
||||||
bool missingLevel = false;
|
|
||||||
bool missingQuest = false;
|
|
||||||
|
|
||||||
if (pl->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL))
|
|
||||||
missingLevel = true;
|
|
||||||
|
|
||||||
// must have one or the other, report the first one that's missing
|
|
||||||
if (at->requiredItem)
|
|
||||||
{
|
{
|
||||||
if (!pl->HasItemCount(at->requiredItem, 1) &&
|
WorldPacket data(SMSG_AREA_TRIGGER_NO_CORPSE);
|
||||||
(!at->requiredItem2 || !GetPlayer()->HasItemCount(at->requiredItem2, 1)))
|
player->GetSession()->SendPacket(&data);
|
||||||
missingItem = true;
|
|
||||||
}
|
|
||||||
else if (at->requiredItem2 && !pl->HasItemCount(at->requiredItem2, 1))
|
|
||||||
missingItem = true;
|
|
||||||
|
|
||||||
bool isRegularTargetMap = !targetMapEntry->IsDungeon() || pl->GetDifficulty(targetMapEntry->IsRaid()) == REGULAR_DIFFICULTY;
|
|
||||||
|
|
||||||
if (!isRegularTargetMap)
|
|
||||||
{
|
|
||||||
if (at->heroicKey)
|
|
||||||
{
|
|
||||||
if (!pl->HasItemCount(at->heroicKey, 1) &&
|
|
||||||
(!at->heroicKey2 || !pl->HasItemCount(at->heroicKey2, 1)))
|
|
||||||
missingItem = true;
|
|
||||||
}
|
|
||||||
else if (at->heroicKey2 && !pl->HasItemCount(at->heroicKey2, 1))
|
|
||||||
missingItem = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isRegularTargetMap)
|
|
||||||
{
|
|
||||||
if (at->requiredQuestHeroic && !pl->GetQuestRewardStatus(at->requiredQuestHeroic))
|
|
||||||
missingQuest = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (at->requiredQuest && !pl->GetQuestRewardStatus(at->requiredQuest))
|
|
||||||
missingQuest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (missingItem || missingLevel || missingQuest)
|
|
||||||
{
|
|
||||||
// hack for "Opening of the Dark Portal"
|
|
||||||
if (missingQuest && at->target_mapId == 269)
|
|
||||||
SendAreaTriggerMessage("%s", at->requiredFailedText.c_str());
|
|
||||||
else if (missingQuest && targetMapEntry->IsContinent())// do not report anything for quest areatriggers
|
|
||||||
return;
|
|
||||||
// hack for TBC heroics
|
|
||||||
else if (missingLevel && !targetMapEntry->IsRaid() && GetPlayer()->GetDifficulty(false) == DUNGEON_DIFFICULTY_HEROIC && targetMapEntry->addon == 1)
|
|
||||||
SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), at->requiredLevel);
|
|
||||||
else
|
|
||||||
pl->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, pl->GetDifficulty(targetMapEntry->IsRaid()));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// need find areatrigger to inner dungeon for landing point
|
||||||
|
if (at->target_mapId != corpseMapId)
|
||||||
|
{
|
||||||
|
if (AreaTrigger const* corpseAt = sObjectMgr.GetMapEntranceTrigger(corpseMapId))
|
||||||
|
{
|
||||||
|
at = corpseAt;
|
||||||
|
targetMapEntry = sMapStore.LookupEntry(at->target_mapId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we can resurrect player, and then check teleport requirements
|
||||||
|
player->ResurrectPlayer(0.5f);
|
||||||
|
player->SpawnCorpseBones();
|
||||||
}
|
}
|
||||||
|
|
||||||
GetPlayer()->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT);
|
// check trigger requirements
|
||||||
|
uint32 miscRequirement = 0;
|
||||||
|
AreaLockStatus lockStatus = player->GetAreaTriggerLockStatus(at, player->GetDifficulty(targetMapEntry->IsRaid()), miscRequirement);
|
||||||
|
switch (lockStatus)
|
||||||
|
{
|
||||||
|
case AREA_LOCKSTATUS_OK:
|
||||||
|
player->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, at->target_Orientation, TELE_TO_NOT_LEAVE_TRANSPORT);
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_TOO_LOW_LEVEL:
|
||||||
|
SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), miscRequirement);
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_ZONE_IN_COMBAT:
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_ZONE_IN_COMBAT);
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_INSTANCE_IS_FULL:
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_MAX_PLAYERS);
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_QUEST_NOT_COMPLETED:
|
||||||
|
if (at->target_mapId == 269) // Exception for Black Morass
|
||||||
|
{
|
||||||
|
SendAreaTriggerMessage(GetMangosString(LANG_TELEREQ_QUEST_BLACK_MORASS));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (targetMapEntry->IsContinent()) // do not report anything for quest areatrigge
|
||||||
|
{
|
||||||
|
DEBUG_LOG("HandleAreaTriggerOpcode: LockAreaStatus %u, do not teleport, no message sent (trigger %u)", lockStatus, Trigger_ID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// No break here!
|
||||||
|
case AREA_LOCKSTATUS_MISSING_ITEM:
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, player->GetDifficulty(targetMapEntry->IsRaid()));
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_MISSING_DIFFICULTY:
|
||||||
|
{
|
||||||
|
Difficulty difficulty = player->GetDifficulty(targetMapEntry->IsRaid());
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY, difficulty > RAID_DIFFICULTY_10MAN_HEROIC ? RAID_DIFFICULTY_10MAN_HEROIC : difficulty);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION:
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_INSUF_EXPAN_LVL, miscRequirement);
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_NOT_ALLOWED:
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_MAP_NOT_ALLOWED);
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_RAID_LOCKED:
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_NEED_GROUP);
|
||||||
|
break;
|
||||||
|
case AREA_LOCKSTATUS_UNKNOWN_ERROR:
|
||||||
|
player->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_ERROR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sLog.outError("HandleAreaTriggerOpcode: unhandled LockAreaStatus %u, when %s attempts to use area-trigger %u", lockStatus, player->GetGuidStr().c_str(), Trigger_ID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::HandleUpdateAccountData(WorldPacket& recv_data)
|
void WorldSession::HandleUpdateAccountData(WorldPacket& recv_data)
|
||||||
|
|
@ -1416,7 +1408,8 @@ void WorldSession::HandleSetDungeonDifficultyOpcode(WorldPacket& recv_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_player->getLevel() < LEVELREQUIREMENT_HEROIC)
|
// Exception to set mode to normal for low-level players
|
||||||
|
if (_player->getLevel() < LEVELREQUIREMENT_HEROIC && mode > REGULAR_DIFFICULTY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Group* pGroup = _player->GetGroup())
|
if (Group* pGroup = _player->GetGroup())
|
||||||
|
|
@ -1460,7 +1453,8 @@ void WorldSession::HandleSetRaidDifficultyOpcode(WorldPacket& recv_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_player->getLevel() < LEVELREQUIREMENT_HEROIC)
|
// Exception to set mode to normal for low-level players
|
||||||
|
if (_player->getLevel() < LEVELREQUIREMENT_HEROIC && mode > REGULAR_DIFFICULTY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Group* pGroup = _player->GetGroup())
|
if (Group* pGroup = _player->GetGroup())
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
|
||||||
if (mInstance)
|
if (mInstance)
|
||||||
{
|
{
|
||||||
Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid());
|
Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid());
|
||||||
if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff))
|
if (MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff))
|
||||||
{
|
{
|
||||||
if (mapDiff->resetTime)
|
if (mapDiff->resetTime)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5573,8 +5573,8 @@ void ObjectMgr::LoadAreaTriggerTeleports()
|
||||||
|
|
||||||
uint32 count = 0;
|
uint32 count = 0;
|
||||||
|
|
||||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||||
QueryResult* result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_quest_done_heroic, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
|
QueryResult* result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_quest_done_heroic, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -5608,12 +5608,11 @@ void ObjectMgr::LoadAreaTriggerTeleports()
|
||||||
at.heroicKey2 = fields[5].GetUInt32();
|
at.heroicKey2 = fields[5].GetUInt32();
|
||||||
at.requiredQuest = fields[6].GetUInt32();
|
at.requiredQuest = fields[6].GetUInt32();
|
||||||
at.requiredQuestHeroic = fields[7].GetUInt32();
|
at.requiredQuestHeroic = fields[7].GetUInt32();
|
||||||
at.requiredFailedText = fields[8].GetCppString();
|
at.target_mapId = fields[8].GetUInt32();
|
||||||
at.target_mapId = fields[9].GetUInt32();
|
at.target_X = fields[9].GetFloat();
|
||||||
at.target_X = fields[10].GetFloat();
|
at.target_Y = fields[10].GetFloat();
|
||||||
at.target_Y = fields[11].GetFloat();
|
at.target_Z = fields[11].GetFloat();
|
||||||
at.target_Z = fields[12].GetFloat();
|
at.target_Orientation = fields[12].GetFloat();
|
||||||
at.target_Orientation = fields[13].GetFloat();
|
|
||||||
|
|
||||||
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
|
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
|
||||||
if (!atEntry)
|
if (!atEntry)
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,6 @@ struct AreaTrigger
|
||||||
uint32 heroicKey2;
|
uint32 heroicKey2;
|
||||||
uint32 requiredQuest;
|
uint32 requiredQuest;
|
||||||
uint32 requiredQuestHeroic;
|
uint32 requiredQuestHeroic;
|
||||||
std::string requiredFailedText;
|
|
||||||
uint32 target_mapId;
|
uint32 target_mapId;
|
||||||
float target_X;
|
float target_X;
|
||||||
float target_Y;
|
float target_Y;
|
||||||
|
|
|
||||||
|
|
@ -16774,7 +16774,7 @@ void Player::_LoadBoundInstances(QueryResult* result)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty));
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapId, Difficulty(difficulty));
|
||||||
if (!mapDiff)
|
if (!mapDiff)
|
||||||
{
|
{
|
||||||
sLog.outError("_LoadBoundInstances: player %s(%d) has bind to nonexistent difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId);
|
sLog.outError("_LoadBoundInstances: player %s(%d) has bind to nonexistent difficulty %d instance for map %u", GetName(), GetGUIDLow(), difficulty, mapId);
|
||||||
|
|
@ -16803,7 +16803,7 @@ void Player::_LoadBoundInstances(QueryResult* result)
|
||||||
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty)
|
InstancePlayerBind* Player::GetBoundInstance(uint32 mapid, Difficulty difficulty)
|
||||||
{
|
{
|
||||||
// some instances only have one difficulty
|
// some instances only have one difficulty
|
||||||
MapDifficulty const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mapid, difficulty);
|
||||||
if (!mapDiff)
|
if (!mapDiff)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
@ -23611,3 +23611,123 @@ void Player::SendRatedBGStats()
|
||||||
|
|
||||||
SendDirectMessage(&data);
|
SendDirectMessage(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AreaLockStatus Player::GetAreaTriggerLockStatus(AreaTrigger const* at, Difficulty difficulty, uint32& miscRequirement)
|
||||||
|
{
|
||||||
|
miscRequirement = 0;
|
||||||
|
|
||||||
|
if (!at)
|
||||||
|
return AREA_LOCKSTATUS_UNKNOWN_ERROR;
|
||||||
|
|
||||||
|
MapEntry const* mapEntry = sMapStore.LookupEntry(at->target_mapId);
|
||||||
|
if (!mapEntry)
|
||||||
|
return AREA_LOCKSTATUS_UNKNOWN_ERROR;
|
||||||
|
|
||||||
|
bool isRegularTargetMap = !mapEntry->IsDungeon() || GetDifficulty(mapEntry->IsRaid()) == REGULAR_DIFFICULTY;
|
||||||
|
|
||||||
|
MapDifficultyEntry const* mapDiff = GetMapDifficultyData(at->target_mapId, difficulty);
|
||||||
|
if (mapEntry->IsDungeon() && !mapDiff)
|
||||||
|
return AREA_LOCKSTATUS_MISSING_DIFFICULTY;
|
||||||
|
|
||||||
|
// Expansion requirement
|
||||||
|
if (GetSession()->Expansion() < mapEntry->Expansion())
|
||||||
|
{
|
||||||
|
miscRequirement = mapEntry->Expansion();
|
||||||
|
return AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gamemaster can always enter
|
||||||
|
if (isGameMaster())
|
||||||
|
return AREA_LOCKSTATUS_OK;
|
||||||
|
|
||||||
|
// Level Requirements
|
||||||
|
if (getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL))
|
||||||
|
{
|
||||||
|
miscRequirement = at->requiredLevel;
|
||||||
|
return AREA_LOCKSTATUS_TOO_LOW_LEVEL;
|
||||||
|
}
|
||||||
|
if (!isRegularTargetMap && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL) && getLevel() < uint32(maxLevelForExpansion[mapEntry->Expansion()]))
|
||||||
|
{
|
||||||
|
miscRequirement = maxLevelForExpansion[mapEntry->Expansion()];
|
||||||
|
return AREA_LOCKSTATUS_TOO_LOW_LEVEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raid Requirements
|
||||||
|
if (mapEntry->IsRaid() && !sWorld.getConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID))
|
||||||
|
if (!GetGroup() || !GetGroup()->isRaidGroup())
|
||||||
|
return AREA_LOCKSTATUS_RAID_LOCKED;
|
||||||
|
|
||||||
|
// Item Requirements: must have requiredItem OR requiredItem2, report the first one that's missing
|
||||||
|
if (at->requiredItem)
|
||||||
|
{
|
||||||
|
if (!HasItemCount(at->requiredItem, 1) &&
|
||||||
|
(!at->requiredItem2 || !HasItemCount(at->requiredItem2, 1)))
|
||||||
|
{
|
||||||
|
miscRequirement = at->requiredItem;
|
||||||
|
return AREA_LOCKSTATUS_MISSING_ITEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (at->requiredItem2 && !HasItemCount(at->requiredItem2, 1))
|
||||||
|
{
|
||||||
|
miscRequirement = at->requiredItem2;
|
||||||
|
return AREA_LOCKSTATUS_MISSING_ITEM;
|
||||||
|
}
|
||||||
|
// Heroic item requirements
|
||||||
|
if (!isRegularTargetMap && at->heroicKey)
|
||||||
|
{
|
||||||
|
if (!HasItemCount(at->heroicKey, 1) && (!at->heroicKey2 || !HasItemCount(at->heroicKey2, 1)))
|
||||||
|
{
|
||||||
|
miscRequirement = at->heroicKey;
|
||||||
|
return AREA_LOCKSTATUS_MISSING_ITEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!isRegularTargetMap && at->heroicKey2 && !HasItemCount(at->heroicKey2, 1))
|
||||||
|
{
|
||||||
|
miscRequirement = at->heroicKey2;
|
||||||
|
return AREA_LOCKSTATUS_MISSING_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quest Requirements
|
||||||
|
if (isRegularTargetMap && at->requiredQuest && !GetQuestRewardStatus(at->requiredQuest))
|
||||||
|
{
|
||||||
|
miscRequirement = at->requiredQuest;
|
||||||
|
return AREA_LOCKSTATUS_QUEST_NOT_COMPLETED;
|
||||||
|
}
|
||||||
|
if (!isRegularTargetMap && at->requiredQuestHeroic && !GetQuestRewardStatus(at->requiredQuestHeroic))
|
||||||
|
{
|
||||||
|
miscRequirement = at->requiredQuestHeroic;
|
||||||
|
return AREA_LOCKSTATUS_QUEST_NOT_COMPLETED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the map is not created, assume it is possible to enter it.
|
||||||
|
DungeonPersistentState* state = GetBoundInstanceSaveForSelfOrGroup(at->target_mapId);
|
||||||
|
Map* map = sMapMgr.FindMap(at->target_mapId, state ? state->GetInstanceId() : 0);
|
||||||
|
|
||||||
|
// ToDo add achievement check
|
||||||
|
|
||||||
|
// Map's state check
|
||||||
|
if (map && map->IsDungeon())
|
||||||
|
{
|
||||||
|
// cannot enter if the instance is full (player cap), GMs don't count
|
||||||
|
if (((DungeonMap*)map)->GetPlayersCountExceptGMs() >= ((DungeonMap*)map)->GetMaxPlayers())
|
||||||
|
return AREA_LOCKSTATUS_INSTANCE_IS_FULL;
|
||||||
|
|
||||||
|
// In Combat check
|
||||||
|
if (map && map->GetInstanceData() && map->GetInstanceData()->IsEncounterInProgress())
|
||||||
|
return AREA_LOCKSTATUS_ZONE_IN_COMBAT;
|
||||||
|
|
||||||
|
// Bind Checks
|
||||||
|
InstancePlayerBind* pBind = GetBoundInstance(at->target_mapId, GetDifficulty(mapEntry->IsRaid()));
|
||||||
|
if (pBind && pBind->perm && pBind->state != state)
|
||||||
|
return AREA_LOCKSTATUS_HAS_BIND;
|
||||||
|
if (pBind && pBind->perm && pBind->state != map->GetPersistentState())
|
||||||
|
return AREA_LOCKSTATUS_HAS_BIND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AREA_LOCKSTATUS_OK;
|
||||||
|
};
|
||||||
|
|
||||||
|
AreaLockStatus Player::GetAreaLockStatus(uint32 mapId, Difficulty difficulty, uint32& miscRequirement)
|
||||||
|
{
|
||||||
|
return GetAreaTriggerLockStatus(sObjectMgr.GetMapEntranceTrigger(mapId), difficulty, miscRequirement);
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ class DungeonPersistentState;
|
||||||
class Spell;
|
class Spell;
|
||||||
class Item;
|
class Item;
|
||||||
|
|
||||||
|
struct AreaTrigger;
|
||||||
|
|
||||||
typedef std::deque<Mail*> PlayerMails;
|
typedef std::deque<Mail*> PlayerMails;
|
||||||
|
|
||||||
#define PLAYER_MAX_SKILLS 128
|
#define PLAYER_MAX_SKILLS 128
|
||||||
|
|
@ -2326,6 +2328,9 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
static void ConvertInstancesToGroup(Player* player, Group* group = NULL, ObjectGuid player_guid = ObjectGuid());
|
static void ConvertInstancesToGroup(Player* player, Group* group = NULL, ObjectGuid player_guid = ObjectGuid());
|
||||||
DungeonPersistentState* GetBoundInstanceSaveForSelfOrGroup(uint32 mapid);
|
DungeonPersistentState* GetBoundInstanceSaveForSelfOrGroup(uint32 mapid);
|
||||||
|
|
||||||
|
AreaLockStatus GetAreaLockStatus(uint32 mapId, Difficulty difficulty, uint32& miscRequirement);
|
||||||
|
AreaLockStatus GetAreaTriggerLockStatus(AreaTrigger const* at, Difficulty difficulty, uint32& miscRequirement);
|
||||||
|
|
||||||
/*********************************************************/
|
/*********************************************************/
|
||||||
/*** GROUP SYSTEM ***/
|
/*** GROUP SYSTEM ***/
|
||||||
/*********************************************************/
|
/*********************************************************/
|
||||||
|
|
|
||||||
|
|
@ -3206,6 +3206,23 @@ enum ActivateTaxiReply
|
||||||
ERR_TAXINOTSTANDING = 12
|
ERR_TAXINOTSTANDING = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AreaLockStatus
|
||||||
|
{
|
||||||
|
AREA_LOCKSTATUS_OK = 0,
|
||||||
|
AREA_LOCKSTATUS_UNKNOWN_ERROR = 1,
|
||||||
|
AREA_LOCKSTATUS_INSUFFICIENT_EXPANSION = 2,
|
||||||
|
AREA_LOCKSTATUS_TOO_LOW_LEVEL = 3,
|
||||||
|
AREA_LOCKSTATUS_TOO_HIGH_LEVEL = 4,
|
||||||
|
AREA_LOCKSTATUS_RAID_LOCKED = 5,
|
||||||
|
AREA_LOCKSTATUS_QUEST_NOT_COMPLETED = 6,
|
||||||
|
AREA_LOCKSTATUS_MISSING_ITEM = 7,
|
||||||
|
AREA_LOCKSTATUS_MISSING_DIFFICULTY = 8,
|
||||||
|
AREA_LOCKSTATUS_ZONE_IN_COMBAT = 9,
|
||||||
|
AREA_LOCKSTATUS_INSTANCE_IS_FULL = 10,
|
||||||
|
AREA_LOCKSTATUS_NOT_ALLOWED = 11,
|
||||||
|
AREA_LOCKSTATUS_HAS_BIND = 12,
|
||||||
|
};
|
||||||
|
|
||||||
// we need to stick to 1 version or half of the stuff will work for someone
|
// we need to stick to 1 version or half of the stuff will work for someone
|
||||||
// others will not and opposite
|
// others will not and opposite
|
||||||
// will only support WoW, WoW:TBC, WoW:WotLK and WoW:Cataclysm 4.3.4 client build 15595...
|
// will only support WoW, WoW:TBC, WoW:WotLK and WoW:Cataclysm 4.3.4 client build 15595...
|
||||||
|
|
@ -3219,4 +3236,14 @@ enum ActivateTaxiReply
|
||||||
// that it not have expansion installed and reject
|
// that it not have expansion installed and reject
|
||||||
#define MAX_EXPANSION 3
|
#define MAX_EXPANSION 3
|
||||||
|
|
||||||
|
// Maxlevel for expansion
|
||||||
|
enum MaxLevel
|
||||||
|
{
|
||||||
|
MAX_LEVEL_CLASSIC = 60,
|
||||||
|
MAX_LEVEL_TBC = 70,
|
||||||
|
MAX_LEVEL_WOTLK = 80,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const MaxLevel maxLevelForExpansion[MAX_EXPANSION + 1] = { MAX_LEVEL_CLASSIC, MAX_LEVEL_TBC, MAX_LEVEL_WOTLK };
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "12194"
|
#define REVISION_NR "12195"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#ifndef __REVISION_SQL_H__
|
#ifndef __REVISION_SQL_H__
|
||||||
#define __REVISION_SQL_H__
|
#define __REVISION_SQL_H__
|
||||||
#define REVISION_DB_CHARACTERS "required_12161_01_characters_characters"
|
#define REVISION_DB_CHARACTERS "required_12161_01_characters_characters"
|
||||||
#define REVISION_DB_MANGOS "required_12186_01_mangos_item_template"
|
#define REVISION_DB_MANGOS "required_12195_02_mangos_mangos_string"
|
||||||
#define REVISION_DB_REALMD "required_12112_01_realmd_account_access"
|
#define REVISION_DB_REALMD "required_12112_01_realmd_account_access"
|
||||||
#endif // __REVISION_SQL_H__
|
#endif // __REVISION_SQL_H__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue