F4MP/codigos originales/tiltedcode/Code/client/Games/Skyrim/Projectiles/Projectile.cpp

155 lines
4.7 KiB
C++
Raw Normal View History

#include "Projectile.h"
#include <Games/Skyrim/Forms/TESObjectWEAP.h>
#include <Games/Skyrim/Forms/MagicItem.h>
#include <Games/Skyrim/Forms/TESAmmo.h>
#include <Actor.h>
#include <Games/ActorExtension.h>
#include <World.h>
#include <Events/ProjectileLaunchedEvent.h>
#include <Games/Skyrim/Forms/TESObjectCELL.h>
#include <Forms/SpellItem.h>
TP_THIS_FUNCTION(TLaunch, BSPointerHandle<Projectile>*, BSPointerHandle<Projectile>, Projectile::LaunchData& arData);
static TLaunch* RealLaunch = nullptr;
BSPointerHandle<Projectile>* Projectile::Launch(BSPointerHandle<Projectile>* apResult, LaunchData& apLaunchData) noexcept
{
BSPointerHandle<Projectile>* result = TiltedPhoques::ThisCall(RealLaunch, apResult, apLaunchData);
TP_ASSERT(result, "No projectile handle returned.");
if (!result)
{
spdlog::error("No projectile handle returned.");
return nullptr;
}
TESObjectREFR* pObject = TESObjectREFR::GetByHandle(result->handle.iBits);
Projectile* pProjectile = Cast<Projectile>(pObject);
TP_ASSERT(pProjectile, "No projectile found.");
if (!pProjectile)
{
spdlog::error("No projectile found.");
return nullptr;
}
pProjectile->fPower = apLaunchData.fPower;
return result;
}
BSPointerHandle<Projectile>* TP_MAKE_THISCALL(HookLaunch, BSPointerHandle<Projectile>, Projectile::LaunchData& arData)
{
// sync concentration spells through spell cast sync, the rest through projectile sync
if (arData.pSpell)
{
if (auto* pSpell = Cast<SpellItem>(arData.pSpell))
{
if (pSpell->eCastingType == MagicSystem::CastingType::CONCENTRATION)
{
return TiltedPhoques::ThisCall(RealLaunch, apThis, arData);
}
}
}
if (arData.pShooter)
{
Actor* pActor = Cast<Actor>(arData.pShooter);
if (pActor)
{
ActorExtension* pExtendedActor = pActor->GetExtension();
if (pExtendedActor->IsRemote())
{
apThis->handle.iBits = 0;
return apThis;
}
}
}
ProjectileLaunchedEvent Event{};
Event.Origin = arData.Origin;
if (arData.pProjectileBase)
Event.ProjectileBaseID = arData.pProjectileBase->formID;
if (arData.pShooter)
Event.ShooterID = arData.pShooter->formID;
if (arData.pFromWeapon)
Event.WeaponID = arData.pFromWeapon->formID;
if (arData.pFromAmmo)
Event.AmmoID = arData.pFromAmmo->formID;
Event.ZAngle = arData.fZAngle;
Event.XAngle = arData.fXAngle;
Event.YAngle = arData.fYAngle;
if (arData.pParentCell)
Event.ParentCellID = arData.pParentCell->formID;
if (arData.pSpell)
Event.SpellID = arData.pSpell->formID;
Event.CastingSource = arData.eCastingSource;
Event.UnkBool1 = arData.bUnkBool1;
Event.Area = arData.iArea;
Event.Power = arData.fPower;
Event.Scale = arData.fScale;
Event.AlwaysHit = arData.bAlwaysHit;
Event.NoDamageOutsideCombat = arData.bNoDamageOutsideCombat;
Event.AutoAim = arData.bAutoAim;
Event.UnkBool2 = arData.bUnkBool2;
Event.DeferInitialization = arData.bDeferInitialization;
Event.ForceConeOfFire = arData.bForceConeOfFire;
auto result = TiltedPhoques::ThisCall(RealLaunch, apThis, arData);
TP_ASSERT(result, "No projectile handle returned.");
TESObjectREFR* pObject = TESObjectREFR::GetByHandle(result->handle.iBits);
Projectile* pProjectile = Cast<Projectile>(pObject);
TP_ASSERT(pProjectile, "No projectile found.");
Event.Power = pProjectile->fPower;
World::Get().GetRunner().Trigger(Event);
return result;
}
static TiltedPhoques::Initializer s_projectileHooks(
[]()
{
POINTER_SKYRIMSE(TLaunch, s_launch, 44108);
RealLaunch = s_launch.Get();
TP_HOOK(&RealLaunch, HookLaunch);
VersionDbPtr<uint8_t> hookLoc(34452);
struct C : TiltedPhoques::CodeGenerator
{
C(uint8_t* apLoc)
{
// replicate
mov(rbx, ptr[rsp + 0x50]);
// nullptr check
cmp(rbx, 0);
jz("exit");
// jump back
jmp_S(apLoc + 0x379);
L("exit");
// return false; scratch space from the registers
mov(al, 0);
add(rsp, 0x138);
pop(r15);
pop(r14);
pop(r13);
pop(r12);
pop(rdi);
pop(rsi);
pop(rbx);
pop(rbp);
ret();
}
} gen(hookLoc.Get());
TiltedPhoques::Jump(hookLoc.Get() + 0x374, gen.getCode());
});