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.Collections.Generic; 13 using System.Linq; 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("Play an animation when a unit exits or blocks the exit after production finished.")] 21 class WithProductionDoorOverlayInfo : ConditionalTraitInfo, IRenderActorPreviewSpritesInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>, Requires<BuildingInfo> 22 { 23 public readonly string Sequence = "build-door"; 24 RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p)25 public IEnumerable<IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) 26 { 27 var anim = new Animation(init.World, image, () => 0); 28 anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => 0); 29 30 var bi = init.Actor.TraitInfo<BuildingInfo>(); 31 var offset = bi.CenterOffset(init.World).Y + 512; // Additional 512 units move from center -> top of cell 32 yield return new SpriteActorPreview(anim, () => WVec.Zero, () => offset, p, rs.Scale); 33 } 34 Create(ActorInitializer init)35 public override object Create(ActorInitializer init) { return new WithProductionDoorOverlay(init.Self, this); } 36 } 37 38 class WithProductionDoorOverlay : ConditionalTrait<WithProductionDoorOverlayInfo>, ITick, INotifyProduction, INotifyDamageStateChanged 39 { 40 readonly Animation door; 41 int desiredFrame; 42 CPos openExit; 43 Actor exitingActor; 44 WithProductionDoorOverlay(Actor self, WithProductionDoorOverlayInfo info)45 public WithProductionDoorOverlay(Actor self, WithProductionDoorOverlayInfo info) 46 : base(info) 47 { 48 var renderSprites = self.Trait<RenderSprites>(); 49 door = new Animation(self.World, renderSprites.GetImage(self)); 50 door.PlayFetchDirection(RenderSprites.NormalizeSequence(door, self.GetDamageState(), info.Sequence), 51 () => desiredFrame - door.CurrentFrame); 52 53 var buildingInfo = self.Info.TraitInfo<BuildingInfo>(); 54 55 var offset = buildingInfo.CenterOffset(self.World).Y + 512; 56 renderSprites.Add(new AnimationWithOffset(door, null, () => IsTraitDisabled, offset)); 57 } 58 ITick.Tick(Actor self)59 void ITick.Tick(Actor self) 60 { 61 if (exitingActor == null) 62 return; 63 64 if (!exitingActor.IsInWorld || exitingActor.Location != openExit || !(exitingActor.CurrentActivity is Mobile.ReturnToCellActivity)) 65 { 66 desiredFrame = 0; 67 exitingActor = null; 68 } 69 } 70 INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e)71 void INotifyDamageStateChanged.DamageStateChanged(Actor self, AttackInfo e) 72 { 73 if (door.CurrentSequence != null) 74 door.ReplaceAnim(RenderSprites.NormalizeSequence(door, e.DamageState, door.CurrentSequence.Name)); 75 } 76 INotifyProduction.UnitProduced(Actor self, Actor other, CPos exit)77 void INotifyProduction.UnitProduced(Actor self, Actor other, CPos exit) 78 { 79 openExit = exit; 80 exitingActor = other; 81 desiredFrame = door.CurrentSequence.Length - 1; 82 } 83 } 84 } 85