1 #region Copyright & License Information 2 /* 3 * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) 4 * This file is part of OpenRA, which is free software. It is made 5 * available to you under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, either version 3 of 7 * the License, or (at your option) any later version. For more 8 * information, see COPYING. 9 */ 10 #endregion 11 12 using System; 13 using System.Collections.Generic; 14 using OpenRA.Graphics; 15 using OpenRA.Mods.Common.Graphics; 16 using OpenRA.Traits; 17 18 namespace OpenRA.Mods.Common.Traits.Render 19 { 20 [Desc("Renders a decorative animation on units and buildings.")] 21 public class WithIdleOverlayInfo : PausableConditionalTraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo> 22 { 23 [SequenceReference] 24 [Desc("Animation to play when the actor is created.")] 25 public readonly string StartSequence = null; 26 27 [SequenceReference] 28 [Desc("Sequence name to use")] 29 public readonly string Sequence = "idle-overlay"; 30 31 [Desc("Position relative to body")] 32 public readonly WVec Offset = WVec.Zero; 33 34 [PaletteReference("IsPlayerPalette")] 35 [Desc("Custom palette name")] 36 public readonly string Palette = null; 37 38 [Desc("Custom palette is a player palette BaseName")] 39 public readonly bool IsPlayerPalette = false; 40 Create(ActorInitializer init)41 public override object Create(ActorInitializer init) { return new WithIdleOverlay(init.Self, this); } 42 RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)43 public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) 44 { 45 if (!EnabledByDefault) 46 yield break; 47 48 if (Palette != null) 49 p = init.WorldRenderer.Palette(Palette); 50 51 Func<int> facing; 52 if (init.Contains<DynamicFacingInit>()) 53 facing = init.Get<DynamicFacingInit, Func<int>>(); 54 else 55 { 56 var f = init.Contains<FacingInit>() ? init.Get<FacingInit, int>() : 0; 57 facing = () => f; 58 } 59 60 var anim = new Animation(init.World, image, facing); 61 anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); 62 63 var body = init.Actor.TraitInfo<BodyOrientationInfo>(); 64 Func<WRot> orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); 65 Func<WVec> offset = () => body.LocalToWorld(Offset.Rotate(orientation())); 66 Func<int> zOffset = () => 67 { 68 var tmpOffset = offset(); 69 return tmpOffset.Y + tmpOffset.Z + 1; 70 }; 71 72 yield return new SpriteActorPreview(anim, offset, zOffset, p, rs.Scale); 73 } 74 } 75 76 public class WithIdleOverlay : PausableConditionalTrait<WithIdleOverlayInfo>, INotifyDamageStateChanged 77 { 78 readonly Animation overlay; 79 WithIdleOverlay(Actor self, WithIdleOverlayInfo info)80 public WithIdleOverlay(Actor self, WithIdleOverlayInfo info) 81 : base(info) 82 { 83 var rs = self.Trait<RenderSprites>(); 84 var body = self.Trait<BodyOrientation>(); 85 86 overlay = new Animation(self.World, rs.GetImage(self), () => IsTraitPaused); 87 if (info.StartSequence != null) 88 overlay.PlayThen(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.StartSequence), 89 () => overlay.PlayRepeating(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.Sequence))); 90 else 91 overlay.PlayRepeating(RenderSprites.NormalizeSequence(overlay, self.GetDamageState(), info.Sequence)); 92 93 var anim = new AnimationWithOffset(overlay, 94 () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), 95 () => IsTraitDisabled, 96 p => RenderUtils.ZOffsetFromCenter(self, p, 1)); 97 98 rs.Add(anim, info.Palette, info.IsPlayerPalette); 99 } 100 INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)101 void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) 102 { 103 overlay.ReplaceAnim(RenderSprites.NormalizeSequence(overlay, e.DamageState, overlay.CurrentSequence.Name)); 104 } 105 } 106 } 107