Description
Long-range cone-type projectiles (BGSProjectile type 16 / "Cone") fired by the player in third person do not fly toward the crosshair. They launch with the character's body pitch instead of the camera/aim pitch, so they typically hit above the aim point, with the error growing with distance. In first person, or with TDM removed, the same spells aim correctly.
Vanilla barely exposes this because vanilla player-castable cone projectiles are short-range sprays (Flames ~600 units). But several spell mods use long-range cone projectiles specifically because cones penetrate actors, e.g.:
- Astral Magic 2 - the Astral Spear line (
_A_AstralSpearProj1/2/3, cone, speed 6000, range 90000, cone spread 0.01)
- Piercing Expert Spells - all its projectiles (cone, range 10000-12000)
With TDM installed these spells are only usable at close range in third person.
Root cause (from reading master)
The engine computes launch direction for player-fired arrow/missile/beam projectiles from the camera/crosshair, so they are unaffected by TDM's camera/character pitch decoupling. Cone projectiles instead launch using the caster's aim/body pitch.
In vanilla third person with a weapon drawn, character pitch is coupled to camera pitch, so the two sources agree. TDM's free camera stores pitch in thirdPersonState->freeRotation.y and leaves the character's data.angle.x unsynced, and:
DirectionalMovementHandler::UpdateFacingCrosshair() transfers only yaw (freeRotation.x) into _desiredAngle when casting - pitch is never synced to the character.
ProjectileHook::ProjectileAimSupport() only handles FormType::ProjectileArrow and FormType::ProjectileMissile (default case = kFreeAim), and the GetLinearVelocity hooks are installed on the Projectile, ArrowProjectile, MissileProjectile vtables only - ConeProjectile overrides are never touched. Func183 covers beams. So cones get no correction under target lock either.
UpdateRotationLockedCam() early-outs when _bIsAiming is true, so while actually casting under target lock the body is not pitched toward the target, and (2) means nothing corrects the projectile afterwards.
Suggested fix
Either (or both):
- Free aim: on cone projectile launch (e.g. the same
InitProjectile call-site hook, or a write_vfunc on RE::VTABLE_ConeProjectile[0]), when the shooter is the player and the camera is third person, re-aim the projectile along the camera-crosshair raycast - the exact math already exists in ProjectileHook::InitProjectile for the mounted-aiming path (project camera→player onto the view ray, raycast, recompute data.angle + node rotation + linearVelocity).
- Target lock: add
case RE::FormType::ProjectileCone: (mapping to Settings::uTargetLockMissileAimType) in ProjectileAimSupport's switch and install the GetLinearVelocity hook on RE::VTABLE_ConeProjectile[0] as well. The velocity-redirect logic should work for cones as-is since it just rewrites linearVelocity and the projectile's angles.
Reproduction
- Install Astral Magic 2 (or any spell using a long-range cone projectile) + TDM.
- In third person, free aim or target lock an enemy ~2000+ units away on flat ground and cast Astral Spear at the reticle.
- The projectile passes visibly above the reticle/target; switching to first person and repeating hits the reticle.
Observed on TDM 2.2.5 in-game (Skyrim SE 1.6.1170); the code references above are from current master (2.2.7), where the relevant logic is unchanged, confirmed not reproducible with TDM's requirements alone (Address Library etc.), appears with TDM alone added.
Description
Long-range cone-type projectiles (
BGSProjectiletype 16 / "Cone") fired by the player in third person do not fly toward the crosshair. They launch with the character's body pitch instead of the camera/aim pitch, so they typically hit above the aim point, with the error growing with distance. In first person, or with TDM removed, the same spells aim correctly.Vanilla barely exposes this because vanilla player-castable cone projectiles are short-range sprays (Flames ~600 units). But several spell mods use long-range cone projectiles specifically because cones penetrate actors, e.g.:
_A_AstralSpearProj1/2/3, cone, speed 6000, range 90000, cone spread 0.01)With TDM installed these spells are only usable at close range in third person.
Root cause (from reading master)
The engine computes launch direction for player-fired arrow/missile/beam projectiles from the camera/crosshair, so they are unaffected by TDM's camera/character pitch decoupling. Cone projectiles instead launch using the caster's aim/body pitch.
In vanilla third person with a weapon drawn, character pitch is coupled to camera pitch, so the two sources agree. TDM's free camera stores pitch in
thirdPersonState->freeRotation.yand leaves the character'sdata.angle.xunsynced, and:DirectionalMovementHandler::UpdateFacingCrosshair()transfers only yaw (freeRotation.x) into_desiredAnglewhen casting - pitch is never synced to the character.ProjectileHook::ProjectileAimSupport()only handlesFormType::ProjectileArrowandFormType::ProjectileMissile(default case =kFreeAim), and theGetLinearVelocityhooks are installed on theProjectile,ArrowProjectile,MissileProjectilevtables only -ConeProjectileoverrides are never touched.Func183covers beams. So cones get no correction under target lock either.UpdateRotationLockedCam()early-outs when_bIsAimingis true, so while actually casting under target lock the body is not pitched toward the target, and (2) means nothing corrects the projectile afterwards.Suggested fix
Either (or both):
InitProjectilecall-site hook, or awrite_vfunconRE::VTABLE_ConeProjectile[0]), when the shooter is the player and the camera is third person, re-aim the projectile along the camera-crosshair raycast - the exact math already exists inProjectileHook::InitProjectilefor the mounted-aiming path (project camera→player onto the view ray, raycast, recomputedata.angle+ node rotation +linearVelocity).case RE::FormType::ProjectileCone:(mapping toSettings::uTargetLockMissileAimType) inProjectileAimSupport's switch and install theGetLinearVelocityhook onRE::VTABLE_ConeProjectile[0]as well. The velocity-redirect logic should work for cones as-is since it just rewriteslinearVelocityand the projectile's angles.Reproduction
Observed on TDM 2.2.5 in-game (Skyrim SE 1.6.1170); the code references above are from current master (2.2.7), where the relevant logic is unchanged, confirmed not reproducible with TDM's requirements alone (Address Library etc.), appears with TDM alone added.