From e1501d5b7ca8f5083beb8f1614bb5ba71b6101e2 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 31 May 2014 18:17:48 +1200 Subject: [PATCH] Add clock overlay to support power beacons. --- OpenRA.Mods.RA/Effects/Beacon.cs | 35 +++++++++++++--- OpenRA.Mods.RA/Effects/NukeLaunch.cs | 2 + OpenRA.Mods.RA/Player/PlaceBeacon.cs | 2 +- .../SupportPowers/AirstrikePower.cs | 36 ++++++++++------- OpenRA.Mods.RA/SupportPowers/NukePower.cs | 38 +++++++++--------- mods/cnc/bits/beaconclock.shp | Bin 0 -> 5932 bytes mods/cnc/sequences/misc.yaml | 4 ++ mods/ra/bits/beaconclock.shp | Bin 0 -> 3732 bytes mods/ra/sequences/misc.yaml | 4 ++ 9 files changed, 83 insertions(+), 38 deletions(-) create mode 100644 mods/cnc/bits/beaconclock.shp create mode 100644 mods/ra/bits/beaconclock.shp diff --git a/OpenRA.Mods.RA/Effects/Beacon.cs b/OpenRA.Mods.RA/Effects/Beacon.cs index ec3d5889ce..a192cc8f00 100644 --- a/OpenRA.Mods.RA/Effects/Beacon.cs +++ b/OpenRA.Mods.RA/Effects/Beacon.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; using OpenRA.Effects; @@ -24,16 +25,18 @@ namespace OpenRA.Mods.RA.Effects readonly Animation arrow; readonly Animation circles; readonly Animation poster; + readonly Animation clock; + static readonly int maxArrowHeight = 512; int arrowHeight = maxArrowHeight; int arrowSpeed = 50; - public Beacon(Player owner, WPos position, int duration, string palettePrefix, string posterType, string posterPalette) + // Player-placed beacons are removed after a delay + public Beacon(Player owner, WPos position, int duration, string palettePrefix) { this.owner = owner; this.position = position; this.palettePrefix = palettePrefix; - this.posterPalette = posterPalette; arrow = new Animation(owner.World, "beacon"); circles = new Animation(owner.World, "beacon"); @@ -41,14 +44,27 @@ namespace OpenRA.Mods.RA.Effects arrow.Play("arrow"); circles.Play("circles"); + if (duration > 0) + owner.World.Add(new DelayedAction(duration, () => owner.World.Remove(this))); + } + + // Support power beacons are expected to clean themselves up + public Beacon(Player owner, WPos position, string palettePrefix, string posterType, string posterPalette, Func clockFraction) + : this(owner, position, -1, palettePrefix) + { + this.posterPalette = posterPalette; + if (posterType != null) { poster = new Animation(owner.World, "beacon"); poster.Play(posterType); - } - if (duration > 0) - owner.World.Add(new DelayedAction(duration, () => owner.World.Remove(this))); + if (clockFraction != null) + { + clock = new Animation(owner.World, "beacon"); + clock.PlayFetchIndex("clock", () => Exts.Clamp((int)(clockFraction() * (clock.CurrentSequence.Length - 1)), 0, clock.CurrentSequence.Length - 1)); + } + } } public void Tick(World world) @@ -63,6 +79,9 @@ namespace OpenRA.Mods.RA.Effects arrow.Tick(); circles.Tick(); + + if (clock != null) + clock.Tick(); } public IEnumerable Render(WorldRenderer r) @@ -78,8 +97,14 @@ namespace OpenRA.Mods.RA.Effects yield return a; if (poster != null) + { foreach (var a in poster.Render(position, r.Palette(posterPalette))) yield return a; + + if (clock != null) + foreach (var a in clock.Render(position, r.Palette(posterPalette))) + yield return a; + } } } } diff --git a/OpenRA.Mods.RA/Effects/NukeLaunch.cs b/OpenRA.Mods.RA/Effects/NukeLaunch.cs index 577eefa0ce..4b466e5003 100755 --- a/OpenRA.Mods.RA/Effects/NukeLaunch.cs +++ b/OpenRA.Mods.RA/Effects/NukeLaunch.cs @@ -90,5 +90,7 @@ namespace OpenRA.Mods.RA.Effects { return anim.Render(pos, wr.Palette("effect")); } + + public float FractionComplete { get { return ticks * 1f / delay; } } } } diff --git a/OpenRA.Mods.RA/Player/PlaceBeacon.cs b/OpenRA.Mods.RA/Player/PlaceBeacon.cs index 658e7cc7b6..4b335ea6ed 100644 --- a/OpenRA.Mods.RA/Player/PlaceBeacon.cs +++ b/OpenRA.Mods.RA/Player/PlaceBeacon.cs @@ -49,7 +49,7 @@ namespace OpenRA.Mods.RA if (playerBeacon != null) self.World.Remove(playerBeacon); - playerBeacon = new Beacon(self.Owner, pos, info.Duration, info.PalettePrefix, null, null); + playerBeacon = new Beacon(self.Owner, pos, info.Duration, info.PalettePrefix); self.World.Add(playerBeacon); if (self.Owner.IsAlliedWith(self.World.RenderPlayer)) diff --git a/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs b/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs index 496e536e4c..e0eb70c3b5 100644 --- a/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs +++ b/OpenRA.Mods.RA/SupportPowers/AirstrikePower.cs @@ -43,6 +43,9 @@ namespace OpenRA.Mods.RA [Desc("Amount of time to keep the camera alive after the aircraft have finished attacking")] public readonly int CameraRemoveDelay = 25; + [Desc("Weapon range offset to apply during the beacon clock calculation")] + public readonly WRange BeaconDistanceOffset = WRange.FromCells(6); + public override object Create(ActorInitializer init) { return new AirstrikePower(init.self, this); } } @@ -55,20 +58,6 @@ namespace OpenRA.Mods.RA { base.Activate(self, order, manager); - Beacon beacon = null; - if (Info.DisplayBeacon) - { - beacon = new Beacon( - order.Player, - order.TargetLocation.CenterPosition, - -1, - Info.BeaconPalettePrefix, - Info.BeaconPoster, - Info.BeaconPosterPalette); - - self.World.Add(beacon); - } - var info = Info as AirstrikePowerInfo; var attackFacing = Util.QuantizeFacing(self.World.SharedRandom.Next(256), info.QuantizedFacings) * (256 / info.QuantizedFacings); var attackRotation = WRot.FromFacing(attackFacing); @@ -81,6 +70,7 @@ namespace OpenRA.Mods.RA Actor flare = null; Actor camera = null; + Beacon beacon = null; Dictionary aircraftInRange = new Dictionary(); Action onEnterRange = a => @@ -147,6 +137,7 @@ namespace OpenRA.Mods.RA var notification = self.Owner.IsAlliedWith(self.World.RenderPlayer) ? Info.LaunchSound : Info.IncomingSound; Sound.Play(notification); + Actor distanceTestActor = null; for (var i = -info.SquadSize / 2; i <= info.SquadSize / 2; i++) { // Even-sized squads skip the lead plane @@ -174,6 +165,23 @@ namespace OpenRA.Mods.RA a.QueueActivity(new Fly(a, Target.FromPos(finishEdge + spawnOffset))); a.QueueActivity(new RemoveSelf()); aircraftInRange.Add(a, false); + distanceTestActor = a; + } + + if (Info.DisplayBeacon) + { + var distance = (target - startEdge).HorizontalLength; + + beacon = new Beacon( + order.Player, + order.TargetLocation.CenterPosition, + Info.BeaconPalettePrefix, + Info.BeaconPoster, + Info.BeaconPosterPalette, + () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Range) * 1f / distance + ); + + w.Add(beacon); } }); } diff --git a/OpenRA.Mods.RA/SupportPowers/NukePower.cs b/OpenRA.Mods.RA/SupportPowers/NukePower.cs index b4f997ec1d..b9c4609719 100755 --- a/OpenRA.Mods.RA/SupportPowers/NukePower.cs +++ b/OpenRA.Mods.RA/SupportPowers/NukePower.cs @@ -68,20 +68,6 @@ namespace OpenRA.Mods.RA { base.Activate(self, order, manager); - Beacon beacon = null; - if (Info.DisplayBeacon) - { - beacon = new Beacon( - order.Player, - order.TargetLocation.CenterPosition, - -1, - Info.BeaconPalettePrefix, - Info.BeaconPoster, - Info.BeaconPosterPalette); - - self.World.Add(beacon); - } - if (self.Owner.IsAlliedWith(self.World.RenderPlayer)) Sound.Play(Info.LaunchSound); else @@ -91,10 +77,12 @@ namespace OpenRA.Mods.RA var rb = self.Trait(); rb.PlayCustomAnim(self, "active"); - self.World.AddFrameEndTask(w => w.Add(new NukeLaunch(self.Owner, npi.MissileWeapon, + var missile = new NukeLaunch(self.Owner, npi.MissileWeapon, self.CenterPosition + body.LocalToWorld(npi.SpawnOffset), order.TargetLocation.CenterPosition, - npi.FlightVelocity, npi.FlightDelay, npi.SkipAscent))); + npi.FlightVelocity, npi.FlightDelay, npi.SkipAscent); + + self.World.AddFrameEndTask(w => w.Add(missile)); if (npi.CameraActor != null) { @@ -111,15 +99,29 @@ namespace OpenRA.Mods.RA self.World.AddFrameEndTask(w => w.Add(new DelayedAction(npi.FlightDelay - npi.CameraSpawnAdvance, addCamera))); } - if (beacon != null) + if (Info.DisplayBeacon) { + var beacon = new Beacon( + order.Player, + order.TargetLocation.CenterPosition, + Info.BeaconPalettePrefix, + Info.BeaconPoster, + Info.BeaconPosterPalette, + () => missile.FractionComplete + ); + + Action removeBeacon = () => self.World.AddFrameEndTask(w => { w.Remove(beacon); beacon = null; }); - self.World.AddFrameEndTask(w => w.Add(new DelayedAction(npi.FlightDelay - npi.BeaconRemoveAdvance, removeBeacon))); + self.World.AddFrameEndTask(w => + { + w.Add(beacon); + w.Add(new DelayedAction(npi.FlightDelay - npi.BeaconRemoveAdvance, removeBeacon)); + }); } } } diff --git a/mods/cnc/bits/beaconclock.shp b/mods/cnc/bits/beaconclock.shp new file mode 100644 index 0000000000000000000000000000000000000000..bab567383741e8c26f59879fd3909025bf4bb596 GIT binary patch literal 5932 zcmb_fX>3(R7@gap(1n&lDTs*Ph6E*&7zFoVAczr(;1WqR5;Ypo7)bnwMw4klK%ngV zCa)q(trQ7Csue9Q{&4{nH&z=p(I28HfoKSN&NuVDUS8SW(`M#=@0_{!J7>O```&c2 z;a_a7Fm;GCtZ~F!tQpSF`>ly1WA6DW;9i|fY=N)ua^QZzbpihjd=2oKfJYXXxDxo$0{{GG;Qqi(As!3-&_WXr z06#XwiG}|DR^Wl)4~6(g;Kvr3co6uBA-W=e|6$-8z#k9M7JL5jViVs8eoBbb0)Gtn zCh(^Mez2>FZvmdv)j!t)d>imL0S_rL@g2ZpOZ<2p@G#)U5WflhkWv#52R|yr38nu2 zM&Oa)KM(Pjz>n%?;=9352ytpRfBymC(cpgzcubjz#{fT5=Eqxs?*l#(@NL~qJP!E& z?tZ);_yOP#0`A+x#18>q8{+Lf{C%~+h5LscQeS*Qe{(O7n`nji7B>AJE&kb9db8G8h`y8 zxj&`J_amF+4}st6&6n8)rqnJH8A@<6iHRg8pyrQYsnt+|G?Xk|Nt+xduZa$~sb~6v)8uo|{DP4X06xCHSGA|u6C!Dos zJBw^$gV6e<*Dn{g3#-coFAX7#T>zKvWP zj|=W=rcQ;v9&|J5hV=H*@?1DF`w}ehGHgLA@Wq$!D~hB<#>ZapOfTEXvo%EleJ)?sga`eKoaD9?~v^?rboD9uVNiU4+ zMq2s2-Ac95TQ=q3MysQaGF`D!bS7?kz)hQ|eHhs-^l<_{zyQJ-HdkGi7Wkb>3u=Q4 zMJt(hSSYbD7#5(0_6hZWhyM2hAr1@mIp`-nWO|_=^(6ZHAn2Tt$wCr7w&p0={&V5q zW0g)uksOC9Ln__2{SSikO?P{~E`rA~N2s}Vewy2J)XU62&-Ad#USrDrnr?;OQIXuO z)5Oo~jvQoFGE;_9b4^d_b4-Po9fZ0<5bY~S;TKCG80ez{{<Q+LWv;L@O&>eMTjzSBSkrT!a^p zF}G^6;wda$GO0~P#7uT{t&B8!I8CT~p_G+|pytG2bo7qXvQ z$#ohV#FQRwT~8W)LpVPNT-|t*8#BmqN{6-*=-ngzgZ4r-l^k0 z!5JC0w#W~;r#}Qa#Cz3+*QlN}syB`5O=I>R)#u0J6ISTvge-mfl~J|KsHz%sQ>O!U gQ7=pAkCZer*q22GH2yas71Wr*dTf>TaBoxZUqsqN3;+NC literal 0 HcmV?d00001 diff --git a/mods/cnc/sequences/misc.yaml b/mods/cnc/sequences/misc.yaml index 33aa39ef28..8d5095f4c0 100644 --- a/mods/cnc/sequences/misc.yaml +++ b/mods/cnc/sequences/misc.yaml @@ -169,6 +169,10 @@ beacon: Start: 0 Length: 1 Offset: 0,-42 + clock: beaconclock + Start: 0 + Length: * + Offset: 0,-42 select: repair: diff --git a/mods/ra/bits/beaconclock.shp b/mods/ra/bits/beaconclock.shp new file mode 100644 index 0000000000000000000000000000000000000000..c18bc3e7601c447e61d58604b7920219285b599d GIT binary patch literal 3732 zcmbtV&re-N6h8MI-s9&(M6B2!W+Z zG}-vqgMGhA(oT$<40sE;3;54~U(QR~4g5~t=6wg;1AIH+*9wvz0zOp;{lLAPAMhK^ z*1j5Sp+(Z8=zp@s+6RIAfR_UP8#o0%+-mkjtBqR#ejM%B13uO!=@Y=Ov|0Z$@KeB> z0r$2``V8>X!M@mTyY$0w9f?lS%-~3UX=7W+TSc1{x;YbIt@=F zdD*92E)NYPrQshsWN2h`NPm4yN@F)uDHU(^OKJGdZ^>Iys@xfn{#eAkl=<@E@O(srco#Qec*}A*I5o=P=1wM(7mv>C^ayLMA$t1&L_H{evw5S)PL#L%(XCxA2 zoY(Y5kDK)9UD2=A;CItExlhe$mre>xr=GvdIkJ;c9Nqo{XNx3TWW_wgIbQeuZlBRN z?E^X`44_SCg`$yhOm!3c&xo@*lObakS>3t+o)V{$Ft4ui|7X}tSKiG_M%;VMx>J$uW}1lxbn|6Uup?#FkQ=U#Q6 zyW7YevX*`09kAX&Todx3#&S-&HI{LCNMor;kFDDdxN)w78z(2fT&zT|*2$aY%W|BR zhm~ba4(X^o;){>@3V3gMQm_TmP}=}EPTE>$tpaKOpojgk0e#E^l!zEIm^}+7UVIX$PfGv&E