diff --git a/OpenRa.DataStructures/float2.cs b/OpenRa.DataStructures/float2.cs index 7377c9ea59..b905791e59 100644 --- a/OpenRa.DataStructures/float2.cs +++ b/OpenRa.DataStructures/float2.cs @@ -25,7 +25,7 @@ namespace OpenRa public static float2 operator -(float2 a) { return new float2(-a.X, -a.Y); } - static float Lerp(float a, float b, float t) { return a + t * (b - a); } + public static float Lerp(float a, float b, float t) { return a + t * (b - a); } public static float2 Lerp(float2 a, float2 b, float t) { diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index f440962df6..ff765c9edb 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -88,6 +88,7 @@ namespace OpenRa.Game var underCursor = Game.UnitInfluence.GetUnitAt( xy ) ?? Game.BuildingInfluence.GetBuildingAt( xy ); + if (underCursor != null && !underCursor.Info.Selectable) underCursor = null; diff --git a/OpenRa.Game/Effects/Bullet.cs b/OpenRa.Game/Effects/Bullet.cs index 3f47590d5e..1243626f63 100644 --- a/OpenRa.Game/Effects/Bullet.cs +++ b/OpenRa.Game/Effects/Bullet.cs @@ -15,6 +15,8 @@ namespace OpenRa.Game.Effects readonly int2 Src; readonly int2 Dest; readonly int2 VisualDest; + readonly int SrcAltitude; + readonly int DestAltitude; int t = 0; Animation anim; @@ -23,7 +25,7 @@ namespace OpenRa.Game.Effects /* src, dest are *pixel* coords */ public Bullet(string weapon, Player owner, Actor firedBy, - int2 src, int2 dest) + int2 src, int2 dest, int srcAltitude, int destAltitude) { Owner = owner; FiredBy = firedBy; @@ -55,7 +57,8 @@ namespace OpenRa.Game.Effects if (t > TotalTime()) /* remove finished bullets */ { Game.world.AddFrameEndTask(w => w.Remove(this)); - Combat.DoImpact(Dest, VisualDest, Weapon, Projectile, Warhead, FiredBy); + Combat.DoImpact(Dest, VisualDest - new int2( 0, DestAltitude ), + Weapon, Projectile, Warhead, FiredBy); } } @@ -65,17 +68,17 @@ namespace OpenRa.Game.Effects { if (anim != null) { - var pos = float2.Lerp( - Src.ToFloat2(), - VisualDest.ToFloat2(), - (float)t / TotalTime()) - 0.5f * anim.Image.size; + var at = (float)t / TotalTime(); + + var altitude = float2.Lerp(SrcAltitude, DestAltitude, at); + var pos = float2.Lerp( Src.ToFloat2(), VisualDest.ToFloat2(), at) + - 0.5f * anim.Image.size - new float2( 0, altitude ); if (Projectile.High || Projectile.Arcing) { if (Projectile.Shadow) yield return new Renderable(anim.Image, pos, 8); - var at = (float)t / TotalTime(); var highPos = pos - new float2(0, (VisualDest - Src).Length * height * 4 * at * (1 - at)); yield return new Renderable(anim.Image, highPos, Owner.Palette); diff --git a/OpenRa.Game/Effects/Missile.cs b/OpenRa.Game/Effects/Missile.cs index f1e1fc2267..ee5d2ce88a 100644 --- a/OpenRa.Game/Effects/Missile.cs +++ b/OpenRa.Game/Effects/Missile.cs @@ -2,6 +2,7 @@ using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; using OpenRa.Game.Traits; +using System; namespace OpenRa.Game.Effects { @@ -17,9 +18,10 @@ namespace OpenRa.Game.Effects readonly Animation anim; int Facing; int t; + int Altitude; public Missile(string weapon, Player owner, Actor firedBy, - int2 src, Actor target) + int2 src, Actor target, int altitude) { Weapon = Rules.WeaponInfo[weapon]; Projectile = Rules.ProjectileInfo[Weapon.Projectile]; @@ -28,6 +30,7 @@ namespace OpenRa.Game.Effects Owner = owner; Target = target; Pos = src.ToFloat2(); + Altitude = altitude; /* todo: initial facing should be turret facing, or unit facing if we're not turreted */ Facing = Traits.Util.GetFacing( Target.CenterLocation - src.ToFloat2(), 0 ); @@ -50,6 +53,10 @@ namespace OpenRa.Game.Effects { t += 40; + var targetUnit = Target.traits.GetOrDefault(); + var targetAltitude = targetUnit != null ? targetUnit.Altitude : 0; + Altitude += Math.Sign(targetAltitude - Altitude); + Traits.Util.TickFacing(ref Facing, Traits.Util.GetFacing(Target.CenterLocation - Pos, Facing), Projectile.ROT); @@ -70,7 +77,7 @@ namespace OpenRa.Game.Effects Pos += move; if (Projectile.Animates) - Game.world.AddFrameEndTask(w => w.Add(new Smoke((Pos - 1.5f * move).ToInt2()))); + Game.world.AddFrameEndTask(w => w.Add(new Smoke((Pos - 1.5f * move - new int2( 0, Altitude )).ToInt2()))); // todo: running out of fuel // todo: turbo boost vs aircraft @@ -78,7 +85,7 @@ namespace OpenRa.Game.Effects public IEnumerable Render() { - yield return new Renderable(anim.Image, Pos - 0.5f * anim.Image.size, 0); + yield return new Renderable(anim.Image, Pos - 0.5f * anim.Image.size - new float2(0, Altitude), 0); } } } diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index bc1bd8a468..6fa6741559 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -224,7 +224,7 @@ namespace OpenRa.Game Rules.TileSet.GetWalkability(Rules.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; } - static IEnumerable FindUnits(float2 a, float2 b) + public static IEnumerable FindUnits(float2 a, float2 b) { var min = float2.Min(a, b); var max = float2.Max(a, b); diff --git a/OpenRa.Game/Traits/AttackBase.cs b/OpenRa.Game/Traits/AttackBase.cs index f558267770..44b0763a5c 100644 --- a/OpenRa.Game/Traits/AttackBase.cs +++ b/OpenRa.Game/Traits/AttackBase.cs @@ -105,19 +105,23 @@ namespace OpenRa.Game.Traits } var firePos = self.CenterLocation.ToInt2() + Util.GetTurretPosition(self, unit, offset, 0f).ToInt2(); - var thisTarget = target; + var thisTarget = target; // closure. + var destUnit = thisTarget.traits.GetOrDefault(); ScheduleDelayedAction(self.Info.FireDelay, () => { + var srcAltitude = unit != null ? unit.Altitude : 0; + var destAltitude = destUnit != null ? destUnit.Altitude : 0; + if( weapon.RenderAsTesla ) Game.world.Add( new TeslaZap( firePos, thisTarget.CenterLocation.ToInt2() ) ); if( Rules.ProjectileInfo[ weapon.Projectile ].ROT != 0 ) Game.world.Add(new Missile(weaponName, self.Owner, self, - firePos, thisTarget)); + firePos, thisTarget, srcAltitude)); else Game.world.Add(new Bullet(weaponName, self.Owner, self, - firePos, thisTarget.CenterLocation.ToInt2())); + firePos, thisTarget.CenterLocation.ToInt2(), srcAltitude, destAltitude)); if (!string.IsNullOrEmpty(weapon.Report)) Sound.Play(weapon.Report + ".aud"); diff --git a/OpenRa.Game/Traits/Explodes.cs b/OpenRa.Game/Traits/Explodes.cs index 7392d08712..f19726d48d 100644 --- a/OpenRa.Game/Traits/Explodes.cs +++ b/OpenRa.Game/Traits/Explodes.cs @@ -14,9 +14,13 @@ namespace OpenRa.Game.Traits { if (self.IsDead) { + var unit = self.traits.GetOrDefault(); + var altitude = unit != null ? unit.Altitude : 0; + Game.world.AddFrameEndTask( w => w.Add(new Bullet("UnitExplode", e.Attacker.Owner, e.Attacker, - self.CenterLocation.ToInt2(), self.CenterLocation.ToInt2()))); + self.CenterLocation.ToInt2(), self.CenterLocation.ToInt2(), + altitude, altitude))); } } } diff --git a/units.ini b/units.ini index a799760dae..7eb75c5745 100755 --- a/units.ini +++ b/units.ini @@ -238,7 +238,7 @@ InitialFacing=50 LongDesc=Anti-Armor base defense.\n Strong vs Tanks\n Weak vs Infantry, Aircraft [AGUN] Description=AA Gun -Traits=Building, Turreted, RenderBuildingTurreted +Traits=Building, Turreted, RenderBuildingTurreted, AttackTurreted, AutoTarget Dimensions=1,2 Footprint=_ x SelectionPriority=3 @@ -260,7 +260,7 @@ SelectionPriority=3 LongDesc=Regenerates the Fog of War nearby, \nobscuring the area.\n Unarmed [SAM] Description=SAM Site -Traits=Building, Turreted, RenderBuildingTurreted +Traits=Building, Turreted, RenderBuildingTurreted, AttackTurreted, AutoTarget Dimensions=2,1 Footprint=xx SelectionPriority=3