EverWrath/src/server/game/Entities/DynamicObject/DynamicObject.cpp
UltraNix 99f1cd84e2
fix(Core/Spells): Improvements to Far Sight spell: (#11683)
* fix(Core/Spells): Improvements to Far Sight spell:

Far Sight should not interrupt while casting another spell.
Corrected setting Far Sight object as an active object.
Fixed grid activation range for active dynamic objects.
When Far Sight is over, the camera be reset to player.
Enable swapping camera between Far Sight and Sentry Totem.
Fixes #6368

* Update.

* Update.
2022-05-23 04:26:51 -03:00

283 lines
7.7 KiB
C++

/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SpellAuraEffects.h"
#include "GameTime.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "ObjectAccessor.h"
#include "Opcodes.h"
#include "ScriptMgr.h"
#include "Transport.h"
#include "UpdateMask.h"
#include "World.h"
DynamicObject::DynamicObject(bool isWorldObject) : WorldObject(isWorldObject), MovableMapObject(),
_aura(nullptr), _removedAura(nullptr), _caster(nullptr), _duration(0), _isViewpoint(false), _updateViewerVisibilityTimer(0)
{
m_objectType |= TYPEMASK_DYNAMICOBJECT;
m_objectTypeId = TYPEID_DYNAMICOBJECT;
m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_POSITION);
m_valuesCount = DYNAMICOBJECT_END;
}
DynamicObject::~DynamicObject()
{
// make sure all references were properly removed
ASSERT(!_aura);
ASSERT(!_caster);
ASSERT(!_isViewpoint);
delete _removedAura;
}
void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */)
{
if (Transport* transport = GetTransport())
{
transport->RemovePassenger(this);
SetTransport(nullptr);
m_movementInfo.transport.Reset();
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
}
WorldObject::CleanupsBeforeDelete(finalCleanup);
}
void DynamicObject::AddToWorld()
{
///- Register the dynamicObject for guid lookup and for caster
if (!IsInWorld())
{
GetMap()->GetObjectsStore().Insert<DynamicObject>(GetGUID(), this);
WorldObject::AddToWorld();
BindToCaster();
}
}
void DynamicObject::RemoveFromWorld()
{
///- Remove the dynamicObject from the accessor and from all lists of objects in world
if (IsInWorld())
{
if (_isViewpoint)
RemoveCasterViewpoint();
if (_aura)
RemoveAura();
// dynobj could get removed in Aura::RemoveAura
if (!IsInWorld())
return;
UnbindFromCaster();
if (Transport* transport = GetTransport())
transport->RemovePassenger(this, true);
WorldObject::RemoveFromWorld();
GetMap()->GetObjectsStore().Remove<DynamicObject>(GetGUID());
}
}
bool DynamicObject::CreateDynamicObject(ObjectGuid::LowType guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type)
{
SetMap(caster->GetMap());
Relocate(pos);
if (!IsPositionValid())
{
LOG_ERROR("dyobject", "DynamicObject (spell {}) not created. Suggested coordinates isn't valid (X: {} Y: {})", spellId, GetPositionX(), GetPositionY());
return false;
}
WorldObject::_Create(guidlow, HighGuid::DynamicObject, caster->GetPhaseMask());
UpdatePositionData();
SetEntry(spellId);
SetObjectScale(1);
SetGuidValue(DYNAMICOBJECT_CASTER, caster->GetGUID());
// The lower word of DYNAMICOBJECT_BYTES must be 0x0001. This value means that the visual radius will be overriden
// by client for most of the "ground patch" visual effect spells and a few "skyfall" ones like Hurricane.
// If any other value is used, the client will _always_ use the radius provided in DYNAMICOBJECT_RADIUS, but
// precompensation is necessary (eg radius *= 2) for many spells. Anyway, blizz sends 0x0001 for all the spells
// I saw sniffed...
SetByteValue(DYNAMICOBJECT_BYTES, 0, type);
SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId);
SetFloatValue(DYNAMICOBJECT_RADIUS, radius);
SetUInt32Value(DYNAMICOBJECT_CASTTIME, GameTime::GetGameTimeMS().count());
if (!GetMap()->AddToMap(this, true))
{
// Returning false will cause the object to be deleted - remove from transport
return false;
}
if (IsWorldObject())
{
setActive(true);
}
return true;
}
void DynamicObject::Update(uint32 p_time)
{
// caster has to be always available and in the same map
ASSERT(_caster);
ASSERT(_caster->GetMap() == GetMap());
bool expired = false;
if (_aura)
{
if (!_aura->IsRemoved())
_aura->UpdateOwner(p_time, this);
// _aura may be set to null in Aura::UpdateOwner call
if (_aura && (_aura->IsRemoved() || _aura->IsExpired()))
expired = true;
}
else
{
if (GetDuration() > int32(p_time))
_duration -= p_time;
else
expired = true;
}
if (expired)
Remove();
else
{
if (_updateViewerVisibilityTimer)
{
if (_updateViewerVisibilityTimer <= p_time)
{
_updateViewerVisibilityTimer = 0;
if (Player* playerCaster = _caster->ToPlayer())
playerCaster->UpdateVisibilityForPlayer();
}
else
_updateViewerVisibilityTimer -= p_time;
}
sScriptMgr->OnDynamicObjectUpdate(this, p_time);
}
}
void DynamicObject::Remove()
{
if (IsInWorld())
{
SendObjectDeSpawnAnim(GetGUID());
RemoveFromWorld();
AddObjectToRemoveList();
}
}
int32 DynamicObject::GetDuration() const
{
if (!_aura)
return _duration;
else
return _aura->GetDuration();
}
void DynamicObject::SetDuration(int32 newDuration)
{
if (!_aura)
_duration = newDuration;
else
_aura->SetDuration(newDuration);
}
void DynamicObject::Delay(int32 delaytime)
{
SetDuration(GetDuration() - delaytime);
}
void DynamicObject::SetAura(Aura* aura)
{
ASSERT(!_aura && aura);
_aura = aura;
}
void DynamicObject::RemoveAura()
{
ASSERT(_aura && !_removedAura);
_removedAura = _aura;
_aura = nullptr;
if (!_removedAura->IsRemoved())
_removedAura->_Remove(AURA_REMOVE_BY_DEFAULT);
}
void DynamicObject::SetCasterViewpoint(bool updateViewerVisibility)
{
if (Player* caster = _caster->ToPlayer())
{
// Remove old farsight viewpoint
if (Unit* farsightObject = ObjectAccessor::GetUnit(*caster, caster->GetGuidValue(PLAYER_FARSIGHT)))
{
_oldFarsightGUID = caster->GetGuidValue(PLAYER_FARSIGHT);
caster->SetViewpoint(farsightObject, false);
}
caster->SetViewpoint(this, true);
_isViewpoint = true;
}
_updateViewerVisibilityTimer = updateViewerVisibility ? 100 : 0;
}
void DynamicObject::RemoveCasterViewpoint()
{
if (Player* caster = _caster->ToPlayer())
{
caster->SetViewpoint(this, false);
_isViewpoint = false;
// Restore prev farsight viewpoint
if (Unit* farsightObject = ObjectAccessor::GetUnit(*caster, _oldFarsightGUID))
{
caster->SetViewpoint(farsightObject, true);
}
_oldFarsightGUID.Clear();
}
}
void DynamicObject::BindToCaster()
{
ASSERT(!_caster);
_caster = ObjectAccessor::GetUnit(*this, GetCasterGUID());
ASSERT(_caster);
ASSERT(_caster->GetMap() == GetMap());
_caster->_RegisterDynObject(this);
}
void DynamicObject::UnbindFromCaster()
{
ASSERT(_caster);
_caster->_UnregisterDynObject(this);
_caster = nullptr;
}