diff --git a/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs new file mode 100644 index 0000000000..2443368df5 --- /dev/null +++ b/OpenRA.Mods.Cnc/Activities/HarvesterDockSequence.cs @@ -0,0 +1,101 @@ +#region Copyright & License Information +/* + * Copyright 2007-2010 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 LICENSE. + */ +#endregion + +using OpenRA.Mods.RA.Activities; +using OpenRA.Traits; +using OpenRA.Traits.Activities; +using System.Collections.Generic; +using OpenRA.Mods.RA.Move; +using OpenRA.Mods.RA; +using OpenRA.Mods.RA.Render; +using System; + +namespace OpenRA.Mods.Cnc +{ + public class HarvesterDockSequence : IActivity + { + enum State + { + Wait, + Dragin, + Dock, + Loop, + Undock, + Dragout + }; + + readonly Actor proc; + readonly Harvester harv; + readonly RenderBuilding rb; + State state; + + int2 startDock; + int2 endDock; + public HarvesterDockSequence(Actor self, Actor proc) + { + this.proc = proc; + state = State.Dragin; + harv = self.Trait(); + rb = proc.Trait(); + startDock = self.Trait().PxPosition; + endDock = proc.Trait().PxPosition + new int2(-15,8); + } + + IActivity NextActivity { get; set; } + + int unloadTicks = 0; + public IActivity Tick(Actor self) + { + switch (state) + { + case State.Wait: + return this; + case State.Dragin: + state = State.Dock; + return Util.SequenceActivities(new Drag(startDock, endDock, 12), this); + case State.Dock: + harv.Visible = false; + rb.PlayCustomAnimThen(proc, "dock-start", () => {rb.PlayCustomAnimRepeating(proc, "dock-loop"); state = State.Loop;}); + state = State.Wait; + return this; + case State.Loop: + if (harv.TickUnload(self, proc)) + state = State.Undock; + return this; + case State.Undock: + rb.PlayCustomAnimThen(proc, "dock-end", () => {harv.Visible = true; state = State.Dragout;}); + state = State.Wait; + return this; + case State.Dragout: + return Util.SequenceActivities(new Drag(endDock, startDock, 12), NextActivity); + } + throw new InvalidOperationException("Invalid harvester dock state"); + } + + public void Cancel(Actor self) + { + state = State.Undock; + } + + public void Queue( IActivity activity ) + { + if( NextActivity != null ) + NextActivity.Queue( activity ); + else + NextActivity = activity; + } + + public IEnumerable GetCurrentPath() + { + yield break; + } + } +} + diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj index 0807395528..ffc278720e 100644 --- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj +++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj @@ -66,6 +66,7 @@ + @@ -97,4 +98,7 @@ copy "$(TargetPath)" "$(SolutionDir)mods/cnc/" cd "$(SolutionDir)" + + + \ No newline at end of file diff --git a/OpenRA.Mods.Cnc/TiberiumRefineryDockAction.cs b/OpenRA.Mods.Cnc/TiberiumRefineryDockAction.cs index bac9671519..6a7173cb8c 100644 --- a/OpenRA.Mods.Cnc/TiberiumRefineryDockAction.cs +++ b/OpenRA.Mods.Cnc/TiberiumRefineryDockAction.cs @@ -19,68 +19,63 @@ using OpenRA.Mods.RA.Move; namespace OpenRA.Mods.Cnc { class TiberiumRefineryDockActionInfo : TraitInfo {} - - class TiberiumRefineryDockAction : IAcceptOreDockAction, INotifyDamage, INotifySold, INotifyCapture + class TiberiumRefineryDockAction : IAcceptOreDockAction, ITick, INotifyDamage, INotifySold, INotifyCapture { Actor dockedHarv = null; bool preventDock = false; public void OnDock(Actor self, Actor harv, DeliverResources dockOrder) { - int2 startDock = harv.Trait().PxPosition; - int2 endDock = self.Trait().PxPosition + new int2(-15,8); var mobile = harv.Trait(); var harvester = harv.Trait(); harv.QueueActivity( new Turn(112) ); + + if (!preventDock) + { + harv.QueueActivity( new CallFunc( () => dockedHarv = harv, false ) ); + harv.QueueActivity( new HarvesterDockSequence(harv, self) ); + harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) ); + } + + // Tell the harvester to start harvesting + // TODO: This belongs on the harv idle activity harv.QueueActivity( new CallFunc( () => { - if (!preventDock) + if (harvester.LastHarvestedCell != int2.Zero) { - dockedHarv = harv; - self.Trait().PlayCustomAnim(self, "active"); - - harv.QueueActivity( new Drag(startDock, endDock, 12) ); - harv.QueueActivity( new CallFunc( () => - { - self.World.AddFrameEndTask( w1 => - { - if (!preventDock) - harvester.Visible = false; - harvester.Deliver(harv, self); - }); - }, false ) ); - harv.QueueActivity( new Wait(18, false ) ); - harv.QueueActivity( new CallFunc( () => harvester.Visible = true, false ) ); - harv.QueueActivity( new Drag(endDock, startDock, 12) ); - harv.QueueActivity( new CallFunc( () => dockedHarv = null, false ) ); - if (harvester.LastHarvestedCell != int2.Zero) - { - harv.QueueActivity( mobile.MoveTo(harvester.LastHarvestedCell, 5) ); - harv.SetTargetLine(Target.FromCell(harvester.LastHarvestedCell), Color.Red, false); - } + harv.QueueActivity( mobile.MoveTo(harvester.LastHarvestedCell, 5) ); + harv.SetTargetLine(Target.FromCell(harvester.LastHarvestedCell), Color.Red, false); } - harv.QueueActivity( new Harvest() ); - }) ); + harv.QueueActivity( new Harvest() ); + })); } - void CancelDock(Actor self, Actor harv) + public void Tick(Actor self) + { + // Harvester was killed while unloading + if (dockedHarv != null && dockedHarv.IsDead()) + { + self.Trait().CancelCustomAnim(self); + dockedHarv = null; + } + } + + void CancelDock(Actor self) { preventDock = true; - if (dockedHarv == null) - return; - - // invisible harvester makes ceiling cat cry - if (!harv.IsDead()) - harv.Trait().Visible = true; + + // Cancel the dock sequence + if (dockedHarv != null && !dockedHarv.IsDead()) + dockedHarv.CancelActivity(); } - public void Selling (Actor self) { CancelDock(self, dockedHarv); } + public void Selling (Actor self) { CancelDock(self); } public void Sold (Actor self) {} public void Damaged (Actor self, AttackInfo e) { if (e.DamageState == DamageState.Dead) - CancelDock(self, dockedHarv); + CancelDock(self); } public void OnCapture (Actor self, Actor captor, Player oldOwner, Player newOwner) diff --git a/OpenRA.Mods.RA/Harvester.cs b/OpenRA.Mods.RA/Harvester.cs index e6d2ac8967..5ae9078e8b 100644 --- a/OpenRA.Mods.RA/Harvester.cs +++ b/OpenRA.Mods.RA/Harvester.cs @@ -80,7 +80,22 @@ namespace OpenRA.Mods.RA if (!contents.ContainsKey(type.info)) contents[type.info] = 1; else contents[type.info]++; } - + + // TODO: N-tick harvester unload. + // Currently unloads everything in one go + // Returns true when unloading is complete + public bool TickUnload(Actor self, Actor proc) + { + if (!proc.IsInWorld) + return false; // fail to deliver if there is no proc. + + // TODO: Unload part of the load. Return false if the proc is full. + proc.Trait().GiveOre(contents.Sum(kv => kv.Key.ValuePerUnit * kv.Value)); + contents.Clear(); + return true; + } + + public void Deliver(Actor self, Actor proc) { if (!proc.IsInWorld) diff --git a/OpenRA.Mods.RA/Render/RenderBuilding.cs b/OpenRA.Mods.RA/Render/RenderBuilding.cs index e2f944853f..54177333ec 100755 --- a/OpenRA.Mods.RA/Render/RenderBuilding.cs +++ b/OpenRA.Mods.RA/Render/RenderBuilding.cs @@ -90,6 +90,11 @@ namespace OpenRA.Mods.RA.Render () => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); }); } + public void CancelCustomAnim(Actor self) + { + anim.PlayRepeating( NormalizeSequence(self, "idle") ); + } + public virtual void Damaged(Actor self, AttackInfo e) { if (!e.DamageStateChanged) diff --git a/mods/cnc/sequences/structures.yaml b/mods/cnc/sequences/structures.yaml index a8030e4e13..3c4e64c8dd 100644 --- a/mods/cnc/sequences/structures.yaml +++ b/mods/cnc/sequences/structures.yaml @@ -35,22 +35,47 @@ nuke: Start: 0 Length: * -proc.proxy: - make: procmake - Start: 0 - Length: * - proc: idle: Start: 0 - active: - Start: 0 - Length: 30 + Length: 6 + Tick: 60 + enroute: + Start: 6 + Length: 6 + Tick: 60 + dock-start: + Start: 12 + Length: 7 + Tick: 60 + dock-loop: + Start: 19 + Length: 5 + Tick: 60 + dock-end: + Start: 24 + Length: 6 + Tick: 60 damaged-idle: Start: 30 - damaged-active: - Start: 30 - Length: 30 + Length: 6 + Tick: 60 + damaged-enroute: + Start: 36 + Length: 6 + Tick: 60 + damaged-dock-start: + Start: 42 + Length: 7 + Tick: 60 + damaged-dock-loop: + Start: 49 + Length: 5 + Tick: 60 + damaged-dock-end: + Start: 54 + Length: 6 + Tick: 60 dead: Start: 60 make: procmake