Core/GameObject: Implement GAMEOBJECT_TYPE_NEW_FLAG_DROP (#28021)

This commit is contained in:
Jeremy
2023-07-24 17:27:28 +02:00
committed by GitHub
parent ea134c0eae
commit 3cfc27f5ca
4 changed files with 147 additions and 1 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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;