diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 203cf1e23a..df81e3eb88 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -86,6 +86,7 @@ namespace OpenRA.Traits bool IsValidTarget(Actor self, Actor saboteur); } public interface IStoreOre { int Capacity { get; } } + public interface INotifyDocking { void Docked(Actor self, Actor harvester); void Undocked(Actor self, Actor harvester); } public interface IEffectiveOwner { bool Disguised { get; } diff --git a/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs index b0a27be2cd..4c827722e1 100644 --- a/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs +++ b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs @@ -52,7 +52,12 @@ namespace OpenRA.Mods.Cnc state = State.Dock; return Util.SequenceActivities(new Drag(startDock, endDock, 12), this); case State.Dock: - ru.PlayCustomAnimation(self, "dock", () => { ru.PlayCustomAnimRepeating(self, "dock-loop"); state = State.Loop; }); + ru.PlayCustomAnimation(self, "dock", () => { + ru.PlayCustomAnimRepeating(self, "dock-loop"); + foreach (var nd in proc.TraitsImplementing()) + nd.Docked(proc, self); + state = State.Loop; + }); state = State.Wait; return this; case State.Loop: @@ -61,6 +66,8 @@ namespace OpenRA.Mods.Cnc return this; case State.Undock: ru.PlayCustomAnimBackwards(self, "dock", () => state = State.DragOut); + foreach (var nd in proc.TraitsImplementing()) + nd.Undocked(proc, self); state = State.Wait; return this; case State.DragOut: diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj index e0b79580d9..fd7d79d8a8 100644 --- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj +++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj @@ -89,6 +89,7 @@ + diff --git a/OpenRA.Mods.D2k/Render/WithDockingOverlay.cs b/OpenRA.Mods.D2k/Render/WithDockingOverlay.cs new file mode 100644 index 0000000000..f995b0b0f1 --- /dev/null +++ b/OpenRA.Mods.D2k/Render/WithDockingOverlay.cs @@ -0,0 +1,74 @@ +#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 OpenRA.Effects; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; +using OpenRA.Mods.RA.Buildings; + +namespace OpenRA.Mods.RA.Render +{ + public class WithDockingOverlayInfo : ITraitInfo, Requires, Requires + { + [Desc("Sequence name to use")] + public readonly string Sequence = "docking-overlay"; + + [Desc("Position relative to body")] + public readonly WVec Offset = WVec.Zero; + + public object Create(ActorInitializer init) { return new WithDockingOverlay(init.self, this); } + } + + public class WithDockingOverlay : INotifyDocking, INotifyBuildComplete, INotifySold + { + WithDockingOverlayInfo info; + Animation overlay; + bool buildComplete, docked; + + public WithDockingOverlay(Actor self, WithDockingOverlayInfo info) + { + this.info = info; + + var rs = self.Trait(); + var body = self.Trait(); + + buildComplete = !self.HasTrait(); // always render instantly for units + + overlay = new Animation(rs.GetImage(self)); + overlay.Play(info.Sequence); + rs.anims.Add("docking_overlay_{0}".F(info.Sequence), + new AnimationWithOffset(overlay, + () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), + () => !buildComplete)); + } + + void PlayDockingOverlay() + { + if (docked) + overlay.PlayThen(info.Sequence, PlayDockingOverlay); + } + + public void BuildingComplete(Actor self) + { + self.World.AddFrameEndTask(w => w.Add(new DelayedAction(120, () => + buildComplete = true))); + } + + public void Sold(Actor self) { } + public void Selling(Actor self) + { + buildComplete = false; + } + + public void Docked(Actor self, Actor harvester) { docked = true; PlayDockingOverlay(); } + public void Undocked(Actor self, Actor harvester) { docked = false; } + } +} \ No newline at end of file diff --git a/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs b/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs index cac6e85bb7..ca9d2c1517 100644 --- a/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs +++ b/OpenRA.Mods.RA/Activities/RAHarvesterDockSequence.cs @@ -45,7 +45,12 @@ namespace OpenRA.Mods.RA state = State.Dock; return Util.SequenceActivities(new Turn(angle), this); case State.Dock: - ru.PlayCustomAnimation(self, "dock", () => {ru.PlayCustomAnimRepeating(self, "dock-loop"); state = State.Loop;}); + ru.PlayCustomAnimation(self, "dock", () => { + ru.PlayCustomAnimRepeating(self, "dock-loop"); + foreach (var nd in proc.TraitsImplementing()) + nd.Docked(proc, self); + state = State.Loop; + }); state = State.Wait; return this; case State.Loop: @@ -59,8 +64,11 @@ namespace OpenRA.Mods.RA case State.Complete: harv.LastLinkedProc = harv.LinkedProc; harv.LinkProc(self, null); + foreach (var nd in proc.TraitsImplementing()) + nd.Undocked(proc, self); return NextActivity; } + throw new InvalidOperationException("Invalid harvester dock state"); } diff --git a/OpenRA.Mods.RA/OreRefinery.cs b/OpenRA.Mods.RA/OreRefinery.cs index a398b98dd8..a3b99010c2 100644 --- a/OpenRA.Mods.RA/OreRefinery.cs +++ b/OpenRA.Mods.RA/OreRefinery.cs @@ -44,6 +44,7 @@ namespace OpenRA.Mods.RA [Sync] bool preventDock = false; public bool AllowDocking { get { return !preventDock; } } + public CVec DeliverOffset { get { return (CVec)Info.DockOffset; } } public virtual Activity DockSequence(Actor harv, Actor self) { return new RAHarvesterDockSequence(harv, self, Info.DockAngle); } @@ -110,11 +111,11 @@ namespace OpenRA.Mods.RA { if (!preventDock) { - harv.QueueActivity( new CallFunc( () => dockedHarv = harv, false ) ); - harv.QueueActivity( DockSequence(harv, self) ); - harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) ); + harv.QueueActivity(new CallFunc( () => dockedHarv = harv, false)); + harv.QueueActivity(DockSequence(harv, self)); + harv.QueueActivity(new CallFunc( () => dockedHarv = null, false)); } - harv.QueueActivity( new CallFunc( () => harv.Trait().ContinueHarvesting(harv) ) ); + harv.QueueActivity(new CallFunc(() => harv.Trait().ContinueHarvesting(harv))); } public void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner) diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index 6e9ef558e9..a583d7ee27 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -190,6 +190,8 @@ CONCRETEB: Facing: 160 ProvidesCustomPrerequisite: Prerequisite: Refinery + WithDockingOverlay@SMOKE: + Sequence: smoke ^SILO: Inherits: ^Building diff --git a/mods/d2k/sequences/structures.yaml b/mods/d2k/sequences/structures.yaml index b6674bdce2..5ee32b28ef 100644 --- a/mods/d2k/sequences/structures.yaml +++ b/mods/d2k/sequences/structures.yaml @@ -475,6 +475,12 @@ refa: icon: DATA Start: 4066 Offset: -30,-24 + smoke: DATA + Start: 3885 + Length: 14 + Offset: 10,-16 + Tick: 200 + BlendMode: Additive siloa: idle: DATA @@ -966,6 +972,12 @@ refh: icon: DATA Start: 4067 Offset: -30,-24 + smoke: DATA + Start: 3885 + Length: 14 + Offset: 10,-16 + Tick: 200 + BlendMode: Additive siloh: idle: DATA @@ -1367,6 +1379,12 @@ refo: icon: DATA Start: 4068 Offset: -30,-24 + smoke: DATA + Start: 3885 + Length: 14 + Offset: 10,-16 + Tick: 200 + BlendMode: Additive siloo: idle: DATA