Core/Spells: Fix teleports within transports (like Blink)

This commit is contained in:
Shauren
2025-10-16 19:06:19 +02:00
parent 73a32a5757
commit a0c8e0255c
3 changed files with 63 additions and 25 deletions

View File

@@ -12801,20 +12801,24 @@ bool Unit::CanSwim() const
return HasUnitFlag(UNIT_FLAG_RENAME | UNIT_FLAG_CAN_SWIM);
}
void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
void Unit::NearTeleportTo(TeleportLocation const& target, bool casting)
{
DisableSpline();
TeleportLocation target{ .Location = { GetMapId(), pos } };
if (GetTypeId() == TYPEID_PLAYER)
ToPlayer()->TeleportTo(target, TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET | (casting ? TELE_TO_SPELL : TELE_TO_NONE));
else
{
SendTeleportPacket(target);
UpdatePosition(pos, true);
UpdatePosition(target.Location, true);
UpdateObjectVisibility();
}
}
void Unit::NearTeleportTo(Position const& pos, bool casting /*= false*/)
{
NearTeleportTo(TeleportLocation{ .Location = { GetMapId(), pos } }, casting);
}
void Unit::SendTeleportPacket(TeleportLocation const& teleportLocation)
{
// SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport
@@ -12856,7 +12860,10 @@ void Unit::SendTeleportPacket(TeleportLocation const& teleportLocation)
moveUpdateTeleport.Status->transport.pos.Relocate(teleportLocation.Location);
}
else
{
moveUpdateTeleport.Status->pos.Relocate(teleportLocation.Location);
moveUpdateTeleport.Status->transport.Reset();
}
}
// Broadcast the packet to everyone except self.

View File

@@ -1122,6 +1122,7 @@ class TC_GAME_API Unit : public WorldObject
void SendSpellDamageResist(Unit* target, uint32 spellId);
void SendSpellDamageImmune(Unit* target, uint32 spellId, bool isPeriodic);
void NearTeleportTo(TeleportLocation const& target, bool casting = false);
void NearTeleportTo(Position const& pos, bool casting = false);
void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false) { NearTeleportTo(Position(x, y, z, orientation), casting); }
void SendTeleportPacket(TeleportLocation const& teleportLocation);

View File

@@ -1010,12 +1010,12 @@ void Spell::EffectTeleportUnits()
}
// Init dest coordinates
WorldLocation targetDest(*destTarget);
if (targetDest.GetMapId() == MAPID_INVALID)
targetDest.m_mapId = unitTarget->GetMapId();
TeleportLocation targetDest{ .Location = *destTarget };
if (targetDest.Location.GetMapId() == MAPID_INVALID)
targetDest.Location.m_mapId = unitTarget->GetMapId();
if (!targetDest.GetOrientation() && m_targets.GetUnitTarget())
targetDest.SetOrientation(m_targets.GetUnitTarget()->GetOrientation());
if (!targetDest.Location.GetOrientation() && m_targets.GetUnitTarget())
targetDest.Location.SetOrientation(m_targets.GetUnitTarget()->GetOrientation());
Player* player = unitTarget->ToPlayer();
@@ -1023,15 +1023,21 @@ void Spell::EffectTeleportUnits()
{
// Custom loading screen
if (uint32 customLoadingScreenId = effectInfo->MiscValue)
if (targetDest.GetMapId() != unitTarget->GetMapId() || !unitTarget->IsInDist2d(targetDest, TELEPORT_MIN_LOAD_SCREEN_DISTANCE))
if (targetDest.Location.GetMapId() != unitTarget->GetMapId() || !unitTarget->IsInDist2d(targetDest.Location, TELEPORT_MIN_LOAD_SCREEN_DISTANCE))
player->SendDirectMessage(WorldPackets::Spells::CustomLoadScreen(m_spellInfo->Id, customLoadingScreenId).Write());
if (ObjectGuid transportGuid = m_destTargets[effectInfo->EffectIndex]._transportGUID; !transportGuid.IsEmpty())
{
targetDest.TransportGuid = transportGuid;
targetDest.Location.Relocate(m_destTargets[effectInfo->EffectIndex]._transportOffset);
}
TeleportToOptions options = GetTeleportOptions(m_caster, unitTarget, m_destTargets[effectInfo->EffectIndex]);
player->TeleportTo(targetDest, options, {}, m_spellInfo->Id);
player->TeleportTo(targetDest, options, m_spellInfo->Id);
}
else if (targetDest.GetMapId() == unitTarget->GetMapId())
unitTarget->NearTeleportTo(targetDest, unitTarget == m_caster);
else if (targetDest.Location.GetMapId() == unitTarget->GetMapId())
unitTarget->NearTeleportTo(targetDest.Location, unitTarget == m_caster);
else
TC_LOG_ERROR("spells", "Spell::EffectTeleportUnits - spellId {} attempted to teleport creature to a different map.", m_spellInfo->Id);
}
@@ -1039,15 +1045,15 @@ void Spell::EffectTeleportUnits()
class DelayedSpellTeleportEvent : public BasicEvent
{
public:
explicit DelayedSpellTeleportEvent(Unit* target, WorldLocation const& targetDest, TeleportToOptions options, uint32 spellId)
explicit DelayedSpellTeleportEvent(Unit* target, TeleportLocation const& targetDest, TeleportToOptions options, uint32 spellId)
: _target(target), _targetDest(targetDest), _options(options), _spellId(spellId){ }
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
{
if (Player* player = _target->ToPlayer())
player->TeleportTo(_targetDest, _options);
else if (_targetDest.GetMapId() == _target->GetMapId())
_target->NearTeleportTo(_targetDest, (_options & TELE_TO_SPELL) != TELE_TO_NONE);
else if (_targetDest.Location.GetMapId() == _target->GetMapId())
_target->NearTeleportTo(_targetDest.Location, (_options & TELE_TO_SPELL) != TELE_TO_NONE);
else
TC_LOG_ERROR("spells", "Spell::EffectTeleportUnitsWithVisualLoadingScreen - spellId {} attempted to teleport creature to a different map.", _spellId);
@@ -1056,7 +1062,7 @@ public:
private:
Unit* _target;
WorldLocation _targetDest;
TeleportLocation _targetDest;
TeleportToOptions _options;
uint32 _spellId;
};
@@ -1077,12 +1083,18 @@ void Spell::EffectTeleportUnitsWithVisualLoadingScreen()
}
// Init dest coordinates
WorldLocation targetDest(*destTarget);
if (targetDest.GetMapId() == MAPID_INVALID)
targetDest.m_mapId = unitTarget->GetMapId();
TeleportLocation targetDest{ .Location = *destTarget };
if (targetDest.Location.GetMapId() == MAPID_INVALID)
targetDest.Location.m_mapId = unitTarget->GetMapId();
if (!targetDest.GetOrientation() && m_targets.GetUnitTarget())
targetDest.SetOrientation(m_targets.GetUnitTarget()->GetOrientation());
if (!targetDest.Location.GetOrientation() && m_targets.GetUnitTarget())
targetDest.Location.SetOrientation(m_targets.GetUnitTarget()->GetOrientation());
if (ObjectGuid transportGuid = m_destTargets[effectInfo->EffectIndex]._transportGUID; !transportGuid.IsEmpty())
{
targetDest.TransportGuid = transportGuid;
targetDest.Location.Relocate(m_destTargets[effectInfo->EffectIndex]._transportOffset);
}
if (effectInfo->MiscValueB)
if (Player* playerTarget = unitTarget->ToPlayer())
@@ -2330,8 +2342,20 @@ void Spell::EffectTeleUnitsFaceCaster()
if (unitTarget->IsInFlight())
return;
if (m_targets.HasDst())
unitTarget->NearTeleportTo(destTarget->GetPositionX(), destTarget->GetPositionY(), destTarget->GetPositionZ(), destTarget->GetAbsoluteAngle(m_caster), unitTarget == m_caster);
if (!m_targets.HasDst())
return;
TeleportLocation targetDest{ .Location = *destTarget };
if (ObjectGuid transportGuid = m_destTargets[effectInfo->EffectIndex]._transportGUID; !transportGuid.IsEmpty())
{
targetDest.TransportGuid = transportGuid;
targetDest.Location.Relocate(m_destTargets[effectInfo->EffectIndex]._transportOffset);
targetDest.Location.SetOrientation(destTarget->GetAbsoluteAngle(m_caster) - targetDest.Location.GetOrientation());
}
else
targetDest.Location.SetOrientation(destTarget->GetAbsoluteAngle(m_caster));
unitTarget->NearTeleportTo(destTarget->GetPositionX(), destTarget->GetPositionY(), destTarget->GetPositionZ(), destTarget->GetAbsoluteAngle(m_caster), unitTarget == m_caster);
}
void Spell::EffectLearnSkill()
@@ -3693,8 +3717,14 @@ void Spell::EffectLeap()
if (!m_targets.HasDst())
return;
Position pos = destTarget->GetPosition();
unitTarget->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), unitTarget == m_caster);
TeleportLocation targetDest{ .Location = *destTarget };
if (ObjectGuid transportGuid = m_destTargets[effectInfo->EffectIndex]._transportGUID; !transportGuid.IsEmpty())
{
targetDest.TransportGuid = transportGuid;
targetDest.Location.Relocate(m_destTargets[effectInfo->EffectIndex]._transportOffset);
}
unitTarget->NearTeleportTo(targetDest, unitTarget == m_caster);
}
void Spell::EffectReputation()