Make Bullet projectile extensible
This commit is contained in:
@@ -134,14 +134,14 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
[Desc("The alpha value [from 0 to 255] of color at the contrail end.")]
|
||||
public readonly int ContrailEndColorAlpha = 0;
|
||||
|
||||
public IProjectile Create(ProjectileArgs args) { return new Bullet(this, args); }
|
||||
public virtual IProjectile Create(ProjectileArgs args) { return new Bullet(this, args); }
|
||||
}
|
||||
|
||||
public class Bullet : IProjectile, ISync
|
||||
{
|
||||
readonly BulletInfo info;
|
||||
readonly ProjectileArgs args;
|
||||
readonly Animation anim;
|
||||
protected readonly ProjectileArgs Args;
|
||||
protected readonly Animation Animation;
|
||||
readonly WAngle facing;
|
||||
readonly WAngle angle;
|
||||
readonly WDist speed;
|
||||
@@ -153,16 +153,18 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
readonly ContrailRenderable contrail;
|
||||
|
||||
[Sync]
|
||||
WPos pos, lastPos, target, source;
|
||||
protected WPos pos, lastPos, target, source;
|
||||
|
||||
int length;
|
||||
int ticks, smokeTicks;
|
||||
int remainingBounces;
|
||||
|
||||
protected bool FlightLengthReached => ticks >= length;
|
||||
|
||||
public Bullet(BulletInfo info, ProjectileArgs args)
|
||||
{
|
||||
this.info = info;
|
||||
this.args = args;
|
||||
Args = args;
|
||||
pos = args.Source;
|
||||
source = args.Source;
|
||||
|
||||
@@ -193,8 +195,8 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
|
||||
if (!string.IsNullOrEmpty(info.Image))
|
||||
{
|
||||
anim = new Animation(world, info.Image, new Func<WAngle>(GetEffectiveFacing));
|
||||
anim.PlayRepeating(info.Sequences.Random(world.SharedRandom));
|
||||
Animation = new Animation(world, info.Image, new Func<WAngle>(GetEffectiveFacing));
|
||||
Animation.PlayRepeating(info.Sequences.Random(world.SharedRandom));
|
||||
}
|
||||
|
||||
if (info.ContrailLength > 0)
|
||||
@@ -230,21 +232,26 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
return new WAngle(effective);
|
||||
}
|
||||
|
||||
public void Tick(World world)
|
||||
public virtual void Tick(World world)
|
||||
{
|
||||
anim?.Tick();
|
||||
Animation?.Tick();
|
||||
|
||||
lastPos = pos;
|
||||
pos = WPos.LerpQuadratic(source, target, angle, ticks, length);
|
||||
|
||||
if (ShouldExplode(world))
|
||||
{
|
||||
if (info.ContrailLength > 0)
|
||||
world.AddFrameEndTask(w => w.Add(new ContrailFader(pos, contrail)));
|
||||
|
||||
Explode(world);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldExplode(World world)
|
||||
{
|
||||
// Check for walls or other blocking obstacles
|
||||
if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, args.SourceActor.Owner, lastPos, pos, info.Width, out var blockedPos))
|
||||
if (info.Blockable && BlocksProjectiles.AnyBlockingActorsBetween(world, Args.SourceActor.Owner, lastPos, pos, info.Width, out var blockedPos))
|
||||
{
|
||||
pos = blockedPos;
|
||||
return true;
|
||||
@@ -274,7 +281,7 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
if (info.InvalidBounceTerrain.Contains(world.Map.GetTerrainInfo(cell).Type))
|
||||
return true;
|
||||
|
||||
if (AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true))
|
||||
if (AnyValidTargetsInRadius(world, pos, info.Width, Args.SourceActor, true))
|
||||
return true;
|
||||
|
||||
target += (pos - source) * info.BounceRangeModifier / 100;
|
||||
@@ -297,26 +304,35 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
return true;
|
||||
|
||||
// After first bounce, check for targets each tick
|
||||
if (remainingBounces < info.BounceCount && AnyValidTargetsInRadius(world, pos, info.Width, args.SourceActor, true))
|
||||
if (remainingBounces < info.BounceCount && AnyValidTargetsInRadius(world, pos, info.Width, Args.SourceActor, true))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
public virtual IEnumerable<IRenderable> Render(WorldRenderer wr)
|
||||
{
|
||||
if (info.ContrailLength > 0)
|
||||
yield return contrail;
|
||||
|
||||
if (anim == null || ticks >= length)
|
||||
if (FlightLengthReached)
|
||||
yield break;
|
||||
|
||||
var world = args.SourceActor.World;
|
||||
foreach (var r in RenderAnimation(wr))
|
||||
yield return r;
|
||||
}
|
||||
|
||||
protected IEnumerable<IRenderable> RenderAnimation(WorldRenderer wr)
|
||||
{
|
||||
if (Animation == null)
|
||||
yield break;
|
||||
|
||||
var world = Args.SourceActor.World;
|
||||
if (!world.FogObscures(pos))
|
||||
{
|
||||
var paletteName = info.Palette;
|
||||
if (paletteName != null && info.IsPlayerPalette)
|
||||
paletteName += args.SourceActor.Owner.InternalName;
|
||||
paletteName += Args.SourceActor.Owner.InternalName;
|
||||
|
||||
var palette = wr.Palette(paletteName);
|
||||
|
||||
@@ -324,31 +340,28 @@ namespace OpenRA.Mods.Common.Projectiles
|
||||
{
|
||||
var dat = world.Map.DistanceAboveTerrain(pos);
|
||||
var shadowPos = pos - new WVec(0, 0, dat.Length);
|
||||
foreach (var r in anim.Render(shadowPos, palette))
|
||||
foreach (var r in Animation.Render(shadowPos, palette))
|
||||
yield return ((IModifyableRenderable)r)
|
||||
.WithTint(shadowColor, ((IModifyableRenderable)r).TintModifiers | TintModifiers.ReplaceColor)
|
||||
.WithAlpha(shadowAlpha);
|
||||
}
|
||||
|
||||
foreach (var r in anim.Render(pos, palette))
|
||||
foreach (var r in Animation.Render(pos, palette))
|
||||
yield return r;
|
||||
}
|
||||
}
|
||||
|
||||
void Explode(World world)
|
||||
protected virtual void Explode(World world)
|
||||
{
|
||||
if (info.ContrailLength > 0)
|
||||
world.AddFrameEndTask(w => w.Add(new ContrailFader(pos, contrail)));
|
||||
|
||||
world.AddFrameEndTask(w => w.Remove(this));
|
||||
|
||||
var warheadArgs = new WarheadArgs(args)
|
||||
var warheadArgs = new WarheadArgs(Args)
|
||||
{
|
||||
ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(lastPos, pos), args.Facing),
|
||||
ImpactOrientation = new WRot(WAngle.Zero, Util.GetVerticalAngle(lastPos, pos), Args.Facing),
|
||||
ImpactPosition = pos,
|
||||
};
|
||||
|
||||
args.Weapon.Impact(Target.FromPos(pos), warheadArgs);
|
||||
Args.Weapon.Impact(Target.FromPos(pos), warheadArgs);
|
||||
}
|
||||
|
||||
bool AnyValidTargetsInRadius(World world, WPos pos, WDist radius, Actor firedBy, bool checkTargetType)
|
||||
|
||||
Reference in New Issue
Block a user