diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 3848b99405..f0e25d48c2 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -304,6 +304,10 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject void SetSpawnId(uint32 spawnId) { m_spawnId = spawnId; } + void SetVisibleByUnitOnly(ObjectGuid unit) { m_visibleByUnitOnly = unit; } + bool IsVisibleByUnitOnly() const { return !m_visibleByUnitOnly.IsEmpty(); } + ObjectGuid GetVisibleByUnitOnly() const { return m_visibleByUnitOnly; } + protected: GameObjectModel* CreateModel(); void UpdateModel(); // updates model in case displayId were changed @@ -362,5 +366,6 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject GameObjectAI* m_AI; bool m_respawnCompatibilityMode; bool _triggerJustAppeared; + ObjectGuid m_visibleByUnitOnly; }; #endif diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 7f103f14f3..0989537745 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1775,6 +1775,10 @@ bool WorldObject::CanSeeOrDetect(WorldObject const* obj, bool ignoreStealth, boo return false; } + if (GameObject const* go = obj->ToGameObject()) + if (go->IsVisibleByUnitOnly() && GetGUID() != go->GetVisibleByUnitOnly()) + return false; + if (!viewpoint) viewpoint = this; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index d6d8fe8d1f..9166b92c58 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1071,7 +1071,7 @@ enum SpellEffects SPELL_EFFECT_ALLOW_CONTROL_PET = 168, SPELL_EFFECT_DESTROY_ITEM = 169, SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES = 170, - SPELL_EFFECT_171 = 171, // Summons gamebject + SPELL_EFFECT_SUMMON_PERSONAL_GAMEOBJECT = 171, // Summons gamebject SPELL_EFFECT_RESURRECT_WITH_AURA = 172, SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB = 173, // Guild tab unlocked (guild perk) SPELL_EFFECT_APPLY_AURA_2 = 174, diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 32d357a763..a2245d0f9e 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -396,6 +396,7 @@ class TC_GAME_API Spell void EffectCastButtons(SpellEffIndex effIndex); void EffectRechargeManaGem(SpellEffIndex effIndex); void EffectGiveCurrency(SpellEffIndex effIndex); + void EffectSummonPersonalGameObject(SpellEffIndex effIndex); void EffectResurrectWithAura(SpellEffIndex effIndex); void EffectCreateAreaTrigger(SpellEffIndex effIndex); void EffectUpdatePlayerPhase(SpellEffIndex effIndex); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index d6167c3f8c..fa4627383d 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -240,7 +240,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //168 SPELL_EFFECT_168 &Spell::EffectNULL, //169 SPELL_EFFECT_DESTROY_ITEM &Spell::EffectUpdateZoneAurasAndPhases, //170 SPELL_EFFECT_UPDATE_ZONE_AURAS_AND_PHASES - &Spell::EffectNULL, //171 SPELL_EFFECT_171 + &Spell::EffectSummonPersonalGameObject, //171 SPELL_EFFECT_SUMMON_PERSONAL_GAMEOBJECT &Spell::EffectResurrectWithAura, //172 SPELL_EFFECT_RESURRECT_WITH_AURA &Spell::EffectUnlockGuildVaultTab, //173 SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB &Spell::EffectApplyAura, //174 SPELL_EFFECT_APPLY_AURA_2 @@ -5538,6 +5538,55 @@ void Spell::EffectUnlockGuildVaultTab(SpellEffIndex effIndex) guild->HandleBuyBankTab(caster->GetSession(), m_spellInfo->Effects[effIndex].BasePoints - 1); // Bank tabs start at zero internally } +void Spell::EffectSummonPersonalGameObject(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) + return; + + uint32 goId = effectInfo->MiscValue; + if (!goId) + return; + + float x, y, z; + if (m_targets.HasDst()) + destTarget->GetPosition(x, y, z); + else + m_caster->GetClosePoint(x, y, z, DEFAULT_PLAYER_BOUNDING_RADIUS); + + Map* map = m_caster->GetMap(); + Position pos = Position(x, y, z, m_caster->GetOrientation()); + QuaternionData rot = QuaternionData::fromEulerAnglesZYX(m_caster->GetOrientation(), 0.f, 0.f); + GameObject* go = GameObject::CreateGameObject(goId, map, pos, rot, 255, GO_STATE_READY); + + if (!go) + { + TC_LOG_WARN("spells", "SpellEffect Failed to summon personal gameobject. SpellId %u, effect %u", m_spellInfo->Id, effIndex); + return; + } + + PhasingHandler::InheritPhaseShift(go, m_caster); + + int32 duration = m_spellInfo->CalcDuration(m_caster); + + go->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0); + go->SetSpellId(m_spellInfo->Id); + go->SetVisibleByUnitOnly(m_caster->GetGUID()); + + ExecuteLogEffectSummonObject(effIndex, go); + + map->AddToMap(go); + + if (GameObject* linkedTrap = go->GetLinkedTrap()) + { + PhasingHandler::InheritPhaseShift(linkedTrap, m_caster); + + linkedTrap->SetRespawnTime(duration > 0 ? duration / IN_MILLISECONDS : 0); + linkedTrap->SetSpellId(m_spellInfo->Id); + + ExecuteLogEffectSummonObject(effIndex, linkedTrap); + } +} + void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 77a86368b5..73e49c4200 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -861,7 +861,7 @@ SpellEffectInfo::StaticData SpellEffectInfo::_data[TOTAL_SPELL_EFFECTS] = {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 168 SPELL_EFFECT_168 {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_ITEM}, // 169 SPELL_EFFECT_DESTROY_ITEM {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 170 SPELL_EFFECT_170 - {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_DEST}, // 171 SPELL_EFFECT_171 + {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_DEST}, // 171 SPELL_EFFECT_SUMMON_PERSONAL_GAMEOBJECT {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_CORPSE_ALLY}, // 172 SPELL_EFFECT_RESURRECT_WITH_AURA {EFFECT_IMPLICIT_TARGET_NONE, TARGET_OBJECT_TYPE_NONE}, // 173 SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB {EFFECT_IMPLICIT_TARGET_EXPLICIT, TARGET_OBJECT_TYPE_UNIT}, // 174 SPELL_EFFECT_APPLY_AURA_2