mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 09:17:18 +00:00
fix(Core/Maps): Enabled dead players to be resurrected at the dungeon entrance if cannot enter it due to some reasons (#7236)
- Closes #6790
This commit is contained in:
@@ -1435,10 +1435,10 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
|
||||
// Check enter rights before map getting to avoid creating instance copy for player
|
||||
// this check not dependent from map instance copy and same for all instance copies of selected map
|
||||
if (!(options & TELE_TO_GM_MODE) && !sMapMgr->CanPlayerEnter(mapid, this, false))
|
||||
if (!(options & TELE_TO_GM_MODE) && sMapMgr->PlayerCannotEnter(mapid, this, false))
|
||||
return false;
|
||||
|
||||
// if CanPlayerEnter -> CanEnter: checked above
|
||||
// if PlayerCannotEnter -> CanEnter: checked above
|
||||
{
|
||||
//lets reset near teleport flag if it wasn't reset during chained teleports
|
||||
SetSemaphoreTeleportNear(0);
|
||||
|
||||
@@ -6971,12 +6971,12 @@ bool Player::CheckInstanceLoginValid()
|
||||
return false;
|
||||
}
|
||||
|
||||
// pussywizard: check CanEnter for GetMap(), because in CanPlayerEnter it is called for a map decided before loading screen (can change)
|
||||
if (!GetMap()->CanEnter(this, true))
|
||||
// pussywizard: check CanEnter for GetMap(), because in PlayerCannotEnter it is called for a map decided before loading screen (can change)
|
||||
if (GetMap()->CannotEnter(this, true))
|
||||
return false;
|
||||
|
||||
// do checks for satisfy accessreqs, instance full, encounter in progress (raid), perm bind group != perm bind player
|
||||
return sMapMgr->CanPlayerEnter(GetMap()->GetId(), this, true);
|
||||
return sMapMgr->PlayerCannotEnter(GetMap()->GetId(), this, true) == Map::CAN_ENTER;
|
||||
}
|
||||
|
||||
bool Player::CheckInstanceCount(uint32 instanceId) const
|
||||
|
||||
@@ -771,8 +771,36 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||
bool teleported = false;
|
||||
if (player->GetMapId() != at->target_mapId)
|
||||
{
|
||||
if (!sMapMgr->CanPlayerEnter(at->target_mapId, player, false))
|
||||
if (Map::EnterState denyReason = sMapMgr->PlayerCannotEnter(at->target_mapId, player, false))
|
||||
{
|
||||
bool reviveAtTrigger = false; // should we revive the player if he is trying to enter the correct instance?
|
||||
switch (denyReason)
|
||||
{
|
||||
case Map::CANNOT_ENTER_NOT_IN_RAID:
|
||||
case Map::CANNOT_ENTER_INSTANCE_BIND_MISMATCH:
|
||||
case Map::CANNOT_ENTER_TOO_MANY_INSTANCES:
|
||||
case Map::CANNOT_ENTER_MAX_PLAYERS:
|
||||
case Map::CANNOT_ENTER_ZONE_IN_COMBAT:
|
||||
reviveAtTrigger = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (reviveAtTrigger) // check if the player is touching the areatrigger leading to the map his corpse is on
|
||||
{
|
||||
if (!player->IsAlive() && player->HasCorpse())
|
||||
{
|
||||
if (player->GetCorpseLocation().GetMapId() == at->target_mapId)
|
||||
{
|
||||
player->ResurrectPlayer(0.5f);
|
||||
player->SpawnCorpseBones();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (Group* group = player->GetGroup())
|
||||
if (group->isLFGGroup() && player->GetMap()->IsDungeon())
|
||||
|
||||
@@ -77,7 +77,7 @@ void WorldSession::HandleMoveWorldportAck()
|
||||
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
|
||||
// the CanEnter checks are done in TeleporTo but conditions may change
|
||||
// while the player is in transit, for example the map may get full
|
||||
if (!newMap || !newMap->CanEnter(GetPlayer(), false))
|
||||
if (!newMap || newMap->CannotEnter(GetPlayer(), false))
|
||||
{
|
||||
LOG_ERROR("network.opcode", "Map %d could not be created for player %s, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUID().ToString().c_str());
|
||||
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
||||
|
||||
@@ -2657,19 +2657,19 @@ void InstanceMap::InitVisibilityDistance()
|
||||
/*
|
||||
Do map specific checks to see if the player can enter
|
||||
*/
|
||||
bool InstanceMap::CanEnter(Player* player, bool loginCheck)
|
||||
Map::EnterState InstanceMap::CannotEnter(Player* player, bool loginCheck)
|
||||
{
|
||||
if (!loginCheck && player->GetMapRef().getTarget() == this)
|
||||
{
|
||||
LOG_ERROR("maps", "InstanceMap::CanEnter - player %s (%s) already in map %d, %d, %d!",
|
||||
player->GetName().c_str(), player->GetGUID().ToString().c_str(), GetId(), GetInstanceId(), GetSpawnMode());
|
||||
ABORT();
|
||||
return false;
|
||||
return CANNOT_ENTER_ALREADY_IN_MAP;
|
||||
}
|
||||
|
||||
// allow GM's to enter
|
||||
if (player->IsGameMaster())
|
||||
return Map::CanEnter(player, loginCheck);
|
||||
return Map::CannotEnter(player, loginCheck);
|
||||
|
||||
// cannot enter if the instance is full (player cap), GMs don't count
|
||||
uint32 maxPlayers = GetMaxPlayers();
|
||||
@@ -2677,7 +2677,7 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
|
||||
{
|
||||
LOG_DEBUG("maps", "MAP: Instance '%u' of map '%s' cannot have more than '%u' players. Player '%s' rejected", GetInstanceId(), GetMapName(), maxPlayers, player->GetName().c_str());
|
||||
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
|
||||
return false;
|
||||
return CANNOT_ENTER_MAX_PLAYERS;
|
||||
}
|
||||
|
||||
// cannot enter while an encounter is in progress on raids
|
||||
@@ -2685,7 +2685,7 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
|
||||
if (checkProgress && GetInstanceScript() && GetInstanceScript()->IsEncounterInProgress())
|
||||
{
|
||||
player->SendTransferAborted(GetId(), TRANSFER_ABORT_ZONE_IN_COMBAT);
|
||||
return false;
|
||||
return CANNOT_ENTER_ZONE_IN_COMBAT;
|
||||
}
|
||||
|
||||
// xinef: dont allow LFG Group to enter other instance that is selected
|
||||
@@ -2694,7 +2694,7 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
|
||||
if (!sLFGMgr->inLfgDungeonMap(group->GetGUID(), GetId(), GetDifficulty()))
|
||||
{
|
||||
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAP_NOT_ALLOWED);
|
||||
return false;
|
||||
return CANNOT_ENTER_UNSPECIFIED_REASON;
|
||||
}
|
||||
|
||||
// cannot enter if instance is in use by another party/soloer that have a permanent save in the same instance id
|
||||
@@ -2710,18 +2710,18 @@ bool InstanceMap::CanEnter(Player* player, bool loginCheck)
|
||||
if (!player->GetGroup()) // player has not group and there is someone inside, deny entry
|
||||
{
|
||||
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
|
||||
return false;
|
||||
return CANNOT_ENTER_INSTANCE_BIND_MISMATCH;
|
||||
}
|
||||
// player inside instance has no group or his groups is different to entering player's one, deny entry
|
||||
if (!iPlayer->GetGroup() || iPlayer->GetGroup() != player->GetGroup())
|
||||
{
|
||||
player->SendTransferAborted(GetId(), TRANSFER_ABORT_MAX_PLAYERS);
|
||||
return false;
|
||||
return CANNOT_ENTER_INSTANCE_BIND_MISMATCH;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Map::CanEnter(player, loginCheck);
|
||||
return Map::CannotEnter(player, loginCheck);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3020,21 +3020,21 @@ void BattlegroundMap::InitVisibilityDistance()
|
||||
m_VisibleDistance = 30.0f;
|
||||
}
|
||||
|
||||
bool BattlegroundMap::CanEnter(Player* player, bool loginCheck)
|
||||
Map::EnterState BattlegroundMap::CannotEnter(Player* player, bool loginCheck)
|
||||
{
|
||||
if (!loginCheck && player->GetMapRef().getTarget() == this)
|
||||
{
|
||||
LOG_ERROR("maps", "BGMap::CanEnter - player %s is already in map!", player->GetGUID().ToString().c_str());
|
||||
ABORT();
|
||||
return false;
|
||||
return CANNOT_ENTER_ALREADY_IN_MAP;
|
||||
}
|
||||
|
||||
if (player->GetBattlegroundId() != GetInstanceId())
|
||||
return false;
|
||||
return CANNOT_ENTER_INSTANCE_BIND_MISMATCH;
|
||||
|
||||
// pussywizard: no need to check player limit here, invitations are limited by Battleground::GetFreeSlotsForTeam
|
||||
|
||||
return Map::CanEnter(player, loginCheck);
|
||||
return Map::CannotEnter(player, loginCheck);
|
||||
}
|
||||
|
||||
bool BattlegroundMap::AddPlayerToMap(Player* player)
|
||||
|
||||
@@ -377,7 +377,25 @@ public:
|
||||
|
||||
[[nodiscard]] uint32 GetInstanceId() const { return i_InstanceId; }
|
||||
[[nodiscard]] uint8 GetSpawnMode() const { return (i_spawnMode); }
|
||||
virtual bool CanEnter(Player* /*player*/, bool /*loginCheck = false*/) { return true; }
|
||||
|
||||
enum EnterState
|
||||
{
|
||||
CAN_ENTER = 0,
|
||||
CANNOT_ENTER_ALREADY_IN_MAP = 1, // Player is already in the map
|
||||
CANNOT_ENTER_NO_ENTRY, // No map entry was found for the target map ID
|
||||
CANNOT_ENTER_UNINSTANCED_DUNGEON, // No instance template was found for dungeon map
|
||||
CANNOT_ENTER_DIFFICULTY_UNAVAILABLE, // Requested instance difficulty is not available for target map
|
||||
CANNOT_ENTER_NOT_IN_RAID, // Target instance is a raid instance and the player is not in a raid group
|
||||
CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE, // Player is dead and their corpse is not in target instance
|
||||
CANNOT_ENTER_INSTANCE_BIND_MISMATCH, // Player's permanent instance save is not compatible with their group's current instance bind
|
||||
CANNOT_ENTER_TOO_MANY_INSTANCES, // Player has entered too many instances recently
|
||||
CANNOT_ENTER_MAX_PLAYERS, // Target map already has the maximum number of players allowed
|
||||
CANNOT_ENTER_ZONE_IN_COMBAT, // A boss encounter is currently in progress on the target map
|
||||
CANNOT_ENTER_UNSPECIFIED_REASON
|
||||
};
|
||||
|
||||
virtual EnterState CannotEnter(Player* /*player*/, bool /*loginCheck = false*/) { return CAN_ENTER; }
|
||||
|
||||
[[nodiscard]] const char* GetMapName() const;
|
||||
|
||||
// have meaning only for instanced map (that have set real difficulty)
|
||||
@@ -756,7 +774,7 @@ public:
|
||||
[[nodiscard]] InstanceScript const* GetInstanceScript() const { return instance_data; }
|
||||
void PermBindAllPlayers();
|
||||
void UnloadAll() override;
|
||||
bool CanEnter(Player* player, bool loginCheck = false) override;
|
||||
EnterState CannotEnter(Player* player, bool loginCheck = false) override;
|
||||
void SendResetWarnings(uint32 timeLeft) const;
|
||||
|
||||
[[nodiscard]] uint32 GetMaxPlayers() const;
|
||||
@@ -778,7 +796,7 @@ public:
|
||||
|
||||
bool AddPlayerToMap(Player*) override;
|
||||
void RemovePlayerFromMap(Player*, bool) override;
|
||||
bool CanEnter(Player* player, bool loginCheck = false) override;
|
||||
EnterState CannotEnter(Player* player, bool loginCheck = false) override;
|
||||
void SetUnload();
|
||||
//void UnloadAll(bool pForce);
|
||||
void RemoveAllPlayers() override;
|
||||
|
||||
@@ -266,8 +266,8 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator& itr)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MapInstanced::CanEnter(Player* /*player*/, bool /*loginCheck*/)
|
||||
Map::EnterState MapInstanced::CannotEnter(Player* /*player*/, bool /*loginCheck*/)
|
||||
{
|
||||
//ABORT();
|
||||
return true;
|
||||
return CAN_ENTER;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
void DelayedUpdate(const uint32 diff) override;
|
||||
//void RelocationNotify();
|
||||
void UnloadAll() override;
|
||||
bool CanEnter(Player* player, bool loginCheck = false) override;
|
||||
EnterState CannotEnter(Player* player, bool loginCheck = false) override;
|
||||
|
||||
Map* CreateInstanceForPlayer(const uint32 mapId, Player* player);
|
||||
Map* FindInstanceMap(uint32 instanceId) const
|
||||
|
||||
@@ -122,18 +122,18 @@ Map* MapManager::FindMap(uint32 mapid, uint32 instanceId) const
|
||||
return ((MapInstanced*)map)->FindInstanceMap(instanceId);
|
||||
}
|
||||
|
||||
bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
Map::EnterState MapManager::PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
{
|
||||
MapEntry const* entry = sMapStore.LookupEntry(mapid);
|
||||
if (!entry)
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_NO_ENTRY;
|
||||
|
||||
if (!entry->IsDungeon())
|
||||
return true;
|
||||
return Map::CAN_ENTER;
|
||||
|
||||
InstanceTemplate const* instance = sObjectMgr->GetInstanceTemplate(mapid);
|
||||
if (!instance)
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_UNINSTANCED_DUNGEON;
|
||||
|
||||
Difficulty targetDifficulty, requestedDifficulty;
|
||||
targetDifficulty = requestedDifficulty = player->GetDifficulty(entry->IsRaid());
|
||||
@@ -142,17 +142,17 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
if (!mapDiff)
|
||||
{
|
||||
player->SendTransferAborted(mapid, TRANSFER_ABORT_DIFFICULTY, requestedDifficulty);
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_DIFFICULTY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
//Bypass checks for GMs
|
||||
if (player->IsGameMaster())
|
||||
return true;
|
||||
return Map::CAN_ENTER;
|
||||
|
||||
char const* mapName = entry->name[player->GetSession()->GetSessionDbcLocale()];
|
||||
|
||||
if (!sScriptMgr->CanEnterMap(player, entry, instance, mapDiff, loginCheck))
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_UNSPECIFIED_REASON;
|
||||
|
||||
Group* group = player->GetGroup();
|
||||
if (entry->IsRaid())
|
||||
@@ -164,7 +164,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
// TODO: this is not a good place to send the message
|
||||
player->GetSession()->SendAreaTriggerMessage(player->GetSession()->GetAcoreString(LANG_INSTANCE_RAID_GROUP_ONLY), mapName);
|
||||
LOG_DEBUG("maps", "MAP: Player '%s' must be in a raid group to enter instance '%s'", player->GetName().c_str(), mapName);
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_NOT_IN_RAID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
if (!sLFGMgr->inLfgDungeonMap(group->GetGUID(), mapid, targetDifficulty))
|
||||
{
|
||||
player->SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED);
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_UNSPECIFIED_REASON;
|
||||
}
|
||||
|
||||
if (!player->IsAlive())
|
||||
@@ -197,13 +197,13 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
WorldPacket data(SMSG_CORPSE_NOT_IN_INSTANCE, 0);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
LOG_DEBUG("maps", "MAP: Player '%s' does not have a corpse in instance '%s' and cannot enter.", player->GetName().c_str(), mapName);
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_CORPSE_IN_DIFFERENT_INSTANCE;
|
||||
}
|
||||
LOG_DEBUG("maps", "MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName().c_str(), mapName);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("maps", "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
|
||||
LOG_DEBUG("maps", "Map::PlayerCannotEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,8 +213,8 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
uint32 destInstId = sInstanceSaveMgr->PlayerGetDestinationInstanceId(player, mapid, targetDifficulty);
|
||||
if (destInstId)
|
||||
if (Map* boundMap = sMapMgr->FindMap(mapid, destInstId))
|
||||
if (!boundMap->CanEnter(player, loginCheck))
|
||||
return false;
|
||||
if (Map::EnterState denyReason = boundMap->CannotEnter(player, loginCheck))
|
||||
return denyReason;
|
||||
}
|
||||
|
||||
// players are only allowed to enter 5 instances per hour
|
||||
@@ -228,12 +228,12 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
if (!player->CheckInstanceCount(instaceIdToCheck) && !player->isDead())
|
||||
{
|
||||
player->SendTransferAborted(mapid, TRANSFER_ABORT_TOO_MANY_INSTANCES);
|
||||
return false;
|
||||
return Map::CANNOT_ENTER_TOO_MANY_INSTANCES;
|
||||
}
|
||||
}
|
||||
|
||||
//Other requirements
|
||||
return player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true);
|
||||
return player->Satisfy(sObjectMgr->GetAccessRequirement(mapid, targetDifficulty), mapid, true) ? Map::CAN_ENTER : Map::CANNOT_ENTER_UNSPECIFIED_REASON;
|
||||
}
|
||||
|
||||
void MapManager::Update(uint32 diff)
|
||||
|
||||
@@ -119,7 +119,7 @@ public:
|
||||
|
||||
void DoDelayedMovesAndRemoves();
|
||||
|
||||
bool CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck = false);
|
||||
Map::EnterState PlayerCannotEnter(uint32 mapid, Player* player, bool loginCheck = false);
|
||||
void InitializeVisibilityDistanceInfo();
|
||||
|
||||
/* statistics */
|
||||
|
||||
@@ -1191,7 +1191,7 @@ void Spell::EffectTeleportUnits(SpellEffIndex /*effIndex*/)
|
||||
uint32 mapid = destTarget->GetMapId();
|
||||
float x, y, z, orientation;
|
||||
destTarget->GetPosition(x, y, z, orientation);
|
||||
target->TeleportTo(mapid, x, y, z, orientation, TELE_TO_GM_MODE); // skip CanPlayerEnter check
|
||||
target->TeleportTo(mapid, x, y, z, orientation, TELE_TO_GM_MODE); // skip PlayerCannotEnter check
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user