mirror of
https://github.com/brues-code/nampower.git
synced 2026-10-10 07:30:01 +00:00
176 lines
7.2 KiB
C++
176 lines
7.2 KiB
C++
//
|
|
// Created by pmacc on 9/21/2024.
|
|
//
|
|
|
|
#include "spellchannel.hpp"
|
|
#include "spellcast.hpp"
|
|
#include "logging.hpp"
|
|
#include "offsets.hpp"
|
|
#include "helper.hpp"
|
|
|
|
namespace Nampower {
|
|
void TriggerSpellChannelStartEvent(uint32_t spellId, uint32_t duration) {
|
|
static char format[] = "%d%s%d";
|
|
|
|
auto playerGuid = game::ClntObjMgrGetActivePlayerGuid();
|
|
auto playerUnit = game::GetObjectPtr(playerGuid);
|
|
auto unitTargetGuid = game::UnitGetTargetGuid(playerUnit); // channel target guid gets updated later
|
|
|
|
char *targetGuidStr = ConvertGuidToString(unitTargetGuid);
|
|
|
|
((int (__cdecl *)(int eventCode,
|
|
char *fmt,
|
|
uint32_t spellIdParam,
|
|
char *targetGuidParam,
|
|
uint32_t durationParam)) Offsets::SignalEventParam)(
|
|
game::SPELL_CHANNEL_START,
|
|
format,
|
|
spellId,
|
|
targetGuidStr,
|
|
duration);
|
|
|
|
FreeGuidString(targetGuidStr);
|
|
}
|
|
|
|
void TriggerSpellChannelUpdateEvent(uint32_t spellId, uint32_t channelRemainingTime) {
|
|
static char format[] = "%d%s%d";
|
|
|
|
auto channelTargetGuid = *reinterpret_cast<uint64_t *>(Offsets::ChannelTargetGuid);
|
|
char *targetGuidStr = ConvertGuidToString(channelTargetGuid);
|
|
|
|
((int (__cdecl *)(int eventCode,
|
|
char *fmt,
|
|
uint32_t spellIdParam,
|
|
char *targetGuidParam,
|
|
uint32_t remainingParam)) Offsets::SignalEventParam)(
|
|
game::SPELL_CHANNEL_UPDATE,
|
|
format,
|
|
spellId,
|
|
targetGuidStr,
|
|
channelRemainingTime);
|
|
|
|
FreeGuidString(targetGuidStr);
|
|
}
|
|
|
|
int SpellChannelStartHandlerHook(hadesmem::PatchDetourBase *detour, uint32_t *opCode, CDataStore *packet) {
|
|
auto const rpos = packet->m_read;
|
|
|
|
uint32_t spellId;
|
|
packet->Get(spellId);
|
|
|
|
uint32_t duration;
|
|
packet->Get(duration);
|
|
|
|
packet->m_read = rpos;
|
|
|
|
DEBUG_LOG("Channel start: " << game::GetSpellName(spellId) << " duration " << duration);
|
|
|
|
if (duration > 0) {
|
|
// check if spell has "Far sight" flag which is used on mind control style abilities
|
|
auto spell = game::GetSpellInfo(spellId);
|
|
if (spell && !(spell->AttributesEx & game::SPELL_ATTR_EX_TOGGLE_FARSIGHT ||
|
|
spellId == 19832 || // bwl orb spell
|
|
spellId == 23014 || // bwl orb spell
|
|
spellId == 13180) // mind control cap
|
|
) {
|
|
auto currentTimeMs = GetTime();
|
|
gCastData.channeling = true;
|
|
gCastData.channelStartMs = currentTimeMs;
|
|
gCastData.channelEndMs = currentTimeMs + duration;
|
|
gCastData.channelSpellId = spellId;
|
|
gCastData.channelDuration = duration;
|
|
|
|
auto originalDuration = game::GetDurationObject(spell->DurationIndex)->m_Duration;
|
|
|
|
float durationReduction = 1.0f;
|
|
|
|
// if this was an Arcane Missiles cast, we need to check if we have the +1 aura
|
|
if (spellId == 5143 ||
|
|
spellId == 5144 ||
|
|
spellId == 5145 ||
|
|
spellId == 8416 ||
|
|
spellId == 8417 ||
|
|
spellId == 10211 ||
|
|
spellId == 10212 ||
|
|
spellId == 25345) {
|
|
// check if we have duration mod > 0
|
|
auto durationModifier = game::GetSpellModifier(spell, game::SPELLMOD_DURATION);
|
|
if (durationModifier > 0) {
|
|
DEBUG_LOG("Adding 1 second to Arcane Missiles duration due to duration mod " << durationModifier);
|
|
originalDuration += 1000;
|
|
}
|
|
}
|
|
|
|
if (originalDuration > 0 && originalDuration < 1000000) {
|
|
durationReduction = float(duration) / float(originalDuration);
|
|
} else {
|
|
DEBUG_LOG("Invalid originalDuration of " << originalDuration << " for "
|
|
<< game::GetSpellName(spellId));
|
|
}
|
|
|
|
uint32_t amplitude = spell->EffectAmplitude[0];
|
|
if (amplitude <= 0 || amplitude > duration) {
|
|
amplitude = spell->EffectAmplitude[1];
|
|
}
|
|
if (amplitude <= 0 || amplitude > duration) {
|
|
amplitude = spell->EffectAmplitude[2];
|
|
}
|
|
|
|
gCastData.channelTickTimeMs = uint32_t(float(amplitude) *
|
|
durationReduction); // the base tick time is usually on the first effect, scale it based on the duration reduction due to haste mechanics
|
|
|
|
DEBUG_LOG("Original tick time " << amplitude << " scaled tick time "
|
|
<< gCastData.channelTickTimeMs);
|
|
|
|
if (gCastData.channelTickTimeMs <= 0 || gCastData.channelTickTimeMs > duration) {
|
|
DEBUG_LOG("Invalid channel tick time for " << game::GetSpellName(spellId)
|
|
<< ", defaulting to duration");
|
|
gCastData.channelTickTimeMs = duration;
|
|
}
|
|
|
|
gCastData.channelNumTicks = 0;
|
|
|
|
gLastCastData.channelStartTimeMs = currentTimeMs;
|
|
} else {
|
|
DEBUG_LOG("Ignoring/resetting channeling for " << game::GetSpellName(spellId));
|
|
ResetChannelingFlags();
|
|
}
|
|
} else {
|
|
ResetChannelingFlags();
|
|
}
|
|
|
|
auto const spellChannelStartHandler = detour->GetTrampolineT<PacketHandlerT>();
|
|
auto ret = spellChannelStartHandler(opCode, packet);
|
|
|
|
TriggerSpellChannelStartEvent(spellId, duration);
|
|
|
|
return ret;
|
|
}
|
|
|
|
// this gets called on damage and when channel ends with the end time of the channel
|
|
int SpellChannelUpdateHandlerHook(hadesmem::PatchDetourBase *detour, uint32_t *opCode, CDataStore *packet) {
|
|
auto const rpos = packet->m_read;
|
|
|
|
uint32_t channelRemainingTime;
|
|
packet->Get(channelRemainingTime);
|
|
|
|
packet->m_read = rpos;
|
|
|
|
TriggerSpellChannelUpdateEvent(gCastData.channelSpellId, channelRemainingTime);
|
|
|
|
if (channelRemainingTime <= 0) {
|
|
DEBUG_LOG("Channel done: " << game::GetSpellName(gCastData.channelSpellId)
|
|
<< " elapsed " << (GetTime() - gLastCastData.channelStartTimeMs)
|
|
<< " original duration " << gCastData.channelDuration);
|
|
ResetChannelingFlags();
|
|
} else {
|
|
DEBUG_LOG("Channel update: " << game::GetSpellName(gCastData.channelSpellId) << " remaining "
|
|
<< channelRemainingTime);
|
|
gCastData.channelEndMs = GetTime() + channelRemainingTime;
|
|
}
|
|
|
|
auto const spellChannelUpdateHandler = detour->GetTrampolineT<PacketHandlerT>();
|
|
return spellChannelUpdateHandler(opCode, packet);
|
|
}
|
|
}
|