diff options
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 86 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Handlers/LootHandler.cpp | 6 | ||||
-rw-r--r-- | src/server/game/Handlers/SpellHandler.cpp | 39 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 5 | ||||
-rw-r--r-- | src/server/shared/SharedDefines.h | 3 |
7 files changed, 79 insertions, 69 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 2453182784a..dc6795969ee 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2554,14 +2554,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_GUILD_BANK: - case GAMEOBJECT_TYPE_MAILBOX: + 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_FISHINGHOLE: + 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: + // 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; } @@ -2623,47 +2644,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 @@ -2679,10 +2660,10 @@ 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() } } + return G3D::CoordinateFrame { { worldRotationQuat }, { GetPositionX(), GetPositionY(), GetPositionZ() } } .toWorldSpace(G3D::Box { { minX, minY, minZ }, { maxX, maxY, maxZ } }) .contains({ pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() }); } @@ -2690,6 +2671,11 @@ bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const 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) @@ -2708,7 +2694,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; diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 257e4ce99db..e44002628a5 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -285,7 +285,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; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 36474ef67c2..9d6bc88d17c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2298,7 +2298,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; @@ -8377,7 +8377,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()) diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 552be19f67a..a685d6c0fbc 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -47,7 +47,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; @@ -118,7 +118,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; @@ -267,7 +267,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; diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index c0d115e755f..b05c972faf9 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -330,6 +330,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) uint32 spellId; uint8 castCount, castFlags; recvPacket >> castCount >> spellId >> 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()); @@ -369,24 +370,38 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) caster = _player; } + // client provided targets + SpellCastTargets targets; + targets.Read(recvPacket, caster); + HandleClientCastFlags(recvPacket, castFlags, targets); + + // not have spell in spellbook if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellId)) { - // 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; } // 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 @@ -415,7 +430,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) spellInfo = actualSpellInfo; } - Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); + Spell* spell = new Spell(caster, spellInfo, triggerFlag); spell->m_cast_count = castCount; // set count of casts spell->prepare(targets); } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index aa567e1b5e3..a48fe01c880 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -7593,6 +7593,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; } } diff --git a/src/server/shared/SharedDefines.h b/src/server/shared/SharedDefines.h index 00b9b1f01ec..19e01ba1865 100644 --- a/src/server/shared/SharedDefines.h +++ b/src/server/shared/SharedDefines.h @@ -2593,7 +2593,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 |