Replace INotifyBuildComplete in render traits with conditions.

This commit is contained in:
Paul Chote
2018-10-05 20:16:36 +00:00
committed by abcdefg30
parent 26b0a06a17
commit 14607f55c5
28 changed files with 152 additions and 407 deletions

View File

@@ -17,38 +17,40 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits.Render namespace OpenRA.Mods.Cnc.Traits.Render
{ {
[Desc("Building animation to play when ProductionAirdrop is used to deliver units.")] [Desc("Building animation to play when ProductionAirdrop is used to deliver units.")]
public class WithDeliveryAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo> public class WithDeliveryAnimationInfo : ConditionalTraitInfo, Requires<WithSpriteBodyInfo>
{ {
[SequenceReference] public readonly string ActiveSequence = "active"; [SequenceReference] public readonly string ActiveSequence = "active";
[SequenceReference] public readonly string IdleSequence = "idle";
[Desc("Which sprite body to play the animation on.")] [Desc("Which sprite body to play the animation on.")]
public readonly string Body = "body"; public readonly string Body = "body";
public object Create(ActorInitializer init) { return new WithDeliveryAnimation(init.Self, this); } public override object Create(ActorInitializer init) { return new WithDeliveryAnimation(init.Self, this); }
} }
public class WithDeliveryAnimation : INotifyDelivery public class WithDeliveryAnimation : ConditionalTrait<WithDeliveryAnimationInfo>, INotifyDelivery
{ {
readonly WithDeliveryAnimationInfo info;
readonly WithSpriteBody wsb; readonly WithSpriteBody wsb;
public WithDeliveryAnimation(Actor self, WithDeliveryAnimationInfo info) public WithDeliveryAnimation(Actor self, WithDeliveryAnimationInfo info)
: base(info)
{ {
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
this.info = info;
} }
public void IncomingDelivery(Actor self) public void IncomingDelivery(Actor self)
{ {
wsb.PlayCustomAnimationRepeating(self, info.ActiveSequence); if (!IsTraitDisabled)
wsb.PlayCustomAnimationRepeating(self, Info.ActiveSequence);
} }
public void Delivered(Actor self) public void Delivered(Actor self)
{ {
wsb.PlayCustomAnimationRepeating(self, info.IdleSequence); wsb.CancelCustomAnimation(self);
}
protected override void TraitDisabled(Actor self)
{
wsb.CancelCustomAnimation(self);
} }
} }
} }

View File

@@ -17,7 +17,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits.Render namespace OpenRA.Mods.Cnc.Traits.Render
{ {
[Desc("Rendered on the refinery when a voxel harvester is docking and undocking.")] [Desc("Rendered on the refinery when a voxel harvester is docking and undocking.")]
public class WithDockingOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo> public class WithDockingOverlayInfo : PausableConditionalTraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "unload-overlay"; [SequenceReference] public readonly string Sequence = "unload-overlay";
@@ -31,29 +31,27 @@ namespace OpenRA.Mods.Cnc.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithDockingOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithDockingOverlay(init.Self, this); }
} }
public class WithDockingOverlay public class WithDockingOverlay : PausableConditionalTrait<WithDockingOverlayInfo>
{ {
public readonly WithDockingOverlayInfo Info;
public readonly AnimationWithOffset WithOffset; public readonly AnimationWithOffset WithOffset;
public bool Visible; public bool Visible;
public WithDockingOverlay(Actor self, WithDockingOverlayInfo info) public WithDockingOverlay(Actor self, WithDockingOverlayInfo info)
: base(info)
{ {
Info = info;
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
var overlay = new Animation(self.World, rs.GetImage(self)); var overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused);
overlay.Play(info.Sequence); overlay.Play(info.Sequence);
WithOffset = new AnimationWithOffset(overlay, WithOffset = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !Visible); () => !Visible || IsTraitDisabled);
rs.Add(WithOffset, info.Palette, info.IsPlayerPalette); rs.Add(WithOffset, info.Palette, info.IsPlayerPalette);
} }

View File

@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Replaces the building animation when it accepts a cash delivery unit.")] [Desc("Replaces the building animation when it accepts a cash delivery unit.")]
public class WithAcceptDeliveredCashAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo> public class WithAcceptDeliveredCashAnimationInfo : ConditionalTraitInfo, Requires<WithSpriteBodyInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "active"; [SequenceReference] public readonly string Sequence = "active";
@@ -23,41 +23,27 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Which sprite body to play the animation on.")] [Desc("Which sprite body to play the animation on.")]
public readonly string Body = "body"; public readonly string Body = "body";
public object Create(ActorInitializer init) { return new WithAcceptDeliveredCashAnimation(init.Self, this); } public override object Create(ActorInitializer init) { return new WithAcceptDeliveredCashAnimation(init.Self, this); }
} }
public class WithAcceptDeliveredCashAnimation : INotifyCashTransfer, INotifyBuildComplete, INotifySold public class WithAcceptDeliveredCashAnimation : ConditionalTrait<WithAcceptDeliveredCashAnimationInfo>, INotifyCashTransfer
{ {
readonly WithAcceptDeliveredCashAnimationInfo info;
readonly WithSpriteBody wsb; readonly WithSpriteBody wsb;
bool buildComplete;
public WithAcceptDeliveredCashAnimation(Actor self, WithAcceptDeliveredCashAnimationInfo info) public WithAcceptDeliveredCashAnimation(Actor self, WithAcceptDeliveredCashAnimationInfo info)
: base(info)
{ {
this.info = info;
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifySold.Sold(Actor self) { }
bool playing; bool playing;
void INotifyCashTransfer.OnAcceptingCash(Actor self, Actor donor) void INotifyCashTransfer.OnAcceptingCash(Actor self, Actor donor)
{ {
if (!buildComplete || playing) if (IsTraitDisabled || playing)
return; return;
playing = true; playing = true;
wsb.PlayCustomAnimation(self, info.Sequence, () => playing = false); wsb.PlayCustomAnimation(self, Info.Sequence, () => playing = false);
} }
void INotifyCashTransfer.OnDeliveringCash(Actor self, Actor acceptor) { } void INotifyCashTransfer.OnDeliveringCash(Actor self, Actor acceptor) { }

View File

@@ -68,8 +68,10 @@ namespace OpenRA.Mods.Common.Traits.Render
bridgeLayer = init.World.WorldActor.Trait<BridgeLayer>(); bridgeLayer = init.World.WorldActor.Trait<BridgeLayer>();
} }
protected override void OnBuildComplete(Actor self) protected override void TraitEnabled(Actor self)
{ {
base.TraitEnabled(self);
if (bridgeInfo.AOffset != CVec.Zero) if (bridgeInfo.AOffset != CVec.Zero)
UpdateNeighbour(bridgeInfo.AOffset); UpdateNeighbour(bridgeInfo.AOffset);

View File

@@ -26,41 +26,25 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithBuildingPlacedAnimation(init.Self, this); } public override object Create(ActorInitializer init) { return new WithBuildingPlacedAnimation(init.Self, this); }
} }
public class WithBuildingPlacedAnimation : ConditionalTrait<WithBuildingPlacedAnimationInfo>, INotifyBuildingPlaced, INotifyBuildComplete, INotifySold, INotifyTransform public class WithBuildingPlacedAnimation : ConditionalTrait<WithBuildingPlacedAnimationInfo>, INotifyBuildingPlaced
{ {
readonly WithSpriteBody wsb; readonly WithSpriteBody wsb;
bool buildComplete;
public WithBuildingPlacedAnimation(Actor self, WithBuildingPlacedAnimationInfo info) public WithBuildingPlacedAnimation(Actor self, WithBuildingPlacedAnimationInfo info)
: base(info) : base(info)
{ {
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>();
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifyTransform.BeforeTransform(Actor self)
{
buildComplete = false;
}
void INotifyTransform.OnTransform(Actor self) { }
void INotifyTransform.AfterTransform(Actor self) { }
void INotifyBuildingPlaced.BuildingPlaced(Actor self) void INotifyBuildingPlaced.BuildingPlaced(Actor self)
{ {
if (!IsTraitDisabled && buildComplete) if (!IsTraitDisabled)
wsb.PlayCustomAnimation(self, Info.Sequence); wsb.PlayCustomAnimation(self, Info.Sequence);
} }
protected override void TraitDisabled(Actor self)
{
wsb.CancelCustomAnimation(self);
}
} }
} }

View File

@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Rendered when the actor constructed a building.")] [Desc("Rendered when the actor constructed a building.")]
public class WithBuildingPlacedOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo> public class WithBuildingPlacedOverlayInfo : ConditionalTraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "crane-overlay"; [SequenceReference] public readonly string Sequence = "crane-overlay";
@@ -29,52 +29,30 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithBuildingPlacedOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithBuildingPlacedOverlay(init.Self, this); }
} }
public class WithBuildingPlacedOverlay : INotifyBuildComplete, INotifySold, INotifyDamageStateChanged, INotifyBuildingPlaced, INotifyTransform public class WithBuildingPlacedOverlay : ConditionalTrait<WithBuildingPlacedOverlayInfo>, INotifyDamageStateChanged, INotifyBuildingPlaced
{ {
readonly Animation overlay; readonly Animation overlay;
bool buildComplete;
bool visible; bool visible;
public WithBuildingPlacedOverlay(Actor self, WithBuildingPlacedOverlayInfo info) public WithBuildingPlacedOverlay(Actor self, WithBuildingPlacedOverlayInfo info)
: base(info)
{ {
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
overlay = new Animation(self.World, rs.GetImage(self)); overlay = new Animation(self.World, rs.GetImage(self));
var anim = new AnimationWithOffset(overlay, var anim = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !visible || !buildComplete); () => !visible || IsTraitDisabled);
overlay.PlayThen(info.Sequence, () => visible = false); overlay.PlayThen(info.Sequence, () => visible = false);
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
visible = false;
}
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifyTransform.BeforeTransform(Actor self)
{
buildComplete = false;
}
void INotifyTransform.OnTransform(Actor self) { }
void INotifyTransform.AfterTransform(Actor self) { }
void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)
{ {
overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name)); overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name));

View File

@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Render trait that varies the animation frame based on the AttackCharges trait's charge level.")] [Desc("Render trait that varies the animation frame based on the AttackCharges trait's charge level.")]
class WithChargeAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo>, Requires<AttackChargesInfo> class WithChargeAnimationInfo : ConditionalTraitInfo, Requires<WithSpriteBodyInfo>, Requires<AttackChargesInfo>
{ {
[SequenceReference] [SequenceReference]
[Desc("Sequence to use for the charge levels.")] [Desc("Sequence to use for the charge levels.")]
@@ -24,26 +24,25 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Which sprite body to play the animation on.")] [Desc("Which sprite body to play the animation on.")]
public readonly string Body = "body"; public readonly string Body = "body";
public object Create(ActorInitializer init) { return new WithChargeAnimation(init.Self, this); } public override object Create(ActorInitializer init) { return new WithChargeAnimation(init.Self, this); }
} }
class WithChargeAnimation : INotifyBuildComplete class WithChargeAnimation : ConditionalTrait<WithChargeAnimationInfo>
{ {
readonly WithChargeAnimationInfo info;
readonly WithSpriteBody wsb; readonly WithSpriteBody wsb;
readonly AttackCharges attackCharges; readonly AttackCharges attackCharges;
public WithChargeAnimation(Actor self, WithChargeAnimationInfo info) public WithChargeAnimation(Actor self, WithChargeAnimationInfo info)
: base(info)
{ {
this.info = info;
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
attackCharges = self.Trait<AttackCharges>(); attackCharges = self.Trait<AttackCharges>();
} }
void INotifyBuildComplete.BuildingComplete(Actor self) protected override void TraitEnabled(Actor self)
{ {
var attackChargesInfo = (AttackChargesInfo)attackCharges.Info; var attackChargesInfo = (AttackChargesInfo)attackCharges.Info;
wsb.DefaultAnimation.PlayFetchIndex(wsb.NormalizeSequence(self, info.Sequence), wsb.DefaultAnimation.PlayFetchIndex(wsb.NormalizeSequence(self, Info.Sequence),
() => int2.Lerp(0, wsb.DefaultAnimation.CurrentSequence.Length, attackCharges.ChargeLevel, attackChargesInfo.ChargeLevel + 1)); () => int2.Lerp(0, wsb.DefaultAnimation.CurrentSequence.Length, attackCharges.ChargeLevel, attackChargesInfo.ChargeLevel + 1));
} }
} }

View File

@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Render overlay that varies the animation frame based on the AttackCharges trait's charge level.")] [Desc("Render overlay that varies the animation frame based on the AttackCharges trait's charge level.")]
class WithChargeOverlayInfo : ITraitInfo, Requires<WithSpriteBodyInfo>, Requires<RenderSpritesInfo> class WithChargeOverlayInfo : PausableConditionalTraitInfo, Requires<WithSpriteBodyInfo>, Requires<RenderSpritesInfo>
{ {
[SequenceReference] [SequenceReference]
[Desc("Sequence to use for the charge levels.")] [Desc("Sequence to use for the charge levels.")]
@@ -27,46 +27,33 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithChargeOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithChargeOverlay(init.Self, this); }
} }
class WithChargeOverlay : INotifyBuildComplete, INotifySold, INotifyDamageStateChanged class WithChargeOverlay : PausableConditionalTrait<WithChargeOverlayInfo>, INotifyDamageStateChanged
{ {
readonly WithChargeOverlayInfo info;
readonly Animation overlay; readonly Animation overlay;
readonly RenderSprites rs;
readonly WithSpriteBody wsb;
bool buildComplete;
public WithChargeOverlay(Actor self, WithChargeOverlayInfo info) public WithChargeOverlay(Actor self, WithChargeOverlayInfo info)
: base(info)
{ {
this.info = info; var rs = self.Trait<RenderSprites>();
rs = self.Trait<RenderSprites>(); var wsb = self.Trait<WithSpriteBody>();
wsb = self.Trait<WithSpriteBody>();
var attackCharges = self.Trait<AttackCharges>(); var attackCharges = self.Trait<AttackCharges>();
var attackChargesInfo = (AttackChargesInfo)attackCharges.Info; var attackChargesInfo = (AttackChargesInfo)attackCharges.Info;
overlay = new Animation(self.World, rs.GetImage(self)); overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused);
overlay.PlayFetchIndex(wsb.NormalizeSequence(self, info.Sequence), overlay.PlayFetchIndex(wsb.NormalizeSequence(self, info.Sequence),
() => int2.Lerp(0, overlay.CurrentSequence.Length, attackCharges.ChargeLevel, attackChargesInfo.ChargeLevel + 1)); () => int2.Lerp(0, overlay.CurrentSequence.Length, attackCharges.ChargeLevel, attackChargesInfo.ChargeLevel + 1));
rs.Add(new AnimationWithOffset(overlay, null, () => !buildComplete, 1024), rs.Add(new AnimationWithOffset(overlay, null, () => IsTraitDisabled, 1024),
info.Palette, info.IsPlayerPalette); info.Palette, info.IsPlayerPalette);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)
{ {
overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, info.Sequence)); overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, Info.Sequence));
} }
void INotifySold.Selling(Actor self) { buildComplete = false; }
void INotifySold.Sold(Actor self) { }
} }
} }

View File

@@ -81,8 +81,10 @@ namespace OpenRA.Mods.Common.Traits.Render
return bridgeInfo.RampActors.Contains(neighbour.Info.Name); return bridgeInfo.RampActors.Contains(neighbour.Info.Name);
} }
protected override void OnBuildComplete(Actor self) protected override void TraitEnabled(Actor self)
{ {
base.TraitEnabled(self);
self.World.AddFrameEndTask(w => self.World.AddFrameEndTask(w =>
{ {
var aRamp = bridgeInfo.AOffset != CVec.Zero && RampExists(self, bridgeInfo.AOffset); var aRamp = bridgeInfo.AOffset != CVec.Zero && RampExists(self, bridgeInfo.AOffset);

View File

@@ -16,7 +16,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Rendered when a harvester is docked.")] [Desc("Rendered when a harvester is docked.")]
public class WithDockedOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo> public class WithDockedOverlayInfo : PausableConditionalTraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "docking-overlay"; [SequenceReference] public readonly string Sequence = "docking-overlay";
@@ -30,31 +30,26 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithDockedOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithDockedOverlay(init.Self, this); }
} }
public class WithDockedOverlay : INotifyDocking, INotifyBuildComplete, INotifySold public class WithDockedOverlay : PausableConditionalTrait<WithDockedOverlayInfo>, INotifyDocking
{ {
readonly WithDockedOverlayInfo info;
readonly AnimationWithOffset anim; readonly AnimationWithOffset anim;
bool buildComplete;
bool docked; bool docked;
public WithDockedOverlay(Actor self, WithDockedOverlayInfo info) public WithDockedOverlay(Actor self, WithDockedOverlayInfo info)
: base(info)
{ {
this.info = info;
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units var overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused);
var overlay = new Animation(self.World, rs.GetImage(self));
overlay.Play(info.Sequence); overlay.Play(info.Sequence);
anim = new AnimationWithOffset(overlay, anim = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !buildComplete || !docked); () => IsTraitDisabled || !docked);
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
@@ -62,18 +57,7 @@ namespace OpenRA.Mods.Common.Traits.Render
void PlayDockingOverlay() void PlayDockingOverlay()
{ {
if (docked) if (docked)
anim.Animation.PlayThen(info.Sequence, PlayDockingOverlay); anim.Animation.PlayThen(Info.Sequence, PlayDockingOverlay);
}
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
} }
void INotifyDocking.Docked(Actor self, Actor harvester) { docked = true; PlayDockingOverlay(); } void INotifyDocking.Docked(Actor self, Actor harvester) { docked = true; PlayDockingOverlay(); }

View File

@@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Traits.Render
void UpdateState(Actor self) void UpdateState(Actor self)
{ {
if (renderOpen) if (renderOpen || IsTraitPaused)
DefaultAnimation.PlayRepeating(NormalizeSequence(self, gateBodyInfo.OpenSequence)); DefaultAnimation.PlayRepeating(NormalizeSequence(self, gateBodyInfo.OpenSequence));
else else
DefaultAnimation.PlayFetchIndex(NormalizeSequence(self, Info.Sequence), GetGateFrame); DefaultAnimation.PlayFetchIndex(NormalizeSequence(self, Info.Sequence), GetGateFrame);
@@ -91,8 +91,10 @@ namespace OpenRA.Mods.Common.Traits.Render
UpdateState(self); UpdateState(self);
} }
protected override void OnBuildComplete(Actor self) protected override void TraitEnabled(Actor self)
{ {
base.TraitEnabled(self);
UpdateState(self); UpdateState(self);
UpdateNeighbours(self); UpdateNeighbours(self);
} }

View File

@@ -28,23 +28,21 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithIdleAnimation(init.Self, this); } public override object Create(ActorInitializer init) { return new WithIdleAnimation(init.Self, this); }
} }
public class WithIdleAnimation : ConditionalTrait<WithIdleAnimationInfo>, ITick, INotifyBuildComplete, INotifySold public class WithIdleAnimation : ConditionalTrait<WithIdleAnimationInfo>, ITick
{ {
readonly WithSpriteBody wsb; readonly WithSpriteBody wsb;
bool buildComplete;
int ticks; int ticks;
public WithIdleAnimation(Actor self, WithIdleAnimationInfo info) public WithIdleAnimation(Actor self, WithIdleAnimationInfo info)
: base(info) : base(info)
{ {
wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == Info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == Info.Body);
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
ticks = info.Interval; ticks = info.Interval;
} }
void ITick.Tick(Actor self) void ITick.Tick(Actor self)
{ {
if (!buildComplete || IsTraitDisabled) if (IsTraitDisabled)
return; return;
if (--ticks <= 0) if (--ticks <= 0)
@@ -54,16 +52,9 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
} }
void INotifyBuildComplete.BuildingComplete(Actor self) protected override void TraitDisabled(Actor self)
{ {
buildComplete = true; wsb.CancelCustomAnimation(self);
} }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifySold.Sold(Actor self) { }
} }
} }

View File

@@ -35,9 +35,6 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
// TODO: Remove this when the buildComplete code is replaced with conditions.
public readonly bool RenderBeforeBuildComplete = false;
public override object Create(ActorInitializer init) { return new WithIdleOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithIdleOverlay(init.Self, this); }
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
@@ -73,10 +70,9 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
} }
public class WithIdleOverlay : PausableConditionalTrait<WithIdleOverlayInfo>, INotifyDamageStateChanged, INotifyBuildComplete, INotifySold, INotifyTransform public class WithIdleOverlay : PausableConditionalTrait<WithIdleOverlayInfo>, INotifyDamageStateChanged
{ {
readonly Animation overlay; readonly Animation overlay;
bool buildComplete;
public WithIdleOverlay(Actor self, WithIdleOverlayInfo info) public WithIdleOverlay(Actor self, WithIdleOverlayInfo info)
: base(info) : base(info)
@@ -84,8 +80,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused);
overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused || (!info.RenderBeforeBuildComplete && !buildComplete));
if (info.StartSequence != null) if (info.StartSequence != null)
overlay.PlayThen(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.StartSequence), overlay.PlayThen(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.StartSequence),
() => overlay.PlayRepeating(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.Sequence))); () => overlay.PlayRepeating(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.Sequence)));
@@ -94,31 +89,12 @@ namespace OpenRA.Mods.Common.Traits.Render
var anim = new AnimationWithOffset(overlay, var anim = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => IsTraitDisabled || (!info.RenderBeforeBuildComplete && !buildComplete), () => IsTraitDisabled,
p => RenderUtils.ZOffsetFromCenter(self, p, 1)); p => RenderUtils.ZOffsetFromCenter(self, p, 1));
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifyTransform.BeforeTransform(Actor self)
{
buildComplete = false;
}
void INotifyTransform.OnTransform(Actor self) { }
void INotifyTransform.AfterTransform(Actor self) { }
void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)
{ {
overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name)); overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name));

View File

@@ -26,33 +26,25 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithNukeLaunchAnimation(init.Self, this); } public override object Create(ActorInitializer init) { return new WithNukeLaunchAnimation(init.Self, this); }
} }
public class WithNukeLaunchAnimation : ConditionalTrait<WithNukeLaunchAnimationInfo>, INotifyNuke, INotifyBuildComplete, INotifySold public class WithNukeLaunchAnimation : ConditionalTrait<WithNukeLaunchAnimationInfo>, INotifyNuke
{ {
readonly WithSpriteBody spriteBody; readonly WithSpriteBody wsb;
bool buildComplete;
public WithNukeLaunchAnimation(Actor self, WithNukeLaunchAnimationInfo info) public WithNukeLaunchAnimation(Actor self, WithNukeLaunchAnimationInfo info)
: base(info) : base(info)
{ {
spriteBody = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == Info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == Info.Body);
} }
void INotifyNuke.Launching(Actor self) void INotifyNuke.Launching(Actor self)
{ {
if (buildComplete && !IsTraitDisabled) if (!IsTraitDisabled)
spriteBody.PlayCustomAnimation(self, Info.Sequence, () => spriteBody.CancelCustomAnimation(self)); wsb.PlayCustomAnimation(self, Info.Sequence, () => wsb.CancelCustomAnimation(self));
} }
void INotifyBuildComplete.BuildingComplete(Actor self) protected override void TraitDisabled(Actor self)
{ {
buildComplete = true; wsb.CancelCustomAnimation(self);
} }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifySold.Sold(Actor self) { }
} }
} }

View File

@@ -33,10 +33,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithNukeLaunchOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithNukeLaunchOverlay(init.Self, this); }
} }
public class WithNukeLaunchOverlay : ConditionalTrait<WithNukeLaunchOverlayInfo>, INotifyBuildComplete, INotifySold, INotifyNuke public class WithNukeLaunchOverlay : ConditionalTrait<WithNukeLaunchOverlayInfo>, INotifyNuke
{ {
readonly Animation overlay; readonly Animation overlay;
bool buildComplete;
bool visible; bool visible;
public WithNukeLaunchOverlay(Actor self, WithNukeLaunchOverlayInfo info) public WithNukeLaunchOverlay(Actor self, WithNukeLaunchOverlayInfo info)
@@ -45,29 +44,17 @@ namespace OpenRA.Mods.Common.Traits.Render
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
overlay = new Animation(self.World, rs.GetImage(self)); overlay = new Animation(self.World, rs.GetImage(self));
overlay.PlayThen(info.Sequence, () => visible = false); overlay.PlayThen(info.Sequence, () => visible = false);
var anim = new AnimationWithOffset(overlay, var anim = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => IsTraitDisabled || !visible || !buildComplete, () => IsTraitDisabled || !visible,
p => RenderUtils.ZOffsetFromCenter(self, p, 1)); p => RenderUtils.ZOffsetFromCenter(self, p, 1));
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifyNuke.Launching(Actor self) void INotifyNuke.Launching(Actor self)
{ {
visible = true; visible = true;

View File

@@ -18,12 +18,10 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Play an animation when a unit exits or blocks the exit after production finished.")] [Desc("Play an animation when a unit exits or blocks the exit after production finished.")]
class WithProductionDoorOverlayInfo : ITraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>, Requires<BuildingInfo> class WithProductionDoorOverlayInfo : ConditionalTraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>, Requires<BuildingInfo>
{ {
public readonly string Sequence = "build-door"; public readonly string Sequence = "build-door";
public object Create(ActorInitializer init) { return new WithProductionDoorOverlay(init.Self, this); }
public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)
{ {
var anim = new Animation(init.World, image, () => 0); var anim = new Animation(init.World, image, () => 0);
@@ -33,18 +31,18 @@ namespace OpenRA.Mods.Common.Traits.Render
var offset = bi.CenterOffset(init.World).Y + 512; // Additional 512 units move from center -> top of cell var offset = bi.CenterOffset(init.World).Y + 512; // Additional 512 units move from center -> top of cell
yield return new SpriteActorPreview(anim, () => WVec.Zero, () => offset, p, rs.Scale); yield return new SpriteActorPreview(anim, () => WVec.Zero, () => offset, p, rs.Scale);
} }
public override object Create(ActorInitializer init) { return new WithProductionDoorOverlay(init.Self, this); }
} }
class WithProductionDoorOverlay : INotifyBuildComplete, ITick, INotifyProduction, INotifySold, INotifyTransform, INotifyDamageStateChanged class WithProductionDoorOverlay : ConditionalTrait<WithProductionDoorOverlayInfo>, ITick, INotifyProduction, INotifyDamageStateChanged
{ {
readonly Animation door; readonly Animation door;
int desiredFrame; int desiredFrame;
CPos openExit; CPos openExit;
bool buildComplete;
public WithProductionDoorOverlay(Actor self, WithProductionDoorOverlayInfo info) public WithProductionDoorOverlay(Actor self, WithProductionDoorOverlayInfo info)
: base(info)
{ {
var renderSprites = self.Trait<RenderSprites>(); var renderSprites = self.Trait<RenderSprites>();
door = new Animation(self.World, renderSprites.GetImage(self)); door = new Animation(self.World, renderSprites.GetImage(self));
@@ -54,12 +52,7 @@ namespace OpenRA.Mods.Common.Traits.Render
var buildingInfo = self.Info.TraitInfo<BuildingInfo>(); var buildingInfo = self.Info.TraitInfo<BuildingInfo>();
var offset = buildingInfo.CenterOffset(self.World).Y + 512; var offset = buildingInfo.CenterOffset(self.World).Y + 512;
renderSprites.Add(new AnimationWithOffset(door, null, () => !buildComplete, offset)); renderSprites.Add(new AnimationWithOffset(door, null, () => IsTraitDisabled, offset));
}
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
} }
void ITick.Tick(Actor self) void ITick.Tick(Actor self)
@@ -79,12 +72,5 @@ namespace OpenRA.Mods.Common.Traits.Render
openExit = exit; openExit = exit;
desiredFrame = door.CurrentSequence.Length - 1; desiredFrame = door.CurrentSequence.Length - 1;
} }
void INotifySold.Selling(Actor self) { buildComplete = false; }
void INotifySold.Sold(Actor self) { }
void INotifyTransform.BeforeTransform(Actor self) { buildComplete = false; }
void INotifyTransform.OnTransform(Actor self) { }
void INotifyTransform.AfterTransform(Actor self) { }
} }
} }

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Renders an animation when the Production trait of the actor is activated.", [Desc("Renders an animation when the Production trait of the actor is activated.",
"Works both with per player ClassicProductionQueue and per building ProductionQueue, but needs any of these.")] "Works both with per player ClassicProductionQueue and per building ProductionQueue, but needs any of these.")]
public class WithProductionOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>, Requires<ProductionInfo> public class WithProductionOverlayInfo : PausableConditionalTraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>, Requires<ProductionInfo>
{ {
[Desc("Queues that should be producing for this overlay to render.")] [Desc("Queues that should be producing for this overlay to render.")]
public readonly HashSet<string> Queues = new HashSet<string>(); public readonly HashSet<string> Queues = new HashSet<string>();
@@ -36,16 +36,14 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithProductionOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithProductionOverlay(init.Self, this); }
} }
public class WithProductionOverlay : INotifyDamageStateChanged, INotifyCreated, INotifyBuildComplete, INotifySold, INotifyOwnerChanged public class WithProductionOverlay : PausableConditionalTrait<WithProductionOverlayInfo>, INotifyDamageStateChanged, INotifyCreated, INotifyOwnerChanged
{ {
readonly WithProductionOverlayInfo info;
readonly Animation overlay; readonly Animation overlay;
readonly ProductionInfo production; readonly ProductionInfo production;
ProductionQueue[] queues; ProductionQueue[] queues;
bool buildComplete;
bool IsProducing bool IsProducing
{ {
@@ -53,21 +51,19 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
public WithProductionOverlay(Actor self, WithProductionOverlayInfo info) public WithProductionOverlay(Actor self, WithProductionOverlayInfo info)
: base(info)
{ {
this.info = info;
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
production = self.Info.TraitInfo<ProductionInfo>(); production = self.Info.TraitInfo<ProductionInfo>();
overlay = new Animation(self.World, rs.GetImage(self)); overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused);
overlay.PlayRepeating(info.Sequence); overlay.PlayRepeating(info.Sequence);
var anim = new AnimationWithOffset(overlay, var anim = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !IsProducing || !buildComplete); () => !IsProducing || IsTraitDisabled);
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
@@ -77,7 +73,7 @@ namespace OpenRA.Mods.Common.Traits.Render
// Per-actor production // Per-actor production
queues = self.TraitsImplementing<ProductionQueue>() queues = self.TraitsImplementing<ProductionQueue>()
.Where(q => production.Produces.Contains(q.Info.Type)) .Where(q => production.Produces.Contains(q.Info.Type))
.Where(q => !info.Queues.Any() || info.Queues.Contains(q.Info.Type)) .Where(q => !Info.Queues.Any() || Info.Queues.Contains(q.Info.Type))
.ToArray(); .ToArray();
if (!queues.Any()) if (!queues.Any())
@@ -85,20 +81,13 @@ namespace OpenRA.Mods.Common.Traits.Render
// Player-wide production // Player-wide production
queues = self.Owner.PlayerActor.TraitsImplementing<ProductionQueue>() queues = self.Owner.PlayerActor.TraitsImplementing<ProductionQueue>()
.Where(q => production.Produces.Contains(q.Info.Type)) .Where(q => production.Produces.Contains(q.Info.Type))
.Where(q => !info.Queues.Any() || info.Queues.Contains(q.Info.Type)) .Where(q => !Info.Queues.Any() || Info.Queues.Contains(q.Info.Type))
.ToArray(); .ToArray();
} }
} }
void INotifyCreated.Created(Actor self) protected override void TraitEnabled(Actor self)
{ {
if (buildComplete)
CacheQueues(self);
}
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
CacheQueues(self); CacheQueues(self);
} }
@@ -107,12 +96,6 @@ namespace OpenRA.Mods.Common.Traits.Render
self.World.AddFrameEndTask(w => CacheQueues(self)); self.World.AddFrameEndTask(w => CacheQueues(self));
} }
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)
{ {
overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name)); overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name));

View File

@@ -39,10 +39,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithRepairOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithRepairOverlay(init.Self, this); }
} }
public class WithRepairOverlay : PausableConditionalTrait<WithRepairOverlayInfo>, INotifyDamageStateChanged, INotifyBuildComplete, INotifySold, INotifyRepair public class WithRepairOverlay : PausableConditionalTrait<WithRepairOverlayInfo>, INotifyDamageStateChanged, INotifyRepair
{ {
readonly Animation overlay; readonly Animation overlay;
bool buildComplete;
bool visible; bool visible;
public WithRepairOverlay(Actor self, WithRepairOverlayInfo info) public WithRepairOverlay(Actor self, WithRepairOverlayInfo info)
@@ -51,29 +50,17 @@ namespace OpenRA.Mods.Common.Traits.Render
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused); overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused);
overlay.PlayThen(info.Sequence, () => visible = false); overlay.PlayThen(info.Sequence, () => visible = false);
var anim = new AnimationWithOffset(overlay, var anim = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => IsTraitDisabled || !visible || !buildComplete, () => IsTraitDisabled || !visible,
p => RenderUtils.ZOffsetFromCenter(self, p, 1)); p => RenderUtils.ZOffsetFromCenter(self, p, 1));
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)
{ {
overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name)); overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name));

View File

@@ -15,27 +15,26 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Displays the fill status of PlayerResources with an extra sprite overlay on the actor.")] [Desc("Displays the fill status of PlayerResources with an extra sprite overlay on the actor.")]
class WithResourcesInfo : ITraitInfo, Requires<WithSpriteBodyInfo>, Requires<RenderSpritesInfo> class WithResourcesInfo : ConditionalTraitInfo, Requires<WithSpriteBodyInfo>, Requires<RenderSpritesInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "resources"; [SequenceReference] public readonly string Sequence = "resources";
public object Create(ActorInitializer init) { return new WithResources(init.Self, this); } public override object Create(ActorInitializer init) { return new WithResources(init.Self, this); }
} }
class WithResources : INotifyBuildComplete, INotifySold, INotifyOwnerChanged, INotifyDamageStateChanged // TODO: Rename to WithResourcesOverlay to conform with our naming conventions
class WithResources : ConditionalTrait<WithResourcesInfo>, INotifyOwnerChanged, INotifyDamageStateChanged
{ {
readonly WithResourcesInfo info;
readonly AnimationWithOffset anim; readonly AnimationWithOffset anim;
readonly RenderSprites rs; readonly RenderSprites rs;
readonly WithSpriteBody wsb; readonly WithSpriteBody wsb;
PlayerResources playerResources; PlayerResources playerResources;
bool buildComplete;
public WithResources(Actor self, WithResourcesInfo info) public WithResources(Actor self, WithResourcesInfo info)
: base(info)
{ {
this.info = info;
rs = self.Trait<RenderSprites>(); rs = self.Trait<RenderSprites>();
wsb = self.Trait<WithSpriteBody>(); wsb = self.Trait<WithSpriteBody>();
playerResources = self.Owner.PlayerActor.Trait<PlayerResources>(); playerResources = self.Owner.PlayerActor.Trait<PlayerResources>();
@@ -46,27 +45,19 @@ namespace OpenRA.Mods.Common.Traits.Render
((10 * a.CurrentSequence.Length - 1) * playerResources.Resources) / (10 * playerResources.ResourceCapacity) : ((10 * a.CurrentSequence.Length - 1) * playerResources.Resources) / (10 * playerResources.ResourceCapacity) :
0); 0);
anim = new AnimationWithOffset(a, null, () => !buildComplete, 1024); anim = new AnimationWithOffset(a, null, () => IsTraitDisabled, 1024);
rs.Add(anim); rs.Add(anim);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)
{ {
if (anim.Animation.CurrentSequence != null) if (anim.Animation.CurrentSequence != null)
anim.Animation.ReplaceAnim(wsb.NormalizeSequence(self, info.Sequence)); anim.Animation.ReplaceAnim(wsb.NormalizeSequence(self, Info.Sequence));
} }
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
{ {
playerResources = newOwner.PlayerActor.Trait<PlayerResources>(); playerResources = newOwner.PlayerActor.Trait<PlayerResources>();
} }
void INotifySold.Selling(Actor self) { rs.Remove(anim); }
void INotifySold.Sold(Actor self) { }
} }
} }

View File

@@ -37,10 +37,9 @@ namespace OpenRA.Mods.Common.Traits.Render
public override object Create(ActorInitializer init) { return new WithResupplyAnimation(init.Self, this); } public override object Create(ActorInitializer init) { return new WithResupplyAnimation(init.Self, this); }
} }
public class WithResupplyAnimation : ConditionalTrait<WithResupplyAnimationInfo>, INotifyRepair, INotifyRearm, INotifyBuildComplete, INotifySold, ITick public class WithResupplyAnimation : ConditionalTrait<WithResupplyAnimationInfo>, INotifyRepair, INotifyRearm, ITick
{ {
readonly WithSpriteBody spriteBody; readonly WithSpriteBody wsb;
bool buildComplete;
bool animPlaying; bool animPlaying;
bool repairing; bool repairing;
bool rearming; bool rearming;
@@ -48,26 +47,26 @@ namespace OpenRA.Mods.Common.Traits.Render
public WithResupplyAnimation(Actor self, WithResupplyAnimationInfo info) public WithResupplyAnimation(Actor self, WithResupplyAnimationInfo info)
: base(info) : base(info)
{ {
spriteBody = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == Info.Body); wsb = self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == Info.Body);
} }
void ITick.Tick(Actor self) void ITick.Tick(Actor self)
{ {
if (!buildComplete || IsTraitDisabled) if (IsTraitDisabled)
return; return;
if (!animPlaying if (!animPlaying
&& ((repairing && Info.PlayAnimationOn.HasFlag(ResupplyType.Repair)) && ((repairing && Info.PlayAnimationOn.HasFlag(ResupplyType.Repair))
|| (rearming && Info.PlayAnimationOn.HasFlag(ResupplyType.Rearm)))) || (rearming && Info.PlayAnimationOn.HasFlag(ResupplyType.Rearm))))
{ {
spriteBody.PlayCustomAnimationRepeating(self, Info.Sequence); wsb.PlayCustomAnimationRepeating(self, Info.Sequence);
animPlaying = true; animPlaying = true;
} }
else if (animPlaying else if (animPlaying
&& (!repairing || !Info.PlayAnimationOn.HasFlag(ResupplyType.Repair)) && (!repairing || !Info.PlayAnimationOn.HasFlag(ResupplyType.Repair))
&& (!rearming || !Info.PlayAnimationOn.HasFlag(ResupplyType.Rearm))) && (!rearming || !Info.PlayAnimationOn.HasFlag(ResupplyType.Rearm)))
{ {
spriteBody.CancelCustomAnimation(self); wsb.CancelCustomAnimation(self);
animPlaying = false; animPlaying = false;
} }
} }
@@ -96,16 +95,11 @@ namespace OpenRA.Mods.Common.Traits.Render
rearming = false; rearming = false;
} }
void INotifyBuildComplete.BuildingComplete(Actor self) protected override void TraitDisabled(Actor self)
{ {
buildComplete = true; // Cancel immediately instead of waiting for the next tick
repairing = rearming = animPlaying = false;
wsb.CancelCustomAnimation(self);
} }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
}
void INotifySold.Sold(Actor self) { }
} }
} }

View File

@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits.Render namespace OpenRA.Mods.Common.Traits.Render
{ {
[Desc("Render trait for buildings that change the sprite according to the remaining resource storage capacity across all depots.")] [Desc("Render trait for buildings that change the sprite according to the remaining resource storage capacity across all depots.")]
class WithSiloAnimationInfo : ITraitInfo, Requires<WithSpriteBodyInfo>, Requires<RenderSpritesInfo> class WithSiloAnimationInfo : ConditionalTraitInfo, Requires<WithSpriteBodyInfo>, Requires<RenderSpritesInfo>
{ {
[Desc("Sequence to use for resources-dependent 'stages'."), SequenceReference] [Desc("Sequence to use for resources-dependent 'stages'."), SequenceReference]
public readonly string Sequence = "stages"; public readonly string Sequence = "stages";
@@ -26,38 +26,35 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Which sprite body to play the animation on.")] [Desc("Which sprite body to play the animation on.")]
public readonly string Body = "body"; public readonly string Body = "body";
public object Create(ActorInitializer init) { return new WithSiloAnimation(init, this); } public override object Create(ActorInitializer init) { return new WithSiloAnimation(init, this); }
} }
class WithSiloAnimation : INotifyBuildComplete, INotifyOwnerChanged class WithSiloAnimation : ConditionalTrait<WithSiloAnimationInfo>, INotifyOwnerChanged
{ {
readonly WithSiloAnimationInfo info;
readonly WithSpriteBody wsb; readonly WithSpriteBody wsb;
PlayerResources playerResources; PlayerResources playerResources;
public WithSiloAnimation(ActorInitializer init, WithSiloAnimationInfo info) public WithSiloAnimation(ActorInitializer init, WithSiloAnimationInfo info)
: base(info)
{ {
this.info = info;
wsb = init.Self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body); wsb = init.Self.TraitsImplementing<WithSpriteBody>().Single(w => w.Info.Name == info.Body);
playerResources = init.Self.Owner.PlayerActor.Trait<PlayerResources>(); playerResources = init.Self.Owner.PlayerActor.Trait<PlayerResources>();
} }
void INotifyBuildComplete.BuildingComplete(Actor self) void PlayAnimation(Actor self)
{ {
wsb.DefaultAnimation.PlayFetchIndex(wsb.NormalizeSequence(self, info.Sequence), wsb.DefaultAnimation.PlayFetchIndex(wsb.NormalizeSequence(self, Info.Sequence),
() => playerResources.ResourceCapacity != 0 () => playerResources.ResourceCapacity != 0
? ((info.Stages * wsb.DefaultAnimation.CurrentSequence.Length - 1) * playerResources.Resources) / (info.Stages * playerResources.ResourceCapacity) ? ((Info.Stages * wsb.DefaultAnimation.CurrentSequence.Length - 1) * playerResources.Resources) / (Info.Stages * playerResources.ResourceCapacity)
: 0); : 0);
} }
void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) void INotifyOwnerChanged.OnOwnerChanged(Actor self, Player oldOwner, Player newOwner)
{ {
playerResources = newOwner.PlayerActor.Trait<PlayerResources>(); playerResources = newOwner.PlayerActor.Trait<PlayerResources>();
PlayAnimation(self);
wsb.DefaultAnimation.PlayFetchIndex(wsb.NormalizeSequence(self, info.Sequence),
() => playerResources.ResourceCapacity != 0
? ((info.Stages * wsb.DefaultAnimation.CurrentSequence.Length - 1) * playerResources.Resources) / (info.Stages * playerResources.ResourceCapacity)
: 0);
} }
protected override void TraitEnabled(Actor self) { PlayAnimation(self); }
} }
} }

View File

@@ -44,7 +44,7 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
} }
public class WithSpriteBody : PausableConditionalTrait<WithSpriteBodyInfo>, INotifyDamageStateChanged, INotifyBuildComplete, IAutoMouseBounds public class WithSpriteBody : PausableConditionalTrait<WithSpriteBodyInfo>, INotifyDamageStateChanged, IAutoMouseBounds
{ {
public readonly Animation DefaultAnimation; public readonly Animation DefaultAnimation;
readonly RenderSprites rs; readonly RenderSprites rs;
@@ -80,17 +80,11 @@ namespace OpenRA.Mods.Common.Traits.Render
return RenderSprites.NormalizeSequence(DefaultAnimation, self.GetDamageState(), sequence); return RenderSprites.NormalizeSequence(DefaultAnimation, self.GetDamageState(), sequence);
} }
protected virtual void OnBuildComplete(Actor self) protected override void TraitEnabled(Actor self)
{ {
DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence)); DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence));
} }
// TODO: Get rid of INotifyBuildComplete in favor of using the condition system
void INotifyBuildComplete.BuildingComplete(Actor self)
{
OnBuildComplete(self);
}
public void PlayCustomAnimation(Actor self, string name, Action after = null) public void PlayCustomAnimation(Actor self, string name, Action after = null)
{ {
DefaultAnimation.PlayThen(NormalizeSequence(self, name), () => DefaultAnimation.PlayThen(NormalizeSequence(self, name), () =>

View File

@@ -70,7 +70,7 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
} }
public class WithSpriteTurret : ConditionalTrait<WithSpriteTurretInfo>, INotifyBuildComplete, INotifySold, INotifyTransform, INotifyDamageStateChanged public class WithSpriteTurret : ConditionalTrait<WithSpriteTurretInfo>, INotifyDamageStateChanged
{ {
public readonly Animation DefaultAnimation; public readonly Animation DefaultAnimation;
readonly RenderSprites rs; readonly RenderSprites rs;
@@ -78,9 +78,6 @@ namespace OpenRA.Mods.Common.Traits.Render
readonly Turreted t; readonly Turreted t;
readonly Armament[] arms; readonly Armament[] arms;
// TODO: This should go away once https://github.com/OpenRA/OpenRA/issues/7035 is implemented
bool buildComplete;
public WithSpriteTurret(Actor self, WithSpriteTurretInfo info) public WithSpriteTurret(Actor self, WithSpriteTurretInfo info)
: base(info) : base(info)
{ {
@@ -90,13 +87,12 @@ namespace OpenRA.Mods.Common.Traits.Render
.First(tt => tt.Name == info.Turret); .First(tt => tt.Name == info.Turret);
arms = self.TraitsImplementing<Armament>() arms = self.TraitsImplementing<Armament>()
.Where(w => w.Info.Turret == info.Turret).ToArray(); .Where(w => w.Info.Turret == info.Turret).ToArray();
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => t.TurretFacing); DefaultAnimation = new Animation(self.World, rs.GetImage(self), () => t.TurretFacing);
DefaultAnimation.PlayRepeating(NormalizeSequence(self, info.Sequence)); DefaultAnimation.PlayRepeating(NormalizeSequence(self, info.Sequence));
rs.Add(new AnimationWithOffset(DefaultAnimation, rs.Add(new AnimationWithOffset(DefaultAnimation,
() => TurretOffset(self), () => TurretOffset(self),
() => IsTraitDisabled || !buildComplete, () => IsTraitDisabled,
p => RenderUtils.ZOffsetFromCenter(self, p, 1)), info.Palette, info.IsPlayerPalette); p => RenderUtils.ZOffsetFromCenter(self, p, 1)), info.Palette, info.IsPlayerPalette);
// Restrict turret facings to match the sprite // Restrict turret facings to match the sprite
@@ -144,12 +140,5 @@ namespace OpenRA.Mods.Common.Traits.Render
{ {
DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence)); DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence));
} }
void INotifyBuildComplete.BuildingComplete(Actor self) { buildComplete = true; }
void INotifySold.Selling(Actor self) { buildComplete = false; }
void INotifySold.Sold(Actor self) { }
void INotifyTransform.BeforeTransform(Actor self) { buildComplete = false; }
void INotifyTransform.OnTransform(Actor self) { }
void INotifyTransform.AfterTransform(Actor toActor) { }
} }
} }

View File

@@ -63,16 +63,13 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
} }
public class WithVoxelBarrel : ConditionalTrait<WithVoxelBarrelInfo>, INotifyBuildComplete, INotifySold, INotifyTransform public class WithVoxelBarrel : ConditionalTrait<WithVoxelBarrelInfo>
{ {
readonly Actor self; readonly Actor self;
readonly Armament armament; readonly Armament armament;
readonly Turreted turreted; readonly Turreted turreted;
readonly BodyOrientation body; readonly BodyOrientation body;
// TODO: This should go away once https://github.com/OpenRA/OpenRA/issues/7035 is implemented
bool buildComplete;
public WithVoxelBarrel(Actor self, WithVoxelBarrelInfo info) public WithVoxelBarrel(Actor self, WithVoxelBarrelInfo info)
: base(info) : base(info)
{ {
@@ -83,12 +80,10 @@ namespace OpenRA.Mods.Common.Traits.Render
turreted = self.TraitsImplementing<Turreted>() turreted = self.TraitsImplementing<Turreted>()
.First(tt => tt.Name == armament.Info.Turret); .First(tt => tt.Name == armament.Info.Turret);
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
var rv = self.Trait<RenderVoxels>(); var rv = self.Trait<RenderVoxels>();
rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence), rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
BarrelOffset, BarrelRotation, BarrelOffset, BarrelRotation,
() => IsTraitDisabled || !buildComplete, () => 0, info.ShowShadow)); () => IsTraitDisabled, () => 0, info.ShowShadow));
} }
WVec BarrelOffset() WVec BarrelOffset()
@@ -110,12 +105,5 @@ namespace OpenRA.Mods.Common.Traits.Render
yield return turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw); yield return turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw);
yield return qb; yield return qb;
} }
void INotifyBuildComplete.BuildingComplete(Actor self) { buildComplete = true; }
void INotifySold.Selling(Actor self) { buildComplete = false; }
void INotifySold.Sold(Actor self) { }
void INotifyTransform.BeforeTransform(Actor self) { buildComplete = false; }
void INotifyTransform.OnTransform(Actor self) { }
void INotifyTransform.AfterTransform(Actor toActor) { }
} }
} }

View File

@@ -51,15 +51,12 @@ namespace OpenRA.Mods.Common.Traits.Render
} }
} }
public class WithVoxelTurret : ConditionalTrait<WithVoxelTurretInfo>, INotifyBuildComplete, INotifySold, INotifyTransform public class WithVoxelTurret : ConditionalTrait<WithVoxelTurretInfo>
{ {
readonly Actor self; readonly Actor self;
readonly Turreted turreted; readonly Turreted turreted;
readonly BodyOrientation body; readonly BodyOrientation body;
// TODO: This should go away once https://github.com/OpenRA/OpenRA/issues/7035 is implemented
bool buildComplete;
public WithVoxelTurret(Actor self, WithVoxelTurretInfo info) public WithVoxelTurret(Actor self, WithVoxelTurretInfo info)
: base(info) : base(info)
{ {
@@ -67,12 +64,11 @@ namespace OpenRA.Mods.Common.Traits.Render
body = self.Trait<BodyOrientation>(); body = self.Trait<BodyOrientation>();
turreted = self.TraitsImplementing<Turreted>() turreted = self.TraitsImplementing<Turreted>()
.First(tt => tt.Name == Info.Turret); .First(tt => tt.Name == Info.Turret);
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>(); // always render instantly for units
var rv = self.Trait<RenderVoxels>(); var rv = self.Trait<RenderVoxels>();
rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence), rv.Add(new ModelAnimation(self.World.ModelCache.GetModelSequence(rv.Image, Info.Sequence),
() => turreted.Position(self), TurretRotation, () => turreted.Position(self), TurretRotation,
() => IsTraitDisabled || !buildComplete, () => 0, info.ShowShadow)); () => IsTraitDisabled, () => 0, info.ShowShadow));
} }
IEnumerable<WRot> TurretRotation() IEnumerable<WRot> TurretRotation()
@@ -82,12 +78,5 @@ namespace OpenRA.Mods.Common.Traits.Render
yield return turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw); yield return turreted.WorldOrientation(self) - b + WRot.FromYaw(b.Yaw - qb.Yaw);
yield return qb; yield return qb;
} }
void INotifyBuildComplete.BuildingComplete(Actor self) { buildComplete = true; }
void INotifySold.Selling(Actor self) { buildComplete = false; }
void INotifySold.Sold(Actor self) { }
void INotifyTransform.BeforeTransform(Actor self) { buildComplete = false; }
void INotifyTransform.OnTransform(Actor self) { }
void INotifyTransform.AfterTransform(Actor toActor) { }
} }
} }

View File

@@ -139,8 +139,11 @@ namespace OpenRA.Mods.Common.Traits.Render
dirty = false; dirty = false;
} }
protected override void OnBuildComplete(Actor self) protected override void TraitEnabled(Actor self)
{ {
base.TraitEnabled(self);
dirty = true;
DefaultAnimation.PlayFetchIndex(NormalizeSequence(self, Info.Sequence), () => adjacent); DefaultAnimation.PlayFetchIndex(NormalizeSequence(self, Info.Sequence), () => adjacent);
UpdateNeighbours(self); UpdateNeighbours(self);
@@ -162,8 +165,6 @@ namespace OpenRA.Mods.Common.Traits.Render
{ {
UpdateNeighbours(self); UpdateNeighbours(self);
} }
protected override void TraitEnabled(Actor self) { dirty = true; }
} }
public class RuntimeNeighbourInit : IActorInit<Dictionary<CPos, string[]>>, ISuppressInitExport public class RuntimeNeighbourInit : IActorInit<Dictionary<CPos, string[]>>, ISuppressInitExport

View File

@@ -17,7 +17,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.D2k.Traits.Render namespace OpenRA.Mods.D2k.Traits.Render
{ {
[Desc("Rendered together with the \"make\" animation.")] [Desc("Rendered together with the \"make\" animation.")]
public class WithCrumbleOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo> public class WithCrumbleOverlayInfo : ConditionalTraitInfo, Requires<RenderSpritesInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "crumble-overlay"; [SequenceReference] public readonly string Sequence = "crumble-overlay";
@@ -28,14 +28,13 @@ namespace OpenRA.Mods.D2k.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithCrumbleOverlay(init, this); } public override object Create(ActorInitializer init) { return new WithCrumbleOverlay(init, this); }
} }
public class WithCrumbleOverlay : INotifyBuildComplete public class WithCrumbleOverlay : ConditionalTrait<WithCrumbleOverlayInfo>
{ {
bool buildComplete = false;
public WithCrumbleOverlay(ActorInitializer init, WithCrumbleOverlayInfo info) public WithCrumbleOverlay(ActorInitializer init, WithCrumbleOverlayInfo info)
: base(info)
{ {
if (init.Contains<SkipMakeAnimsInit>()) if (init.Contains<SkipMakeAnimsInit>())
return; return;
@@ -43,17 +42,12 @@ namespace OpenRA.Mods.D2k.Traits.Render
var rs = init.Self.Trait<RenderSprites>(); var rs = init.Self.Trait<RenderSprites>();
var overlay = new Animation(init.World, rs.GetImage(init.Self)); var overlay = new Animation(init.World, rs.GetImage(init.Self));
var anim = new AnimationWithOffset(overlay, null, () => !buildComplete); var anim = new AnimationWithOffset(overlay, null, () => IsTraitDisabled);
// Remove the animation once it is complete // Remove the animation once it is complete
overlay.PlayThen(info.Sequence, () => init.World.AddFrameEndTask(w => rs.Remove(anim))); overlay.PlayThen(info.Sequence, () => init.World.AddFrameEndTask(w => rs.Remove(anim)));
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
} }
} }

View File

@@ -18,7 +18,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.D2k.Traits.Render namespace OpenRA.Mods.D2k.Traits.Render
{ {
[Desc("Rendered when ProductionAirdrop is in progress.")] [Desc("Rendered when ProductionAirdrop is in progress.")]
public class WithDeliveryOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo> public class WithDeliveryOverlayInfo : PausableConditionalTraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>
{ {
[Desc("Sequence name to use")] [Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "active"; [SequenceReference] public readonly string Sequence = "active";
@@ -32,28 +32,21 @@ namespace OpenRA.Mods.D2k.Traits.Render
[Desc("Custom palette is a player palette BaseName")] [Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false; public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithDeliveryOverlay(init.Self, this); } public override object Create(ActorInitializer init) { return new WithDeliveryOverlay(init.Self, this); }
} }
public class WithDeliveryOverlay : INotifyBuildComplete, INotifySold, INotifyDelivery public class WithDeliveryOverlay : PausableConditionalTrait<WithDeliveryOverlayInfo>, INotifyDelivery
{ {
readonly WithDeliveryOverlayInfo info;
readonly AnimationWithOffset anim; readonly AnimationWithOffset anim;
bool buildComplete;
bool delivering; bool delivering;
public WithDeliveryOverlay(Actor self, WithDeliveryOverlayInfo info) public WithDeliveryOverlay(Actor self, WithDeliveryOverlayInfo info)
: base(info)
{ {
this.info = info;
var rs = self.Trait<RenderSprites>(); var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>(); var body = self.Trait<BodyOrientation>();
// always render instantly for units var overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused);
buildComplete = !self.Info.HasTraitInfo<BuildingInfo>();
var overlay = new Animation(self.World, rs.GetImage(self));
overlay.Play(info.Sequence); overlay.Play(info.Sequence);
// These translucent overlays should not be included in highlight flashes // These translucent overlays should not be included in highlight flashes
@@ -61,7 +54,7 @@ namespace OpenRA.Mods.D2k.Traits.Render
anim = new AnimationWithOffset(overlay, anim = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !buildComplete || !delivering); () => IsTraitDisabled || !delivering);
rs.Add(anim, info.Palette, info.IsPlayerPalette); rs.Add(anim, info.Palette, info.IsPlayerPalette);
} }
@@ -69,18 +62,7 @@ namespace OpenRA.Mods.D2k.Traits.Render
void PlayDeliveryOverlay() void PlayDeliveryOverlay()
{ {
if (delivering) if (delivering)
anim.Animation.PlayThen(info.Sequence, PlayDeliveryOverlay); anim.Animation.PlayThen(Info.Sequence, PlayDeliveryOverlay);
}
void INotifyBuildComplete.BuildingComplete(Actor self)
{
buildComplete = true;
}
void INotifySold.Sold(Actor self) { }
void INotifySold.Selling(Actor self)
{
buildComplete = false;
} }
void INotifyDelivery.IncomingDelivery(Actor self) { delivering = true; PlayDeliveryOverlay(); } void INotifyDelivery.IncomingDelivery(Actor self) { delivering = true; PlayDeliveryOverlay(); }