diff --git a/OpenRA.Mods.RA/Activities/MakeAnimation.cs b/OpenRA.Mods.RA/Activities/MakeAnimation.cs deleted file mode 100644 index 2ebde3fc79..0000000000 --- a/OpenRA.Mods.RA/Activities/MakeAnimation.cs +++ /dev/null @@ -1,71 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 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. For more information, - * see COPYING. - */ -#endregion - -using System; -using OpenRA.Mods.RA.Buildings; -using OpenRA.Mods.RA.Render; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA.Activities -{ - class MakeAnimation : Activity - { - readonly bool Reversed; - readonly Action OnComplete; - RenderBuilding rb; - - public MakeAnimation(Actor self, Action onComplete) : this(self, false, onComplete) {} - public MakeAnimation(Actor self, bool reversed, Action onComplete) - { - Reversed = reversed; - OnComplete = onComplete; - } - - bool complete = false; - bool started = false; - - public override Activity Tick(Actor self) - { - if (self.IsDead()) - return NextActivity; - - if (started) - { - // Don't break the actor if someone has overriden the animation prematurely - if (rb.DefaultAnimation.CurrentSequence.Name != "make") - { - complete = true; - OnComplete(); - } - return complete ? NextActivity : this; - } - - started = true; - rb = self.Trait(); - if (Reversed) - { - // TODO: These don't belong here - var bi = self.Info.Traits.GetOrDefault(); - if (bi != null) - foreach (var s in bi.SellSounds) - Sound.PlayToPlayer(self.Owner, s, self.CenterPosition); - - rb.PlayCustomAnimBackwards(self, "make", () => { OnComplete(); complete = true;}); - } - else - rb.PlayCustomAnimThen(self, "make", () => { OnComplete(); complete = true;}); - - return this; - } - - // Cannot be cancelled - public override void Cancel(Actor self) { } - } -} diff --git a/OpenRA.Mods.RA/Activities/Transform.cs b/OpenRA.Mods.RA/Activities/Transform.cs index 47012b5454..4c83e96357 100644 --- a/OpenRA.Mods.RA/Activities/Transform.cs +++ b/OpenRA.Mods.RA/Activities/Transform.cs @@ -76,8 +76,8 @@ namespace OpenRA.Mods.RA.Activities init.Add(new RuntimeCargoInit(cargo.Passengers.ToArray())); var a = w.CreateActor(ToActor, init); - foreach (var nt in self.TraitsImplementing()) - nt.OnTransformed(a); + foreach (var nt in self.TraitsImplementing()) + nt.AfterTransform(a); if (selected) w.Selection.Add(w, a); diff --git a/OpenRA.Mods.RA/Buildings/Building.cs b/OpenRA.Mods.RA/Buildings/Building.cs index 0167f7b20f..a467b7c288 100644 --- a/OpenRA.Mods.RA/Buildings/Building.cs +++ b/OpenRA.Mods.RA/Buildings/Building.cs @@ -34,8 +34,9 @@ namespace OpenRA.Mods.RA.Buildings public readonly bool RequiresBaseProvider = false; public readonly bool AllowInvalidPlacement = false; - public readonly string[] BuildSounds = {"placbldg.aud", "build5.aud"}; - public readonly string[] SellSounds = {"cashturn.aud"}; + public readonly string[] BuildSounds = { "placbldg.aud", "build5.aud" }; + public readonly string[] SellSounds = { "cashturn.aud" }; + public readonly string[] UndeploySounds = { "cashturn.aud" }; public object Create(ActorInitializer init) { return new Building(init, this); } @@ -99,7 +100,7 @@ namespace OpenRA.Mods.RA.Buildings } } - public class Building : INotifyDamage, IOccupySpace, INotifyCapture, INotifyBuildComplete, INotifySold, ISync, ITechTreePrerequisite, INotifyAddedToWorld, INotifyRemovedFromWorld + public class Building : INotifyDamage, IOccupySpace, INotifyCapture, INotifyBuildComplete, INotifySold, INotifyTransform, ISync, ITechTreePrerequisite, INotifyAddedToWorld, INotifyRemovedFromWorld { public readonly BuildingInfo Info; public bool BuildComplete { get; private set; } @@ -185,7 +186,21 @@ namespace OpenRA.Mods.RA.Buildings Locked = false; } - public void Selling(Actor self) { BuildComplete = false; } + public void Selling(Actor self) + { + foreach (var s in Info.SellSounds) + Sound.PlayToPlayer(self.Owner, s, self.CenterPosition); + + BuildComplete = false; + } public void Sold(Actor self) { } + + public void BeforeTransform(Actor self) + { + foreach (var s in Info.UndeploySounds) + Sound.PlayToPlayer(self.Owner, s, self.CenterPosition); + } + public void OnTransform(Actor self) { } + public void AfterTransform(Actor self) { } } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 0c161c64c9..a7c9bdafbe 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -100,7 +100,6 @@ - @@ -519,6 +518,7 @@ + diff --git a/OpenRA.Mods.RA/Player/ProductionQueue.cs b/OpenRA.Mods.RA/Player/ProductionQueue.cs index cfce76529f..b719c72862 100644 --- a/OpenRA.Mods.RA/Player/ProductionQueue.cs +++ b/OpenRA.Mods.RA/Player/ProductionQueue.cs @@ -140,7 +140,10 @@ namespace OpenRA.Mods.RA public void Killed(Actor killed, AttackInfo e) { if (killed == self) ClearQueue(); } public void Selling(Actor self) { } public void Sold(Actor self) { ClearQueue(); } + + public void BeforeTransform(Actor self) { } public void OnTransform(Actor self) { ClearQueue(); } + public void AfterTransform(Actor self) { } void CacheProduceables(Actor playerActor) { diff --git a/OpenRA.Mods.RA/Render/RenderBuilding.cs b/OpenRA.Mods.RA/Render/RenderBuilding.cs index 937589094a..91355b05f8 100755 --- a/OpenRA.Mods.RA/Render/RenderBuilding.cs +++ b/OpenRA.Mods.RA/Render/RenderBuilding.cs @@ -19,7 +19,6 @@ namespace OpenRA.Mods.RA.Render { public class RenderBuildingInfo : RenderSimpleInfo, Requires, IPlaceBuildingDecoration { - public readonly bool HasMakeAnimation = true; public readonly bool PauseOnLowPower = false; public override object Create(ActorInitializer init) { return new RenderBuilding(init, this);} @@ -34,9 +33,11 @@ namespace OpenRA.Mods.RA.Render } } - public class RenderBuilding : RenderSimple, INotifyDamageStateChanged + public class RenderBuilding : RenderSimple, INotifyDamageStateChanged, INotifyBuildComplete { RenderBuildingInfo info; + bool buildComplete; + bool skipMakeAnimation; public RenderBuilding(ActorInitializer init, RenderBuildingInfo info) : this(init, info, () => 0) { } @@ -46,24 +47,27 @@ namespace OpenRA.Mods.RA.Render { var self = init.self; this.info = info; + skipMakeAnimation = init.Contains(); - // Work around a bogus crash DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle")); self.Trait().SetAutodetectedFacings(DefaultAnimation.CurrentSequence.Facings); - - // Can't call Complete() directly from ctor because other traits haven't been inited yet - if (self.Info.Traits.Get().HasMakeAnimation && !init.Contains()) - self.QueueActivity(new MakeAnimation(self, () => Complete(self))); - else - self.QueueActivity(new CallFunc(() => Complete(self))); } - void Complete(Actor self) + public override void TickRender(WorldRenderer wr, Actor self) { - DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle")); - foreach (var x in self.TraitsImplementing()) - x.BuildingComplete(self); + base.TickRender(wr, self); + if (buildComplete) + return; + + buildComplete = true; + if (!self.HasTrait() || skipMakeAnimation) + foreach (var notify in self.TraitsImplementing()) + notify.BuildingComplete(self); + } + + public virtual void BuildingComplete(Actor self) + { if (info.PauseOnLowPower) { var disabled = self.TraitsImplementing(); diff --git a/OpenRA.Mods.RA/Render/RenderBuildingSilo.cs b/OpenRA.Mods.RA/Render/RenderBuildingSilo.cs index b2413b55ae..7b2114e972 100644 --- a/OpenRA.Mods.RA/Render/RenderBuildingSilo.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingSilo.cs @@ -27,7 +27,7 @@ namespace OpenRA.Mods.RA.Render playerResources = init.self.Owner.PlayerActor.Trait(); } - public void BuildingComplete(Actor self) + public override void BuildingComplete(Actor self) { var animation = (self.GetDamageState() >= DamageState.Heavy) ? "damaged-idle" : "idle"; diff --git a/OpenRA.Mods.RA/Render/RenderBuildingWall.cs b/OpenRA.Mods.RA/Render/RenderBuildingWall.cs index 35488a30dc..5a6c83eecf 100644 --- a/OpenRA.Mods.RA/Render/RenderBuildingWall.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingWall.cs @@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA.Render public override object Create(ActorInitializer init) { return new RenderBuildingWall(init, this); } } - class RenderBuildingWall : RenderBuilding, INotifyBuildComplete, INotifyAddedToWorld, INotifyRemovedFromWorld + class RenderBuildingWall : RenderBuilding, INotifyAddedToWorld, INotifyRemovedFromWorld { readonly RenderBuildingWallInfo info; int adjacent = 0; @@ -34,9 +34,10 @@ namespace OpenRA.Mods.RA.Render this.info = info; } - public void BuildingComplete(Actor self) + public override void BuildingComplete(Actor self) { DefaultAnimation.PlayFetchIndex(info.Sequence, () => adjacent); + UpdateNeighbours(self); } public override void DamageStateChanged(Actor self, AttackInfo e) diff --git a/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs b/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs index bec94ee4ee..1638821b87 100755 --- a/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs @@ -55,7 +55,7 @@ namespace OpenRA.Mods.RA.Render () => !buildComplete, offset)); } - public void BuildingComplete( Actor self ) + public override void BuildingComplete(Actor self) { roof.Play(NormalizeSequence(self, self.GetDamageState() > DamageState.Heavy ? "damaged-idle-top" : "idle-top")); diff --git a/OpenRA.Mods.RA/Render/WithMakeAnimation.cs b/OpenRA.Mods.RA/Render/WithMakeAnimation.cs new file mode 100644 index 0000000000..545185d5ed --- /dev/null +++ b/OpenRA.Mods.RA/Render/WithMakeAnimation.cs @@ -0,0 +1,64 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Render; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + public class WithMakeAnimationInfo : ITraitInfo, Requires + { + [Desc("Sequence name to use")] + public readonly string Sequence = "make"; + + public object Create(ActorInitializer init) { return new WithMakeAnimation(init, this); } + } + + public class WithMakeAnimation : ITickRender + { + WithMakeAnimationInfo info; + RenderBuilding building; + bool buildComplete; + + public WithMakeAnimation(ActorInitializer init, WithMakeAnimationInfo info) + { + building = init.self.Trait(); + this.info = info; + buildComplete = init.Contains(); + } + + public void TickRender(WorldRenderer wr, Actor self) + { + if (self.IsDead() || buildComplete) + return; + + buildComplete = true; + + building.PlayCustomAnimThen(self, info.Sequence, () => + { + foreach (var notify in self.TraitsImplementing()) + notify.BuildingComplete(self); + }); + } + + public void Reverse(Actor self, Activity activity) + { + building.PlayCustomAnimBackwards(self, info.Sequence, () => { + building.PlayCustomAnim(self, info.Sequence); // avoids visual glitches as we wait for the actor to get destroyed + self.QueueActivity(activity); + }); + } + } +} diff --git a/OpenRA.Mods.RA/Sellable.cs b/OpenRA.Mods.RA/Sellable.cs index 738e1ce10c..77a04c7b2e 100644 --- a/OpenRA.Mods.RA/Sellable.cs +++ b/OpenRA.Mods.RA/Sellable.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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. For more information, @@ -34,15 +34,16 @@ namespace OpenRA.Mods.RA if (!self.Trait().Lock()) return; + self.CancelActivity(); + foreach (var ns in self.TraitsImplementing()) ns.Selling(self); - self.CancelActivity(); - - var rb = self.TraitOrDefault(); - if (rb != null && self.Info.Traits.Get().HasMakeAnimation) - self.QueueActivity(new MakeAnimation(self, true, () => rb.PlayCustomAnim(self, "make"))); - self.QueueActivity(new Sell()); + var makeAnimation = self.TraitOrDefault(); + if (makeAnimation != null) + makeAnimation.Reverse(self, new Sell()); + else + self.QueueActivity(new Sell()); } } } diff --git a/OpenRA.Mods.RA/TraitsInterfaces.cs b/OpenRA.Mods.RA/TraitsInterfaces.cs index 0e166c14ff..3ec75b1301 100755 --- a/OpenRA.Mods.RA/TraitsInterfaces.cs +++ b/OpenRA.Mods.RA/TraitsInterfaces.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2014 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. For more information, @@ -47,8 +47,7 @@ namespace OpenRA.Mods.RA } public interface INotifyParachuteLanded { void OnLanded(); } - public interface INotifyTransform { void OnTransform(Actor self); } - public interface INotifyTransformed { void OnTransformed(Actor toActor); } + public interface INotifyTransform { void BeforeTransform(Actor self); void OnTransform(Actor self); void AfterTransform(Actor toActor); } public interface INotifyAttack { void Attacking(Actor self, Target target, Armament a, Barrel barrel); } public interface INotifyChat { bool OnChat(string from, string message); } } diff --git a/OpenRA.Mods.RA/Transforms.cs b/OpenRA.Mods.RA/Transforms.cs index 34c7904aec..7ec82563ec 100644 --- a/OpenRA.Mods.RA/Transforms.cs +++ b/OpenRA.Mods.RA/Transforms.cs @@ -88,11 +88,15 @@ namespace OpenRA.Mods.RA if (self.HasTrait()) self.QueueActivity(new Turn(info.Facing)); - var rb = self.TraitOrDefault(); - if (rb != null && self.Info.Traits.Get().HasMakeAnimation) - self.QueueActivity(new MakeAnimation(self, true, () => rb.PlayCustomAnim(self, "make"))); + foreach (var nt in self.TraitsImplementing()) + nt.BeforeTransform(self); - self.QueueActivity(new Transform(self, info.IntoActor) { Offset = info.Offset, Facing = info.Facing, Sounds = info.TransformSounds, Race = race }); + var transform = new Transform(self, info.IntoActor) { Offset = info.Offset, Facing = info.Facing, Sounds = info.TransformSounds, Race = race }; + var makeAnimation = self.TraitOrDefault(); + if (makeAnimation != null) + makeAnimation.Reverse(self, transform); + else + self.QueueActivity(transform); } public void ResolveOrder(Actor self, Order order) diff --git a/OpenRA.Utility/UpgradeRules.cs b/OpenRA.Utility/UpgradeRules.cs index 12551fb493..e6c7964477 100644 --- a/OpenRA.Utility/UpgradeRules.cs +++ b/OpenRA.Utility/UpgradeRules.cs @@ -252,6 +252,20 @@ namespace OpenRA.Utility node.Key = "StoresResources"; } + // make animation is now it's own trait + if (engineVersion < 20140621) + { + if (depth == 1 && (node.Key.StartsWith("RenderBuilding"))) + node.Value.Nodes.RemoveAll(n => n.Key == "HasMakeAnimation"); + + if (node.Value.Nodes.Any(n => n.Key.StartsWith("RenderBuilding")) + && !node.Value.Nodes.Any(n => n.Key == "RenderBuildingWall") + && !node.Value.Nodes.Any(n => n.Key == "WithMakeAnimation")) + { + node.Value.Nodes.Add(new MiniYamlNode("WithMakeAnimation", new MiniYaml(""))); + } + } + // ParachuteAttachment was merged into Parachutable if (engineVersion < 20140701) { diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 99853981c1..51c36dacc5 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -355,6 +355,7 @@ LuaScriptEvents: Demolishable: ScriptTriggers: + WithMakeAnimation: ^BaseBuilding: Inherits: ^Building @@ -395,6 +396,7 @@ StartsRevealed: true LuaScriptEvents: ScriptTriggers: + WithMakeAnimation: ^TechBuilding: Inherits: ^CivBuilding @@ -418,6 +420,7 @@ Palette: terrain EditorAppearance: UseTerrainPalette: true + WithMakeAnimation: ^CivFieldHusk: AppearsOnRadar: @@ -436,6 +439,7 @@ StartsRevealed: true LuaScriptEvents: ScriptTriggers: + WithMakeAnimation: ^Wall: AppearsOnRadar: @@ -456,7 +460,6 @@ LineBuildNode: Types: wall RenderBuildingWall: - HasMakeAnimation: false Palette: staticterrain GivesExperience: EditorAppearance: @@ -493,6 +496,7 @@ StartsRevealed: true LuaScriptEvents: ScriptTriggers: + WithMakeAnimation: ^TibTree: Tooltip: @@ -510,6 +514,7 @@ FrozenUnderFog: StartsRevealed: true LuaScriptEvents: + WithMakeAnimation: ^Rock: Tooltip: @@ -529,6 +534,7 @@ StartsRevealed: true LuaScriptEvents: ScriptTriggers: + WithMakeAnimation: ^Husk: Health: diff --git a/mods/cnc/rules/tech.yaml b/mods/cnc/rules/tech.yaml index 7d618558df..40a3843308 100644 --- a/mods/cnc/rules/tech.yaml +++ b/mods/cnc/rules/tech.yaml @@ -94,4 +94,5 @@ MISS: Cost: 2000 Bib: HasMinibib: Yes + WithMakeAnimation: diff --git a/mods/cnc/rules/trees.yaml b/mods/cnc/rules/trees.yaml index d1c9b72964..ce52e9aecc 100644 --- a/mods/cnc/rules/trees.yaml +++ b/mods/cnc/rules/trees.yaml @@ -67,19 +67,16 @@ T01: EditorTilesetFilter: ExcludeTilesets: DESERT - T02: Inherits: ^Tree EditorTilesetFilter: ExcludeTilesets: DESERT - T03: Inherits: ^Tree EditorTilesetFilter: ExcludeTilesets: DESERT - T04: Inherits: ^Tree @@ -88,19 +85,16 @@ T05: EditorTilesetFilter: ExcludeTilesets: DESERT - T06: Inherits: ^Tree EditorTilesetFilter: ExcludeTilesets: DESERT - T07: Inherits: ^Tree EditorTilesetFilter: ExcludeTilesets: DESERT - T08: Inherits: ^Tree Building: diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 08863b5172..a9eaa8b4e5 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -280,4 +280,5 @@ Pieces: 3, 7 Range: 2c0, 5c0 ScriptTriggers: + WithMakeAnimation: diff --git a/mods/d2k/rules/misc.yaml b/mods/d2k/rules/misc.yaml index d7029ac83d..bef6076078 100644 --- a/mods/d2k/rules/misc.yaml +++ b/mods/d2k/rules/misc.yaml @@ -116,6 +116,7 @@ SPICEBLOOM: RadarColorFromTerrain: Terrain: Spice BodyOrientation: + WithMakeAnimation: CAMERA: Immobile: diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index dfb79f154d..a9a173bbe2 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -426,7 +426,6 @@ CONCRETEB: TargetableBuilding: TargetTypes: Ground RenderBuildingWall: - HasMakeAnimation: false Image: walla EditorAppearance: RelativeToTopLeft: yes @@ -476,7 +475,6 @@ WALL: RenderRangeCircle: -RenderBuilding: RenderBuildingWall: - HasMakeAnimation: false BodyOrientation: QuantizedFacings: 32 WithTurret: @@ -528,7 +526,6 @@ WALL: RenderRangeCircle: -RenderBuilding: RenderBuildingWall: - HasMakeAnimation: false BodyOrientation: QuantizedFacings: 32 WithTurret: @@ -720,7 +717,6 @@ PALACEC: Footprint: xxx xxx Dimensions: 3,2 RenderBuilding: - HasMakeAnimation: false HEAVYC: Inherits: ^HEAVY diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 0f5d0eac3d..9b9ae2bf28 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -274,6 +274,7 @@ DamagedSound: kaboom1.aud DestroyedSound: kaboom22.aud RenderBuilding: + WithMakeAnimation: WithBuildingExplosion: RepairableBuilding: EngineerRepairable: @@ -324,7 +325,6 @@ TargetableBuilding: TargetTypes: Ground, DetonateAttack RenderBuildingWall: - HasMakeAnimation: false Palette: terrain GivesExperience: EditorAppearance: @@ -352,6 +352,7 @@ Name: Civilian Building ProximityCaptor: Types: CivilianBuilding + -WithMakeAnimation: -AcceptsSupplies: -GivesBuildableArea: -Sellable: diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index 5c65dcfac7..1b1ebddacd 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -40,6 +40,7 @@ LuaScriptEvents: Demolishable: ScriptTriggers: + WithMakeAnimation: ^Wall: AppearsOnRadar: @@ -65,7 +66,6 @@ TargetableBuilding: TargetTypes: Ground, C4 RenderBuildingWall: - HasMakeAnimation: no GivesExperience: EditorAppearance: RelativeToTopLeft: yes