diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 107 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 23 | ||||
-rw-r--r-- | src/server/game/Maps/ZoneScript.h | 5 | ||||
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuraEffects.cpp | 13 |
4 files changed, 147 insertions, 1 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index dc210de3aac..4d46568c92b 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -503,6 +503,51 @@ void SetTransportAutoCycleBetweenStopFrames::Execute(GameObjectTypeBase& type) c if (Transport* transport = dynamic_cast<Transport*>(&type)) transport->SetAutoCycleBetweenStopFrames(_on); } + +class NewFlag : public GameObjectTypeBase +{ +public: + explicit NewFlag(GameObject& owner) : GameObjectTypeBase(owner), _state(FlagState::InBase), _respawnTime(0) { } + + void SetState(FlagState newState, Player* player) + { + FlagState oldState = _state; + _state = newState; + _owner.UpdateObjectVisibility(); + if (ZoneScript* zoneScript = _owner.GetZoneScript()) + zoneScript->OnFlagStateChange(&_owner, oldState, _state, player); + + if (newState == FlagState::Respawning) + _respawnTime = GameTime::GetGameTimeMS() + _owner.GetGOInfo()->newflag.RespawnTime; + else + _respawnTime = 0; + } + + void Update([[maybe_unused]] uint32 diff) override + { + if (_state == FlagState::Respawning && GameTime::GetGameTimeMS() >= _respawnTime) + SetState(FlagState::InBase, nullptr); + } + + bool IsNeverVisibleFor([[maybe_unused]] WorldObject const* seer, [[maybe_unused]] bool allowServersideObjects) const override + { + return _state != FlagState::InBase; + } + +private: + FlagState _state; + time_t _respawnTime; +}; + +SetNewFlagState::SetNewFlagState(FlagState state, Player* player) : _state(state), _player(player) +{ +} + +void SetNewFlagState::Execute(GameObjectTypeBase& type) const +{ + if (NewFlag* newFlag = dynamic_cast<NewFlag*>(&type)) + newFlag->SetState(_state, _player); +} } GameObject::GameObject() : WorldObject(false), MapObject(), @@ -797,6 +842,9 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD m_invisibility.AddValue(INVISIBILITY_TRAP, 300); } break; + case GAMEOBJECT_TYPE_NEW_FLAG: + m_goTypeImpl = std::make_unique<GameObjectType::NewFlag>(*this); + break; case GAMEOBJECT_TYPE_PHASEABLE_MO: RemoveFlag(GameObjectFlags(0xF00)); SetFlag(GameObjectFlags((m_goInfo->phaseableMO.AreaNameSet & 0xF) << 8)); @@ -1317,6 +1365,13 @@ void GameObject::Update(uint32 diff) else if (!GetOwnerGUID().IsEmpty() || GetSpellId()) { SetRespawnTime(0); + + if (GetGoType() == GAMEOBJECT_TYPE_NEW_FLAG_DROP) + { + if (GameObject* go = GetMap()->GetGameObject(GetOwnerGUID())) + go->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::InBase, nullptr)); + } + Delete(); return; } @@ -1807,6 +1862,9 @@ bool GameObject::IsNeverVisibleFor(WorldObject const* seer, bool allowServerside if (!GetDisplayId() && GetGOInfo()->IsDisplayMandatory()) return true; + if (m_goTypeImpl) + return m_goTypeImpl->IsNeverVisibleFor(seer, allowServersideObjects); + return false; } @@ -2892,8 +2950,48 @@ void GameObject::Use(Unit* user) return; spellId = info->newflag.pickupSpell; + spellCaster = nullptr; break; } + case GAMEOBJECT_TYPE_NEW_FLAG_DROP: + { + GameObjectTemplate const* info = GetGOInfo(); + if (!info) + return; + + if (user->GetTypeId() != TYPEID_PLAYER) + return; + + if (GameObject* owner = GetMap()->GetGameObject(GetOwnerGUID())) + { + if (owner->GetGoType() == GAMEOBJECT_TYPE_NEW_FLAG) + { + // friendly with enemy flag means you're taking it + bool defenderInteract = !owner->IsFriendlyTo(user); + if (defenderInteract && owner->GetGOInfo()->newflag.ReturnonDefenderInteract) + { + Delete(); + owner->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::InBase, user->ToPlayer())); + return; + } + else + { + // we let the owner cast the spell for now + // so that caster guid is set correctly + SpellCastResult result = owner->CastSpell(user, owner->GetGOInfo()->newflag.pickupSpell, CastSpellExtraArgs(TRIGGERED_FULL_MASK)); + if (result == SPELL_CAST_OK) + { + Delete(); + owner->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Taken, user->ToPlayer())); + return; + } + } + } + } + + Delete(); + return; + } case GAMEOBJECT_TYPE_ITEM_FORGE: { GameObjectTemplate const* info = GetGOInfo(); @@ -3047,7 +3145,14 @@ void GameObject::Use(Unit* user) if (spellCaster) spellCaster->CastSpell(user, spellId, triggered); else - CastSpell(user, spellId); + { + SpellCastResult castResult = CastSpell(user, spellId); + if (castResult == SPELL_FAILED_SUCCESS) + { + if (GetGoType() == GAMEOBJECT_TYPE_NEW_FLAG) + HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Taken, user->ToPlayer())); + } + } } void GameObject::SendCustomAnim(uint32 anim) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 62362de5a6d..8c08ef627b5 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -35,6 +35,16 @@ struct Loot; struct TransportAnimation; enum TriggerCastFlags : uint32; +// enum for GAMEOBJECT_TYPE_NEW_FLAG +// values taken from world state +enum class FlagState : uint8 +{ + InBase = 1, + Taken, + Dropped, + Respawning +}; + namespace WorldPackets { namespace Battleground @@ -60,6 +70,7 @@ public: virtual void Update([[maybe_unused]] uint32 diff) { } virtual void OnStateChanged([[maybe_unused]] GOState oldState, [[maybe_unused]] GOState newState) { } virtual void OnRelocated() { } + virtual bool IsNeverVisibleFor([[maybe_unused]] WorldObject const* seer, [[maybe_unused]] bool allowServersideObjects) const { return false; } protected: GameObject& _owner; @@ -77,6 +88,18 @@ public: private: bool _on; }; + +class TC_GAME_API SetNewFlagState : public GameObjectTypeBase::CustomCommand +{ +public: + explicit SetNewFlagState(FlagState state, Player* player); + + void Execute(GameObjectTypeBase& type) const override; + +private: + FlagState _state; + Player* _player; +}; } union GameObjectValue diff --git a/src/server/game/Maps/ZoneScript.h b/src/server/game/Maps/ZoneScript.h index ad0cab88b24..02da0e1261c 100644 --- a/src/server/game/Maps/ZoneScript.h +++ b/src/server/game/Maps/ZoneScript.h @@ -23,10 +23,13 @@ class Creature; class GameObject; +class Player; class Unit; class WorldObject; struct CreatureData; +enum class FlagState : uint8; + class TC_GAME_API ZoneScript { public: @@ -62,6 +65,8 @@ class TC_GAME_API ZoneScript virtual void TriggerGameEvent(uint32 gameEventId, WorldObject* source = nullptr, WorldObject* target = nullptr); virtual void ProcessEvent(WorldObject* /*obj*/, uint32 /*eventId*/, WorldObject* /*invoker*/) { } + + virtual void OnFlagStateChange([[maybe_unused]] GameObject* flagInBase, [[maybe_unused]] FlagState oldValue, [[maybe_unused]] FlagState newValue, [[maybe_unused]] Player* player) { } }; #endif diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 5d9e0ea60f7..d511bc2dfa3 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -6209,6 +6209,19 @@ void AuraEffect::HandleBattlegroundPlayerPosition(AuraApplication const* aurApp, if (!target) return; + if (!apply) + { + if (GameObject* gameObjectCaster = target->GetMap()->GetGameObject(GetCasterGUID())) + { + if (gameObjectCaster->GetGoType() == GAMEOBJECT_TYPE_NEW_FLAG) + { + gameObjectCaster->HandleCustomTypeCommand(GameObjectType::SetNewFlagState(FlagState::Dropped, target)); + if (GameObject* droppedFlag = gameObjectCaster->SummonGameObject(gameObjectCaster->GetGOInfo()->newflag.FlagDrop, target->GetPosition(), QuaternionData::fromEulerAnglesZYX(target->GetOrientation(), 0.f, 0.f), Seconds(gameObjectCaster->GetGOInfo()->newflag.ExpireDuration / 1000), GO_SUMMON_TIMED_DESPAWN)) + droppedFlag->SetOwnerGUID(gameObjectCaster->GetGUID()); + } + } + } + BattlegroundMap* battlegroundMap = target->GetMap()->ToBattlegroundMap(); if (!battlegroundMap) return; |