From 711bad91a3c87a9437969c9afa1e355aa3f46389 Mon Sep 17 00:00:00 2001 From: Voidwalker Date: Thu, 28 Dec 2017 12:18:29 +0000 Subject: [PATCH] Generalize WormManager into ActorSpawnManager. Added support of multiple actors, conditions and types. --- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 2 + OpenRA.Mods.Common/Traits/ActorSpawner.cs | 34 +++++ .../Traits/World/ActorSpawnManager.cs | 116 ++++++++++++++++++ .../UtilityCommands/UpgradeRules.cs | 15 +++ OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj | 2 - OpenRA.Mods.D2k/Traits/Sandworm.cs | 6 +- OpenRA.Mods.D2k/Traits/World/WormManager.cs | 113 ----------------- OpenRA.Mods.D2k/Traits/WormSpawner.cs | 19 --- mods/d2k/maps/mount-idaho/rules.yaml | 2 +- mods/d2k/maps/oasis-conquest/rules.yaml | 2 +- mods/d2k/maps/pasty-mesa/rules.yaml | 2 +- mods/d2k/maps/shellmap/rules.yaml | 2 +- mods/d2k/rules/campaign-rules.yaml | 2 +- mods/d2k/rules/misc.yaml | 2 +- mods/d2k/rules/world.yaml | 3 +- 15 files changed, 178 insertions(+), 144 deletions(-) create mode 100644 OpenRA.Mods.Common/Traits/ActorSpawner.cs create mode 100644 OpenRA.Mods.Common/Traits/World/ActorSpawnManager.cs delete mode 100644 OpenRA.Mods.D2k/Traits/World/WormManager.cs delete mode 100644 OpenRA.Mods.D2k/Traits/WormSpawner.cs diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 8767e17ce7..a78dc915c3 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -552,6 +552,8 @@ + + diff --git a/OpenRA.Mods.Common/Traits/ActorSpawner.cs b/OpenRA.Mods.Common/Traits/ActorSpawner.cs new file mode 100644 index 0000000000..ea1c8b5723 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/ActorSpawner.cs @@ -0,0 +1,34 @@ +#region Copyright & License Information +/* + * Copyright 2007-2018 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; +using System.Collections.Generic; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("An actor with this trait indicates a valid spawn point for actors of ActorSpawnManager.")] + public class ActorSpawnerInfo : ConditionalTraitInfo + { + [Desc("Type of ActorSpawner with which it connects.")] + public readonly HashSet Types = new HashSet() { }; + + public override object Create(ActorInitializer init) { return new ActorSpawner(this); } + } + + public class ActorSpawner : ConditionalTrait + { + public ActorSpawner(ActorSpawnerInfo info) + : base(info) { } + + public HashSet Types { get { return Info.Types; } } + } +} diff --git a/OpenRA.Mods.Common/Traits/World/ActorSpawnManager.cs b/OpenRA.Mods.Common/Traits/World/ActorSpawnManager.cs new file mode 100644 index 0000000000..e10249e896 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/World/ActorSpawnManager.cs @@ -0,0 +1,116 @@ +#region Copyright & License Information +/* + * Copyright 2007-2018 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; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Controls the spawning of specified actor types. Attach this to the world actor.")] + public class ActorSpawnManagerInfo : ConditionalTraitInfo, Requires + { + [Desc("Minimum number of actors.")] + public readonly int Minimum = 0; + + [Desc("Maximum number of actors.")] + public readonly int Maximum = 4; + + [Desc("Time (in ticks) between actor spawn.")] + public readonly int SpawnInterval = 6000; + + [FieldLoader.Require] + [ActorReference] + [Desc("Name of the actor that will be randomly picked to spawn.")] + public readonly string[] Actors = { }; + + public readonly string Owner = "Creeps"; + + [Desc("Type of ActorSpawner with which it connects.")] + public readonly HashSet Types = new HashSet() { }; + + public override object Create(ActorInitializer init) { return new ActorSpawnManager(init.Self, this); } + } + + public class ActorSpawnManager : ConditionalTrait, ITick, INotifyCreated + { + readonly ActorSpawnManagerInfo info; + TraitPair[] spawnPointActors; + + bool enabled; + int spawnCountdown; + int actorsPresent; + + public ActorSpawnManager(Actor self, ActorSpawnManagerInfo info) : base(info) + { + this.info = info; + } + + void INotifyCreated.Created(Actor self) + { + self.World.AddFrameEndTask(w => + { + spawnPointActors = w.ActorsWithTrait() + .Where(x => info.Types.Overlaps(x.Trait.Types) || !x.Trait.Types.Any()) + .ToArray(); + + enabled = self.Trait().Enabled && spawnPointActors.Any(); + }); + } + + void ITick.Tick(Actor self) + { + if (IsTraitDisabled || !enabled) + return; + + if (info.Maximum < 1 || actorsPresent >= info.Maximum) + return; + + if (--spawnCountdown > 0 && actorsPresent >= info.Minimum) + return; + + spawnCountdown = info.SpawnInterval; + + do + { + // Always spawn at least one actor, plus + // however many needed to reach the minimum. + SpawnActor(self); + } while (actorsPresent < info.Minimum); + } + + WPos SpawnActor(Actor self) + { + var spawnPoint = GetRandomSpawnPoint(self.World.SharedRandom); + self.World.AddFrameEndTask(w => w.CreateActor(info.Actors.Random(self.World.SharedRandom), new TypeDictionary + { + new OwnerInit(w.Players.First(x => x.PlayerName == info.Owner)), + new LocationInit(spawnPoint.Location) + })); + + actorsPresent++; + + return spawnPoint.CenterPosition; + } + + Actor GetRandomSpawnPoint(Support.MersenneTwister random) + { + return spawnPointActors.Random(random).Actor; + } + + public void DecreaseActorCount() + { + actorsPresent--; + } + } +} diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 3d40f70088..8d9c2156bb 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -1635,6 +1635,21 @@ namespace OpenRA.Mods.Common.UtilityCommands } } + if (engineVersion < 20180225) + { + if (node.Key == "WormSpawner") + RenameNodeKey(node, "ActorSpawner"); + + if (node.Key == "WormManager") + { + RenameNodeKey(node, "ActorSpawnManager"); + + var wormSignature = node.Value.Nodes.FirstOrDefault(n => n.Key == "WormSignature"); + if (wormSignature != null) + wormSignature.Key = "Actors"; + } + } + UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1); } diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj index bfed6c8eec..3f2340997f 100644 --- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj +++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj @@ -80,9 +80,7 @@ - - diff --git a/OpenRA.Mods.D2k/Traits/Sandworm.cs b/OpenRA.Mods.D2k/Traits/Sandworm.cs index 5a21607921..30f310293b 100644 --- a/OpenRA.Mods.D2k/Traits/Sandworm.cs +++ b/OpenRA.Mods.D2k/Traits/Sandworm.cs @@ -37,7 +37,7 @@ namespace OpenRA.Mods.D2k.Traits { public readonly SandwormInfo WormInfo; - readonly WormManager manager; + readonly ActorSpawnManager manager; readonly Mobile mobile; readonly AttackBase attackTrait; @@ -54,7 +54,7 @@ namespace OpenRA.Mods.D2k.Traits WormInfo = info; mobile = self.Trait(); attackTrait = self.Trait(); - manager = self.World.WorldActor.Trait(); + manager = self.World.WorldActor.Trait(); } public override void DoAction(Actor self, CPos targetCell) @@ -140,7 +140,7 @@ namespace OpenRA.Mods.D2k.Traits if (disposed) return; - manager.DecreaseWormCount(); + manager.DecreaseActorCount(); disposed = true; } } diff --git a/OpenRA.Mods.D2k/Traits/World/WormManager.cs b/OpenRA.Mods.D2k/Traits/World/WormManager.cs deleted file mode 100644 index 8044624ef9..0000000000 --- a/OpenRA.Mods.D2k/Traits/World/WormManager.cs +++ /dev/null @@ -1,113 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2018 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; -using System.Collections.Generic; -using System.Linq; -using OpenRA.Mods.Common.Traits; -using OpenRA.Primitives; -using OpenRA.Traits; - -namespace OpenRA.Mods.D2k.Traits -{ - [Desc("Controls the spawning of sandworms. Attach this to the world actor.")] - class WormManagerInfo : ITraitInfo, Requires - { - [Desc("Minimum number of worms")] - public readonly int Minimum = 0; - - [Desc("Maximum number of worms")] - public readonly int Maximum = 4; - - [Desc("Time (in ticks) between worm spawn.")] - public readonly int SpawnInterval = 6000; - - [Desc("Name of the actor that will be spawned.")] - public readonly string WormSignature = "sandworm"; - - public readonly string WormSignNotification = "WormSign"; - public readonly string WormOwnerPlayer = "Creeps"; - - public object Create(ActorInitializer init) { return new WormManager(init.Self, this); } - } - - class WormManager : ITick, INotifyCreated - { - readonly WormManagerInfo info; - readonly Lazy spawnPointActors; - - bool enabled; - int spawnCountdown; - int wormsPresent; - - public WormManager(Actor self, WormManagerInfo info) - { - this.info = info; - spawnPointActors = Exts.Lazy(() => self.World.ActorsHavingTrait().ToArray()); - } - - void INotifyCreated.Created(Actor self) - { - enabled = self.Trait().Enabled; - } - - void ITick.Tick(Actor self) - { - if (!enabled) - return; - - if (!spawnPointActors.Value.Any()) - return; - - // Apparently someone doesn't want worms or the maximum number of worms has been reached - if (info.Maximum < 1 || wormsPresent >= info.Maximum) - return; - - if (--spawnCountdown > 0 && wormsPresent >= info.Minimum) - return; - - spawnCountdown = info.SpawnInterval; - - var wormLocations = new List(); - - do - { - // Always spawn at least one worm, plus however many - // more we need to reach the defined minimum count. - wormLocations.Add(SpawnWorm(self)); - } while (wormsPresent < info.Minimum); - } - - WPos SpawnWorm(Actor self) - { - var spawnPoint = GetRandomSpawnPoint(self); - self.World.AddFrameEndTask(w => w.CreateActor(info.WormSignature, new TypeDictionary - { - new OwnerInit(w.Players.First(x => x.PlayerName == info.WormOwnerPlayer)), - new LocationInit(spawnPoint.Location) - })); - - wormsPresent++; - - return spawnPoint.CenterPosition; - } - - Actor GetRandomSpawnPoint(Actor self) - { - return spawnPointActors.Value.Random(self.World.SharedRandom); - } - - public void DecreaseWormCount() - { - wormsPresent--; - } - } -} diff --git a/OpenRA.Mods.D2k/Traits/WormSpawner.cs b/OpenRA.Mods.D2k/Traits/WormSpawner.cs deleted file mode 100644 index 499e1a0f3d..0000000000 --- a/OpenRA.Mods.D2k/Traits/WormSpawner.cs +++ /dev/null @@ -1,19 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2018 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 OpenRA.Traits; - -namespace OpenRA.Mods.D2k.Traits -{ - [Desc("An actor with this trait indicates a valid spawn point for sandworms.")] - class WormSpawnerInfo : TraitInfo { } - class WormSpawner { } -} \ No newline at end of file diff --git a/mods/d2k/maps/mount-idaho/rules.yaml b/mods/d2k/maps/mount-idaho/rules.yaml index 114a8bf4e9..eb556d164f 100644 --- a/mods/d2k/maps/mount-idaho/rules.yaml +++ b/mods/d2k/maps/mount-idaho/rules.yaml @@ -1,4 +1,4 @@ World: - WormManager: + ActorSpawnManager: Minimum: 1 Maximum: 2 diff --git a/mods/d2k/maps/oasis-conquest/rules.yaml b/mods/d2k/maps/oasis-conquest/rules.yaml index 363d4add29..93bcc8dd13 100644 --- a/mods/d2k/maps/oasis-conquest/rules.yaml +++ b/mods/d2k/maps/oasis-conquest/rules.yaml @@ -1,4 +1,4 @@ World: - WormManager: + ActorSpawnManager: Minimum: 3 Maximum: 6 diff --git a/mods/d2k/maps/pasty-mesa/rules.yaml b/mods/d2k/maps/pasty-mesa/rules.yaml index 114a8bf4e9..eb556d164f 100644 --- a/mods/d2k/maps/pasty-mesa/rules.yaml +++ b/mods/d2k/maps/pasty-mesa/rules.yaml @@ -1,4 +1,4 @@ World: - WormManager: + ActorSpawnManager: Minimum: 1 Maximum: 2 diff --git a/mods/d2k/maps/shellmap/rules.yaml b/mods/d2k/maps/shellmap/rules.yaml index 402728dfb1..9579520ef8 100644 --- a/mods/d2k/maps/shellmap/rules.yaml +++ b/mods/d2k/maps/shellmap/rules.yaml @@ -8,7 +8,7 @@ World: -MPStartLocations: ResourceType@Spice: ValuePerUnit: 0 - WormManager: + ActorSpawnManager: Minimum: 1 Maximum: 3 MusicPlaylist: diff --git a/mods/d2k/rules/campaign-rules.yaml b/mods/d2k/rules/campaign-rules.yaml index 38ee587331..7807fed2d2 100644 --- a/mods/d2k/rules/campaign-rules.yaml +++ b/mods/d2k/rules/campaign-rules.yaml @@ -16,7 +16,7 @@ World: -MPStartLocations: ObjectivesPanel: PanelName: MISSION_OBJECTIVES - WormManager: + ActorSpawnManager: Minimum: 1 Maximum: 1 MapCreeps: diff --git a/mods/d2k/rules/misc.yaml b/mods/d2k/rules/misc.yaml index 2bc5abd3da..e2eefdc98b 100644 --- a/mods/d2k/rules/misc.yaml +++ b/mods/d2k/rules/misc.yaml @@ -204,7 +204,7 @@ wormspawner: WithSpriteBody: BodyOrientation: QuantizedFacings: 1 - WormSpawner: + ActorSpawner: EditorTilesetFilter: Categories: System diff --git a/mods/d2k/rules/world.yaml b/mods/d2k/rules/world.yaml index 427a864fbf..03067b25c7 100644 --- a/mods/d2k/rules/world.yaml +++ b/mods/d2k/rules/world.yaml @@ -72,7 +72,8 @@ World: BuildingInfluence: ProductionQueueFromSelection: ProductionPaletteWidget: PRODUCTION_PALETTE - WormManager: + ActorSpawnManager: + Actors: sandworm CrateSpawner: Minimum: 0 Maximum: 2