#include "Projectile.h" #include #include #include #include #include #include #include #include #include TP_THIS_FUNCTION(TLaunch, BSPointerHandle*, BSPointerHandle, Projectile::LaunchData& arData); static TLaunch* RealLaunch = nullptr; BSPointerHandle* Projectile::Launch(BSPointerHandle* apResult, LaunchData& apLaunchData) noexcept { BSPointerHandle* 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(pObject); TP_ASSERT(pProjectile, "No projectile found."); if (!pProjectile) { spdlog::error("No projectile found."); return nullptr; } pProjectile->fPower = apLaunchData.fPower; return result; } BSPointerHandle* TP_MAKE_THISCALL(HookLaunch, BSPointerHandle, Projectile::LaunchData& arData) { // sync concentration spells through spell cast sync, the rest through projectile sync if (arData.pSpell) { if (auto* pSpell = Cast(arData.pSpell)) { if (pSpell->eCastingType == MagicSystem::CastingType::CONCENTRATION) { return TiltedPhoques::ThisCall(RealLaunch, apThis, arData); } } } if (arData.pShooter) { Actor* pActor = Cast(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(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 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()); });