Merge pull request #6471 from reaperrr/missile-lockon

Added functionality and descriptions to Missile projectile
This commit is contained in:
Chris Forbes
2014-09-18 09:12:21 +12:00
3 changed files with 31 additions and 19 deletions

View File

@@ -70,8 +70,8 @@ namespace OpenRA.Mods.RA.Effects
if (info.Angle.Length > 1 && info.Speed.Length > 1) if (info.Angle.Length > 1 && info.Speed.Length > 1)
{ {
angle = new WAngle(args.SourceActor.World.SharedRandom.Next(info.Angle[0].Angle, info.Angle[1].Angle)); angle = new WAngle(world.SharedRandom.Next(info.Angle[0].Angle, info.Angle[1].Angle));
speed = new WRange(args.SourceActor.World.SharedRandom.Next(info.Speed[0].Range, info.Speed[1].Range)); speed = new WRange(world.SharedRandom.Next(info.Speed[0].Range, info.Speed[1].Range));
} }
else else
{ {
@@ -86,7 +86,7 @@ namespace OpenRA.Mods.RA.Effects
.Select(m => m.GetInaccuracyModifier()); .Select(m => m.GetInaccuracyModifier());
var inaccuracy = Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Range, modifiers); var inaccuracy = Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Range, modifiers);
var maxOffset = inaccuracy * (target - pos).Length / args.Weapon.Range.Range; var maxOffset = inaccuracy * (target - pos).Length / args.Weapon.Range.Range;
target += WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * maxOffset / 1024; target += WVec.FromPDF(world.SharedRandom, 2) * maxOffset / 1024;
} }
facing = Traits.Util.GetFacing(target - pos, 0); facing = Traits.Util.GetFacing(target - pos, 0);
@@ -101,7 +101,7 @@ namespace OpenRA.Mods.RA.Effects
if (info.ContrailLength > 0) if (info.ContrailLength > 0)
{ {
var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor; var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
trail = new ContrailRenderable(args.SourceActor.World, color, info.ContrailLength, info.ContrailDelay, 0); trail = new ContrailRenderable(world, color, info.ContrailLength, info.ContrailDelay, 0);
} }
smokeTicks = info.TrailDelay; smokeTicks = info.TrailDelay;

View File

@@ -23,7 +23,9 @@ namespace OpenRA.Mods.RA.Effects
{ {
[Desc("Projectile speed in WRange / tick")] [Desc("Projectile speed in WRange / tick")]
public readonly WRange Speed = new WRange(8); public readonly WRange Speed = new WRange(8);
[Desc("Maximum vertical pitch when changing altitude.")]
public readonly WAngle MaximumPitch = WAngle.FromDegrees(30); public readonly WAngle MaximumPitch = WAngle.FromDegrees(30);
[Desc("How many ticks before this missile is armed and can explode.")]
public readonly int Arm = 0; public readonly int Arm = 0;
[Desc("Check for whether an actor with BlocksBullets: trait blocks fire")] [Desc("Check for whether an actor with BlocksBullets: trait blocks fire")]
public readonly bool High = false; public readonly bool High = false;
@@ -31,11 +33,14 @@ namespace OpenRA.Mods.RA.Effects
public readonly string Trail = null; public readonly string Trail = null;
[Desc("Maximum offset at the maximum range")] [Desc("Maximum offset at the maximum range")]
public readonly WRange Inaccuracy = WRange.Zero; public readonly WRange Inaccuracy = WRange.Zero;
[Desc("Probability of locking onto and following target.")]
public readonly int LockOnProbability = 100;
public readonly string Image = null; public readonly string Image = null;
[Desc("Rate of Turning")] [Desc("Rate of Turning")]
public readonly int ROT = 5; public readonly int ROT = 5;
[Desc("Explode when following the target longer than this.")] [Desc("Explode when following the target longer than this.")]
public readonly int RangeLimit = 0; public readonly int RangeLimit = 0;
[Desc("If fired at aircraft, increase speed by 50%.")]
public readonly bool TurboBoost = false; public readonly bool TurboBoost = false;
public readonly int TrailInterval = 2; public readonly int TrailInterval = 2;
public readonly int ContrailLength = 0; public readonly int ContrailLength = 0;
@@ -45,18 +50,16 @@ namespace OpenRA.Mods.RA.Effects
public readonly bool Jammable = true; public readonly bool Jammable = true;
[Desc("Explodes when leaving the following terrain type, e.g., Water for torpedoes.")] [Desc("Explodes when leaving the following terrain type, e.g., Water for torpedoes.")]
public readonly string BoundToTerrainType = ""; public readonly string BoundToTerrainType = "";
[Desc("Explodes when inside this proximity radius to target.",
"Note: If this value is lower than the missile speed, this check might",
"not trigger fast enough, causing the missile to fly past the target.")]
public readonly WRange CloseEnough = new WRange(298);
public IEffect Create(ProjectileArgs args) { return new Missile(this, args); } public IEffect Create(ProjectileArgs args) { return new Missile(this, args); }
} }
class Missile : IEffect, ISync class Missile : IEffect, ISync
{ {
// HACK: the missile movement code isn't smart enough to explode
// when the projectile passes the actor. This defines an arbitrary
// proximity radius that they will explode within, which makes
// missiles difficult to consistently balance.
static readonly WRange MissileCloseEnough = new WRange(298);
readonly MissileInfo info; readonly MissileInfo info;
readonly ProjectileArgs args; readonly ProjectileArgs args;
readonly Animation anim; readonly Animation anim;
@@ -71,6 +74,8 @@ namespace OpenRA.Mods.RA.Effects
[Sync] WVec offset; [Sync] WVec offset;
[Sync] int ticks; [Sync] int ticks;
[Sync] bool lockOn = false;
[Sync] public Actor SourceActor { get { return args.SourceActor; } } [Sync] public Actor SourceActor { get { return args.SourceActor; } }
[Sync] public Target GuidedTarget { get { return args.GuidedTarget; } } [Sync] public Target GuidedTarget { get { return args.GuidedTarget; } }
@@ -84,24 +89,29 @@ namespace OpenRA.Mods.RA.Effects
targetPosition = args.PassiveTarget; targetPosition = args.PassiveTarget;
var world = args.SourceActor.World;
if (world.SharedRandom.Next(100) <= info.LockOnProbability)
lockOn = true;
if (info.Inaccuracy.Range > 0) if (info.Inaccuracy.Range > 0)
{ {
var modifiers = args.SourceActor.TraitsImplementing<IInaccuracyModifier>() var modifiers = args.SourceActor.TraitsImplementing<IInaccuracyModifier>()
.Select(m => m.GetInaccuracyModifier()); .Select(m => m.GetInaccuracyModifier());
var inaccuracy = Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Range, modifiers); var inaccuracy = Traits.Util.ApplyPercentageModifiers(info.Inaccuracy.Range, modifiers);
offset = WVec.FromPDF(args.SourceActor.World.SharedRandom, 2) * inaccuracy / 1024; offset = WVec.FromPDF(world.SharedRandom, 2) * inaccuracy / 1024;
} }
if (info.Image != null) if (info.Image != null)
{ {
anim = new Animation(args.SourceActor.World, info.Image, () => facing); anim = new Animation(world, info.Image, () => facing);
anim.PlayRepeating("idle"); anim.PlayRepeating("idle");
} }
if (info.ContrailLength > 0) if (info.ContrailLength > 0)
{ {
var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor; var color = info.ContrailUsePlayerColor ? ContrailRenderable.ChooseColor(args.SourceActor) : info.ContrailColor;
trail = new ContrailRenderable(args.SourceActor.World, color, info.ContrailLength, info.ContrailDelay, 0); trail = new ContrailRenderable(world, color, info.ContrailLength, info.ContrailDelay, 0);
} }
} }
@@ -122,7 +132,7 @@ namespace OpenRA.Mods.RA.Effects
anim.Tick(); anim.Tick();
// Missile tracks target // Missile tracks target
if (args.GuidedTarget.IsValidFor(args.SourceActor)) if (args.GuidedTarget.IsValidFor(args.SourceActor) && lockOn)
targetPosition = args.GuidedTarget.CenterPosition; targetPosition = args.GuidedTarget.CenterPosition;
var dist = targetPosition + offset - pos; var dist = targetPosition + offset - pos;
@@ -164,7 +174,7 @@ namespace OpenRA.Mods.RA.Effects
var cell = world.Map.CellContaining(pos); var cell = world.Map.CellContaining(pos);
var shouldExplode = (pos.Z < 0) // Hit the ground var shouldExplode = (pos.Z < 0) // Hit the ground
|| (dist.LengthSquared < MissileCloseEnough.Range * MissileCloseEnough.Range) // Within range || (dist.LengthSquared < info.CloseEnough.Range * info.CloseEnough.Range) // Within range
|| (info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel || (info.RangeLimit != 0 && ticks > info.RangeLimit) // Ran out of fuel
|| (!info.High && world.ActorMap.GetUnitsAt(cell).Any(a => a.HasTrait<IBlocksBullets>())) // Hit a wall || (!info.High && world.ActorMap.GetUnitsAt(cell).Any(a => a.HasTrait<IBlocksBullets>())) // Hit a wall
|| !world.Map.Contains(cell) // This also avoids an IndexOutOfRangeException in GetTerrainInfo below. || !world.Map.Contains(cell) // This also avoids an IndexOutOfRangeException in GetTerrainInfo below.

View File

@@ -88,16 +88,18 @@ Bazooka:
Palette: ra Palette: ra
Projectile: Missile Projectile: Missile
Speed: 213 Speed: 213
Arm: 2 Arm: 3
High: yes High: true
Shadow: true Shadow: true
Inaccuracy: 128 Inaccuracy: 128
Image: DRAGON Image: DRAGON
ROT: 8 ROT: 8
RangeLimit: 35 RangeLimit: 50
CloseEnough: 256
LockOnProbability: 80
Warhead@1Dam: SpreadDamage Warhead@1Dam: SpreadDamage
Spread: 128 Spread: 128
Damage: 25 Damage: 35
DeathType: 2 DeathType: 2
ValidTargets: Ground, Air ValidTargets: Ground, Air
Versus: Versus: