diff options
| -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;  | 
