From 6ab2871fd10a2b4c4f8f434b8b2949cce2e49e09 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 14 Jul 2018 18:50:02 -0400 Subject: [PATCH] Beneficial spells will now correctly inherit targets RestTimer Example PC A is fighting mob B. PC C casts a heal on PC A. PC C will inherit the timer from PC A. This is done because beneficial spells have a "witness" check from NPCs so there is a chance PC C would not gain aggro and could just keep on going with no RestTimer which allows them to fast regen while actively participating. --- zone/client.cpp | 31 +++++++++++++++++++++++++++++++ zone/client.h | 1 + zone/spells.cpp | 2 ++ 3 files changed, 34 insertions(+) diff --git a/zone/client.cpp b/zone/client.cpp index 68645309e..82bca086e 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -4608,6 +4608,7 @@ void Client::IncrementAggroCount(bool raid_target) uint32 newtimer = raid_target ? RuleI(Character, RestRegenRaidTimeToActivate) : RuleI(Character, RestRegenTimeToActivate); + // save the new timer if it's higher m_pp.RestTimer = std::max(m_pp.RestTimer, newtimer); // If we already had aggro before this method was called, the combat indicator should already be up for SoF clients, @@ -4661,6 +4662,36 @@ void Client::DecrementAggroCount() } } +// when we cast a beneficial spell we need to steal our targets current timer +// That's what we use this for +void Client::UpdateRestTimer(uint32 new_timer) +{ + // their timer was 0, so we don't do anything + if (new_timer == 0) + return; + + if (!RuleB(Character, RestRegenEnabled)) + return; + + // so if we're currently on aggro, we check our saved timer + if (AggroCount) { + if (m_pp.RestTimer < new_timer) // our timer needs to be updated, don't need to update client here + m_pp.RestTimer = new_timer; + } else { // if we're not aggro, we need to check if current timer needs updating + if (rest_timer.GetRemainingTime() < new_timer) { + rest_timer.Start(new_timer); + if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) { + auto outapp = new EQApplicationPacket(OP_RestState, 5); + char *Buffer = (char *)outapp->pBuffer; + VARSTRUCT_ENCODE_TYPE(uint8, Buffer, 0x00); + VARSTRUCT_ENCODE_TYPE(uint32, Buffer, new_timer); + QueuePacket(outapp); + safe_delete(outapp); + } + } + } +} + void Client::SendPVPStats() { // This sends the data to the client to populate the PVP Stats Window. diff --git a/zone/client.h b/zone/client.h index 7d0982fc2..77b509e4f 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1397,6 +1397,7 @@ private: void CalcRestState(); // if they have aggro (AggroCount != 0) their timer is saved in m_pp.RestTimer, else we need to get current timer inline uint32 GetRestTimer() const { return AggroCount ? m_pp.RestTimer : rest_timer.GetRemainingTime() / 1000; } + void UpdateRestTimer(uint32 new_timer); uint32 pLastUpdate; uint32 pLastUpdateWZ; diff --git a/zone/spells.cpp b/zone/spells.cpp index 537e7358e..6edda023c 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3895,6 +3895,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r spelltar->SetHateAmountOnEnt(this, std::max(newhate, 1)); } } else if (IsBeneficialSpell(spell_id) && !IsSummonPCSpell(spell_id)) { + if (spelltar->IsClient() && IsClient()) + CastToClient()->UpdateRestTimer(spelltar->CastToClient()->GetRestTimer()); entity_list.AddHealAggro( spelltar, this, CheckHealAggroAmount(spell_id, spelltar, (spelltar->GetMaxHP() - spelltar->GetHP())));