F4MP/codigos originales/tiltedcode/Code/client/Games/Skyrim/Magic/MagicTarget.cpp

251 lines
8.9 KiB
C++
Raw Normal View History

#include "MagicTarget.h"
#include <Actor.h>
#include <World.h>
#include "EffectItem.h"
#include <Structs/Skyrim/AnimationGraphDescriptor_WerewolfBehavior.h>
#include <Structs/Skyrim/AnimationGraphDescriptor_VampireLordBehavior.h>
#include <Events/AddTargetEvent.h>
#include <Events/HitEvent.h>
#include <Games/ActorExtension.h>
#include <Games/Overrides.h>
#include <PlayerCharacter.h>
#include <Effects/ActiveEffect.h>
TP_THIS_FUNCTION(TAddTarget, bool, MagicTarget, MagicTarget::AddTargetData& arData);
TP_THIS_FUNCTION(TCheckAddEffectTargetData, bool, MagicTarget::AddTargetData, void* arArgs, float afResistance);
TP_THIS_FUNCTION(TFindTargets, bool, MagicCaster, float afEffectivenessMult, int32_t* aruiTargetCount,
TESBoundObject* apSource, char abLoadCast, char abAdjust);
TP_THIS_FUNCTION(TAdjustForPerks, void, ActiveEffect, Actor* apCaster, MagicTarget* apTarget);
TP_THIS_FUNCTION(THasPerk, bool, Actor, TESForm* apPerk, void* apUnk1, double* afReturnValue);
TP_THIS_FUNCTION(TGetPerkRank, uint8_t, Actor, TESForm* apPerk);
static TAddTarget* RealAddTarget = nullptr;
static TCheckAddEffectTargetData* RealCheckAddEffectTargetData = nullptr;
static TFindTargets* RealFindTargets = nullptr;
static TAdjustForPerks* RealAdjustForPerks = nullptr;
static THasPerk* RealHasPerk = nullptr;
static TGetPerkRank* RealGetPerkRank = nullptr;
static thread_local bool s_autoSucceedEffectCheck = false;
static thread_local bool s_applyHealPerkBonus = false;
static thread_local bool s_applyStaminaPerkBonus = false;
void MagicTarget::DispelAllSpells(bool aNow) noexcept
{
TP_THIS_FUNCTION(TDispelAllSpells, void, MagicTarget, bool aNow);
POINTER_SKYRIMSE(TDispelAllSpells, dispelAllSpells, 34512);
TiltedPhoques::ThisCall(dispelAllSpells, this, aNow);
}
bool MagicTarget::AddTarget(AddTargetData& arData, bool aApplyHealPerkBonus, bool aApplyStaminaPerkBonus) noexcept
{
s_autoSucceedEffectCheck = true;
s_applyHealPerkBonus = aApplyHealPerkBonus;
s_applyStaminaPerkBonus = aApplyStaminaPerkBonus;
bool result = TiltedPhoques::ThisCall(RealAddTarget, this, arData);
s_autoSucceedEffectCheck = false;
s_applyHealPerkBonus = false;
s_applyStaminaPerkBonus = false;
return result;
}
bool MagicTarget::AddTargetData::ShouldSync()
{
return !pEffectItem->IsSummonEffect() && !pSpell->IsInvisibilitySpell() && !pSpell->IsWardSpell();
}
// Some effects are player specific, and do not need to be synced.
bool MagicTarget::AddTargetData::IsForbiddenEffect(Actor* apTarget)
{
if (apTarget != PlayerCharacter::Get())
return false;
return pEffectItem->IsNightVisionEffect();
}
Actor* MagicTarget::GetTargetAsActor()
{
TP_THIS_FUNCTION(TGetTargetAsActor, Actor*, MagicTarget);
POINTER_SKYRIMSE(TGetTargetAsActor, getTargetAsActor, 34529);
return TiltedPhoques::ThisCall(getTargetAsActor, this);
}
bool TP_MAKE_THISCALL(HookAddTarget, MagicTarget, MagicTarget::AddTargetData& arData)
{
Actor* pTargetActor = apThis->GetTargetAsActor();
if (!pTargetActor || arData.IsForbiddenEffect(pTargetActor))
return TiltedPhoques::ThisCall(RealAddTarget, apThis, arData);
ActorExtension* pTargetActorEx = pTargetActor->GetExtension();
if (arData.pEffectItem->IsWerewolfEffect())
pTargetActorEx->GraphDescriptorHash = AnimationGraphDescriptor_WerewolfBehavior::m_key;
if (arData.pEffectItem->IsVampireLordEffect())
pTargetActorEx->GraphDescriptorHash = AnimationGraphDescriptor_VampireLordBehavior::m_key;
if (ScopedSpellCastOverride::IsOverriden())
return TiltedPhoques::ThisCall(RealAddTarget, apThis, arData);
AddTargetEvent addTargetEvent{};
addTargetEvent.TargetID = pTargetActor->formID;
addTargetEvent.CasterID = arData.pCaster ? arData.pCaster->formID : 0;
addTargetEvent.SpellID = arData.pSpell->formID;
addTargetEvent.EffectID = arData.pEffectItem->pEffectSetting->formID;
addTargetEvent.Magnitude = arData.fMagnitude;
addTargetEvent.IsDualCasting = arData.bDualCast;
if (pTargetActorEx->IsRemotePlayer())
{
if (!arData.pCaster)
return false;
if (!arData.pSpell->IsHealingSpell() && !arData.pSpell->IsBuffSpell())
return false;
ActorExtension* pCasterExtension = arData.pCaster->GetExtension();
if (!pCasterExtension->IsLocalPlayer())
return false;
if (arData.pSpell->IsHealingSpell())
{
addTargetEvent.ApplyHealPerkBonus = arData.pCaster->HasPerk(0x581f8);
addTargetEvent.ApplyStaminaPerkBonus = arData.pCaster->HasPerk(0x581f9);
}
bool result = TiltedPhoques::ThisCall(RealAddTarget, apThis, arData);
if (result)
World::Get().GetRunner().Trigger(addTargetEvent);
return result;
}
if (pTargetActorEx->IsLocalPlayer())
{
if (arData.pCaster)
{
ActorExtension* pCasterExtension = arData.pCaster->GetExtension();
if (pCasterExtension->IsRemotePlayer())
{
if (!World::Get().GetServerSettings().PvpEnabled)
return false;
// Heal and buff spells are already synced by the caster.
if (arData.pSpell->IsHealingSpell() || arData.pSpell->IsBuffSpell())
return false;
}
}
bool result = TiltedPhoques::ThisCall(RealAddTarget, apThis, arData);
if (result && arData.ShouldSync())
World::Get().GetRunner().Trigger(addTargetEvent);
return result;
}
if (arData.pCaster)
{
ActorExtension* pCasterExtension = arData.pCaster->GetExtension();
if (pCasterExtension->IsLocalPlayer())
{
bool result = TiltedPhoques::ThisCall(RealAddTarget, apThis, arData);
if (result && arData.ShouldSync())
World::Get().GetRunner().Trigger(addTargetEvent);
return result;
}
else if (pCasterExtension->IsRemotePlayer())
{
// Send out a HitEvent because TakeDamage is never triggered.
World::Get().GetRunner().Trigger(HitEvent(arData.pCaster->formID, pTargetActor->formID));
return false;
}
}
if (pTargetActorEx->IsLocal())
{
bool result = TiltedPhoques::ThisCall(RealAddTarget, apThis, arData);
if (result && arData.ShouldSync())
World::Get().GetRunner().Trigger(addTargetEvent);
return result;
}
else
{
return false;
}
}
bool TP_MAKE_THISCALL(HookCheckAddEffectTargetData, MagicTarget::AddTargetData, void* arArgs, float afResistance)
{
if (s_autoSucceedEffectCheck)
return true;
return TiltedPhoques::ThisCall(RealCheckAddEffectTargetData, apThis, arArgs, afResistance);
}
bool TP_MAKE_THISCALL(HookFindTargets, MagicCaster, float afEffectivenessMult, int32_t* aruiTargetCount, TESBoundObject* apSource, char abLoadCast, char abAdjust)
{
return TiltedPhoques::ThisCall(RealFindTargets, apThis, afEffectivenessMult, aruiTargetCount, apSource, abLoadCast, abAdjust);
}
void TP_MAKE_THISCALL(HookAdjustForPerks, ActiveEffect, Actor* apCaster, MagicTarget* apTarget)
{
TiltedPhoques::ThisCall(RealAdjustForPerks, apThis, apCaster, apTarget);
if (s_applyHealPerkBonus)
apThis->fMagnitude *= 1.5f;
}
bool TP_MAKE_THISCALL(HookHasPerk, Actor, TESForm* apPerk, void* apUnk1, double* afReturnValue)
{
ActorExtension* pExtension = apThis ? apThis->GetExtension() : nullptr;
if (pExtension && pExtension->IsRemotePlayer())
{
if (apPerk && apPerk->formID == 0x581f9)
{
if (s_applyStaminaPerkBonus)
{
if (afReturnValue)
*afReturnValue = 1.f;
return true;
}
}
}
return TiltedPhoques::ThisCall(RealHasPerk, apThis, apPerk, apUnk1, afReturnValue);
}
uint8_t TP_MAKE_THISCALL(HookGetPerkRank, Actor, TESForm* apPerk)
{
return TiltedPhoques::ThisCall(RealGetPerkRank, apThis, apPerk);
}
static TiltedPhoques::Initializer s_magicTargetHooks([]() {
POINTER_SKYRIMSE(TAddTarget, addTarget, 34526);
POINTER_SKYRIMSE(TCheckAddEffectTargetData, checkAddEffectTargetData, 34525);
POINTER_SKYRIMSE(TFindTargets, findTargets, 34410);
POINTER_SKYRIMSE(TAdjustForPerks, adjustForPerks, 34053);
POINTER_SKYRIMSE(THasPerk, hasPerk, 21622);
POINTER_SKYRIMSE(TGetPerkRank, getPerkRank, 37698);
RealAddTarget = addTarget.Get();
RealCheckAddEffectTargetData = checkAddEffectTargetData.Get();
RealFindTargets = findTargets.Get();
RealAdjustForPerks = adjustForPerks.Get();
RealHasPerk = hasPerk.Get();
RealGetPerkRank = getPerkRank.Get();
TP_HOOK(&RealAddTarget, HookAddTarget);
TP_HOOK(&RealCheckAddEffectTargetData, HookCheckAddEffectTargetData);
TP_HOOK(&RealFindTargets, HookFindTargets);
TP_HOOK(&RealAdjustForPerks, HookAdjustForPerks);
TP_HOOK(&RealHasPerk, HookHasPerk);
//TP_HOOK(&RealGetPerkRank, HookGetPerkRank);
});