Core/Objects: ported Heartbeat implementation fron master branch
This commit is contained in:
1 parent
352ce7e1b3
commit
e8588fd5ba
30 files changed
+257
-184
No files matched your search
@@ -467,7 +467,6 @@ void BossAI::_Reset()
|
||||
if (!me->IsAlive())
|
||||
return;
|
||||
|
||||
me->SetCombatPulseDelay(0);
|
||||
me->ResetLootMode();
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
@@ -503,7 +502,6 @@ void BossAI::_JustEngagedWith(Unit* who)
|
||||
instance->SetBossState(_bossId, IN_PROGRESS);
|
||||
}
|
||||
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
DoZoneInCombat();
|
||||
ScheduleTasks();
|
||||
|
||||
@@ -279,7 +279,7 @@ bool ForcedDespawnDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
|
||||
Creature::Creature(bool isWorldObject): Unit(isWorldObject), MapObject(),
|
||||
m_groupLootTimer(0), lootingGroupLowGUID(0), m_PlayerDamageReq(0),
|
||||
m_lootRecipient(), m_lootRecipientGroup(0), _pickpocketLootRestore(0), m_corpseRemoveTime(0), m_respawnTime(0),
|
||||
m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE),
|
||||
m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500), m_reactState(REACT_AGGRESSIVE),
|
||||
m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
|
||||
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_cannotReachTarget(false), m_cannotReachTimer(0), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
|
||||
m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0), _cyclicSplinePathId(0),
|
||||
@@ -809,34 +809,6 @@ void Creature::Update(uint32 diff)
|
||||
m_boundaryCheckTime -= diff;
|
||||
}
|
||||
|
||||
// if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now
|
||||
if (m_combatPulseDelay > 0 && IsEngaged() && GetMap()->IsDungeon())
|
||||
{
|
||||
if (diff > m_combatPulseTime)
|
||||
m_combatPulseTime = 0;
|
||||
else
|
||||
m_combatPulseTime -= diff;
|
||||
|
||||
if (m_combatPulseTime == 0)
|
||||
{
|
||||
Map::PlayerList const& players = GetMap()->GetPlayers();
|
||||
if (!players.isEmpty())
|
||||
for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
|
||||
{
|
||||
if (Player* player = it->GetSource())
|
||||
{
|
||||
if (player->IsGameMaster())
|
||||
continue;
|
||||
|
||||
if (player->IsAlive() && IsHostileTo(player))
|
||||
EngageWithTarget(player);
|
||||
}
|
||||
}
|
||||
|
||||
m_combatPulseTime = m_combatPulseDelay * IN_MILLISECONDS;
|
||||
}
|
||||
}
|
||||
|
||||
// do not allow the AI to be changed during update
|
||||
Unit::AIUpdateTick(diff);
|
||||
|
||||
@@ -866,6 +838,14 @@ void Creature::Update(uint32 diff)
|
||||
}
|
||||
}
|
||||
|
||||
void Creature::Heartbeat()
|
||||
{
|
||||
Unit::Heartbeat();
|
||||
|
||||
// Creatures with CREATURE_STATIC_FLAG_2_FORCE_PARTY_MEMBERS_INTO_COMBAT periodically force party members into combat
|
||||
ForcePartyMembersIntoCombat();
|
||||
}
|
||||
|
||||
void Creature::RegenerateHealth()
|
||||
{
|
||||
if (!isRegeneratingHealth())
|
||||
@@ -3316,6 +3296,9 @@ void Creature::AtEngage(Unit* target)
|
||||
|
||||
if (GetAI() && !IsControlledByPlayer())
|
||||
SendAIReaction(AI_REACTION_HOSTILE);
|
||||
|
||||
// Creatures with CREATURE_STATIC_FLAG_2_FORCE_PARTY_MEMBERS_INTO_COMBAT periodically force party members into combat
|
||||
ForcePartyMembersIntoCombat();
|
||||
}
|
||||
|
||||
void Creature::AtDisengage()
|
||||
@@ -3327,6 +3310,41 @@ void Creature::AtDisengage()
|
||||
SetUInt32Value(UNIT_DYNAMIC_FLAGS, GetCreatureTemplate()->dynamicflags);
|
||||
}
|
||||
|
||||
void Creature::ForcePartyMembersIntoCombat()
|
||||
{
|
||||
if (!_staticFlags.HasFlag(CREATURE_STATIC_FLAG_2_FORCE_PARTY_MEMBERS_INTO_COMBAT) || !IsEngaged())
|
||||
return;
|
||||
|
||||
Trinity::Containers::FlatSet<Group const*> partiesToForceIntoCombat;
|
||||
for (auto const& [_, combatReference] : GetCombatManager().GetPvECombatRefs())
|
||||
{
|
||||
//if (combatReference->IsSuppressedFor(this))
|
||||
// continue;
|
||||
|
||||
Unit* other = combatReference->GetOther(this);
|
||||
|
||||
Player* player = other ? other->ToPlayer() : nullptr;
|
||||
if (!player || player->IsGameMaster())
|
||||
continue;
|
||||
|
||||
if (Group const* group = player->GetGroup())
|
||||
partiesToForceIntoCombat.insert(group);
|
||||
}
|
||||
|
||||
for (Group const* partyToForceIntoCombat : partiesToForceIntoCombat)
|
||||
{
|
||||
for (GroupReference const* ref = partyToForceIntoCombat->GetFirstMember(); ref != nullptr; ref = ref->next())
|
||||
{
|
||||
Player* player = ref->GetSource();
|
||||
if (!player || !player->IsInWorld() || player->GetMap() != GetMap() || player->IsGameMaster())
|
||||
continue;
|
||||
|
||||
EngageWithTarget(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Creature::IsEscorted() const
|
||||
{
|
||||
if (CreatureAI* ai = AI())
|
||||
|
||||
@@ -86,7 +86,9 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
|
||||
ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
|
||||
|
||||
void Update(uint32 time) override; // overwrited Unit::Update
|
||||
void Update(uint32 time) override; // overwritten Unit::Update
|
||||
void Heartbeat() override;
|
||||
|
||||
void GetRespawnPosition(float &x, float &y, float &z, float* ori = nullptr, float* dist = nullptr) const;
|
||||
bool IsSpawnedOnTransport() const { return m_creatureData && m_creatureData->mapId != GetMapId(); }
|
||||
|
||||
@@ -273,13 +275,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
void SetWanderDistance(float dist) { m_wanderDistance = dist; }
|
||||
|
||||
void DoImmediateBoundaryCheck() { m_boundaryCheckTime = 0; }
|
||||
uint32 GetCombatPulseDelay() const { return m_combatPulseDelay; }
|
||||
void SetCombatPulseDelay(uint32 delay) // (secs) interval at which the creature pulses the entire zone into combat (only works in dungeons)
|
||||
{
|
||||
m_combatPulseDelay = delay;
|
||||
if (m_combatPulseTime == 0 || m_combatPulseTime > delay)
|
||||
m_combatPulseTime = delay;
|
||||
}
|
||||
|
||||
uint32 m_groupLootTimer; // (msecs)timer used for group loot
|
||||
ObjectGuid::LowType lootingGroupLowGUID; // used to find group which is looting corpse
|
||||
@@ -377,6 +372,8 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
void AtEngage(Unit* target) override;
|
||||
void AtDisengage() override;
|
||||
|
||||
void ForcePartyMembersIntoCombat();
|
||||
|
||||
bool HasStaticFlag(CreatureStaticFlags flag) const { return _staticFlags.HasFlag(flag); }
|
||||
bool HasStaticFlag(CreatureStaticFlags2 flag) const { return _staticFlags.HasFlag(flag); }
|
||||
bool HasStaticFlag(CreatureStaticFlags3 flag) const { return _staticFlags.HasFlag(flag); }
|
||||
@@ -416,8 +413,6 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance
|
||||
float m_wanderDistance;
|
||||
uint32 m_boundaryCheckTime; // (msecs) remaining time for next evade boundary check
|
||||
uint32 m_combatPulseTime; // (msecs) remaining time for next zone-in-combat pulse
|
||||
uint32 m_combatPulseDelay; // (secs) how often the creature puts the entire zone in combat (only works in dungeons)
|
||||
|
||||
ReactStates m_reactState; // for AI, not charmInfo
|
||||
void RegenerateHealth() override;
|
||||
|
||||
@@ -827,7 +827,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, P
|
||||
|
||||
void GameObject::Update(uint32 diff)
|
||||
{
|
||||
m_Events.Update(diff);
|
||||
WorldObject::Update(diff);
|
||||
|
||||
if (AI())
|
||||
AI()->UpdateAI(diff);
|
||||
|
||||
@@ -101,6 +101,18 @@ WorldObject::~WorldObject()
|
||||
}
|
||||
}
|
||||
|
||||
void WorldObject::Update(uint32 diff)
|
||||
{
|
||||
m_Events.Update(diff);
|
||||
|
||||
_heartbeatTimer -= Milliseconds(diff);
|
||||
while (_heartbeatTimer <= 0ms)
|
||||
{
|
||||
_heartbeatTimer += HEARTBEAT_INTERVAL;
|
||||
Heartbeat();
|
||||
}
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
if (IsInWorld())
|
||||
@@ -1117,7 +1129,7 @@ bool Object::PrintIndexError(uint32 index, bool set) const
|
||||
WorldObject::WorldObject(bool isWorldObject) : Object(), WorldLocation(), LastUsedScriptID(0),
|
||||
m_movementInfo(), m_name(""), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr),
|
||||
m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(true), m_liquidStatus(LIQUID_MAP_NO_WATER),
|
||||
m_wmoGroupID(0), m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0),
|
||||
m_wmoGroupID(0), m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0), _heartbeatTimer(HEARTBEAT_INTERVAL),
|
||||
m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0)
|
||||
{
|
||||
m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST);
|
||||
@@ -1190,6 +1202,8 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
|
||||
|
||||
if (TransportBase* transport = GetTransport())
|
||||
transport->RemovePassenger(this);
|
||||
|
||||
m_Events.KillAllEvents(false); // non-delatable (currently cast spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
|
||||
}
|
||||
|
||||
void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh)
|
||||
|
||||
@@ -88,6 +88,7 @@ struct CreateObjectBits
|
||||
};
|
||||
|
||||
float const DEFAULT_COLLISION_HEIGHT = 2.03128f; // Most common value in dbc
|
||||
static constexpr Milliseconds const HEARTBEAT_INTERVAL = 5s + 200ms;
|
||||
|
||||
class TC_GAME_API Object
|
||||
{
|
||||
@@ -314,7 +315,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
public:
|
||||
virtual ~WorldObject();
|
||||
|
||||
virtual void Update (uint32 /*time_diff*/) { }
|
||||
virtual void Update(uint32 diff);
|
||||
|
||||
void _Create(ObjectGuid::LowType guidlow, HighGuid guidhigh);
|
||||
void AddToWorld() override;
|
||||
@@ -608,6 +609,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
virtual bool IsInvisibleDueToDespawn() const { return false; }
|
||||
//difference from IsAlwaysVisibleFor: 1. after distance check; 2. use owner or charmer as seer
|
||||
virtual bool IsAlwaysDetectableFor(WorldObject const* /*seer*/) const { return false; }
|
||||
|
||||
virtual void Heartbeat() { }
|
||||
private:
|
||||
Map* m_currMap; // current object's Map location
|
||||
|
||||
@@ -620,6 +623,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
|
||||
ObjectGuid _privateObjectOwner;
|
||||
|
||||
Milliseconds _heartbeatTimer;
|
||||
|
||||
virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool incOwnRadius = true, bool incTargetRadius = true) const;
|
||||
|
||||
bool CanNeverSee(WorldObject const* obj) const;
|
||||
|
||||
@@ -118,8 +118,6 @@
|
||||
#include "WorldStatePackets.h"
|
||||
#include <G3D/g3dmath.h>
|
||||
|
||||
#define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
|
||||
|
||||
// corpse reclaim times
|
||||
#define DEATH_EXPIRE_STEP (5*MINUTE)
|
||||
#define MAX_DEATH_COUNT 3
|
||||
@@ -171,11 +169,9 @@ Player::Player(WorldSession* session): Unit(true)
|
||||
|
||||
m_comboPoints = 0;
|
||||
|
||||
m_foodEmoteTimerCount = 0;
|
||||
m_weaponChangeTimer = 0;
|
||||
|
||||
m_zoneUpdateId = uint32(-1);
|
||||
m_zoneUpdateTimer = 0;
|
||||
|
||||
m_areaUpdateId = 0;
|
||||
m_team = 0;
|
||||
@@ -355,7 +351,6 @@ Player::Player(WorldSession* session): Unit(true)
|
||||
_hasValidLFGLeavePoint = false;
|
||||
_archaeology = std::make_unique<Archaeology>(this);
|
||||
m_petScalingSynchTimer.Reset(1000);
|
||||
m_groupUpdateTimer.Reset(5000);
|
||||
}
|
||||
|
||||
Player::~Player()
|
||||
@@ -1133,37 +1128,6 @@ void Player::Update(uint32 p_time)
|
||||
m_weaponChangeTimer -= p_time;
|
||||
}
|
||||
|
||||
if (m_zoneUpdateTimer > 0)
|
||||
{
|
||||
if (p_time >= m_zoneUpdateTimer)
|
||||
{
|
||||
// On zone update tick check if we are still in an inn if we are supposed to be in one
|
||||
if (HasRestFlag(REST_FLAG_IN_TAVERN))
|
||||
{
|
||||
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(GetInnTriggerId());
|
||||
if (!atEntry || !IsInAreaTriggerRadius(atEntry))
|
||||
RemoveRestFlag(REST_FLAG_IN_TAVERN);
|
||||
}
|
||||
|
||||
uint32 newzone, newarea;
|
||||
GetZoneAndAreaId(newzone, newarea);
|
||||
|
||||
if (m_zoneUpdateId != newzone)
|
||||
UpdateZone(newzone, newarea); // also update area
|
||||
else
|
||||
{
|
||||
// use area updates as well
|
||||
// needed for free far all arenas for example
|
||||
if (m_areaUpdateId != newarea)
|
||||
UpdateArea(newarea);
|
||||
|
||||
m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_zoneUpdateTimer -= p_time;
|
||||
}
|
||||
|
||||
// Power regeneration update
|
||||
_powerUpdateTimer -= p_time;
|
||||
if (IsAlive())
|
||||
@@ -1267,14 +1231,6 @@ void Player::Update(uint32 p_time)
|
||||
}
|
||||
}
|
||||
|
||||
// group update
|
||||
m_groupUpdateTimer.Update(p_time);
|
||||
if (m_groupUpdateTimer.Passed())
|
||||
{
|
||||
SendUpdateToOutOfRangeGroupMembers();
|
||||
m_groupUpdateTimer.Reset(5000);
|
||||
}
|
||||
|
||||
Pet* pet = GetPet();
|
||||
if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityRange()) && !pet->isPossessed())
|
||||
//if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
|
||||
@@ -1311,6 +1267,24 @@ void Player::Update(uint32 p_time)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Player::Heartbeat()
|
||||
{
|
||||
Unit::Heartbeat();
|
||||
|
||||
// Group update
|
||||
SendUpdateToOutOfRangeGroupMembers();
|
||||
|
||||
// Updating Zone and AreaId. This will also trigger spell_area and phasing related updates
|
||||
UpdateZoneAndAreaId();
|
||||
|
||||
// Updating auras which can only be used inside or outside (such as Mounts)
|
||||
UpdateIndoorsOutdoorsAuras();
|
||||
|
||||
// Updating the resting state when entering resting places
|
||||
UpdateTavernRestingState();
|
||||
}
|
||||
|
||||
void Player::setDeathState(DeathState s)
|
||||
{
|
||||
uint32 ressSpellId = 0;
|
||||
@@ -1808,8 +1782,6 @@ bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Wo
|
||||
|
||||
void Player::RegenerateAll(uint32 diff)
|
||||
{
|
||||
m_foodEmoteTimerCount += diff;
|
||||
|
||||
Regenerate(POWER_ENERGY, diff);
|
||||
Regenerate(POWER_MANA, diff);
|
||||
Regenerate(POWER_FOCUS, diff);
|
||||
@@ -1838,37 +1810,6 @@ void Player::RegenerateAll(uint32 diff)
|
||||
SetRuneCooldown(runeToRegen, (cd > (diff * cdmod)) ? cd - (diff * cdmod) : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Handles the emotes for drinking and eating.
|
||||
// According to sniffs there is a background timer going on that repeats independed from the time window where the aura applies.
|
||||
// That's why we dont need to reset the timer on apply. In sniffs I have seen that the first call for the spell visual is totally random, then after
|
||||
// 5 seconds over and over again which confirms my theory that we have a independed timer.
|
||||
if (m_foodEmoteTimerCount >= 5000)
|
||||
{
|
||||
std::vector<AuraEffect*> auraList;
|
||||
AuraEffectList const& ModRegenAuras = GetAuraEffectsByType(SPELL_AURA_MOD_REGEN);
|
||||
AuraEffectList const& ModPowerRegenAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN);
|
||||
|
||||
auraList.reserve(ModRegenAuras.size() + ModPowerRegenAuras.size());
|
||||
auraList.insert(auraList.end(), ModRegenAuras.begin(), ModRegenAuras.end());
|
||||
auraList.insert(auraList.end(), ModPowerRegenAuras.begin(), ModPowerRegenAuras.end());
|
||||
|
||||
for (auto itr = auraList.begin(); itr != auraList.end(); ++itr)
|
||||
{
|
||||
// Food emote comes above drinking emote if we have to decide (mage regen food for example)
|
||||
if ((*itr)->GetBase()->HasEffectType(SPELL_AURA_MOD_REGEN) && (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing))
|
||||
{
|
||||
SendPlaySpellVisualKit(SPELL_VISUAL_KIT_FOOD, 0, 0);
|
||||
break;
|
||||
}
|
||||
else if ((*itr)->GetBase()->HasEffectType(SPELL_AURA_MOD_POWER_REGEN) && (*itr)->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing))
|
||||
{
|
||||
SendPlaySpellVisualKit(SPELL_VISUAL_KIT_DRINK, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_foodEmoteTimerCount -= 5000;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RegenerateHealth()
|
||||
@@ -5913,7 +5854,7 @@ bool Player::UpdatePosition(float x, float y, float z, float orientation, bool t
|
||||
SetGroupUpdateFlag(GROUP_UPDATE_FLAG_WMO_GROUP_ID);
|
||||
}
|
||||
|
||||
CheckAreaExploreAndOutdoor();
|
||||
CheckAreaExplore();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5969,7 +5910,7 @@ void Player::SendMovieStart(uint32 movieId)
|
||||
SendDirectMessage(packet.Write());
|
||||
}
|
||||
|
||||
void Player::CheckAreaExploreAndOutdoor()
|
||||
void Player::CheckAreaExplore()
|
||||
{
|
||||
if (!IsAlive())
|
||||
return;
|
||||
@@ -5977,9 +5918,6 @@ void Player::CheckAreaExploreAndOutdoor()
|
||||
if (IsInFlight())
|
||||
return;
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !IsOutdoors())
|
||||
RemoveAurasWithAttribute(SPELL_ATTR0_ONLY_OUTDOORS);
|
||||
|
||||
uint32 const areaId = GetAreaId();
|
||||
SetAreaExplored(areaId);
|
||||
}
|
||||
@@ -6052,6 +5990,39 @@ void Player::SetAreaExplored(uint32 areaId)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateZoneAndAreaId()
|
||||
{
|
||||
uint32 newzone = 0, newarea = 0;
|
||||
GetZoneAndAreaId(newzone, newarea);
|
||||
|
||||
if (m_zoneUpdateId != newzone)
|
||||
UpdateZone(newzone, newarea); // also update area
|
||||
else
|
||||
{
|
||||
// use area updates as well
|
||||
// needed for free far all arenas for example
|
||||
if (m_areaUpdateId != newarea)
|
||||
UpdateArea(newarea);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateIndoorsOutdoorsAuras()
|
||||
{
|
||||
if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK))
|
||||
RemoveAurasWithAttribute(IsOutdoors() ? SPELL_ATTR0_ONLY_INDOORS : SPELL_ATTR0_ONLY_OUTDOORS);
|
||||
}
|
||||
|
||||
void Player::UpdateTavernRestingState()
|
||||
{
|
||||
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(GetInnTriggerId());
|
||||
|
||||
if (HasRestFlag(REST_FLAG_IN_TAVERN) && (!atEntry || !IsInAreaTriggerRadius(atEntry)))
|
||||
RemoveRestFlag(REST_FLAG_IN_TAVERN);
|
||||
else if (!HasRestFlag(REST_FLAG_IN_TAVERN) && IsInAreaTriggerRadius(atEntry))
|
||||
SetRestFlag(REST_FLAG_IN_TAVERN);
|
||||
}
|
||||
|
||||
|
||||
uint32 Player::TeamForRace(uint8 race)
|
||||
{
|
||||
if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race))
|
||||
@@ -7032,7 +7003,6 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
||||
|
||||
uint32 const oldZone = m_zoneUpdateId;
|
||||
m_zoneUpdateId = newZone;
|
||||
m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL;
|
||||
|
||||
GetMap()->UpdatePlayerZoneStats(oldZone, newZone);
|
||||
|
||||
@@ -27629,7 +27599,7 @@ void Player::SetActiveSpec(uint8 spec)
|
||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::ChangeSpec);
|
||||
}
|
||||
|
||||
void Player::SetRestFlag(RestFlag restFlag, uint32 triggerId /*= 0*/)
|
||||
void Player::SetRestFlag(RestFlag restFlag)
|
||||
{
|
||||
uint32 oldRestMask = _restFlagMask;
|
||||
_restFlagMask |= restFlag;
|
||||
@@ -27639,10 +27609,7 @@ void Player::SetRestFlag(RestFlag restFlag, uint32 triggerId /*= 0*/)
|
||||
_restTime = GameTime::GetGameTime();
|
||||
SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
|
||||
}
|
||||
|
||||
if (triggerId)
|
||||
inn_triggerId = triggerId;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::RemoveRestFlag(RestFlag restFlag)
|
||||
{
|
||||
|
||||
@@ -410,7 +410,7 @@ enum PlayerFlags
|
||||
PLAYER_FLAGS_UNK21 = 0x00200000,
|
||||
PLAYER_FLAGS_COMMENTATOR2 = 0x00400000,
|
||||
PLAYER_FLAGS_DISABLE_CASTING_EXCEPT_ABILITIES = 0x00800000, // disables casting any ability except for the ones specified in the aura effect's SpellClassMask
|
||||
PLAYER_FLAGS_DISABLE_ATTACKING_EXCEPT_ABILITIES = 0x01000000, // disables all attacks including ability casts except for the ones specified in the aura effect's SpellClassMask
|
||||
PLAYER_FLAGS_DISABLE_ATTACKING_EXCEPT_ABILITIES = 0x01000000, // disables all attacks including ability casts except for the ones specified in the aura effect's SpellClassMask
|
||||
PLAYER_FLAGS_NO_XP_GAIN = 0x02000000,
|
||||
PLAYER_FLAGS_UNK26 = 0x04000000,
|
||||
PLAYER_FLAGS_AUTO_DECLINE_GUILD = 0x08000000, // Automatically declines guild invites
|
||||
@@ -1044,6 +1044,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
|
||||
void Update(uint32 time) override;
|
||||
|
||||
void Heartbeat() override;
|
||||
|
||||
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const override;
|
||||
|
||||
bool IsInAreaTriggerRadius(AreaTriggerEntry const* trigger) const;
|
||||
@@ -1118,11 +1120,12 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void SetRestBonus(float rest_bonus_new);
|
||||
|
||||
bool HasRestFlag(RestFlag restFlag) const { return (_restFlagMask & restFlag) != 0; }
|
||||
void SetRestFlag(RestFlag restFlag, uint32 triggerId = 0);
|
||||
void SetRestFlag(RestFlag restFlag);
|
||||
void RemoveRestFlag(RestFlag restFlag);
|
||||
|
||||
uint32 GetXPRestBonus(uint32 xp);
|
||||
uint32 GetInnTriggerId() const { return inn_triggerId; }
|
||||
void SetInnTriggerID(uint32 id) { inn_triggerId = id; }
|
||||
|
||||
Pet* GetPet() const;
|
||||
Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime);
|
||||
@@ -1924,9 +1927,14 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void SetSemaphoreTeleportFar(bool semphsetting) { mSemaphoreTeleport_Far = semphsetting; }
|
||||
void ProcessDelayedOperations();
|
||||
|
||||
void CheckAreaExploreAndOutdoor(void);
|
||||
void CheckAreaExplore();
|
||||
void SetAreaExplored(uint32 areaId);
|
||||
|
||||
// These methods are used to periodically update certain area and aura based mechanics used in Heartbeat and Movement
|
||||
void UpdateZoneAndAreaId();
|
||||
void UpdateIndoorsOutdoorsAuras();
|
||||
void UpdateTavernRestingState();
|
||||
|
||||
static uint32 TeamForRace(uint8 race);
|
||||
uint32 GetTeam() const { return m_team; }
|
||||
TeamId GetTeamId() const { return m_team == ALLIANCE ? TEAM_ALLIANCE : TEAM_HORDE; }
|
||||
@@ -2390,7 +2398,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
protected:
|
||||
// Gamemaster whisper whitelist
|
||||
GuidList WhisperList;
|
||||
uint32 m_foodEmoteTimerCount;
|
||||
uint32 m_contestedPvPTimer;
|
||||
|
||||
/*********************************************************/
|
||||
@@ -2615,7 +2622,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
uint32 m_weaponChangeTimer;
|
||||
|
||||
uint32 m_zoneUpdateId;
|
||||
uint32 m_zoneUpdateTimer;
|
||||
uint32 m_areaUpdateId;
|
||||
|
||||
uint32 m_deathTimer;
|
||||
@@ -2758,7 +2764,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
std::vector<PlayerPetData*> PlayerPetDataStore;
|
||||
|
||||
TimeTrackerSmall m_petScalingSynchTimer;
|
||||
TimeTrackerSmall m_groupUpdateTimer;
|
||||
};
|
||||
|
||||
TC_GAME_API void AddItemsSetItem(Player* player, Item* item);
|
||||
|
||||
@@ -413,7 +413,7 @@ void Unit::Update(uint32 p_time)
|
||||
// WARNING! Order of execution here is important, do not change.
|
||||
// Spells must be processed with event system BEFORE they go to _UpdateSpells.
|
||||
// Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad.
|
||||
m_Events.Update(p_time);
|
||||
WorldObject::Update(p_time);
|
||||
|
||||
CheckPendingMovementAcks();
|
||||
|
||||
@@ -503,6 +503,25 @@ void Unit::Update(uint32 p_time)
|
||||
RefreshAI();
|
||||
}
|
||||
|
||||
void Unit::Heartbeat()
|
||||
{
|
||||
WorldObject::Heartbeat();
|
||||
|
||||
// SMSG_FLIGHT_SPLINE_SYNC for cyclic splines
|
||||
SendFlightSplineSyncUpdate();
|
||||
|
||||
// Trigger heartbeat procs and generic aura behavior such as food emotes and invoking aura script hooks
|
||||
TriggerAuraHeartbeat();
|
||||
}
|
||||
|
||||
void Unit::TriggerAuraHeartbeat()
|
||||
{
|
||||
for (auto const& [_, auraApplication] : m_appliedAuras)
|
||||
auraApplication->GetBase()->Heartbeat();
|
||||
|
||||
Unit::ProcSkillsAndAuras(this, nullptr, PROC_FLAG_HEARTBEAT, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
bool Unit::haveOffhandWeapon() const
|
||||
{
|
||||
if (Player const* player = ToPlayer())
|
||||
@@ -527,20 +546,6 @@ void Unit::UpdateSplineMovement(uint32 t_diff)
|
||||
movespline->updateState(t_diff);
|
||||
bool arrived = movespline->Finalized();
|
||||
|
||||
if (movespline->isCyclic())
|
||||
{
|
||||
m_splineSyncTimer.Update(t_diff);
|
||||
if (m_splineSyncTimer.Passed())
|
||||
{
|
||||
m_splineSyncTimer.Reset(5000); // Retail value, do not change
|
||||
|
||||
WorldPackets::Movement::FlightSplineSync packet;
|
||||
packet.Guid = GetGUID();
|
||||
packet.SplineDist = Movement::PacketBuilder::GetFlightSplineSyncDist(*movespline);
|
||||
SendMessageToSet(packet.Write(), IsPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
if (arrived)
|
||||
{
|
||||
DisableSpline();
|
||||
@@ -575,6 +580,17 @@ void Unit::UpdateSplinePosition()
|
||||
UpdatePosition(loc.x, loc.y, loc.z, loc.orientation);
|
||||
}
|
||||
|
||||
void Unit::SendFlightSplineSyncUpdate()
|
||||
{
|
||||
if (!movespline->isCyclic() || movespline->Finalized())
|
||||
return;
|
||||
|
||||
WorldPackets::Movement::FlightSplineSync flightSplineSync;
|
||||
flightSplineSync.Guid = GetGUID();
|
||||
flightSplineSync.SplineDist = float(movespline->timePassed()) / movespline->Duration();
|
||||
SendMessageToSet(flightSplineSync.Write(), true);
|
||||
}
|
||||
|
||||
void Unit::InterruptMovementBasedAuras()
|
||||
{
|
||||
// TODO: Check if orientation transport offset changed instead of only global orientation
|
||||
@@ -9625,7 +9641,6 @@ void Unit::CleanupBeforeRemoveFromMap(bool finalCleanup)
|
||||
if (finalCleanup)
|
||||
m_cleanupDone = true;
|
||||
|
||||
m_Events.KillAllEvents(false); // non-delatable (currently cast spells) will not deleted now but it will deleted at call in Map::RemoveAllObjectsInRemoveList
|
||||
CombatStop();
|
||||
ClearComboPointHolders();
|
||||
}
|
||||
|
||||
@@ -825,6 +825,9 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
virtual void Update(uint32 time) override;
|
||||
|
||||
void Heartbeat() override;
|
||||
void TriggerAuraHeartbeat();
|
||||
|
||||
void setAttackTimer(WeaponAttackType type, uint32 time) { m_attackTimer[type] = time; }
|
||||
void resetAttackTimer(WeaponAttackType type = BASE_ATTACK);
|
||||
uint32 getAttackTimer(WeaponAttackType type) const { return m_attackTimer[type]; }
|
||||
@@ -1871,6 +1874,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
void UpdateSplineMovement(uint32 t_diff);
|
||||
void UpdateSplinePosition();
|
||||
void SendFlightSplineSyncUpdate();
|
||||
|
||||
// player or player's pet
|
||||
float GetCombatRatingReduction(CombatRating cr) const;
|
||||
@@ -1886,7 +1890,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
private:
|
||||
uint32 m_state; // Even derived shouldn't modify
|
||||
TimeTrackerSmall m_splineSyncTimer;
|
||||
|
||||
std::array<DiminishingReturn, DIMINISHING_MAX> m_Diminishing;
|
||||
|
||||
|
||||
@@ -681,7 +681,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recvData)
|
||||
if (sObjectMgr->IsTavernAreaTrigger(triggerId))
|
||||
{
|
||||
// set resting flag we are in the inn
|
||||
player->SetRestFlag(REST_FLAG_IN_TAVERN, atEntry->ID);
|
||||
player->SetInnTriggerID(atEntry->ID);
|
||||
|
||||
if (sWorld->IsFFAPvPRealm())
|
||||
player->RemoveByteFlag(UNIT_FIELD_BYTES_2, UNIT_BYTES_2_OFFSET_PVP_FLAG, UNIT_BYTE2_FLAG_FFA_PVP);
|
||||
|
||||
@@ -445,12 +445,33 @@ void WorldSession::HandleMovementOpcode(uint16 opcode, MovementInfo& movementInf
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
plrMover->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
|
||||
|
||||
if (opcode == MSG_MOVE_JUMP)
|
||||
{
|
||||
plrMover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::Jump);
|
||||
Unit::ProcSkillsAndAuras(plrMover, nullptr, PROC_FLAG_JUMP, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_NONE, PROC_HIT_NONE, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Whenever a player stops a movement action, several position based checks and updates are being performed
|
||||
switch (opcode)
|
||||
{
|
||||
case CMSG_MOVE_SET_CAN_FLY:
|
||||
case MSG_MOVE_FALL_LAND:
|
||||
case MSG_MOVE_STOP:
|
||||
case MSG_MOVE_STOP_STRAFE:
|
||||
case MSG_MOVE_STOP_TURN:
|
||||
case MSG_MOVE_STOP_SWIM:
|
||||
case MSG_MOVE_STOP_PITCH:
|
||||
case MSG_MOVE_STOP_ASCEND:
|
||||
plrMover->UpdateZoneAndAreaId();
|
||||
plrMover->UpdateIndoorsOutdoorsAuras();
|
||||
plrMover->UpdateTavernRestingState();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -413,6 +413,11 @@ class CreatureGameObjectScriptRegistrySwapHooks
|
||||
// Hook which is called before a gameobject is swapped
|
||||
static void UnloadResetScript(GameObject* gameobject)
|
||||
{
|
||||
|
||||
// Remove deletable events only,
|
||||
// otherwise it causes crashes with non-deletable spell events.
|
||||
gameobject->m_Events.KillAllEvents(false);
|
||||
|
||||
gameobject->AI()->Reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -2056,6 +2056,19 @@ void Aura::CallScriptAfterDispel(DispelInfo* dispelInfo)
|
||||
}
|
||||
}
|
||||
|
||||
void Aura::CallScriptOnHeartbeat()
|
||||
{
|
||||
for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
|
||||
{
|
||||
(*scritr)->_PrepareScriptCall(AURA_SCRIPT_HOOK_ON_HEARTBEAT);
|
||||
auto hookItrEnd = (*scritr)->OnHeartbeat.end(), hookItr = (*scritr)->OnHeartbeat.begin();
|
||||
for (; hookItr != hookItrEnd; ++hookItr)
|
||||
hookItr->Call();
|
||||
|
||||
(*scritr)->_FinishScriptCall();
|
||||
}
|
||||
}
|
||||
|
||||
bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode)
|
||||
{
|
||||
bool preventDefault = false;
|
||||
@@ -2535,6 +2548,29 @@ void UnitAura::AddStaticApplication(Unit* target, uint8 effMask)
|
||||
_staticApplications[target->GetGUID()] |= effMask;
|
||||
}
|
||||
|
||||
void UnitAura::Heartbeat()
|
||||
{
|
||||
Aura::Heartbeat();
|
||||
|
||||
// Periodic food and drink emote animation
|
||||
HandlePeriodicFoodSpellVisualKit();
|
||||
}
|
||||
|
||||
void UnitAura::HandlePeriodicFoodSpellVisualKit()
|
||||
{
|
||||
SpellSpecificType specificType = GetSpellInfo()->GetSpellSpecific();
|
||||
|
||||
bool food = specificType == SPELL_SPECIFIC_FOOD || specificType == SPELL_SPECIFIC_FOOD_AND_DRINK;
|
||||
bool drink = specificType == SPELL_SPECIFIC_DRINK || specificType == SPELL_SPECIFIC_FOOD_AND_DRINK;
|
||||
|
||||
if (food)
|
||||
GetUnitOwner()->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_FOOD, 0, 0);
|
||||
|
||||
if (drink)
|
||||
GetUnitOwner()->SendPlaySpellVisualKit(SPELL_VISUAL_KIT_DRINK, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
DynObjAura::DynObjAura(AuraCreateInfo const& createInfo)
|
||||
: Aura(createInfo)
|
||||
{
|
||||
|
||||
@@ -237,12 +237,14 @@ class TC_GAME_API Aura
|
||||
uint8 GetProcEffectMask(AuraApplication* aurApp, ProcEventInfo& eventInfo, std::chrono::steady_clock::time_point now) const;
|
||||
float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const;
|
||||
void TriggerProcOnEvent(uint8 procEffectMask, AuraApplication* aurApp, ProcEventInfo& eventInfo);
|
||||
virtual void Heartbeat() { }
|
||||
|
||||
// AuraScript
|
||||
void LoadScripts();
|
||||
bool CallScriptCheckAreaTargetHandlers(Unit* target);
|
||||
void CallScriptDispel(DispelInfo* dispelInfo);
|
||||
void CallScriptAfterDispel(DispelInfo* dispelInfo);
|
||||
void CallScriptOnHeartbeat();
|
||||
bool CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode);
|
||||
bool CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode);
|
||||
void CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraApplication const* aurApp, AuraEffectHandleModes mode);
|
||||
@@ -337,6 +339,9 @@ class TC_GAME_API UnitAura : public Aura
|
||||
|
||||
void AddStaticApplication(Unit* target, uint8 effMask);
|
||||
|
||||
void Heartbeat() override;
|
||||
void HandlePeriodicFoodSpellVisualKit();
|
||||
|
||||
private:
|
||||
DiminishingGroup m_AuraDRGroup; // Diminishing
|
||||
std::unordered_map<ObjectGuid, uint8> _staticApplications; // non-area auras
|
||||
|
||||
@@ -112,7 +112,7 @@ enum ProcFlags
|
||||
{
|
||||
PROC_FLAG_NONE = 0x00000000,
|
||||
|
||||
PROC_FLAG_HEARTBEAT = 0x00000001, // 00 Killed by agressor - not sure about this flag
|
||||
PROC_FLAG_HEARTBEAT = 0x00000001, // 00 Heartbeat
|
||||
PROC_FLAG_KILL = 0x00000002, // 01 Kill target (in most cases need XP/Honor reward)
|
||||
|
||||
PROC_FLAG_DEAL_MELEE_SWING = 0x00000004, // 02 Done melee auto attack
|
||||
|
||||
@@ -229,7 +229,7 @@ class TC_GAME_API _SpellScript
|
||||
|
||||
template <typename Derived = _SpellScript>
|
||||
EffectNameHookHandler(Derived* owner, HookType<Derived> hookFunction, uint8 effIndex, uint16 effName)
|
||||
: BaseHookHandler(owner, hookFunction, effIndex,
|
||||
: BaseHookHandler(owner, hookFunction, effIndex,
|
||||
[_effectName = effName](SpellEffectInfo const& effectInfo) {
|
||||
return _effectName == SPELL_EFFECT_ANY || effectInfo.Effect == _effectName;
|
||||
}), _effName(effName)
|
||||
@@ -491,7 +491,7 @@ class TC_GAME_API SpellScript : public _SpellScript
|
||||
// internal use classes & functions
|
||||
// DO NOT OVERRIDE THESE IN SCRIPTS
|
||||
public:
|
||||
|
||||
|
||||
using CheckCastHook = HookHandler<SpellCastResult>;
|
||||
using EffectNameHook = EffectNameHookHandler<void, SpellEffIndex>;
|
||||
using HitHook = HookHandler<void>;
|
||||
@@ -742,6 +742,7 @@ enum AuraScriptHookType
|
||||
AURA_SCRIPT_HOOK_CHECK_AREA_TARGET,
|
||||
AURA_SCRIPT_HOOK_DISPEL,
|
||||
AURA_SCRIPT_HOOK_AFTER_DISPEL,
|
||||
AURA_SCRIPT_HOOK_ON_HEARTBEAT,
|
||||
// Spell Proc Hooks
|
||||
AURA_SCRIPT_HOOK_CHECK_PROC,
|
||||
AURA_SCRIPT_HOOK_CHECK_EFFECT_PROC,
|
||||
@@ -767,6 +768,7 @@ class TC_GAME_API AuraScript : public _SpellScript
|
||||
|
||||
using AuraCheckAreaTargetHookHandler = HookHandler<bool, Unit*>;
|
||||
using AuraDispelHookHandler = HookHandler<void, DispelInfo*>;
|
||||
using AuraHeartbeatHookHandler = HookHandler<void>;
|
||||
using AuraEffectPeriodicHookHandler = AuraNameHookHandler<void, AuraEffect const*>;
|
||||
using AuraEffectUpdatePeriodicHookHandler = AuraNameHookHandler<void, AuraEffect*>;
|
||||
using AuraEffectCalcAmountHookHandler = AuraNameHookHandler<void, AuraEffect const*, int32&, bool&>;
|
||||
@@ -811,7 +813,7 @@ class TC_GAME_API AuraScript : public _SpellScript
|
||||
};
|
||||
|
||||
using AuraEffectApplyHookHandler = AuraEffectHandleModeHookHandler<void, AuraEffect const*, AuraEffectHandleModes>;
|
||||
|
||||
|
||||
struct TC_GAME_API AuraEffectAbsorbHookHandler : AuraNameHookHandler<void, AuraEffect*, DamageInfo&, uint32&>
|
||||
{
|
||||
//> Base type shorthand.
|
||||
@@ -878,7 +880,7 @@ class TC_GAME_API AuraScript : public _SpellScript
|
||||
AuraScript()
|
||||
: _SpellScript(), m_aura(nullptr), m_auraApplication(nullptr), m_defaultActionPrevented(false),
|
||||
DoCheckAreaTarget(this),
|
||||
OnDispel(this), AfterDispel(this),
|
||||
OnDispel(this), AfterDispel(this), OnHeartbeat(this),
|
||||
OnEffectApply(this), AfterEffectApply(this),
|
||||
OnEffectRemove(this), AfterEffectRemove(this),
|
||||
OnEffectPeriodic(this), OnEffectUpdatePeriodic(this),
|
||||
@@ -935,6 +937,11 @@ class TC_GAME_API AuraScript : public _SpellScript
|
||||
// where function is: void function (DispelInfo* dispelInfo);
|
||||
AuraDispelHookHandler::HookList AfterDispel;
|
||||
|
||||
// executed on every heartbeat of a unit
|
||||
// example: OnHeartbeat.Register(this, class::function);
|
||||
// where function is: void function();
|
||||
AuraHeartbeatHookHandler::HookList OnHeartbeat;
|
||||
|
||||
// executed when aura effect is applied with specified mode to target
|
||||
// should be used when when effect handler preventing/replacing is needed, do not use this hook for triggering spellcasts/removing auras etc - may be unsafe
|
||||
// example: OnEffectApply.Register(this, &class::function, EffectIndexSpecifier, EffectAuraNameSpecifier);
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace ThroneOfTheTides::Ozumat
|
||||
enum Texts
|
||||
{
|
||||
// Neptulon
|
||||
SAY_INTRO_1 = 0,
|
||||
SAY_INTRO_1 = 0,
|
||||
SAY_INTRO_2 = 1,
|
||||
SAY_PURIFY_WATERS_1 = 2,
|
||||
SAY_PURIFY_WATERS_2 = 3,
|
||||
@@ -431,7 +431,7 @@ struct npc_ozumat_neptulon : public ScriptedAI
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
|
||||
@@ -494,7 +494,6 @@ struct npc_ozumat_neptulon : public ScriptedAI
|
||||
break;
|
||||
case NPC_OZUMAT_COMBAT_TRIGGER:
|
||||
summon->SetReactState(REACT_PASSIVE);
|
||||
summon->SetCombatPulseDelay(1);
|
||||
summon->AI()->DoZoneInCombat();
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -274,7 +274,6 @@ class boss_blood_council_controller : public CreatureScript
|
||||
return;
|
||||
}
|
||||
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
DoZoneInCombat();
|
||||
instance->SetBossState(DATA_BLOOD_PRINCE_COUNCIL, IN_PROGRESS);
|
||||
@@ -452,7 +451,6 @@ struct BloodPrincesBossAI : public BossAI
|
||||
{
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
me->SetCombatPulseDelay(0);
|
||||
|
||||
me->SetImmuneToPC(false);
|
||||
_isEmpowered = false;
|
||||
@@ -462,7 +460,6 @@ struct BloodPrincesBossAI : public BossAI
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
if (Creature* controller = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_BLOOD_PRINCES_CONTROL)))
|
||||
DoZoneInCombat(controller);
|
||||
|
||||
@@ -251,7 +251,6 @@ class boss_lady_deathwhisper : public CreatureScript
|
||||
}
|
||||
|
||||
_phase = PHASE_ONE;
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
DoZoneInCombat();
|
||||
scheduler.CancelGroup(GROUP_INTRO);
|
||||
|
||||
@@ -281,7 +281,6 @@ class boss_professor_putricide : public CreatureScript
|
||||
Talk(SAY_AGGRO);
|
||||
DoCast(me, SPELL_OOZE_TANK_PROTECTION, true);
|
||||
DoZoneInCombat(me);
|
||||
me->SetCombatPulseDelay(5);
|
||||
instance->SetBossState(DATA_PROFESSOR_PUTRICIDE, IN_PROGRESS);
|
||||
}
|
||||
|
||||
|
||||
@@ -284,7 +284,6 @@ class boss_sindragosa : public CreatureScript
|
||||
DoCast(me, SPELL_PERMAEATING_CHILL);
|
||||
Talk(SAY_AGGRO);
|
||||
instance->SetBossState(DATA_SINDRAGOSA, IN_PROGRESS);
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
me->SetFarVisible(true);
|
||||
DoZoneInCombat();
|
||||
|
||||
@@ -550,7 +550,6 @@ class boss_the_lich_king : public CreatureScript
|
||||
}
|
||||
|
||||
me->setActive(true);
|
||||
me->SetCombatPulseDelay(5);
|
||||
DoZoneInCombat();
|
||||
|
||||
events.SetPhase(PHASE_ONE);
|
||||
|
||||
@@ -528,7 +528,6 @@ class npc_green_dragon_combat_trigger : public CreatureScript
|
||||
EngagementStart(target);
|
||||
|
||||
me->setActive(true);
|
||||
me->SetCombatPulseDelay(5);
|
||||
DoZoneInCombat();
|
||||
instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, IN_PROGRESS);
|
||||
if (Creature* valithria = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_VALITHRIA_DREAMWALKER)))
|
||||
|
||||
@@ -178,7 +178,6 @@ struct boss_four_horsemen_baseAI : public BossAI
|
||||
case ACTION_BEGIN_FIGHTING:
|
||||
if (_ourMovementFinished)
|
||||
break;
|
||||
me->SetCombatPulseDelay(5);
|
||||
BeginFighting();
|
||||
_ourMovementFinished = true;
|
||||
break;
|
||||
@@ -306,7 +305,6 @@ struct boss_four_horsemen_baseAI : public BossAI
|
||||
_ourMovementFinished = false;
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
SetCombatMovement(false);
|
||||
me->SetCombatPulseDelay(0);
|
||||
me->ResetLootMode();
|
||||
events.Reset();
|
||||
summons.DespawnAll();
|
||||
|
||||
@@ -346,7 +346,6 @@ class boss_gothik : public CreatureScript
|
||||
if (me->IsInCombat())
|
||||
{
|
||||
summon->AI()->DoAction(_gateIsOpen ? ACTION_GATE_OPENED : ACTION_ACQUIRE_TARGET);
|
||||
summon->SetCombatPulseDelay(5);
|
||||
}
|
||||
else
|
||||
summon->DespawnOrUnsummon();
|
||||
|
||||
@@ -803,7 +803,6 @@ public:
|
||||
me->SetVisible(false);
|
||||
me->SetHomePosition(me->GetPosition());
|
||||
DoZoneInCombat();
|
||||
me->SetCombatPulseDelay(5);
|
||||
_visibilityTimer = 2 * IN_MILLISECONDS;
|
||||
_bloodTapTimer = 25 * IN_MILLISECONDS;
|
||||
break;
|
||||
@@ -836,7 +835,6 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetCombatPulseDelay(0);
|
||||
ScriptedAI::Reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -330,14 +330,12 @@ struct PalehoofMinionsBossAI : public BossAI
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetCombatPulseDelay(0);
|
||||
events.Reset();
|
||||
DoCastSelf(SPELL_FREEZE, true);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
ScheduleTasks();
|
||||
}
|
||||
|
||||
@@ -243,14 +243,12 @@ struct IllidariCouncilBossAI : public BossAI
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
me->SetCombatPulseDelay(0);
|
||||
events.Reset();
|
||||
DoCastSelf(SPELL_BALANCE_OF_POWER, true);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
if (Creature* illidari = instance->GetCreature(DATA_ILLIDARI_COUNCIL))
|
||||
DoZoneInCombat(illidari);
|
||||
|
||||
@@ -334,7 +334,6 @@ struct boss_essence_of_suffering : public BossAI
|
||||
|
||||
void JustEngagedWith(Unit* /*who*/) override
|
||||
{
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
|
||||
events.ScheduleEvent(EVENT_SOUL_DRAIN, 20s);
|
||||
@@ -405,7 +404,6 @@ struct boss_essence_of_desire : public BossAI
|
||||
events.ScheduleEvent(EVENT_RUNE_SHIELD, 16s);
|
||||
events.ScheduleEvent(EVENT_DEADEN, 31s);
|
||||
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
Talk(DESI_SAY_FREED);
|
||||
}
|
||||
@@ -513,7 +511,6 @@ struct boss_essence_of_anger : public BossAI
|
||||
events.ScheduleEvent(EVENT_SPITE, 20s);
|
||||
events.ScheduleEvent(EVENT_FREED_2, Seconds(1), Minutes(3));
|
||||
|
||||
me->SetCombatPulseDelay(5);
|
||||
me->setActive(true);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user