mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-23 02:25:38 +01:00
Core/Object: Range check (#23179) (ported commit: 32e1de39a2)
This commit is contained in:
@@ -41,6 +41,8 @@
|
||||
#include "Transport.h"
|
||||
#include "UpdateFieldFlags.h"
|
||||
#include "World.h"
|
||||
#include <G3D/Box.h>
|
||||
#include <G3D/CoordinateFrame.h>
|
||||
#include <G3D/Quat.h>
|
||||
|
||||
bool QuaternionData::isUnit() const
|
||||
@@ -246,7 +248,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
|
||||
return false;
|
||||
}
|
||||
|
||||
SetWorldRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
SetLocalRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
GameObjectAddon const* gameObjectAddon = sObjectMgr->GetGameObjectAddon(GetSpawnId());
|
||||
|
||||
// For most of gameobjects is (0, 0, 0, 1) quaternion, there are only some transports with not standard rotation
|
||||
@@ -868,7 +870,7 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
|
||||
data.id = GetEntry();
|
||||
data.spawnPoint.WorldRelocate(this);
|
||||
data.phaseMask = phaseMask;
|
||||
data.rotation = m_worldRotation;
|
||||
data.rotation = m_localRotation;
|
||||
data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
|
||||
data.animprogress = GetGoAnimProgress();
|
||||
data.goState = GetGoState();
|
||||
@@ -896,10 +898,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
|
||||
stmt->setFloat(index++, GetPositionY());
|
||||
stmt->setFloat(index++, GetPositionZ());
|
||||
stmt->setFloat(index++, GetOrientation());
|
||||
stmt->setFloat(index++, m_worldRotation.x);
|
||||
stmt->setFloat(index++, m_worldRotation.y);
|
||||
stmt->setFloat(index++, m_worldRotation.z);
|
||||
stmt->setFloat(index++, m_worldRotation.w);
|
||||
stmt->setFloat(index++, m_localRotation.x);
|
||||
stmt->setFloat(index++, m_localRotation.y);
|
||||
stmt->setFloat(index++, m_localRotation.z);
|
||||
stmt->setFloat(index++, m_localRotation.w);
|
||||
stmt->setInt32(index++, int32(m_respawnDelayTime));
|
||||
stmt->setUInt8(index++, GetGoAnimProgress());
|
||||
stmt->setUInt8(index++, uint8(GetGoState()));
|
||||
@@ -2030,21 +2032,21 @@ void GameObject::UpdatePackedRotation()
|
||||
static const int32 PACK_YZ_MASK = (PACK_YZ << 1) - 1;
|
||||
static const int32 PACK_X_MASK = (PACK_X << 1) - 1;
|
||||
|
||||
int8 w_sign = (m_worldRotation.w >= 0.f ? 1 : -1);
|
||||
int64 x = int32(m_worldRotation.x * PACK_X) * w_sign & PACK_X_MASK;
|
||||
int64 y = int32(m_worldRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK;
|
||||
int64 z = int32(m_worldRotation.z * PACK_YZ) * w_sign & PACK_YZ_MASK;
|
||||
int8 w_sign = (m_localRotation.w >= 0.f ? 1 : -1);
|
||||
int64 x = int32(m_localRotation.x * PACK_X) * w_sign & PACK_X_MASK;
|
||||
int64 y = int32(m_localRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK;
|
||||
int64 z = int32(m_localRotation.z * PACK_YZ) * w_sign & PACK_YZ_MASK;
|
||||
m_packedRotation = z | (y << 21) | (x << 42);
|
||||
}
|
||||
|
||||
void GameObject::SetWorldRotation(float qx, float qy, float qz, float qw)
|
||||
void GameObject::SetLocalRotation(float qx, float qy, float qz, float qw)
|
||||
{
|
||||
G3D::Quat rotation(qx, qy, qz, qw);
|
||||
rotation.unitize();
|
||||
m_worldRotation.x = rotation.x;
|
||||
m_worldRotation.y = rotation.y;
|
||||
m_worldRotation.z = rotation.z;
|
||||
m_worldRotation.w = rotation.w;
|
||||
m_localRotation.x = rotation.x;
|
||||
m_localRotation.y = rotation.y;
|
||||
m_localRotation.z = rotation.z;
|
||||
m_localRotation.w = rotation.w;
|
||||
UpdatePackedRotation();
|
||||
}
|
||||
|
||||
@@ -2056,10 +2058,27 @@ void GameObject::SetParentRotation(QuaternionData const& rotation)
|
||||
SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, rotation.w);
|
||||
}
|
||||
|
||||
void GameObject::SetWorldRotationAngles(float z_rot, float y_rot, float x_rot)
|
||||
void GameObject::SetLocalRotationAngles(float z_rot, float y_rot, float x_rot)
|
||||
{
|
||||
G3D::Quat quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot));
|
||||
SetWorldRotation(quat.x, quat.y, quat.z, quat.w);
|
||||
SetLocalRotation(quat.x, quat.y, quat.z, quat.w);
|
||||
}
|
||||
|
||||
QuaternionData GameObject::GetWorldRotation() const
|
||||
{
|
||||
QuaternionData localRotation = GetLocalRotation();
|
||||
if (Transport* transport = GetTransport())
|
||||
{
|
||||
QuaternionData worldRotation = transport->GetWorldRotation();
|
||||
|
||||
G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w);
|
||||
G3D::Quat localRotationQuat(localRotation.x, localRotation.y, localRotation.z, localRotation.w);
|
||||
|
||||
G3D::Quat resultRotation = localRotationQuat * worldRotationQuat;
|
||||
|
||||
return QuaternionData(resultRotation.x, resultRotation.y, resultRotation.z, resultRotation.w);
|
||||
}
|
||||
return localRotation;
|
||||
}
|
||||
|
||||
void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)
|
||||
@@ -2453,9 +2472,6 @@ float GameObject::GetInteractionDistance() const
|
||||
case GAMEOBJECT_TYPE_FISHINGHOLE:
|
||||
case GAMEOBJECT_TYPE_FISHINGNODE:
|
||||
return 20.0f + CONTACT_DISTANCE; // max spell range
|
||||
case GAMEOBJECT_TYPE_DOOR:
|
||||
case GAMEOBJECT_TYPE_QUESTGIVER:
|
||||
return INTERACTION_DISTANCE + GetFloatValue(OBJECT_FIELD_SCALE_X);
|
||||
default:
|
||||
return INTERACTION_DISTANCE;
|
||||
}
|
||||
@@ -2564,3 +2580,119 @@ MapTransport const* GameObject::ToMapTransport() const
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GameObject::IsAtInteractDistance(Player const* player, SpellInfo const* spell) const
|
||||
{
|
||||
if (spell || (spell = GetSpellForLock(player)))
|
||||
{
|
||||
float maxRange = spell->GetMaxRange(spell->IsPositive());
|
||||
|
||||
if (GetGoType() == GAMEOBJECT_TYPE_SPELL_FOCUS)
|
||||
return maxRange * maxRange >= GetExactDistSq(player);
|
||||
|
||||
if (GameObjectDisplayInfoEntry const* displayInfo = sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId))
|
||||
return IsAtInteractDistance(*player, maxRange);
|
||||
}
|
||||
|
||||
float distance;
|
||||
switch (GetGoType())
|
||||
{
|
||||
case GAMEOBJECT_TYPE_AREADAMAGE:
|
||||
distance = 0.0f;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_QUESTGIVER:
|
||||
case GAMEOBJECT_TYPE_TEXT:
|
||||
case GAMEOBJECT_TYPE_FLAGSTAND:
|
||||
case GAMEOBJECT_TYPE_FLAGDROP:
|
||||
case GAMEOBJECT_TYPE_MINI_GAME:
|
||||
distance = 5.5555553f;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_BINDER:
|
||||
distance = 10.0f;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_CHAIR:
|
||||
case GAMEOBJECT_TYPE_BARBER_CHAIR:
|
||||
distance = 3.0f;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_FISHINGNODE:
|
||||
distance = 100.0f;
|
||||
break;
|
||||
case GAMEOBJECT_TYPE_CAMERA:
|
||||
case GAMEOBJECT_TYPE_MAP_OBJECT:
|
||||
case GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY:
|
||||
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
|
||||
case GAMEOBJECT_TYPE_DOOR:
|
||||
default:
|
||||
distance = 5.0f;
|
||||
break;
|
||||
|
||||
// Following values are not blizzlike
|
||||
case GAMEOBJECT_TYPE_MAILBOX:
|
||||
// Successful mailbox interaction is rather critical to the client, failing it will start a minute-long cooldown until the next mail query may be executed.
|
||||
// And since movement info update is not sent with mailbox interaction query, server may find the player outside of interaction range. Thus we increase it.
|
||||
distance = 10.0f; // 5.0f is blizzlike
|
||||
break;
|
||||
}
|
||||
|
||||
return IsAtInteractDistance(*player, distance);
|
||||
}
|
||||
|
||||
bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const
|
||||
{
|
||||
if (GameObjectDisplayInfoEntry const* displayInfo = sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId))
|
||||
{
|
||||
float scale = GetObjectScale();
|
||||
|
||||
float minX = displayInfo->minX * scale - radius;
|
||||
float minY = displayInfo->minY * scale - radius;
|
||||
float minZ = displayInfo->minZ * scale - radius;
|
||||
float maxX = displayInfo->maxX * scale + radius;
|
||||
float maxY = displayInfo->maxY * scale + radius;
|
||||
float maxZ = displayInfo->maxZ * scale + radius;
|
||||
|
||||
QuaternionData localRotation = GetLocalRotation();
|
||||
G3D::Quat localRotationQuat(localRotation.x, localRotation.y, localRotation.z, localRotation.w);
|
||||
|
||||
return G3D::CoordinateFrame { { localRotationQuat }, { GetPositionX(), GetPositionY(), GetPositionZ() } }
|
||||
.toWorldSpace(G3D::Box { { minX, minY, minZ }, { maxX, maxY, maxZ } })
|
||||
.contains({ pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() });
|
||||
}
|
||||
|
||||
return GetExactDist(&pos) <= radius;
|
||||
}
|
||||
|
||||
SpellInfo const* GameObject::GetSpellForLock(Player const* player) const
|
||||
{
|
||||
if (!player)
|
||||
return nullptr;
|
||||
|
||||
uint32 lockId = GetGOInfo()->GetLockId();
|
||||
if (!lockId)
|
||||
return nullptr;
|
||||
|
||||
LockEntry const* lock = sLockStore.LookupEntry(lockId);
|
||||
if (!lock)
|
||||
return nullptr;
|
||||
|
||||
for (uint8 i = 0; i < MAX_LOCK_CASE; ++i)
|
||||
{
|
||||
if (!lock->Type[i])
|
||||
continue;
|
||||
|
||||
if (lock->Type[i] == LOCK_KEY_SKILL)
|
||||
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(lock->Index[i]))
|
||||
return spell;
|
||||
|
||||
if (lock->Type[i] != LOCK_KEY_SKILL)
|
||||
break;
|
||||
|
||||
for (auto&& playerSpell : player->GetSpellMap())
|
||||
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(playerSpell.first))
|
||||
for (auto&& effect : spell->Effects)
|
||||
if (effect.Effect == SPELL_EFFECT_OPEN_LOCK && ((uint32) effect.MiscValue) == lock->Index[i])
|
||||
if (effect.CalcValue(player) >= int32(lock->Skill[i]))
|
||||
return spell;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -103,11 +103,13 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
|
||||
|
||||
// z_rot, y_rot, x_rot - rotation angles around z, y and x axes
|
||||
void SetWorldRotationAngles(float z_rot, float y_rot, float x_rot);
|
||||
void SetWorldRotation(float qx, float qy, float qz, float qw);
|
||||
void SetLocalRotationAngles(float z_rot, float y_rot, float x_rot);
|
||||
void SetLocalRotation(float qx, float qy, float qz, float qw);
|
||||
void SetParentRotation(QuaternionData const& rotation); // transforms(rotates) transport's path
|
||||
QuaternionData const& GetWorldRotation() const { return m_worldRotation; }
|
||||
int64 GetPackedWorldRotation() const { return m_packedRotation; }
|
||||
QuaternionData const& GetLocalRotation() const { return m_localRotation; }
|
||||
int64 GetPackedLocalRotation() const { return m_packedRotation; }
|
||||
|
||||
QuaternionData GetWorldRotation() const;
|
||||
|
||||
// overwrite WorldObject function for proper name localization
|
||||
std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override;
|
||||
@@ -286,6 +288,11 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
|
||||
void UpdateModelPosition();
|
||||
|
||||
bool IsAtInteractDistance(Position const& pos, float radius) const;
|
||||
bool IsAtInteractDistance(Player const* player, SpellInfo const* spell) const;
|
||||
|
||||
SpellInfo const* GetSpellForLock(Player const* player) const;
|
||||
|
||||
void AIM_Destroy();
|
||||
bool AIM_Initialize();
|
||||
|
||||
@@ -322,7 +329,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
GameObjectValue m_goValue;
|
||||
|
||||
int64 m_packedRotation;
|
||||
QuaternionData m_worldRotation;
|
||||
QuaternionData m_localRotation;
|
||||
Position m_stationaryPosition;
|
||||
|
||||
ObjectGuid m_lootRecipient;
|
||||
|
||||
@@ -600,7 +600,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
|
||||
}
|
||||
|
||||
if (flags & UPDATEFLAG_ROTATION)
|
||||
*data << uint64(ToGameObject()->GetPackedWorldRotation());
|
||||
*data << uint64(ToGameObject()->GetPackedLocalRotation());
|
||||
|
||||
if (flags & UPDATEFLAG_UNK5)
|
||||
{
|
||||
|
||||
@@ -177,7 +177,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, Map* map, uint
|
||||
|
||||
GameObjectAddon const* gameObjectAddon = sObjectMgr->GetGameObjectAddon(GetSpawnId());
|
||||
|
||||
SetWorldRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
SetLocalRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||
|
||||
// For most of gameobjects is (0, 0, 0, 1) quaternion, there are only some transports with not standard rotation
|
||||
QuaternionData parentRotation;
|
||||
@@ -583,7 +583,7 @@ bool MapTransport::CreateMapTransport(ObjectGuid::LowType guidlow, uint32 entry,
|
||||
m_goValue.Transport.PathProgress = 0;
|
||||
SetPeriod(tInfo->pathTime);
|
||||
SetGoState(!m_goInfo->moTransport.canBeStopped ? GO_STATE_READY : GO_STATE_ACTIVE);
|
||||
SetWorldRotation(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
SetLocalRotation(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
SetParentRotation(QuaternionData());
|
||||
|
||||
m_model = CreateModel();
|
||||
|
||||
@@ -6439,9 +6439,6 @@ SpellCastResult Spell::CheckRange(bool strict) const
|
||||
if (m_spellInfo->RangeEntry && m_spellInfo->RangeEntry->type != SPELL_RANGE_MELEE && !strict)
|
||||
maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
|
||||
|
||||
// save the original values before squaring them
|
||||
float origMinRange = minRange, origMaxRange = maxRange;
|
||||
|
||||
// get square values for sqr distance checks
|
||||
minRange *= minRange;
|
||||
maxRange *= maxRange;
|
||||
@@ -6463,10 +6460,7 @@ SpellCastResult Spell::CheckRange(bool strict) const
|
||||
|
||||
if (GameObject* goTarget = m_targets.GetGOTarget())
|
||||
{
|
||||
if (origMinRange > 0.0f && goTarget->IsInRange(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), origMinRange))
|
||||
return SPELL_FAILED_OUT_OF_RANGE;
|
||||
|
||||
if (!goTarget->IsInRange(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), origMaxRange))
|
||||
if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo))
|
||||
return SPELL_FAILED_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
|
||||
@@ -445,7 +445,7 @@ public:
|
||||
}
|
||||
|
||||
object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
|
||||
object->SetWorldRotationAngles(oz, oy, ox);
|
||||
object->SetLocalRotationAngles(oz, oy, ox);
|
||||
object->SaveToDB();
|
||||
|
||||
handler->PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, object->GetGUID().GetCounter(), object->GetGOInfo()->name.c_str(), object->GetGUID().GetCounter(), oz);
|
||||
|
||||
Reference in New Issue
Block a user