diff options
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 88 | ||||
-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 | 33 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/SharedDefines.h | 3 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 5 |
7 files changed, 81 insertions, 63 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index b023fef1d5f..ea6f340863a 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2800,14 +2800,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; } @@ -2900,51 +2921,11 @@ bool GameObject::IsAtInteractDistance(Player const* player, SpellInfo const* spe if (GetGoType() == GAMEOBJECT_TYPE_SPELL_FOCUS) return maxRange * maxRange >= GetExactDistSq(player); - if (GameObjectDisplayInfoEntry const* displayInfo = sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId)) + if (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); + return IsAtInteractDistance(*player, GetInteractionDistance()); } bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const @@ -2960,10 +2941,10 @@ bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const float maxY = displayInfo->GeoBoxMax.Y * scale + radius; float maxZ = displayInfo->GeoBoxMax.Z * 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() }); } @@ -2971,6 +2952,11 @@ bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const return GetExactDist(&pos) <= radius; } +bool GameObject::IsWithinDistInMap(Player const* player) const +{ + return IsInMap(player) && IsInPhase(player) && IsAtInteractDistance(player); +} + SpellInfo const* GameObject::GetSpellForLock(Player const* player) const { if (!player) @@ -2989,7 +2975,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], GetMap()->GetDifficultyID())) return spell; diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 39323bcb34d..f6ad0fc2eac 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -300,7 +300,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 f24f12540e4..df0101c7101 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2055,7 +2055,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; @@ -8763,7 +8763,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa } 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 93f0b1947e0..f2c5ad4f15c 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -78,7 +78,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPackets::Loot::LootItem& p 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); continue; @@ -158,7 +158,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet 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; @@ -328,7 +328,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 ec9d24d02d3..cfc2b1cefcd 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -299,9 +299,35 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast) caster = _player; } + TriggerCastFlags triggerFlag = TRIGGERED_NONE; + + // client provided targets + SpellCastTargets targets(caster, cast.Cast); + // check known spell or raid marker spell (which not requires player to know it) if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->HasEffect(SPELL_EFFECT_CHANGE_RAID_MARKER) && !spellInfo->HasAttribute(SPELL_ATTR8_RAID_MARKER)) - 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 spellInfo = caster->GetCastSpellInfo(spellInfo); @@ -310,9 +336,6 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast) if (_player->isPossessing()) return; - // client provided targets - SpellCastTargets targets(caster, cast.Cast); - // Client is resending autoshot cast opcode when other spell is cast during shoot rotation // Skip it to prevent "interrupt" message // Also check targets! target may have changed and we need to interrupt current spell @@ -334,7 +357,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& cast) if (cast.Cast.MoveUpdate) HandleMovementOpcode(CMSG_MOVE_STOP, *cast.Cast.MoveUpdate); - Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE); + Spell* spell = new Spell(caster, spellInfo, triggerFlag); WorldPackets::Spells::SpellPrepare spellPrepare; spellPrepare.ClientCastID = cast.Cast.CastID; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 241f1fe0495..a4a73b8fe61 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -4326,7 +4326,8 @@ enum LockKeyType { LOCK_KEY_NONE = 0, LOCK_KEY_ITEM = 1, - LOCK_KEY_SKILL = 2 + LOCK_KEY_SKILL = 2, + LOCK_KEY_SPELL = 3, }; // LockType.dbc (9.0.2.37176) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 8083c08479f..8e755f1cb2e 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -7782,6 +7782,11 @@ SpellCastResult Spell::CanOpenLock(SpellEffectInfo const& effect, uint32 lockId, return SPELL_CAST_OK; } + case LOCK_KEY_SPELL: + if (m_spellInfo->Id == uint32(lockInfo->Index[j])) + return SPELL_CAST_OK; + reqKey = true; + break; } } |