Adds LockOnProbability to missiles.
Turns CloseEnough from a hack into a feature. Adds some descriptions. Caches args.SourceActor.World.
This commit is contained in:
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user