diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 4361998394..c857a32a33 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -74,6 +74,8 @@ namespace OpenRA.Traits public interface INotifyOwnerChanged { void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner); } public interface INotifyCapture { void OnCapture(Actor self, Actor captor, Player oldOwner, Player newOwner); } public interface INotifyOtherCaptured { void OnActorCaptured(Actor self, Actor captured, Actor captor, Player oldOwner, Player newOwner); } + public interface INotifyHarvest { void Harvested(Actor self, ResourceType resource); } + public interface IAcceptInfiltrator { void OnInfiltrate(Actor self, Actor infiltrator); } public interface IStoreOre { int Capacity { get; } } public interface IToolTip diff --git a/OpenRA.Mods.RA/Activities/FindResources.cs b/OpenRA.Mods.RA/Activities/FindResources.cs index f48226ba57..4860ebe0a2 100755 --- a/OpenRA.Mods.RA/Activities/FindResources.cs +++ b/OpenRA.Mods.RA/Activities/FindResources.cs @@ -135,45 +135,51 @@ namespace OpenRA.Mods.RA.Activities public class HarvestResource : Activity { - bool isHarvesting = false; - public override Activity Tick(Actor self) { - if (isHarvesting) return this; - var territory = self.World.WorldActor.TraitOrDefault(); if (IsCanceled) { - if (territory != null) territory.UnclaimByActor(self); + if (territory != null) + territory.UnclaimByActor(self); return NextActivity; } var harv = self.Trait(); + var harvInfo = self.Info.Traits.Get(); harv.LastHarvestedCell = self.Location; if (harv.IsFull) { - if (territory != null) territory.UnclaimByActor(self); + if (territory != null) + territory.UnclaimByActor(self); return NextActivity; } + // Turn to one of the harvestable facings + if (harvInfo.HarvestFacings != 0) + { + var facing = self.Trait().Facing; + var desired = Util.QuantizeFacing(facing, harvInfo.HarvestFacings) * (256 / harvInfo.HarvestFacings); + if (desired != facing) + return Util.SequenceActivities(new Turn(desired), this); + } + var resLayer = self.World.WorldActor.Trait(); var resource = resLayer.Harvest(self.Location); if (resource == null) { - if (territory != null) territory.UnclaimByActor(self); + if (territory != null) + territory.UnclaimByActor(self); return NextActivity; } - var renderUnit = self.Trait(); /* better have one of these! */ - if (renderUnit.anim.CurrentSequence.Name != "harvest") - { - isHarvesting = true; - renderUnit.PlayCustomAnimation(self, "harvest", () => isHarvesting = false); - } - harv.AcceptResource(resource); - return this; + + foreach (var t in self.TraitsImplementing()) + t.Harvested(self, resource); + + return Util.SequenceActivities(new Wait(harvInfo.LoadTicksPerBale), this); } } } diff --git a/OpenRA.Mods.RA/Harvester.cs b/OpenRA.Mods.RA/Harvester.cs index e959e489d6..6803329716 100644 --- a/OpenRA.Mods.RA/Harvester.cs +++ b/OpenRA.Mods.RA/Harvester.cs @@ -21,8 +21,10 @@ namespace OpenRA.Mods.RA public class HarvesterInfo : ITraitInfo { public readonly int Capacity = 28; + public readonly int LoadTicksPerBale = 4; public readonly int UnloadTicksPerBale = 4; public readonly int PipCount = 7; + public readonly int HarvestFacings = 0; public readonly string[] Resources = { }; public readonly decimal FullyLoadedSpeed = .85m; /// diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 515a2c40e6..afcdaf3229 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -454,6 +454,7 @@ + diff --git a/OpenRA.Mods.RA/Render/RenderHarvester.cs b/OpenRA.Mods.RA/Render/RenderHarvester.cs index 0bef4c064e..705ef6f668 100644 --- a/OpenRA.Mods.RA/Render/RenderHarvester.cs +++ b/OpenRA.Mods.RA/Render/RenderHarvester.cs @@ -18,22 +18,24 @@ namespace OpenRA.Mods.RA.Render { class RenderHarvesterInfo : RenderUnitInfo, Requires { - public readonly string[] ImagesByFullness = { "harvempty", "harvhalf", "harv" }; + public readonly string[] ImagesByFullness = {"harv"}; public override object Create(ActorInitializer init) { return new RenderHarvester(init.self, this); } } - class RenderHarvester : RenderUnit + class RenderHarvester : RenderUnit, INotifyHarvest { Harvester harv; RenderHarvesterInfo info; - public RenderHarvester(Actor self, RenderHarvesterInfo info) : base(self) + public RenderHarvester(Actor self, RenderHarvesterInfo info) + : base(self) { this.info = info; - harv = self.Trait(); - foreach( var image in info.ImagesByFullness ) - new Animation( image ); /* just force these to get loaded upfront */ + + // HACK: Force images to be loaded up-front + foreach (var image in info.ImagesByFullness) + new Animation(image); } public override void Tick(Actor self) @@ -42,9 +44,15 @@ namespace OpenRA.Mods.RA.Render var desiredImage = info.ImagesByFullness[desiredState]; if (anim.Name != desiredImage) - anim.ChangeImage( desiredImage, "idle" ); + anim.ChangeImage(desiredImage, "idle"); base.Tick(self); } + + public void Harvested(Actor self, ResourceType resource) + { + if (anim.CurrentSequence.Name != "harvest") + PlayCustomAnim(self, "harvest"); + } } } \ No newline at end of file diff --git a/OpenRA.Mods.RA/Render/WithHarvestAnimation.cs b/OpenRA.Mods.RA/Render/WithHarvestAnimation.cs new file mode 100644 index 0000000000..81c10a6455 --- /dev/null +++ b/OpenRA.Mods.RA/Render/WithHarvestAnimation.cs @@ -0,0 +1,62 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 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.Collections.Generic; +using System.Linq; +using OpenRA.FileFormats; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Render +{ + class WithHarvestAnimationInfo : ITraitInfo, Requires, Requires + { + [Desc("Sequence name to use")] + public readonly string Sequence = "harvest"; + + [Desc("Position relative to body")] + public readonly WVec Offset = WVec.Zero; + + [Desc("Additional draw-order offset")] + public readonly int ZOffset = 0; + + public object Create(ActorInitializer init) { return new WithHarvestAnimation(init.self, this); } + } + + class WithHarvestAnimation : INotifyHarvest + { + WithHarvestAnimationInfo info; + Animation anim; + bool visible; + + public WithHarvestAnimation(Actor self, WithHarvestAnimationInfo info) + { + this.info = info; + var rs = self.Trait(); + var body = self.Trait(); + + anim = new Animation(rs.GetImage(self), RenderSimple.MakeFacingFunc(self)); + anim.Play(info.Sequence); + rs.anims.Add("harvest_{0}".F(info.Sequence), new AnimationWithOffset(anim, + () => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))), + () => !visible, + p => WithTurret.ZOffsetFromCenter(self, p, info.ZOffset))); + } + + public void Harvested(Actor self, ResourceType resource) + { + if (visible) + return; + + visible = true; + anim.PlayThen(info.Sequence, () => visible = false); + } + } +} diff --git a/mods/cnc/rules/vehicles.yaml b/mods/cnc/rules/vehicles.yaml index c8dd847d1b..568e1664c6 100644 --- a/mods/cnc/rules/vehicles.yaml +++ b/mods/cnc/rules/vehicles.yaml @@ -58,6 +58,7 @@ HARV: Resources: Tiberium, BlueTiberium PipCount: 7 Capacity: 20 + LoadTicksPerBale: 6 UnloadTicksPerBale: 12 SearchFromProcRadius: 24 SearchFromOrderRadius: 12 @@ -75,6 +76,8 @@ HARV: LeavesHusk: HuskActor: HARV.Husk -GainsExperience: + -RenderUnit: + RenderHarvester: APC: Inherits: ^Tank diff --git a/mods/d2k/bits/harvest2.shp b/mods/d2k/bits/harvest2.shp new file mode 100644 index 0000000000..b09ec60ab1 Binary files /dev/null and b/mods/d2k/bits/harvest2.shp differ diff --git a/mods/d2k/bits/unload2.shp b/mods/d2k/bits/unload2.shp new file mode 100644 index 0000000000..2b69c2c078 Binary files /dev/null and b/mods/d2k/bits/unload2.shp differ diff --git a/mods/d2k/rules/vehicles.yaml b/mods/d2k/rules/vehicles.yaml index e36fb7a29e..e81f07ae29 100644 --- a/mods/d2k/rules/vehicles.yaml +++ b/mods/d2k/rules/vehicles.yaml @@ -64,6 +64,7 @@ HARVESTER: Harvester: PipCount: 10 Capacity: 40 + HarvestFacings: 8 Resources: Spice UnloadTicksPerBale: 5 # How far away from our linked refinery to find resources (in cells): @@ -87,6 +88,8 @@ HARVESTER: -AttackMove: LeavesHusk: HuskActor: Harvester.Husk + WithHarvestAnimation: + ZOffset: 1 HARVESTER.Husk: Inherits: ^Husk diff --git a/mods/d2k/sequences.yaml b/mods/d2k/sequences.yaml index 54e60533af..6bec54887a 100644 --- a/mods/d2k/sequences.yaml +++ b/mods/d2k/sequences.yaml @@ -67,15 +67,15 @@ harvester: idle: Start: 0 Facings: 32 - harvest: #TODO use the real overlay instead of this hacky paintjob - Start: 32 - Length: 8 + harvest: harvest2 + Start: 0 + Length: 6 Facings: 8 - Tick: 40 - dock: unload + Tick: 80 + dock: unload2 Start: 0 Length: 10 - dock-loop: unload + dock-loop: unload2 Start: 10 Length: 1 diff --git a/mods/ra/rules/vehicles.yaml b/mods/ra/rules/vehicles.yaml index 2aefff50d9..f72d8ad7bb 100644 --- a/mods/ra/rules/vehicles.yaml +++ b/mods/ra/rules/vehicles.yaml @@ -261,6 +261,7 @@ HARV: RevealsShroud: Range: 4 RenderHarvester: + ImagesByFullness: harvempty, harvhalf, harv -AttackMove: GpsDot: String:Harvester