aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy <Golrag@users.noreply.github.com>2023-07-24 17:27:28 +0200
committerGitHub <noreply@github.com>2023-07-24 17:27:28 +0200
commit3cfc27f5ca81402ed41973a0206838e7a0352070 (patch)
tree2a40775d9d47e69774a61d7f70405e5f8bc93b0c
parentea134c0eae83b4cdbb5f0e941ed867a144bb01f6 (diff)
Core/GameObject: Implement GAMEOBJECT_TYPE_NEW_FLAG_DROP (#28021)
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp107
-rw-r--r--src/server/game/Entities/GameObject/GameObject.h23
-rw-r--r--src/server/game/Maps/ZoneScript.h5
-rw-r--r--src/server/game/Spells/Auras/SpellAuraEffects.cpp13
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;