* Core/Object: Range check vol. 2 (#23226) (ported commit: 78070163dc6b9bb34ab2d006e9cc218548e861b7)
* Core/Object: Fix all missing parts for #23062
This commit is contained in:
1 parent
950eff5fda
commit
69907a6d6d
7 files changed
+82
-72
No files matched your search
@@ -2464,14 +2464,35 @@ float GameObject::GetInteractionDistance() const
|
||||
{
|
||||
switch (GetGoType())
|
||||
{
|
||||
/// @todo find out how the client calculates the maximal usage distance to spellless working
|
||||
// gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
|
||||
case GAMEOBJECT_TYPE_AREADAMAGE:
|
||||
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_MAILBOX:
|
||||
return 10.0f;
|
||||
case GAMEOBJECT_TYPE_FISHINGHOLE:
|
||||
case GAMEOBJECT_TYPE_FISHINGNODE:
|
||||
return 20.0f + CONTACT_DISTANCE; // max spell range
|
||||
// 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.
|
||||
return 10.0f; // 5.0f is blizzlike
|
||||
default:
|
||||
return INTERACTION_DISTANCE;
|
||||
}
|
||||
@@ -2594,47 +2615,7 @@ bool GameObject::IsAtInteractDistance(Player const* player, SpellInfo const* spe
|
||||
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);
|
||||
return IsAtInteractDistance(*player, GetInteractionDistance());
|
||||
}
|
||||
|
||||
bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const
|
||||
@@ -2650,17 +2631,23 @@ bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const
|
||||
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);
|
||||
QuaternionData worldRotation = GetWorldRotation();
|
||||
G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.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 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(this) && InSamePhase(this) && IsAtInteractDistance(player);
|
||||
}
|
||||
|
||||
|
||||
SpellInfo const* GameObject::GetSpellForLock(Player const* player) const
|
||||
{
|
||||
if (!player)
|
||||
@@ -2679,7 +2666,7 @@ SpellInfo const* GameObject::GetSpellForLock(Player const* player) const
|
||||
if (!lock->Type[i])
|
||||
continue;
|
||||
|
||||
if (lock->Type[i] == LOCK_KEY_SKILL)
|
||||
if (lock->Type[i] == LOCK_KEY_SPELL)
|
||||
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(lock->Index[i]))
|
||||
return spell;
|
||||
|
||||
|
||||
@@ -289,7 +289,10 @@ 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;
|
||||
bool IsAtInteractDistance(Player const* player, SpellInfo const* spell = nullptr) const;
|
||||
|
||||
bool IsWithinDistInMap(Player const* player) const;
|
||||
using WorldObject::IsWithinDistInMap;
|
||||
|
||||
SpellInfo const* GetSpellForLock(Player const* player) const;
|
||||
|
||||
|
||||
@@ -2455,7 +2455,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const
|
||||
if (!go)
|
||||
return nullptr;
|
||||
|
||||
if (!go->IsWithinDistInMap(this, go->GetInteractionDistance()))
|
||||
if (!go->IsWithinDistInMap(this))
|
||||
return nullptr;
|
||||
|
||||
return go;
|
||||
@@ -8707,7 +8707,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lootType != LOOT_FISHINGHOLE && ((lootType != LOOT_FISHING && lootType != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE))
|
||||
if (lootType != LOOT_FISHINGHOLE && ((lootType != LOOT_FISHING && lootType != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this))
|
||||
return true;
|
||||
|
||||
if (lootType == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault())
|
||||
|
||||
@@ -50,7 +50,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
|
||||
GameObject* go = player->GetMap()->GetGameObject(lguid);
|
||||
|
||||
// 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);
|
||||
return;
|
||||
@@ -164,7 +164,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
|
||||
GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);
|
||||
|
||||
// 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;
|
||||
|
||||
break;
|
||||
@@ -321,7 +321,7 @@ void WorldSession::DoLootRelease(ObjectGuid 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
|
||||
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;
|
||||
|
||||
loot = &go->loot;
|
||||
|
||||
@@ -363,6 +363,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
recvPacket >> spellId;
|
||||
recvPacket >> glyphIndex;
|
||||
recvPacket >> castFlags;
|
||||
TriggerCastFlags triggerFlag = TRIGGERED_NONE;
|
||||
|
||||
TC_LOG_DEBUG("network", "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u", castCount, spellId, castFlags, (uint32)recvPacket.size());
|
||||
|
||||
@@ -402,12 +403,33 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
caster = _player;
|
||||
}
|
||||
|
||||
// client provided targets
|
||||
SpellCastTargets targets;
|
||||
targets.Read(recvPacket, caster);
|
||||
HandleClientCastFlags(recvPacket, castFlags, targets);
|
||||
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->IsRaidMarker() &&
|
||||
!caster->ToPlayer()->HasArchProject(static_cast<uint16>(spellInfo->ResearchProjectId)))
|
||||
{
|
||||
// not have spell in spellbook
|
||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
||||
return;
|
||||
bool allow = false;
|
||||
|
||||
// allow casting of unknown spells for special lock cases
|
||||
if (GameObject *go = targets.GetGOTarget())
|
||||
if (go->GetSpellForLock(caster->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;
|
||||
}
|
||||
|
||||
// Check possible spell cast overrides
|
||||
@@ -415,15 +437,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
|
||||
// can't use our own spells when we're in possession of another unit,
|
||||
if (_player->isPossessing())
|
||||
{
|
||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
||||
return;
|
||||
}
|
||||
|
||||
// client provided targets
|
||||
SpellCastTargets targets;
|
||||
targets.Read(recvPacket, caster);
|
||||
HandleClientCastFlags(recvPacket, castFlags, targets);
|
||||
|
||||
// Client is resending autoshot cast opcode when other spell is cast during shoot rotation
|
||||
// Skip it to prevent "interrupt" message
|
||||
@@ -452,7 +466,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
spellInfo = actualSpellInfo;
|
||||
}
|
||||
|
||||
Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE, ObjectGuid::Empty, false);
|
||||
Spell* spell = new Spell(caster, spellInfo, triggerFlag, ObjectGuid::Empty, false);
|
||||
spell->m_cast_count = castCount; // set count of casts
|
||||
spell->m_glyphIndex = glyphIndex;
|
||||
spell->prepare(&targets);
|
||||
|
||||
@@ -2949,7 +2949,8 @@ enum LockKeyType
|
||||
{
|
||||
LOCK_KEY_NONE = 0,
|
||||
LOCK_KEY_ITEM = 1,
|
||||
LOCK_KEY_SKILL = 2
|
||||
LOCK_KEY_SKILL = 2,
|
||||
LOCK_KEY_SPELL = 3
|
||||
};
|
||||
|
||||
enum LockType
|
||||
|
||||
@@ -7619,6 +7619,11 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk
|
||||
}
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
case LOCK_KEY_SPELL:
|
||||
if (m_spellInfo->Id == lockInfo->Index[j])
|
||||
return SPELL_CAST_OK;
|
||||
reqKey = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user