From 871576b3006e9f91e853f20b4fbbd2a2f3259cdb Mon Sep 17 00:00:00 2001 From: reaperrr Date: Sat, 5 Nov 2016 18:52:37 +0100 Subject: [PATCH 1/7] Add delay and full duration support to beacons Previously, support power beacons were hardcoded to unlimited duration and then cleaned up directly by the support power. This is problematic if we want the beacon to remove itself after a certain delay, though. --- OpenRA.Mods.Common/Effects/Beacon.cs | 17 +++++++++++++---- .../Traits/SupportPowers/AirstrikePower.cs | 2 +- OpenRA.Mods.TS/Effects/AnimatedBeacon.cs | 10 +++++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/OpenRA.Mods.Common/Effects/Beacon.cs b/OpenRA.Mods.Common/Effects/Beacon.cs index 434df3b015..059e7ab9b4 100644 --- a/OpenRA.Mods.Common/Effects/Beacon.cs +++ b/OpenRA.Mods.Common/Effects/Beacon.cs @@ -32,18 +32,21 @@ namespace OpenRA.Mods.Common.Effects readonly Animation clock; readonly int duration; + int delay; int arrowHeight = MaxArrowHeight; int arrowSpeed = 50; int tick; // Player-placed beacons are removed after a delay - public Beacon(Player owner, WPos position, int duration, string beaconPalette, bool isPlayerPalette, string beaconCollection, string arrowSprite, string circleSprite) + public Beacon(Player owner, WPos position, int duration, string beaconPalette, bool isPlayerPalette, + string beaconCollection, string arrowSprite, string circleSprite, int delay = 0) { this.owner = owner; this.position = position; this.beaconPalette = beaconPalette; this.isPlayerPalette = isPlayerPalette; this.duration = duration; + this.delay = delay; if (!string.IsNullOrEmpty(arrowSprite)) { @@ -58,10 +61,10 @@ namespace OpenRA.Mods.Common.Effects } } - // Support power beacons are expected to clean themselves up + // By default, support power beacons are expected to clean themselves up public Beacon(Player owner, WPos position, bool isPlayerPalette, string palette, string posterCollection, string posterType, string posterPalette, - string arrowSequence, string circleSequence, string clockSequence, Func clockFraction) - : this(owner, position, -1, palette, isPlayerPalette, posterCollection, arrowSequence, circleSequence) + string arrowSequence, string circleSequence, string clockSequence, Func clockFraction, int delay = 0, int duration = -1) + : this(owner, position, duration, palette, isPlayerPalette, posterCollection, arrowSequence, circleSequence, delay) { this.posterPalette = posterPalette; @@ -80,6 +83,9 @@ namespace OpenRA.Mods.Common.Effects void IEffect.Tick(World world) { + if (delay-- > 0) + return; + arrowHeight += arrowSpeed; var clamped = arrowHeight.Clamp(0, MaxArrowHeight); if (arrowHeight != clamped) @@ -105,6 +111,9 @@ namespace OpenRA.Mods.Common.Effects IEnumerable IEffectAboveShroud.RenderAboveShroud(WorldRenderer r) { + if (delay > 0) + yield break; + if (!owner.IsAlliedWith(owner.World.RenderPlayer)) yield break; diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs index 6ae356a9ea..2b5db5d083 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs @@ -176,7 +176,7 @@ namespace OpenRA.Mods.Common.Traits Info.ArrowSequence, Info.CircleSequence, Info.ClockSequence, - () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance); + () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance); w.Add(beacon); } diff --git a/OpenRA.Mods.TS/Effects/AnimatedBeacon.cs b/OpenRA.Mods.TS/Effects/AnimatedBeacon.cs index 317dd2b596..c537af4a9e 100644 --- a/OpenRA.Mods.TS/Effects/AnimatedBeacon.cs +++ b/OpenRA.Mods.TS/Effects/AnimatedBeacon.cs @@ -27,15 +27,17 @@ namespace OpenRA.Mods.TS.Effects readonly Animation beacon; readonly int duration; + int delay; int tick; - public AnimatedBeacon(Player owner, WPos position, int duration, string beaconPalette, bool isPlayerPalette, string beaconImage, string beaconSequence) + public AnimatedBeacon(Player owner, WPos position, int duration, string beaconPalette, bool isPlayerPalette, string beaconImage, string beaconSequence, int delay = 0) { this.owner = owner; this.position = position; this.beaconPalette = beaconPalette; this.isPlayerPalette = isPlayerPalette; this.duration = duration; + this.delay = delay; if (!string.IsNullOrEmpty(beaconSequence)) { @@ -49,6 +51,9 @@ namespace OpenRA.Mods.TS.Effects void IEffect.Tick(World world) { + if (delay-- > 0) + return; + if (beacon != null) beacon.Tick(); @@ -60,6 +65,9 @@ namespace OpenRA.Mods.TS.Effects IEnumerable IEffectAboveShroud.RenderAboveShroud(WorldRenderer r) { + if (delay > 0) + return SpriteRenderable.None; + if (beacon == null) return SpriteRenderable.None; From aa53553cdf482c79172437a23bc5008c2454ff01 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Sat, 5 Nov 2016 23:05:30 +0100 Subject: [PATCH 2/7] Add BeaconDelay to SupportPower --- OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs | 3 ++- OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs | 3 +++ OpenRA.Mods.RA/Traits/SupportPowers/ParatroopersPower.cs | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs index 2b5db5d083..f5107d0d35 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/AirstrikePower.cs @@ -176,7 +176,8 @@ namespace OpenRA.Mods.Common.Traits Info.ArrowSequence, Info.CircleSequence, Info.ClockSequence, - () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance); + () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance, + Info.BeaconDelay); w.Add(beacon); } diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs index 6432579b9c..d323dd8b2e 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/SupportPower.cs @@ -64,6 +64,9 @@ namespace OpenRA.Mods.Common.Traits [SequenceReference("BeaconImage")] public readonly string ArrowSequence = "arrow"; [SequenceReference("BeaconImage")] public readonly string CircleSequence = "circles"; + [Desc("Delay after launch, measured in ticks.")] + public readonly int BeaconDelay = 0; + public readonly bool DisplayRadarPing = false; [Desc("Measured in ticks.")] diff --git a/OpenRA.Mods.RA/Traits/SupportPowers/ParatroopersPower.cs b/OpenRA.Mods.RA/Traits/SupportPowers/ParatroopersPower.cs index a48efa983a..c97d234220 100644 --- a/OpenRA.Mods.RA/Traits/SupportPowers/ParatroopersPower.cs +++ b/OpenRA.Mods.RA/Traits/SupportPowers/ParatroopersPower.cs @@ -212,7 +212,8 @@ namespace OpenRA.Mods.RA.Traits Info.ArrowSequence, Info.CircleSequence, Info.ClockSequence, - () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance); + () => 1 - ((distanceTestActor.CenterPosition - target).HorizontalLength - info.BeaconDistanceOffset.Length) * 1f / distance, + Info.BeaconDelay); w.Add(beacon); } From 79add6113c658536dc89390a8c033d4e658a780d Mon Sep 17 00:00:00 2001 From: reaperrr Date: Sat, 5 Nov 2016 18:52:58 +0100 Subject: [PATCH 3/7] Add RevealShroudEffect This allows support powers etc. to reveal shroud for customizable amount of ticks and after customizable delay, instead of spawning camera actors. --- .../Effects/RevealShroudEffect.cs | 81 +++++++++++++++++++ OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 + 2 files changed, 82 insertions(+) create mode 100644 OpenRA.Mods.Common/Effects/RevealShroudEffect.cs diff --git a/OpenRA.Mods.Common/Effects/RevealShroudEffect.cs b/OpenRA.Mods.Common/Effects/RevealShroudEffect.cs new file mode 100644 index 0000000000..116bffd7a2 --- /dev/null +++ b/OpenRA.Mods.Common/Effects/RevealShroudEffect.cs @@ -0,0 +1,81 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Effects +{ + public class RevealShroudEffect : IEffect + { + static readonly PPos[] NoCells = { }; + + readonly WPos pos; + readonly Player player; + readonly Shroud.SourceType sourceType; + readonly WDist revealRadius; + readonly Stance validStances; + readonly int duration; + + int ticks; + + public RevealShroudEffect(WPos pos, WDist radius, Shroud.SourceType type, Player forPlayer, Stance stances, int delay = 0, int duration = 50) + { + this.pos = pos; + player = forPlayer; + revealRadius = radius; + validStances = stances; + sourceType = type; + this.duration = duration; + ticks = -delay; + } + + void AddCellsToPlayerShroud(Player p, PPos[] uv) { if (!validStances.HasStance(p.Stances[player])) return; p.Shroud.AddSource(this, sourceType, uv); } + + void RemoveCellsFromPlayerShroud(Player p) { p.Shroud.RemoveSource(this); } + + PPos[] ProjectedCells(World world) + { + var map = world.Map; + var range = revealRadius; + if (range == WDist.Zero) + return NoCells; + + return Shroud.ProjectedCellsInRange(map, pos, range) + .ToArray(); + } + + public void Tick(World world) + { + if (ticks == 0) + { + var cells = ProjectedCells(world); + foreach (var p in world.Players) + AddCellsToPlayerShroud(p, cells); + } + + if (ticks == duration) + { + foreach (var p in world.Players) + RemoveCellsFromPlayerShroud(p); + + world.AddFrameEndTask(w => w.Remove(this)); + } + + ticks++; + } + + public IEnumerable Render(WorldRenderer wr) { return SpriteRenderable.None; } + } +} diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 93aaa12c61..51e210ca26 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -138,6 +138,7 @@ + From 079908d238fda1463f920f0099a7101fd8aeebe3 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Sat, 5 Nov 2016 21:27:38 +0100 Subject: [PATCH 4/7] Make NukePower use RevealShroudEffect instead of camera actor Additionally, remove the DelayedAction and let the beacon remove itself instead. --- .../Traits/SupportPowers/NukePower.cs | 34 ++++++------------- mods/cnc/rules/structures.yaml | 2 +- mods/d2k/rules/structures.yaml | 2 +- mods/ra/rules/structures.yaml | 2 +- mods/ts/rules/nod-support.yaml | 2 +- 5 files changed, 15 insertions(+), 27 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs index 5630466860..cd6d760e14 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs @@ -54,9 +54,11 @@ namespace OpenRA.Mods.Common.Traits [Desc("Amount of time before detonation to remove the beacon")] public readonly int BeaconRemoveAdvance = 25; - [ActorReference] - [Desc("Actor to spawn before detonation")] - public readonly string CameraActor = null; + [Desc("Range of cells the camera should reveal around target cell.")] + public readonly WDist CameraRange = WDist.Zero; + + [Desc("Reveal cells to players with these stances only.")] + public readonly Stance CameraStances = Stance.Ally; [Desc("Amount of time before detonation to spawn the camera")] public readonly int CameraSpawnAdvance = 25; @@ -114,19 +116,10 @@ namespace OpenRA.Mods.Common.Traits self.World.AddFrameEndTask(w => w.Add(missile)); - if (info.CameraActor != null) + if (info.CameraRange != WDist.Zero) { - var camera = self.World.CreateActor(false, info.CameraActor, new TypeDictionary - { - new LocationInit(order.TargetLocation), - new OwnerInit(self.Owner), - }); - - camera.QueueActivity(new Wait(info.CameraSpawnAdvance + info.CameraRemoveDelay)); - camera.QueueActivity(new RemoveSelf()); - - Action addCamera = () => self.World.AddFrameEndTask(w => w.Add(camera)); - self.World.AddFrameEndTask(w => w.Add(new DelayedAction(info.FlightDelay - info.CameraSpawnAdvance, addCamera))); + self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, Shroud.SourceType.Visibility, self.Owner, info.CameraStances, + info.FlightDelay - info.CameraSpawnAdvance, info.CameraSpawnAdvance + info.CameraRemoveDelay))); } if (Info.DisplayBeacon) @@ -142,18 +135,13 @@ namespace OpenRA.Mods.Common.Traits Info.ArrowSequence, Info.CircleSequence, Info.ClockSequence, - () => missile.FractionComplete); - - Action removeBeacon = () => self.World.AddFrameEndTask(w => - { - w.Remove(beacon); - beacon = null; - }); + () => missile.FractionComplete, + Info.BeaconDelay, + info.FlightDelay - info.BeaconRemoveAdvance); self.World.AddFrameEndTask(w => { w.Add(beacon); - w.Add(new DelayedAction(info.FlightDelay - info.BeaconRemoveAdvance, removeBeacon)); }); } } diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml index bdd61aa228..06a1c452a5 100644 --- a/mods/cnc/rules/structures.yaml +++ b/mods/cnc/rules/structures.yaml @@ -633,7 +633,7 @@ TMPL: BeaconPoster: atomic BeaconPosterPalette: beaconposter DisplayRadarPing: True - CameraActor: camera + CameraRange: 10c0 SupportPowerChargeBar: Power: Amount: -150 diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 4630126854..769e780d10 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -951,7 +951,7 @@ palace: SpawnOffset: -512,1c171,0 DisplayBeacon: True DisplayRadarPing: True - CameraActor: camera + CameraRange: 10c0 ActivationSequence: ProduceActorPower@fremen: Description: Recruit Fremen diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index 2520993e2b..490a26c410 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -36,8 +36,8 @@ MSLO: DisplayBeacon: True DisplayRadarPing: True BeaconPoster: atomicon - CameraActor: camera FlashType: Nuke + CameraRange: 10c0 CanPowerDown: PowerupSound: EnablePower PowerdownSound: DisablePower diff --git a/mods/ts/rules/nod-support.yaml b/mods/ts/rules/nod-support.yaml index 62606a522c..0739de0296 100644 --- a/mods/ts/rules/nod-support.yaml +++ b/mods/ts/rules/nod-support.yaml @@ -272,6 +272,6 @@ NAMISL: DisplayBeacon: False DisplayRadarPing: True BeaconPoster: - CameraActor: camera + CameraRange: 10c0 SelectionDecorations: VisualBounds: 75,48 From ec5c3a710dd54ebff3192bdee329631e768526ea Mon Sep 17 00:00:00 2001 From: reaperrr Date: Sat, 5 Nov 2016 21:31:51 +0100 Subject: [PATCH 5/7] NukePower description style fixes --- .../Traits/SupportPowers/NukePower.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs index cd6d760e14..449ee5ddb3 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs @@ -39,19 +39,19 @@ namespace OpenRA.Mods.Common.Traits [Desc("Palette to use for the missile weapon image.")] [PaletteReference("IsPlayerPalette")] public readonly string MissilePalette = "effect"; - [Desc("Custom palette is a player palette BaseName")] + [Desc("Custom palette is a player palette BaseName.")] public readonly bool IsPlayerPalette = false; - [Desc("Travel time - split equally between ascent and descent")] + [Desc("Travel time - split equally between ascent and descent.")] public readonly int FlightDelay = 400; - [Desc("Visual ascent velocity in WDist / tick")] + [Desc("Visual ascent velocity in WDist / tick.")] public readonly WDist FlightVelocity = new WDist(512); - [Desc("Descend immediately on the target, with half the FlightDelay")] + [Desc("Descend immediately on the target, with half the FlightDelay.")] public readonly bool SkipAscent = false; - [Desc("Amount of time before detonation to remove the beacon")] + [Desc("Amount of time before detonation to remove the beacon.")] public readonly int BeaconRemoveAdvance = 25; [Desc("Range of cells the camera should reveal around target cell.")] @@ -60,10 +60,10 @@ namespace OpenRA.Mods.Common.Traits [Desc("Reveal cells to players with these stances only.")] public readonly Stance CameraStances = Stance.Ally; - [Desc("Amount of time before detonation to spawn the camera")] + [Desc("Amount of time before detonation to spawn the camera.")] public readonly int CameraSpawnAdvance = 25; - [Desc("Amount of time after detonation to remove the camera")] + [Desc("Amount of time after detonation to remove the camera.")] public readonly int CameraRemoveDelay = 25; [Desc("Corresponds to `Type` from `FlashPaletteEffect` on the world actor.")] From e582ba759f230462f91b6c79ae729910a8f454a9 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Sat, 5 Nov 2016 23:56:03 +0100 Subject: [PATCH 6/7] NukePower CameraActor removal upgrade rule --- .../UtilityCommands/UpgradeRules.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index f43ce3a431..5c03999e99 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -704,6 +704,22 @@ namespace OpenRA.Mods.Common.UtilityCommands RenameNodeKey(node, "-ConditionManager"); } + // Replaced NukePower CameraActor with CameraRange (effect-based reveal) + if (engineVersion < 20161227) + { + var nukePower = node.Value.Nodes.FirstOrDefault(n => n.Key.StartsWith("NukePower")); + if (nukePower != null) + { + var cameraActor = nukePower.Value.Nodes.FirstOrDefault(n => n.Key == "CameraActor"); + if (cameraActor != null) + { + nukePower.Value.Nodes.Remove(cameraActor); + nukePower.Value.Nodes.Add(new MiniYamlNode("CameraRange", "10")); + Console.WriteLine("If your camera actor had a different reveal range than 10, you'll need to correct that manually"); + } + } + } + UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1); } From f6924d740ec70bf5db15066b9b26536703ad495b Mon Sep 17 00:00:00 2001 From: reaperrr Date: Mon, 5 Dec 2016 21:49:47 +0100 Subject: [PATCH 7/7] Add RevealGeneratedShroud toggle to NukePower To give modders a choice. --- OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs index 449ee5ddb3..d5a2438a44 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs @@ -57,6 +57,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Range of cells the camera should reveal around target cell.")] public readonly WDist CameraRange = WDist.Zero; + [Desc("Can the camera reveal shroud generated by the GeneratesShroud trait?")] + public readonly bool RevealGeneratedShroud = true; + [Desc("Reveal cells to players with these stances only.")] public readonly Stance CameraStances = Stance.Ally; @@ -118,7 +121,10 @@ namespace OpenRA.Mods.Common.Traits if (info.CameraRange != WDist.Zero) { - self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, Shroud.SourceType.Visibility, self.Owner, info.CameraStances, + var type = info.RevealGeneratedShroud ? Shroud.SourceType.Visibility + : Shroud.SourceType.PassiveVisibility; + + self.World.AddFrameEndTask(w => w.Add(new RevealShroudEffect(targetPosition, info.CameraRange, type, self.Owner, info.CameraStances, info.FlightDelay - info.CameraSpawnAdvance, info.CameraSpawnAdvance + info.CameraRemoveDelay))); }