diff --git a/OpenRA.Game/GameRules/WeaponInfo.cs b/OpenRA.Game/GameRules/WeaponInfo.cs index 49ad380049..f2f67e79cc 100644 --- a/OpenRA.Game/GameRules/WeaponInfo.cs +++ b/OpenRA.Game/GameRules/WeaponInfo.cs @@ -38,6 +38,8 @@ namespace OpenRA.GameRules public WeaponInfo Weapon; public int[] DamageModifiers = { }; public WPos? Source; + public WRot ImpactOrientation; + public WPos ImpactPosition; public Actor SourceActor; public Target WeaponTarget; @@ -45,6 +47,7 @@ namespace OpenRA.GameRules { Weapon = args.Weapon; DamageModifiers = args.DamageModifiers; + ImpactPosition = args.PassiveTarget; Source = args.Source; SourceActor = args.SourceActor; WeaponTarget = args.GuidedTarget; diff --git a/OpenRA.Mods.Common/Projectiles/AreaBeam.cs b/OpenRA.Mods.Common/Projectiles/AreaBeam.cs index 1cb2084f2f..728286ffc5 100644 --- a/OpenRA.Mods.Common/Projectiles/AreaBeam.cs +++ b/OpenRA.Mods.Common/Projectiles/AreaBeam.cs @@ -237,6 +237,12 @@ namespace OpenRA.Mods.Common.Projectiles var warheadArgs = new WarheadArgs(args) { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target), args.CurrentMuzzleFacing()), + + // Calculating an impact position is bogus for line damage. + // FindActorsOnLine guarantees that the beam touches the target's HitShape, + // so we just assume a center hit to avoid bogus warhead recalculations. + ImpactPosition = a.CenterPosition, DamageModifiers = adjustedModifiers.ToArray(), }; diff --git a/OpenRA.Mods.Common/Projectiles/Bullet.cs b/OpenRA.Mods.Common/Projectiles/Bullet.cs index 29fc755d7f..0470215d8e 100644 --- a/OpenRA.Mods.Common/Projectiles/Bullet.cs +++ b/OpenRA.Mods.Common/Projectiles/Bullet.cs @@ -122,7 +122,7 @@ namespace OpenRA.Mods.Common.Projectiles ContrailRenderable contrail; [Sync] - WPos pos, target, source; + WPos pos, lastPos, target, source; int length; int ticks, smokeTicks; @@ -200,7 +200,7 @@ namespace OpenRA.Mods.Common.Projectiles if (anim != null) anim.Tick(); - var lastPos = pos; + lastPos = pos; pos = WPos.LerpQuadratic(source, target, angle, ticks, length); // Check for walls or other blocking obstacles @@ -287,7 +287,13 @@ namespace OpenRA.Mods.Common.Projectiles world.AddFrameEndTask(w => w.Remove(this)); - args.Weapon.Impact(Target.FromPos(pos), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(lastPos, pos), args.Facing), + ImpactPosition = pos, + }; + + args.Weapon.Impact(Target.FromPos(pos), warheadArgs); } bool AnyValidTargetsInRadius(World world, WPos pos, WDist radius, Actor firedBy, bool checkTargetType) diff --git a/OpenRA.Mods.Common/Projectiles/GravityBomb.cs b/OpenRA.Mods.Common/Projectiles/GravityBomb.cs index 9deb1b905f..d18a694e4e 100644 --- a/OpenRA.Mods.Common/Projectiles/GravityBomb.cs +++ b/OpenRA.Mods.Common/Projectiles/GravityBomb.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using OpenRA.GameRules; using OpenRA.Graphics; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Projectiles @@ -58,7 +59,7 @@ namespace OpenRA.Mods.Common.Projectiles WVec velocity; [Sync] - WPos pos; + WPos pos, lastPos; public GravityBomb(GravityBombInfo info, ProjectileArgs args) { @@ -82,6 +83,7 @@ namespace OpenRA.Mods.Common.Projectiles public void Tick(World world) { + lastPos = pos; pos += velocity; velocity += acceleration; @@ -90,7 +92,13 @@ namespace OpenRA.Mods.Common.Projectiles pos += new WVec(0, 0, args.PassiveTarget.Z - pos.Z); world.AddFrameEndTask(w => w.Remove(this)); - args.Weapon.Impact(Target.FromPos(pos), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(lastPos, pos), args.Facing), + ImpactPosition = pos, + }; + + args.Weapon.Impact(Target.FromPos(pos), warheadArgs); } if (anim != null) diff --git a/OpenRA.Mods.Common/Projectiles/InstantHit.cs b/OpenRA.Mods.Common/Projectiles/InstantHit.cs index 7624ef6522..a9b9651c70 100644 --- a/OpenRA.Mods.Common/Projectiles/InstantHit.cs +++ b/OpenRA.Mods.Common/Projectiles/InstantHit.cs @@ -81,7 +81,13 @@ namespace OpenRA.Mods.Common.Projectiles target = Target.FromPos(blockedPos); } - args.Weapon.Impact(target, new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target.CenterPosition), args.Facing), + ImpactPosition = target.CenterPosition, + }; + + args.Weapon.Impact(target, warheadArgs); world.AddFrameEndTask(w => w.Remove(this)); } diff --git a/OpenRA.Mods.Common/Projectiles/LaserZap.cs b/OpenRA.Mods.Common/Projectiles/LaserZap.cs index 09c12589e1..f199ea215d 100644 --- a/OpenRA.Mods.Common/Projectiles/LaserZap.cs +++ b/OpenRA.Mods.Common/Projectiles/LaserZap.cs @@ -168,7 +168,13 @@ namespace OpenRA.Mods.Common.Projectiles if (ticks < info.DamageDuration && --interval <= 0) { - args.Weapon.Impact(Target.FromPos(target), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(source, target), args.CurrentMuzzleFacing()), + ImpactPosition = target, + }; + + args.Weapon.Impact(Target.FromPos(target), warheadArgs); interval = info.DamageInterval; } diff --git a/OpenRA.Mods.Common/Projectiles/Missile.cs b/OpenRA.Mods.Common/Projectiles/Missile.cs index b7f2be2a8d..8346cedb25 100644 --- a/OpenRA.Mods.Common/Projectiles/Missile.cs +++ b/OpenRA.Mods.Common/Projectiles/Missile.cs @@ -895,7 +895,13 @@ namespace OpenRA.Mods.Common.Projectiles if (ticks <= info.Arm) return; - args.Weapon.Impact(Target.FromPos(pos), new WarheadArgs(args)); + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, WAngle.FromFacing(vFacing), WAngle.FromFacing(hFacing)), + ImpactPosition = pos, + }; + + args.Weapon.Impact(Target.FromPos(pos), warheadArgs); } public IEnumerable Render(WorldRenderer wr) diff --git a/OpenRA.Mods.Common/Projectiles/Railgun.cs b/OpenRA.Mods.Common/Projectiles/Railgun.cs index f8bb6e8fa1..1c95e3615f 100644 --- a/OpenRA.Mods.Common/Projectiles/Railgun.cs +++ b/OpenRA.Mods.Common/Projectiles/Railgun.cs @@ -199,12 +199,32 @@ namespace OpenRA.Mods.Common.Projectiles animationComplete = true; if (!info.DamageActorsInLine) - args.Weapon.Impact(Target.FromPos(target), new WarheadArgs(args)); + { + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target), args.Facing), + ImpactPosition = target, + }; + + args.Weapon.Impact(Target.FromPos(target), warheadArgs); + } else { var actors = world.FindActorsOnLine(args.Source, target, info.BeamWidth); foreach (var a in actors) - args.Weapon.Impact(Target.FromActor(a), new WarheadArgs(args)); + { + var warheadArgs = new WarheadArgs(args) + { + ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(args.Source, target), args.Facing), + + // Calculating an impact position is bogus for line damage. + // FindActorsOnLine guarantees that the beam touches the target's HitShape, + // so we just assume a center hit to avoid bogus warhead recalculations. + ImpactPosition = a.CenterPosition, + }; + + args.Weapon.Impact(Target.FromActor(a), warheadArgs); + } } } diff --git a/OpenRA.Mods.Common/Util.cs b/OpenRA.Mods.Common/Util.cs index 1acb1d2f9f..2a130fd589 100644 --- a/OpenRA.Mods.Common/Util.cs +++ b/OpenRA.Mods.Common/Util.cs @@ -108,6 +108,15 @@ namespace OpenRA.Mods.Common return WPos.Lerp(fromPos, toPos, 1, 2); } + public static WAngle GetVerticalAngle(WPos source, WPos target) + { + var delta = target - source; + var horizontalDelta = delta.HorizontalLength; + var verticalVector = new WVec(-delta.Z, -horizontalDelta, 0); + + return verticalVector.Yaw; + } + public static IEnumerable Shuffle(this IEnumerable ts, MersenneTwister random) { // Fisher-Yates