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.Effects; 15 using OpenRA.Graphics; 16 using OpenRA.Scripting; 17 18 namespace OpenRA.Mods.Common.Effects 19 { 20 public class Beacon : IEffect, IScriptBindable, IEffectAboveShroud 21 { 22 static readonly int MaxArrowHeight = 512; 23 24 readonly Player owner; 25 readonly WPos position; 26 readonly bool isPlayerPalette; 27 readonly string beaconPalette, posterPalette; 28 readonly Animation arrow, beacon, circles, clock, poster; 29 readonly int duration; 30 31 int delay; 32 int arrowHeight = MaxArrowHeight; 33 int arrowSpeed = 50; 34 int tick; 35 36 // Player-placed beacons are removed after a delay Beacon(Player owner, WPos position, int duration, string beaconPalette, bool isPlayerPalette, string beaconCollection, string beaconSequence, string arrowSprite, string circleSprite, int delay = 0)37 public Beacon(Player owner, WPos position, int duration, string beaconPalette, bool isPlayerPalette, 38 string beaconCollection, string beaconSequence, string arrowSprite, string circleSprite, int delay = 0) 39 { 40 this.owner = owner; 41 this.position = position; 42 this.beaconPalette = beaconPalette; 43 this.isPlayerPalette = isPlayerPalette; 44 this.duration = duration; 45 this.delay = delay; 46 47 if (!string.IsNullOrEmpty(beaconSequence)) 48 { 49 beacon = new Animation(owner.World, beaconCollection); 50 beacon.PlayRepeating(beaconSequence); 51 } 52 53 if (!string.IsNullOrEmpty(arrowSprite)) 54 { 55 arrow = new Animation(owner.World, beaconCollection); 56 arrow.Play(arrowSprite); 57 } 58 59 if (!string.IsNullOrEmpty(circleSprite)) 60 { 61 circles = new Animation(owner.World, beaconCollection); 62 circles.Play(circleSprite); 63 } 64 } 65 66 // By default, support power beacons are expected to clean themselves up Beacon(Player owner, WPos position, bool isPlayerPalette, string palette, string posterCollection, string posterType, string posterPalette, string beaconSequence, string arrowSequence, string circleSequence, string clockSequence, Func<float> clockFraction, int delay = 0, int duration = -1)67 public Beacon(Player owner, WPos position, bool isPlayerPalette, string palette, string posterCollection, string posterType, string posterPalette, 68 string beaconSequence, string arrowSequence, string circleSequence, string clockSequence, Func<float> clockFraction, int delay = 0, int duration = -1) 69 : this(owner, position, duration, palette, isPlayerPalette, posterCollection, beaconSequence, arrowSequence, circleSequence, delay) 70 { 71 this.posterPalette = posterPalette; 72 73 if (posterType != null) 74 { 75 poster = new Animation(owner.World, posterCollection); 76 poster.Play(posterType); 77 78 if (clockFraction != null) 79 { 80 clock = new Animation(owner.World, posterCollection); 81 clock.PlayFetchIndex(clockSequence, () => Exts.Clamp((int)(clockFraction() * (clock.CurrentSequence.Length - 1)), 0, clock.CurrentSequence.Length - 1)); 82 } 83 } 84 } 85 IEffect.Tick(World world)86 void IEffect.Tick(World world) 87 { 88 if (delay-- > 0) 89 return; 90 91 arrowHeight += arrowSpeed; 92 var clamped = arrowHeight.Clamp(0, MaxArrowHeight); 93 if (arrowHeight != clamped) 94 { 95 arrowHeight = clamped; 96 arrowSpeed *= -1; 97 } 98 99 if (arrow != null) 100 arrow.Tick(); 101 102 if (beacon != null) 103 beacon.Tick(); 104 105 if (circles != null) 106 circles.Tick(); 107 108 if (clock != null) 109 clock.Tick(); 110 111 if (duration > 0 && duration <= tick++) 112 owner.World.AddFrameEndTask(w => w.Remove(this)); 113 } 114 IEffect.Render(WorldRenderer r)115 IEnumerable<IRenderable> IEffect.Render(WorldRenderer r) { return SpriteRenderable.None; } 116 IEffectAboveShroud.RenderAboveShroud(WorldRenderer r)117 IEnumerable<IRenderable> IEffectAboveShroud.RenderAboveShroud(WorldRenderer r) 118 { 119 if (delay > 0) 120 yield break; 121 122 if (!owner.IsAlliedWith(owner.World.RenderPlayer)) 123 yield break; 124 125 var palette = r.Palette(isPlayerPalette ? beaconPalette + owner.InternalName : beaconPalette); 126 127 if (beacon != null) 128 foreach (var a in beacon.Render(position, palette)) 129 yield return a; 130 131 if (circles != null) 132 foreach (var a in circles.Render(position, palette)) 133 yield return a; 134 135 if (arrow != null) 136 foreach (var a in arrow.Render(position + new WVec(0, 0, arrowHeight), palette)) 137 yield return a; 138 139 if (poster != null) 140 { 141 foreach (var a in poster.Render(position, r.Palette(posterPalette))) 142 yield return a; 143 144 if (clock != null) 145 foreach (var a in clock.Render(position, r.Palette(posterPalette))) 146 yield return a; 147 } 148 } 149 } 150 } 151