aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2018-09-17 13:14:56 +0200
committerTreeston <treeston.mmoc@gmail.com>2018-09-17 13:14:56 +0200
commit28591fd1658e3e4842d64f330f27c233dc69aad2 (patch)
treed8947d256615f4bf86aebd8c0dbb8c746472654f /src
parent003cc56d70c9b07f4484cb82484091ab4013895a (diff)
Core/Player: Delay resurrection on release for unreachable maps until teleport has completed. Closes #21481.
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp9
-rw-r--r--src/server/game/Entities/Player/Player.h6
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp110
3 files changed, 68 insertions, 57 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 48b17451f6d..7f37550b0f9 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1708,6 +1708,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
UnsummonPetTemporaryIfAny();
}
+ if (!IsAlive() && options & TELE_REVIVE_AT_TELEPORT)
+ ResurrectPlayer(0.5f);
+
if (!(options & TELE_TO_NOT_LEAVE_COMBAT))
CombatStop();
@@ -1814,6 +1817,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
oldmap->RemovePlayerFromMap(this, false);
m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
+ m_teleport_options = options;
SetFallInformation(0, GetPositionZ());
// if the player is saved before worldportack (at logout for example)
// this will be used instead of the current location in SaveToDB
@@ -4952,10 +4956,11 @@ void Player::RepopAtGraveyard()
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
+ bool shouldResurrect = false;
// Such zones are considered unreachable as a ghost and the player must be automatically revived
if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
{
- ResurrectPlayer(0.5f);
+ shouldResurrect = true;
SpawnCorpseBones();
}
@@ -4979,7 +4984,7 @@ void Player::RepopAtGraveyard()
// and don't show spirit healer location
if (ClosestGrave)
{
- TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation());
+ TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation(), shouldResurrect ? TELE_REVIVE_AT_TELEPORT : 0);
if (isDead()) // not send if alive, because it used in TeleportTo()
{
WorldPacket data(SMSG_DEATH_RELEASE_LOC, 4*4); // show spirit healer position on minimap
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 14f252b2cce..98f952bc0e3 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -672,7 +672,8 @@ enum TeleportToOptions
TELE_TO_NOT_LEAVE_COMBAT = 0x04,
TELE_TO_NOT_UNSUMMON_PET = 0x08,
TELE_TO_SPELL = 0x10,
- TELE_TO_TRANSPORT_TELEPORT = 0x20
+ TELE_TO_TRANSPORT_TELEPORT = 0x20,
+ TELE_REVIVE_AT_TELEPORT = 0x40
};
/// Type of environmental damages
@@ -1721,7 +1722,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue);
WorldLocation& GetTeleportDest() { return m_teleport_dest; }
- bool IsBeingTeleported() const { return mSemaphoreTeleport_Near || mSemaphoreTeleport_Far; }
+ uint32 GetTeleportOptions() const { return m_teleport_options; }
+ bool IsBeingTeleported() const { return IsBeingTeleportedNear() || IsBeingTeleportedFar(); }
bool IsBeingTeleportedNear() const { return mSemaphoreTeleport_Near; }
bool IsBeingTeleportedFar() const { return mSemaphoreTeleport_Far; }
void SetSemaphoreTeleportNear(bool semphsetting) { mSemaphoreTeleport_Near = semphsetting; }
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index dd8f9bd94c7..276a3abece8 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -43,14 +43,15 @@ void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recvData*/)
void WorldSession::HandleMoveWorldportAck()
{
+ Player* player = GetPlayer();
// ignore unexpected far teleports
- if (!GetPlayer()->IsBeingTeleportedFar())
+ if (!player->IsBeingTeleportedFar())
return;
- GetPlayer()->SetSemaphoreTeleportFar(false);
+ player->SetSemaphoreTeleportFar(false);
// get the teleport destination
- WorldLocation const& loc = GetPlayer()->GetTeleportDest();
+ WorldLocation const& loc = player->GetTeleportDest();
// possible errors in the coordinate validity check
if (!MapManager::IsValidMapCoord(loc))
@@ -64,90 +65,93 @@ void WorldSession::HandleMoveWorldportAck()
InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId());
// reset instance validity, except if going to an instance inside an instance
- if (GetPlayer()->m_InstanceValid == false && !mInstance)
- GetPlayer()->m_InstanceValid = true;
+ if (player->m_InstanceValid == false && !mInstance)
+ player->m_InstanceValid = true;
- Map* oldMap = GetPlayer()->GetMap();
- Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
+ Map* oldMap = player->GetMap();
+ Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), player);
- if (GetPlayer()->IsInWorld())
+ if (player->IsInWorld())
{
- TC_LOG_ERROR("network", "%s %s is still in world when teleported from map %s (%u) to new map %s (%u)", GetPlayer()->GetGUID().ToString().c_str(), GetPlayer()->GetName().c_str(), oldMap->GetMapName(), oldMap->GetId(), newMap ? newMap->GetMapName() : "Unknown", loc.GetMapId());
- oldMap->RemovePlayerFromMap(GetPlayer(), false);
+ TC_LOG_ERROR("network", "%s %s is still in world when teleported from map %s (%u) to new map %s (%u)", player->GetGUID().ToString().c_str(), player->GetName().c_str(), oldMap->GetMapName(), oldMap->GetId(), newMap ? newMap->GetMapName() : "Unknown", loc.GetMapId());
+ oldMap->RemovePlayerFromMap(player, false);
}
// relocate the player to the teleport destination
// the CannotEnter 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->CannotEnter(GetPlayer()))
+ if (!newMap || newMap->CannotEnter(player))
{
- TC_LOG_ERROR("network", "Map %d (%s) could not be created for player %d (%s), porting player to homebind", loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown", GetPlayer()->GetGUID().GetCounter(), GetPlayer()->GetName().c_str());
- GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
+ TC_LOG_ERROR("network", "Map %d (%s) could not be created for player %d (%s), porting player to homebind", loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown", player->GetGUID().GetCounter(), player->GetName().c_str());
+ player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation());
return;
}
- float z = loc.GetPositionZ() + GetPlayer()->GetHoverOffset();
- GetPlayer()->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
- GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ());
+ float z = loc.GetPositionZ() + player->GetHoverOffset();
+ player->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
+ player->SetFallInformation(0, player->GetPositionZ());
- GetPlayer()->ResetMap();
- GetPlayer()->SetMap(newMap);
+ player->ResetMap();
+ player->SetMap(newMap);
- GetPlayer()->SendInitialPacketsBeforeAddToMap();
- if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer()))
+ player->SendInitialPacketsBeforeAddToMap();
+ if (!player->GetMap()->AddPlayerToMap(player))
{
TC_LOG_ERROR("network", "WORLD: failed to teleport player %s (%d) to map %d (%s) because of unknown reason!",
- GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().GetCounter(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown");
- GetPlayer()->ResetMap();
- GetPlayer()->SetMap(oldMap);
- GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
+ player->GetName().c_str(), player->GetGUID().GetCounter(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown");
+ player->ResetMap();
+ player->SetMap(oldMap);
+ player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, player->GetOrientation());
return;
}
// battleground state prepare (in case join to BG), at relogin/tele player not invited
// only add to bg group and object, if the player was invited (else he entered through command)
- if (_player->InBattleground())
+ if (player->InBattleground())
{
// cleanup setting if outdated
if (!mEntry->IsBattlegroundOrArena())
{
// We're not in BG
- _player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE);
+ player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE);
// reset destination bg team
- _player->SetBGTeam(0);
+ player->SetBGTeam(0);
}
// join to bg case
- else if (Battleground* bg = _player->GetBattleground())
+ else if (Battleground* bg = player->GetBattleground())
{
- if (_player->IsInvitedForBattlegroundInstance(_player->GetBattlegroundId()))
- bg->AddPlayer(_player);
+ if (player->IsInvitedForBattlegroundInstance(player->GetBattlegroundId()))
+ bg->AddPlayer(player);
}
}
- GetPlayer()->SendInitialPacketsAfterAddToMap();
+ player->SendInitialPacketsAfterAddToMap();
// flight fast teleport case
- if (GetPlayer()->IsInFlight())
+ if (player->IsInFlight())
{
- if (!_player->InBattleground())
+ if (!player->InBattleground())
{
// short preparations to continue flight
- MovementGenerator* movementGenerator = GetPlayer()->GetMotionMaster()->GetCurrentMovementGenerator();
- movementGenerator->Initialize(GetPlayer());
+ MovementGenerator* movementGenerator = player->GetMotionMaster()->GetCurrentMovementGenerator();
+ movementGenerator->Initialize(player);
return;
}
// battleground state prepare, stop flight
- GetPlayer()->FinishTaxiFlight();
+ player->FinishTaxiFlight();
}
+ if (!player->IsAlive() && player->GetTeleportOptions() & TELE_REVIVE_AT_TELEPORT)
+ player->ResurrectPlayer(0.5f);
+
// resurrect character at enter into instance where his corpse exist after add to map
- if (mEntry->IsDungeon() && !GetPlayer()->IsAlive())
+ if (mEntry->IsDungeon() && !player->IsAlive())
{
- if (GetPlayer()->GetCorpseLocation().GetMapId() == mEntry->MapID)
+ if (player->GetCorpseLocation().GetMapId() == mEntry->MapID)
{
- GetPlayer()->ResurrectPlayer(0.5f, false);
- GetPlayer()->SpawnCorpseBones();
+ player->ResurrectPlayer(0.5f);
+ player->SpawnCorpseBones();
}
}
@@ -155,7 +159,7 @@ void WorldSession::HandleMoveWorldportAck()
if (mInstance)
{
// check if this instance has a reset time and send it to player if so
- Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid());
+ Difficulty diff = player->GetDifficulty(mEntry->IsRaid());
if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff))
{
if (mapDiff->resetTime)
@@ -163,14 +167,14 @@ void WorldSession::HandleMoveWorldportAck()
if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->MapID, diff))
{
uint32 timeleft = uint32(timeReset - GameTime::GetGameTime());
- GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true);
+ player->SendInstanceResetWarning(mEntry->MapID, diff, timeleft, true);
}
}
}
// check if instance is valid
- if (!GetPlayer()->CheckInstanceValidity(false))
- GetPlayer()->m_InstanceValid = false;
+ if (!player->CheckInstanceValidity(false))
+ player->m_InstanceValid = false;
// instance mounting is handled in InstanceTemplate
allowMount = mInstance->AllowMount;
@@ -178,26 +182,26 @@ void WorldSession::HandleMoveWorldportAck()
// mount allow check
if (!allowMount)
- _player->RemoveAurasByType(SPELL_AURA_MOUNTED);
+ player->RemoveAurasByType(SPELL_AURA_MOUNTED);
// update zone immediately, otherwise leave channel will cause crash in mtmap
uint32 newzone, newarea;
- GetPlayer()->GetZoneAndAreaId(newzone, newarea);
- GetPlayer()->UpdateZone(newzone, newarea);
+ player->GetZoneAndAreaId(newzone, newarea);
+ player->UpdateZone(newzone, newarea);
// honorless target
- if (GetPlayer()->pvpInfo.IsHostile)
- GetPlayer()->CastSpell(GetPlayer(), 2479, true);
+ if (player->pvpInfo.IsHostile)
+ player->CastSpell(player, 2479, true);
// in friendly area
- else if (GetPlayer()->IsPvP() && !GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
- GetPlayer()->UpdatePvP(false, false);
+ else if (player->IsPvP() && !player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
+ player->UpdatePvP(false, false);
// resummon pet
- GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
+ player->ResummonPetTemporaryUnSummonedIfAny();
//lets process all delayed operations on successful teleport
- GetPlayer()->ProcessDelayedOperations();
+ player->ProcessDelayedOperations();
}
void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData)