diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 925629b8ac..c6f815cdf8 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -627,6 +627,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs new file mode 100644 index 0000000000..da624216fc --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Render/WithDecoration.cs @@ -0,0 +1,108 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Displays a custom animation if conditions are satisfied.")] + public class WithDecorationInfo : UpgradableTraitInfo, ITraitInfo + { + [Desc("Image used for this decoration. Defaults to the actor's type.")] + public readonly string Image = null; + + [Desc("Sequence used for this decoration (can be animated).")] + public readonly string Sequence = null; + + [Desc("Palette to render the sprite in. Reference the world actor's PaletteFrom* traits.")] + public readonly string Palette = "chrome"; + + [Desc("Pixel offset relative to the top-left point of the actor's bounds.")] + public readonly int2 Offset = int2.Zero; + + [Desc("The Z offset to apply when rendering this decoration.")] + public readonly int ZOffset = 1; + + [Desc("Visual scale of the image.")] + public readonly float Scale = 1f; + + [Desc("Should this be visible to allied players?")] + public readonly bool ShowToAllies = true; + + [Desc("Should this be visible to enemy players?")] + public readonly bool ShowToEnemies = false; + + public virtual object Create(ActorInitializer init) { return new WithDecoration(init.Self, this); } + } + + public class WithDecoration : UpgradableTrait, IRender + { + readonly WithDecorationInfo info; + readonly string image; + readonly Animation anim; + + public WithDecoration(Actor self, WithDecorationInfo info) + : base(info) + { + this.info = info; + image = info.Image ?? self.Info.Name; + anim = new Animation(self.World, image); + anim.Paused = () => self.World.Paused; + anim.PlayRepeating(info.Sequence); + } + + public virtual bool ShouldRender(Actor self) { return true; } + + public IEnumerable Render(Actor self, WorldRenderer wr) + { + if (IsTraitDisabled) + yield break; + + if (self.IsDead || !self.IsInWorld) + yield break; + + if (anim == null) + yield break; + + var allied = self.Owner.IsAlliedWith(self.World.RenderPlayer); + + if (!allied && !info.ShowToEnemies) + yield break; + + if (allied && !info.ShowToAllies) + yield break; + + if (!ShouldRender(self)) + yield break; + + if (self.World.FogObscures(self)) + yield break; + + var pxPos = wr.ScreenPxPosition(self.CenterPosition); + var actorBounds = self.Bounds; + actorBounds.Offset(pxPos.X, pxPos.Y); + pxPos = new int2(actorBounds.Left, actorBounds.Top); + + var img = anim.Image; + var imgSize = img.Size.ToInt2(); + pxPos = pxPos.WithX(pxPos.X + imgSize.X / 2).WithY(pxPos.Y + imgSize.Y / 2); + + pxPos += info.Offset; + var renderPos = wr.Position(pxPos); + + anim.Tick(); + + yield return new SpriteRenderable(img, renderPos, WVec.Zero, info.ZOffset, wr.Palette(info.Palette), info.Scale, true); + } + } +} diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj index 28bf2f6044..62e1e86805 100644 --- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj +++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj @@ -97,6 +97,7 @@ + diff --git a/OpenRA.Mods.D2k/Traits/Render/WithDecorationCarryable.cs b/OpenRA.Mods.D2k/Traits/Render/WithDecorationCarryable.cs new file mode 100644 index 0000000000..68f3369833 --- /dev/null +++ b/OpenRA.Mods.D2k/Traits/Render/WithDecorationCarryable.cs @@ -0,0 +1,38 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.D2k.Traits +{ + [Desc("Displays a sprite when the carryable actor is waiting for pickup.")] + public class WithDecorationCarryableInfo : WithDecorationInfo, Requires + { + public override object Create(ActorInitializer init) { return new WithDecorationCarryable(init.Self, this); } + } + + public class WithDecorationCarryable : WithDecoration + { + readonly Carryable carryable; + + public WithDecorationCarryable(Actor self, WithDecorationCarryableInfo info) + : base(self, info) + { + carryable = self.Trait(); + } + + public override bool ShouldRender(Actor self) + { + return carryable.Reserved; + } + } +} diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 9e1e6d43b0..01f94612b9 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -106,6 +106,7 @@ + diff --git a/OpenRA.Mods.RA/Traits/Render/WithDecorationDisguised.cs b/OpenRA.Mods.RA/Traits/Render/WithDecorationDisguised.cs new file mode 100644 index 0000000000..b08d6697dd --- /dev/null +++ b/OpenRA.Mods.RA/Traits/Render/WithDecorationDisguised.cs @@ -0,0 +1,42 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA.Traits +{ + public class WithDecorationDisguisedInfo : WithDecorationInfo, Requires + { + [Desc("Require an active disguise to render this decoration?")] + public readonly bool RequireDisguise = true; + + public override object Create(ActorInitializer init) { return new WithDecorationDisguised(init.Self, this); } + } + + public class WithDecorationDisguised : WithDecoration + { + readonly WithDecorationDisguisedInfo info; + readonly Disguise disguise; + + public WithDecorationDisguised(Actor self, WithDecorationDisguisedInfo info) + : base(self, info) + { + this.info = info; + disguise = self.Trait(); + } + + public override bool ShouldRender(Actor self) + { + return !info.RequireDisguise || disguise.Disguised; + } + } +} \ No newline at end of file diff --git a/mods/d2k/rules/vehicles.yaml b/mods/d2k/rules/vehicles.yaml index 91b43bded4..1c178d084d 100644 --- a/mods/d2k/rules/vehicles.yaml +++ b/mods/d2k/rules/vehicles.yaml @@ -62,6 +62,10 @@ harvester: SearchFromProcRadius: 24 SearchFromOrderRadius: 12 Carryable: + WithDecorationCarryable: + Image: pips + Sequence: pickup-indicator + Offset: -12, -12 Health: HP: 1000 Armor: diff --git a/mods/d2k/sequences/misc.yaml b/mods/d2k/sequences/misc.yaml index 3b7c17adbb..ce15cac2cc 100644 --- a/mods/d2k/sequences/misc.yaml +++ b/mods/d2k/sequences/misc.yaml @@ -112,6 +112,8 @@ pips: groups: DATA.R8 Start: 17 Length: 10 + pickup-indicator: DATA.R8 + Start: 112 tag-primary: DATA.R8 Start: 110 pip-empty: DATA.R8