Make Bullet projectile extensible

This commit is contained in:
michaeldgg2
2023-06-23 18:52:59 +02:00
committed by Gustas
parent e1940eec77
commit a14cc8cc4d

View File

@@ -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)