feat(Core/Gameobject): add a range check for gameobjects (#7521)
This commit is contained in:
@@ -24,6 +24,8 @@
|
|||||||
#include "UpdateFieldFlags.h"
|
#include "UpdateFieldFlags.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include <G3D/Quat.h>
|
#include <G3D/Quat.h>
|
||||||
|
#include <G3D/Box.h>
|
||||||
|
#include <G3D/CoordinateFrame.h>
|
||||||
|
|
||||||
#ifdef ELUNA
|
#ifdef ELUNA
|
||||||
#include "LuaEngine.h"
|
#include "LuaEngine.h"
|
||||||
@@ -277,15 +279,19 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
|
|||||||
// used switch since there should be more
|
// used switch since there should be more
|
||||||
case 181233: // maexxna portal effect
|
case 181233: // maexxna portal effect
|
||||||
case 181575: // maexxna portal
|
case 181575: // maexxna portal
|
||||||
SetWorldRotation(rotation);
|
SetLocalRotation(rotation);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// xinef: hackfix - but make it possible to use original WorldRotation (using special gameobject addon data)
|
// xinef: hackfix - but make it possible to use original WorldRotation (using special gameobject addon data)
|
||||||
// pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct
|
// pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct
|
||||||
if (addon && addon->invisibilityType == INVISIBILITY_GENERAL && addon->InvisibilityValue == 0)
|
if (addon && addon->invisibilityType == INVISIBILITY_GENERAL && addon->InvisibilityValue == 0)
|
||||||
SetWorldRotation(rotation);
|
{
|
||||||
|
SetLocalRotation(rotation);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SetWorldRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
|
{
|
||||||
|
SetLocalRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -879,7 +885,7 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool
|
|||||||
data.posY = GetPositionY();
|
data.posY = GetPositionY();
|
||||||
data.posZ = GetPositionZ();
|
data.posZ = GetPositionZ();
|
||||||
data.orientation = GetOrientation();
|
data.orientation = GetOrientation();
|
||||||
data.rotation = m_worldRotation;
|
data.rotation = m_localRotation;
|
||||||
data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
|
data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
|
||||||
data.animprogress = GetGoAnimProgress();
|
data.animprogress = GetGoAnimProgress();
|
||||||
data.go_state = GetGoState();
|
data.go_state = GetGoState();
|
||||||
@@ -905,10 +911,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool
|
|||||||
stmt->setFloat(index++, GetPositionY());
|
stmt->setFloat(index++, GetPositionY());
|
||||||
stmt->setFloat(index++, GetPositionZ());
|
stmt->setFloat(index++, GetPositionZ());
|
||||||
stmt->setFloat(index++, GetOrientation());
|
stmt->setFloat(index++, GetOrientation());
|
||||||
stmt->setFloat(index++, m_worldRotation.x);
|
stmt->setFloat(index++, m_localRotation.x);
|
||||||
stmt->setFloat(index++, m_worldRotation.y);
|
stmt->setFloat(index++, m_localRotation.y);
|
||||||
stmt->setFloat(index++, m_worldRotation.z);
|
stmt->setFloat(index++, m_localRotation.z);
|
||||||
stmt->setFloat(index++, m_worldRotation.w);
|
stmt->setFloat(index++, m_localRotation.w);
|
||||||
stmt->setInt32(index++, int32(m_respawnDelayTime));
|
stmt->setInt32(index++, int32(m_respawnDelayTime));
|
||||||
stmt->setUInt8(index++, GetGoAnimProgress());
|
stmt->setUInt8(index++, GetGoAnimProgress());
|
||||||
stmt->setUInt8(index++, uint8(GetGoState()));
|
stmt->setUInt8(index++, uint8(GetGoState()));
|
||||||
@@ -2003,14 +2009,14 @@ void GameObject::UpdatePackedRotation()
|
|||||||
static const int32 PACK_X = PACK_YZ << 1;
|
static const int32 PACK_X = PACK_YZ << 1;
|
||||||
static const int32 PACK_YZ_MASK = (PACK_YZ << 1) - 1;
|
static const int32 PACK_YZ_MASK = (PACK_YZ << 1) - 1;
|
||||||
static const int32 PACK_X_MASK = (PACK_X << 1) - 1;
|
static const int32 PACK_X_MASK = (PACK_X << 1) - 1;
|
||||||
int8 w_sign = (m_worldRotation.w >= 0.f ? 1 : -1);
|
int8 w_sign = (m_localRotation.w >= 0.f ? 1 : -1);
|
||||||
int64 x = int32(m_worldRotation.x * PACK_X) * w_sign & PACK_X_MASK;
|
int64 x = int32(m_localRotation.x * PACK_X) * w_sign & PACK_X_MASK;
|
||||||
int64 y = int32(m_worldRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK;
|
int64 y = int32(m_localRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK;
|
||||||
int64 z = int32(m_worldRotation.z * 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);
|
m_packedRotation = z | (y << 21) | (x << 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameObject::SetWorldRotation(G3D::Quat const& rot)
|
void GameObject::SetLocalRotation(G3D::Quat const& rot)
|
||||||
{
|
{
|
||||||
G3D::Quat rotation;
|
G3D::Quat rotation;
|
||||||
// Temporary solution for gameobjects that have no rotation data in DB:
|
// Temporary solution for gameobjects that have no rotation data in DB:
|
||||||
@@ -2020,7 +2026,7 @@ void GameObject::SetWorldRotation(G3D::Quat const& rot)
|
|||||||
rotation = rot;
|
rotation = rot;
|
||||||
|
|
||||||
rotation.unitize();
|
rotation.unitize();
|
||||||
m_worldRotation = rotation;
|
m_localRotation = rotation;
|
||||||
UpdatePackedRotation();
|
UpdatePackedRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2032,9 +2038,26 @@ void GameObject::SetTransportPathRotation(float qx, float qy, float qz, float qw
|
|||||||
SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, qw);
|
SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, qw);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameObject::SetWorldRotationAngles(float z_rot, float y_rot, float x_rot)
|
void GameObject::SetLocalRotationAngles(float z_rot, float y_rot, float x_rot)
|
||||||
{
|
{
|
||||||
SetWorldRotation(G3D::Quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot)));
|
SetLocalRotation(G3D::Quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot)));
|
||||||
|
}
|
||||||
|
|
||||||
|
G3D::Quat GameObject::GetWorldRotation() const
|
||||||
|
{
|
||||||
|
G3D::Quat localRotation = GetLocalRotation();
|
||||||
|
if (Transport* transport = GetTransport())
|
||||||
|
{
|
||||||
|
G3D::Quat 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 G3D::Quat(resultRotation.x, resultRotation.y, resultRotation.z, resultRotation.w);
|
||||||
|
}
|
||||||
|
return localRotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)
|
void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)
|
||||||
@@ -2509,18 +2532,39 @@ void GameObject::SetPosition(float x, float y, float z, float o)
|
|||||||
GetMap()->GameObjectRelocation(this, x, y, z, o);
|
GetMap()->GameObjectRelocation(this, x, y, z, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
float GameObject::GetInteractionDistance()
|
float GameObject::GetInteractionDistance() const
|
||||||
{
|
{
|
||||||
switch (GetGoType())
|
switch (GetGoType())
|
||||||
{
|
{
|
||||||
/// @todo find out how the client calculates the maximal usage distance to spellless working
|
case GAMEOBJECT_TYPE_AREADAMAGE:
|
||||||
// gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
|
return 0.0f;
|
||||||
|
case GAMEOBJECT_TYPE_QUESTGIVER:
|
||||||
|
case GAMEOBJECT_TYPE_TEXT:
|
||||||
|
case GAMEOBJECT_TYPE_FLAGSTAND:
|
||||||
|
case GAMEOBJECT_TYPE_FLAGDROP:
|
||||||
|
case GAMEOBJECT_TYPE_MINI_GAME:
|
||||||
|
return 5.5555553f;
|
||||||
|
case GAMEOBJECT_TYPE_BINDER:
|
||||||
|
return 10.0f;
|
||||||
|
case GAMEOBJECT_TYPE_CHAIR:
|
||||||
|
case GAMEOBJECT_TYPE_BARBER_CHAIR:
|
||||||
|
return 3.0f;
|
||||||
|
case GAMEOBJECT_TYPE_FISHINGNODE:
|
||||||
|
return 100.0f;
|
||||||
|
case GAMEOBJECT_TYPE_FISHINGHOLE:
|
||||||
|
return 20.0f + CONTACT_DISTANCE; // max spell range
|
||||||
|
case GAMEOBJECT_TYPE_CAMERA:
|
||||||
|
case GAMEOBJECT_TYPE_MAP_OBJECT:
|
||||||
|
case GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY:
|
||||||
|
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
|
||||||
|
case GAMEOBJECT_TYPE_DOOR:
|
||||||
|
return 5.0f;
|
||||||
|
// Following values are not blizzlike
|
||||||
case GAMEOBJECT_TYPE_GUILD_BANK:
|
case GAMEOBJECT_TYPE_GUILD_BANK:
|
||||||
case GAMEOBJECT_TYPE_MAILBOX:
|
case GAMEOBJECT_TYPE_MAILBOX:
|
||||||
return 10.0f;
|
// 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.
|
||||||
case GAMEOBJECT_TYPE_FISHINGHOLE:
|
// 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.
|
||||||
case GAMEOBJECT_TYPE_FISHINGNODE:
|
return 10.0f; // 5.0f is blizzlike
|
||||||
return 20.0f + CONTACT_DISTANCE; // max spell range
|
|
||||||
default:
|
default:
|
||||||
return INTERACTION_DISTANCE;
|
return INTERACTION_DISTANCE;
|
||||||
}
|
}
|
||||||
@@ -2562,3 +2606,110 @@ GameObjectModel* GameObject::CreateModel()
|
|||||||
{
|
{
|
||||||
return GameObjectModel::Create(std::make_unique<GameObjectModelOwnerImpl>(this), sWorld->GetDataPath());
|
return GameObjectModel::Create(std::make_unique<GameObjectModelOwnerImpl>(this), sWorld->GetDataPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId))
|
||||||
|
{
|
||||||
|
return IsAtInteractDistance(*player, maxRange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsAtInteractDistance(*player, GetInteractionDistance());
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
G3D::Quat worldRotation = GetWorldRotation();
|
||||||
|
G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w);
|
||||||
|
|
||||||
|
return G3D::CoordinateFrame {{worldRotationQuat}, {GetPositionX(), GetPositionY(), GetPositionZ()}}.toWorldSpace(G3D::Box {{minX, minY, minZ}, {maxX, maxY, maxZ}}).contains({pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()});
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetExactDist(&pos) <= radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameObject::IsWithinDistInMap(Player const* player) const
|
||||||
|
{
|
||||||
|
return IsInMap(player) && InSamePhase(player) && IsAtInteractDistance(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_SPELL)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -751,10 +751,12 @@ public:
|
|||||||
[[nodiscard]] ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
|
[[nodiscard]] ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
|
||||||
|
|
||||||
// z_rot, y_rot, x_rot - rotation angles around z, y and x axes
|
// 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 SetLocalRotationAngles(float z_rot, float y_rot, float x_rot);
|
||||||
void SetWorldRotation(G3D::Quat const& rot);
|
void SetLocalRotation(G3D::Quat const& rot);
|
||||||
void SetTransportPathRotation(float qx, float qy, float qz, float qw);
|
void SetTransportPathRotation(float qx, float qy, float qz, float qw);
|
||||||
[[nodiscard]] int64 GetPackedWorldRotation() const { return m_packedRotation; }
|
[[nodiscard]] G3D::Quat const& GetLocalRotation() const { return m_localRotation; }
|
||||||
|
[[nodiscard]] int64 GetPackedLocalRotation() const { return m_packedRotation; }
|
||||||
|
[[nodiscard]] G3D::Quat GetWorldRotation() const;
|
||||||
|
|
||||||
// overwrite WorldObject function for proper name localization
|
// overwrite WorldObject function for proper name localization
|
||||||
[[nodiscard]] std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override;
|
[[nodiscard]] std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override;
|
||||||
@@ -946,10 +948,18 @@ public:
|
|||||||
[[nodiscard]] float GetStationaryZ() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
|
[[nodiscard]] float GetStationaryZ() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetPositionZ(); return GetPositionZ(); }
|
||||||
[[nodiscard]] float GetStationaryO() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); }
|
[[nodiscard]] float GetStationaryO() const override { if (GetGOInfo()->type != GAMEOBJECT_TYPE_MO_TRANSPORT) return m_stationaryPosition.GetOrientation(); return GetOrientation(); }
|
||||||
|
|
||||||
float GetInteractionDistance();
|
[[nodiscard]] float GetInteractionDistance() const;
|
||||||
|
|
||||||
void UpdateModelPosition();
|
void UpdateModelPosition();
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsAtInteractDistance(Position const& pos, float radius) const;
|
||||||
|
[[nodiscard]] bool IsAtInteractDistance(Player const* player, SpellInfo const* spell = nullptr) const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsWithinDistInMap(Player const* player) const;
|
||||||
|
using WorldObject::IsWithinDistInMap;
|
||||||
|
|
||||||
|
[[nodiscard]] SpellInfo const* GetSpellForLock(Player const* player) const;
|
||||||
|
|
||||||
static std::unordered_map<int, goEventFlag> gameObjectToEventFlag; // Gameobject -> event flag
|
static std::unordered_map<int, goEventFlag> gameObjectToEventFlag; // Gameobject -> event flag
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -979,7 +989,7 @@ protected:
|
|||||||
bool m_allowModifyDestructibleBuilding;
|
bool m_allowModifyDestructibleBuilding;
|
||||||
|
|
||||||
int64 m_packedRotation;
|
int64 m_packedRotation;
|
||||||
G3D::Quat m_worldRotation;
|
G3D::Quat m_localRotation;
|
||||||
Position m_stationaryPosition;
|
Position m_stationaryPosition;
|
||||||
|
|
||||||
ObjectGuid m_lootRecipient;
|
ObjectGuid m_lootRecipient;
|
||||||
|
|||||||
@@ -432,7 +432,9 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
|
|||||||
|
|
||||||
// 0x200
|
// 0x200
|
||||||
if (flags & UPDATEFLAG_ROTATION)
|
if (flags & UPDATEFLAG_ROTATION)
|
||||||
*data << int64(ToGameObject()->GetPackedWorldRotation());
|
{
|
||||||
|
*data << int64(ToGameObject()->GetPackedLocalRotation());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
|
void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
|
||||||
|
|||||||
@@ -2058,8 +2058,10 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid guid, GameobjectTy
|
|||||||
{
|
{
|
||||||
if (go->GetGoType() == type)
|
if (go->GetGoType() == type)
|
||||||
{
|
{
|
||||||
if (go->IsWithinDistInMap(this, go->GetInteractionDistance()))
|
if (go->IsWithinDistInMap(this))
|
||||||
|
{
|
||||||
return go;
|
return go;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DEBUG("maps", "IsGameObjectOfTypeInRange: GameObject '%s' [%s] is too far away from player %s [%s] to be used by him (distance=%f, maximal 10 is allowed)",
|
LOG_DEBUG("maps", "IsGameObjectOfTypeInRange: GameObject '%s' [%s] is too far away from player %s [%s] to be used by him (distance=%f, maximal 10 is allowed)",
|
||||||
go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this));
|
go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this));
|
||||||
@@ -7472,7 +7474,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
|||||||
|
|
||||||
// not check distance for GO in case owned GO (fishing bobber case, for example)
|
// not check distance for GO in case owned GO (fishing bobber case, for example)
|
||||||
// And permit out of range GO with no owner in case fishing hole
|
// And permit out of range GO with no owner in case fishing hole
|
||||||
if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
|
if (!go || (loot_type != LOOT_FISHINGHOLE && ((loot_type != LOOT_FISHING && loot_type != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this)) || (loot_type == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault()))
|
||||||
{
|
{
|
||||||
go->ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
|
go->ForceValuesUpdateAtIndex(GAMEOBJECT_BYTES_1);
|
||||||
SendLootRelease(guid);
|
SendLootRelease(guid);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ bool MotionTransport::CreateMoTrans(ObjectGuid::LowType guidlow, uint32 entry, u
|
|||||||
SetName(goinfo->name);
|
SetName(goinfo->name);
|
||||||
|
|
||||||
// pussywizard: no WorldRotation for MotionTransports
|
// pussywizard: no WorldRotation for MotionTransports
|
||||||
SetWorldRotation(G3D::Quat());
|
SetLocalRotation(G3D::Quat());
|
||||||
// pussywizard: no PathRotation for MotionTransports
|
// pussywizard: no PathRotation for MotionTransports
|
||||||
SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f);
|
SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
@@ -706,7 +706,7 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
|
|||||||
|
|
||||||
// pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct
|
// pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct
|
||||||
//SetWorldRotation( /*for StaticTransport we need 2 rotation Quats in db for World- and Path- Rotation*/ );
|
//SetWorldRotation( /*for StaticTransport we need 2 rotation Quats in db for World- and Path- Rotation*/ );
|
||||||
SetWorldRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
|
SetLocalRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
|
||||||
// pussywizard: PathRotation for StaticTransport (only StaticTransports have PathRotation)
|
// pussywizard: PathRotation for StaticTransport (only StaticTransports have PathRotation)
|
||||||
SetTransportPathRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
SetTransportPathRotation(rotation.x, rotation.y, rotation.z, rotation.w);
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
|
|||||||
// go = nullptr;
|
// go = nullptr;
|
||||||
|
|
||||||
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
|
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
|
||||||
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)))
|
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player)))
|
||||||
{
|
{
|
||||||
player->SendLootRelease(lguid);
|
player->SendLootRelease(lguid);
|
||||||
return;
|
return;
|
||||||
@@ -111,8 +111,10 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
|
|||||||
GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);
|
GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);
|
||||||
|
|
||||||
// do not check distance for GO if player is the owner of it (ex. fishing bobber)
|
// do not check distance for GO if player is the owner of it (ex. fishing bobber)
|
||||||
if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE))))
|
if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player))))
|
||||||
|
{
|
||||||
loot = &go->loot;
|
loot = &go->loot;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -262,8 +264,10 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
|
|||||||
GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid);
|
GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid);
|
||||||
|
|
||||||
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
|
// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
|
||||||
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)))
|
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player)))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
loot = &go->loot;
|
loot = &go->loot;
|
||||||
|
|
||||||
|
|||||||
@@ -328,6 +328,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
|||||||
uint32 spellId;
|
uint32 spellId;
|
||||||
uint8 castCount, castFlags;
|
uint8 castCount, castFlags;
|
||||||
recvPacket >> castCount >> spellId >> castFlags;
|
recvPacket >> castCount >> spellId >> castFlags;
|
||||||
|
TriggerCastFlags triggerFlag = TRIGGERED_NONE;
|
||||||
|
|
||||||
uint32 oldSpellId = spellId;
|
uint32 oldSpellId = spellId;
|
||||||
|
|
||||||
@@ -350,14 +351,40 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// client provided targets
|
||||||
|
SpellCastTargets targets;
|
||||||
|
targets.Read(recvPacket, mover);
|
||||||
|
HandleClientCastFlags(recvPacket, castFlags, targets);
|
||||||
|
|
||||||
|
// not have spell in spellbook
|
||||||
if (mover->GetTypeId() == TYPEID_PLAYER)
|
if (mover->GetTypeId() == TYPEID_PLAYER)
|
||||||
{
|
{
|
||||||
// not have spell in spellbook or spell passive and not casted by client
|
// not have spell in spellbook or spell passive and not casted by client
|
||||||
if( !(spellInfo->Targets & TARGET_FLAG_GAMEOBJECT_ITEM) && (!mover->ToPlayer()->HasActiveSpell(spellId) || spellInfo->IsPassive()) )
|
if( !(spellInfo->Targets & TARGET_FLAG_GAMEOBJECT_ITEM) && (!mover->ToPlayer()->HasActiveSpell(spellId) || spellInfo->IsPassive()) )
|
||||||
{
|
{
|
||||||
//cheater? kick? ban?
|
bool allow = false;
|
||||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
|
||||||
return;
|
// allow casting of unknown spells for special lock cases
|
||||||
|
if (GameObject* go = targets.GetGOTarget())
|
||||||
|
{
|
||||||
|
if (go->GetSpellForLock(mover->ToPlayer()) == spellInfo)
|
||||||
|
{
|
||||||
|
allow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Preparation for #23204
|
||||||
|
// allow casting of spells triggered by clientside periodic trigger auras
|
||||||
|
/*
|
||||||
|
if (caster->HasAuraTypeWithTriggerSpell(SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT, spellId))
|
||||||
|
{
|
||||||
|
allow = true;
|
||||||
|
triggerFlag = TRIGGERED_FULL_MASK;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!allow)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -407,15 +434,9 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
|||||||
// can't use our own spells when we're in possession of another unit,
|
// can't use our own spells when we're in possession of another unit,
|
||||||
if (_player->isPossessing())
|
if (_player->isPossessing())
|
||||||
{
|
{
|
||||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// client provided targets
|
|
||||||
SpellCastTargets targets;
|
|
||||||
targets.Read(recvPacket, mover);
|
|
||||||
HandleClientCastFlags(recvPacket, castFlags, targets);
|
|
||||||
|
|
||||||
// pussywizard: HandleClientCastFlags calls HandleMovementOpcodes, which can result in pretty much anything. Caster not in map will crash at GetMap() for spell difficulty in Spell constructor.
|
// pussywizard: HandleClientCastFlags calls HandleMovementOpcodes, which can result in pretty much anything. Caster not in map will crash at GetMap() for spell difficulty in Spell constructor.
|
||||||
if (!mover->FindMap())
|
if (!mover->FindMap())
|
||||||
{
|
{
|
||||||
@@ -433,7 +454,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
|||||||
spellInfo = actualSpellInfo;
|
spellInfo = actualSpellInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
Spell* spell = new Spell(mover, spellInfo, TRIGGERED_NONE, ObjectGuid::Empty, false);
|
Spell* spell = new Spell(mover, spellInfo, triggerFlag, ObjectGuid::Empty, false);
|
||||||
|
|
||||||
sScriptMgr->ValidateSpellAtCastSpellResult(_player, mover, spell, oldSpellId, spellId);
|
sScriptMgr->ValidateSpellAtCastSpellResult(_player, mover, spell, oldSpellId, spellId);
|
||||||
|
|
||||||
|
|||||||
@@ -6480,6 +6480,14 @@ SpellCastResult Spell::CheckRange(bool strict)
|
|||||||
return SPELL_FAILED_TOO_CLOSE;
|
return SPELL_FAILED_TOO_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GameObject* goTarget = m_targets.GetGOTarget())
|
||||||
|
{
|
||||||
|
if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo))
|
||||||
|
{
|
||||||
|
return SPELL_FAILED_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_targets.HasDst() && !m_targets.HasTraj())
|
if (m_targets.HasDst() && !m_targets.HasTraj())
|
||||||
{
|
{
|
||||||
if (!m_caster->IsWithinDist3d(m_targets.GetDstPos(), max_range))
|
if (!m_caster->IsWithinDist3d(m_targets.GetDstPos(), max_range))
|
||||||
@@ -7767,6 +7775,15 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk
|
|||||||
|
|
||||||
return SPELL_CAST_OK;
|
return SPELL_CAST_OK;
|
||||||
}
|
}
|
||||||
|
case LOCK_KEY_SPELL:
|
||||||
|
{
|
||||||
|
if (m_spellInfo->Id == lockInfo->Index[j])
|
||||||
|
{
|
||||||
|
return SPELL_CAST_OK;
|
||||||
|
}
|
||||||
|
reqKey = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ public:
|
|||||||
Map* map = object->GetMap();
|
Map* map = object->GetMap();
|
||||||
|
|
||||||
object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), oz);
|
object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), oz);
|
||||||
object->SetWorldRotationAngles(oz, oy, ox);
|
object->SetLocalRotationAngles(oz, oy, ox);
|
||||||
|
|
||||||
object->SaveToDB(true);
|
object->SaveToDB(true);
|
||||||
|
|
||||||
|
|||||||
@@ -2463,7 +2463,8 @@ enum LockKeyType
|
|||||||
{
|
{
|
||||||
LOCK_KEY_NONE = 0,
|
LOCK_KEY_NONE = 0,
|
||||||
LOCK_KEY_ITEM = 1,
|
LOCK_KEY_ITEM = 1,
|
||||||
LOCK_KEY_SKILL = 2
|
LOCK_KEY_SKILL = 2,
|
||||||
|
LOCK_KEY_SPELL = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum LockType
|
enum LockType
|
||||||
|
|||||||
Reference in New Issue
Block a user