diff --git a/OpenRA.Mods.Common/Traits/KillsSelf.cs b/OpenRA.Mods.Common/Traits/KillsSelf.cs index 8cf55e8489..7714115366 100644 --- a/OpenRA.Mods.Common/Traits/KillsSelf.cs +++ b/OpenRA.Mods.Common/Traits/KillsSelf.cs @@ -18,13 +18,21 @@ namespace OpenRA.Mods.Common.Traits [Desc("Remove the actor from the world (and destroy it) instead of killing it.")] public readonly bool RemoveInstead = false; - public override object Create(ActorInitializer init) { return new KillsSelf(this); } + [Desc("The amount of time (in ticks) before the actor dies. Two values indicate a range between which a random value is chosen.")] + public readonly int[] Delay = { 250 }; + + public override object Create(ActorInitializer init) { return new KillsSelf(init.Self, this); } } - class KillsSelf : ConditionalTrait, INotifyAddedToWorld + class KillsSelf : ConditionalTrait, INotifyAddedToWorld, ITick { - public KillsSelf(KillsSelfInfo info) - : base(info) { } + int lifetime; + + public KillsSelf(Actor self, KillsSelfInfo info) + : base(info) + { + lifetime = Util.RandomDelay(self.World, info.Delay); + } public void AddedToWorld(Actor self) { @@ -37,10 +45,30 @@ namespace OpenRA.Mods.Common.Traits if (self.IsDead) return; + if (lifetime > 0) + return; + if (Info.RemoveInstead || !self.Info.HasTraitInfo()) self.Dispose(); else self.Kill(self); } + + void ITick.Tick(Actor self) + { + if (self.IsDead || IsTraitDisabled) + return; + + if (!self.World.Map.Contains(self.Location)) + return; + + if (lifetime-- == 0) + { + if (Info.RemoveInstead || !self.Info.HasTraitInfo()) + self.Dispose(); + else + self.Kill(self); + } + } } } diff --git a/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs b/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs index 24df531d2d..9de38d242d 100644 --- a/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs +++ b/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs @@ -40,7 +40,7 @@ namespace OpenRA.Mods.Common.Traits.Sound public AmbientSound(Actor self, AmbientSoundInfo info) : base(info) { - delay = RandomDelay(self.World, info.Delay); + delay = Util.RandomDelay(self.World, info.Delay); loop = Info.Interval.Length == 0 || (Info.Interval.Length == 1 && Info.Interval[0] == 0); } @@ -63,7 +63,7 @@ namespace OpenRA.Mods.Common.Traits.Sound { StartSound(self); if (!loop) - delay = RandomDelay(self.World, Info.Interval); + delay = Util.RandomDelay(self.World, Info.Interval); } } @@ -89,18 +89,7 @@ namespace OpenRA.Mods.Common.Traits.Sound currentSound = null; } - static int RandomDelay(World world, int[] range) - { - if (range.Length == 0) - return 0; - - if (range.Length == 1) - return range[0]; - - return world.SharedRandom.Next(range[0], range[1]); - } - - protected override void TraitEnabled(Actor self) { delay = RandomDelay(self.World, Info.Delay); } + protected override void TraitEnabled(Actor self) { delay = Util.RandomDelay(self.World, Info.Delay); } protected override void TraitDisabled(Actor self) { StopSound(); } void INotifyRemovedFromWorld.RemovedFromWorld(Actor self) { StopSound(); } diff --git a/OpenRA.Mods.Common/Util.cs b/OpenRA.Mods.Common/Util.cs index cbd10b5b0a..f2820bf75e 100644 --- a/OpenRA.Mods.Common/Util.cs +++ b/OpenRA.Mods.Common/Util.cs @@ -164,5 +164,16 @@ namespace OpenRA.Mods.Common yield return p; } } + + public static int RandomDelay(World world, int[] range) + { + if (range.Length == 0) + return 0; + + if (range.Length == 1) + return range[0]; + + return world.SharedRandom.Next(range[0], range[1]); + } } } diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index f706c08cbb..d147f7aa05 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -781,6 +781,26 @@ namespace OpenRA.Mods.Common.UtilityCommands if (node.Key.StartsWith("UpgradeOverlay", StringComparison.Ordinal)) RenameNodeKey(node, "WithColoredOverlay" + node.Key.Substring(14)); + // Remove SpiceBloom.RespawnDelay to get rid of DelayedAction, and rename GrowthDelay to Lifetime + if (engineVersion < 20170203) + { + var spiceBloom = node.Value.Nodes.FirstOrDefault(n => n.Key == "SpiceBloom"); + if (spiceBloom != null) + { + var respawnDelay = spiceBloom.Value.Nodes.FirstOrDefault(n => n.Key == "RespawnDelay"); + if (respawnDelay != null) + { + spiceBloom.Value.Nodes.Remove(respawnDelay); + Console.WriteLine("RespawnDelay has been removed from SpiceBloom for technical reasons."); + Console.WriteLine("Increase self-kill delay of the spice bloom spawnpoint actor instead."); + } + + var growthDelay = spiceBloom.Value.Nodes.FirstOrDefault(n => n.Key == "GrowthDelay"); + if (growthDelay != null) + growthDelay.Key = "Lifetime"; + } + } + UpgradeActorRules(modData, engineVersion, ref node.Value.Nodes, node, depth + 1); } diff --git a/OpenRA.Mods.D2k/Traits/SpiceBloom.cs b/OpenRA.Mods.D2k/Traits/SpiceBloom.cs index 334185b7e8..2989d48f04 100644 --- a/OpenRA.Mods.D2k/Traits/SpiceBloom.cs +++ b/OpenRA.Mods.D2k/Traits/SpiceBloom.cs @@ -32,11 +32,8 @@ namespace OpenRA.Mods.D2k.Traits [SequenceReference] public readonly string[] GrowthSequences = { "grow1", "grow2", "grow3" }; - [Desc("The range of time (in ticks) that the spicebloom will take to respawn.")] - public readonly int[] RespawnDelay = { 1500, 2500 }; - - [Desc("The range of time (in ticks) that the spicebloom will take to grow.")] - public readonly int[] GrowthDelay = { 1000, 3000 }; + [Desc("The range of time (in ticks) that the spicebloom will take to grow until it blows up.")] + public readonly int[] Lifetime = { 1000, 3000 }; public readonly string ResourceType = "Spice"; @@ -72,7 +69,6 @@ namespace OpenRA.Mods.D2k.Traits readonly ResourceLayer resLayer; readonly AnimationWithOffset anim; - readonly int respawnTicks; readonly int growTicks; int ticks; @@ -88,12 +84,11 @@ namespace OpenRA.Mods.D2k.Traits anim = new AnimationWithOffset(new Animation(init.Self.World, render.GetImage(self)), null, () => self.IsDead); render.Add(anim); - respawnTicks = self.World.SharedRandom.Next(info.RespawnDelay[0], info.RespawnDelay[1]); - growTicks = self.World.SharedRandom.Next(info.GrowthDelay[0], info.GrowthDelay[1]); + growTicks = self.World.SharedRandom.Next(info.Lifetime[0], info.Lifetime[1]); anim.Animation.Play(info.GrowthSequences[0]); } - public void Tick(Actor self) + void ITick.Tick(Actor self) { if (!self.World.Map.Contains(self.Location)) return; @@ -158,24 +153,22 @@ namespace OpenRA.Mods.D2k.Traits } } - public void Killed(Actor self, AttackInfo e) + void INotifyKilled.Killed(Actor self, AttackInfo e) { if (!string.IsNullOrEmpty(info.Weapon)) SeedResources(self); - self.World.AddFrameEndTask(t => t.Add(new DelayedAction(respawnTicks, () => + var td = new TypeDictionary { - var td = new TypeDictionary - { - new ParentActorInit(self), - new LocationInit(self.Location), - new CenterPositionInit(self.CenterPosition), - new OwnerInit(self.Owner), - new FactionInit(self.Owner.Faction.InternalName), - new SkipMakeAnimsInit() - }; - self.World.CreateActor(info.SpawnActor, td); - }))); + new ParentActorInit(self), + new LocationInit(self.Location), + new CenterPositionInit(self.CenterPosition), + new OwnerInit(self.Owner), + new FactionInit(self.Owner.Faction.InternalName), + new SkipMakeAnimsInit() + }; + + self.World.AddFrameEndTask(w => w.CreateActor(info.SpawnActor, td)); } } } diff --git a/mods/d2k/rules/arrakis.yaml b/mods/d2k/rules/arrakis.yaml index f5873ab319..228664f7bf 100644 --- a/mods/d2k/rules/arrakis.yaml +++ b/mods/d2k/rules/arrakis.yaml @@ -1,22 +1,30 @@ spicebloom.spawnpoint: - HiddenUnderShroud: - Type: CenterPosition + EditorOnlyTooltip: + Name: Spice Bloom spawnpoint + AlwaysVisible: + RenderSpritesEditorOnly: + Image: spicebloom + Palette: effect50alpha + WithSpriteBody: + Sequence: grow3 BodyOrientation: QuantizedFacings: 1 - RenderSprites: - Image: spicebloom - SpiceBloom: - GrowthTerrainTypes: SpiceSand - SpawnActor: spicebloom - GrowthSequences: grow0 - GrowthDelay: 250, 750 - RespawnDelay: 1, 2 + ConditionManager: + GrantConditionOnTerrain: + Condition: clearsand + TerrainTypes: SpiceSand + KillsSelf: + RequiresCondition: clearsand + Delay: 1750, 3250 + SpawnActorOnDeath: + Actor: spicebloom Explodes: Weapon: BloomSpawn EmptyWeapon: BloomSpawn Health: HP: 9999 - Radius: 1 + Shape: Circle + Radius: 1 Immobile: OccupiesSpace: false @@ -43,7 +51,8 @@ spicebloom: Immobile: Health: HP: 1 - Radius: 512 + Shape: Circle + Radius: 512 Targetable: TargetTypes: Ground RequiresForceFire: true