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