diff --git a/OpenRA.Mods.Common/Projectiles/Bullet.cs b/OpenRA.Mods.Common/Projectiles/Bullet.cs index 575ccd34cb..181272276a 100644 --- a/OpenRA.Mods.Common/Projectiles/Bullet.cs +++ b/OpenRA.Mods.Common/Projectiles/Bullet.cs @@ -50,9 +50,8 @@ namespace OpenRA.Mods.Common.Projectiles [Desc("Does this projectile have a shadow?")] public readonly bool Shadow = false; - [PaletteReference] - [Desc("Palette to use for this projectile's shadow if Shadow is true.")] - public readonly string ShadowPalette = "shadow"; + [Desc("Color to draw shadow if Shadow is true.")] + public readonly Color ShadowColor = Color.FromArgb(140, 0, 0, 0); [Desc("Trail animation.")] public readonly string TrailImage = null; @@ -122,6 +121,9 @@ namespace OpenRA.Mods.Common.Projectiles readonly WDist speed; readonly string trailPalette; + readonly float3 shadowColor; + readonly float shadowAlpha; + ContrailRenderable contrail; [Sync] @@ -181,6 +183,9 @@ namespace OpenRA.Mods.Common.Projectiles smokeTicks = info.TrailDelay; remainingBounces = info.BounceCount; + + shadowColor = new float3(info.ShadowColor.R, info.ShadowColor.G, info.ShadowColor.B) / 255f; + shadowAlpha = info.ShadowColor.A; } WAngle GetEffectiveFacing() @@ -286,8 +291,10 @@ namespace OpenRA.Mods.Common.Projectiles { var dat = world.Map.DistanceAboveTerrain(pos); var shadowPos = pos - new WVec(0, 0, dat.Length); - foreach (var r in anim.Render(shadowPos, wr.Palette(info.ShadowPalette))) - yield return r; + foreach (var r in anim.Render(shadowPos, wr.Palette(info.Palette))) + yield return ((IModifyableRenderable)r) + .WithTint(shadowColor, ((IModifyableRenderable)r).TintModifiers | TintModifiers.ReplaceColor) + .WithAlpha(shadowAlpha); } var palette = wr.Palette(info.Palette + (info.IsPlayerPalette ? args.SourceActor.Owner.InternalName : "")); diff --git a/OpenRA.Mods.Common/Projectiles/GravityBomb.cs b/OpenRA.Mods.Common/Projectiles/GravityBomb.cs index 2280d2ccd9..0650bd91e8 100644 --- a/OpenRA.Mods.Common/Projectiles/GravityBomb.cs +++ b/OpenRA.Mods.Common/Projectiles/GravityBomb.cs @@ -12,6 +12,7 @@ using System.Collections.Generic; using OpenRA.GameRules; using OpenRA.Graphics; +using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Projectiles @@ -35,10 +36,11 @@ namespace OpenRA.Mods.Common.Projectiles [Desc("Palette is a player palette BaseName")] public readonly bool IsPlayerPalette = false; + [Desc("Does this projectile have a shadow?")] public readonly bool Shadow = false; - [PaletteReference] - public readonly string ShadowPalette = "shadow"; + [Desc("Color to draw shadow if Shadow is true.")] + public readonly Color ShadowColor = Color.FromArgb(140, 0, 0, 0); [Desc("Projectile movement vector per tick (forward, right, up), use negative values for opposite directions.")] public readonly WVec Velocity = WVec.Zero; @@ -55,6 +57,10 @@ namespace OpenRA.Mods.Common.Projectiles readonly Animation anim; readonly ProjectileArgs args; readonly WVec acceleration; + + readonly float3 shadowColor; + readonly float shadowAlpha; + WVec velocity; [Sync] @@ -78,6 +84,9 @@ namespace OpenRA.Mods.Common.Projectiles else anim.PlayRepeating(info.Sequences.Random(args.SourceActor.World.SharedRandom)); } + + shadowColor = new float3(info.ShadowColor.R, info.ShadowColor.G, info.ShadowColor.B) / 255f; + shadowAlpha = info.ShadowColor.A; } public void Tick(World world) @@ -115,8 +124,10 @@ namespace OpenRA.Mods.Common.Projectiles { var dat = world.Map.DistanceAboveTerrain(pos); var shadowPos = pos - new WVec(0, 0, dat.Length); - foreach (var r in anim.Render(shadowPos, wr.Palette(info.ShadowPalette))) - yield return r; + foreach (var r in anim.Render(shadowPos, wr.Palette(info.Palette))) + yield return ((IModifyableRenderable)r) + .WithTint(shadowColor, ((IModifyableRenderable)r).TintModifiers | TintModifiers.ReplaceColor) + .WithAlpha(shadowAlpha); } var palette = wr.Palette(info.Palette + (info.IsPlayerPalette ? args.SourceActor.Owner.InternalName : "")); diff --git a/OpenRA.Mods.Common/Projectiles/Missile.cs b/OpenRA.Mods.Common/Projectiles/Missile.cs index af5906166e..0d9db120ee 100644 --- a/OpenRA.Mods.Common/Projectiles/Missile.cs +++ b/OpenRA.Mods.Common/Projectiles/Missile.cs @@ -37,9 +37,12 @@ namespace OpenRA.Mods.Common.Projectiles [Desc("Palette is a player palette BaseName")] public readonly bool IsPlayerPalette = false; - [Desc("Should the projectile's shadow be rendered?")] + [Desc("Does this projectile have a shadow?")] public readonly bool Shadow = false; + [Desc("Color to draw shadow if Shadow is true.")] + public readonly Color ShadowColor = Color.FromArgb(140, 0, 0, 0); + [Desc("Minimum vertical launch angle (pitch).")] public readonly WAngle MinimumLaunchAngle = new WAngle(-64); @@ -180,6 +183,9 @@ namespace OpenRA.Mods.Common.Projectiles readonly WAngle minLaunchAngle; readonly WAngle maxLaunchAngle; + readonly float3 shadowColor; + readonly float shadowAlpha; + int ticks; int ticksToNextSmoke; @@ -264,6 +270,9 @@ namespace OpenRA.Mods.Common.Projectiles trailPalette = info.TrailPalette; if (info.TrailUsePlayerPalette) trailPalette += args.SourceActor.Owner.InternalName; + + shadowColor = new float3(info.ShadowColor.R, info.ShadowColor.G, info.ShadowColor.B) / 255f; + shadowAlpha = info.ShadowColor.A; } static int LoopRadius(int speed, int rot) @@ -916,8 +925,10 @@ namespace OpenRA.Mods.Common.Projectiles { var dat = world.Map.DistanceAboveTerrain(pos); var shadowPos = pos - new WVec(0, 0, dat.Length); - foreach (var r in anim.Render(shadowPos, wr.Palette("shadow"))) - yield return r; + foreach (var r in anim.Render(shadowPos, wr.Palette(info.Palette))) + yield return ((IModifyableRenderable)r) + .WithTint(shadowColor, ((IModifyableRenderable)r).TintModifiers | TintModifiers.ReplaceColor) + .WithAlpha(shadowAlpha); } var palette = wr.Palette(info.Palette + (info.IsPlayerPalette ? args.SourceActor.Owner.InternalName : "")); diff --git a/OpenRA.Mods.Common/Traits/Render/WithParachute.cs b/OpenRA.Mods.Common/Traits/Render/WithParachute.cs index 3436122db0..e407732231 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithParachute.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithParachute.cs @@ -53,9 +53,8 @@ namespace OpenRA.Mods.Common.Traits.Render [Desc("Paradropped unit's shadow sequence.")] public readonly string ShadowSequence = null; - [PaletteReference(false)] - [Desc("Palette used to render the paradropped unit's shadow.")] - public readonly string ShadowPalette = "shadow"; + [Desc("Color to render the paradropped unit's shadow.")] + public readonly Color ShadowColor = Color.FromArgb(140, 0, 0, 0); [Desc("Shadow position relative to the paradropped unit's intended landing position.")] public readonly WVec ShadowOffset = new WVec(0, 128, 0); @@ -108,6 +107,8 @@ namespace OpenRA.Mods.Common.Traits.Render readonly Animation shadow; readonly AnimationWithOffset anim; readonly WithParachuteInfo info; + readonly float3 shadowColor; + readonly float shadowAlpha; bool renderProlonged = false; @@ -135,6 +136,9 @@ namespace OpenRA.Mods.Common.Traits.Render var rs = self.Trait(); rs.Add(anim, info.Palette, info.IsPlayerPalette); + + shadowColor = new float3(info.ShadowColor.R, info.ShadowColor.G, info.ShadowColor.B) / 255f; + shadowAlpha = info.ShadowColor.A / 255f; } protected override void TraitEnabled(Actor self) @@ -175,9 +179,9 @@ namespace OpenRA.Mods.Common.Traits.Render var dat = self.World.Map.DistanceAboveTerrain(self.CenterPosition); var pos = self.CenterPosition - new WVec(0, 0, dat.Length); - var palette = wr.Palette(info.ShadowPalette); - var tintModifiers = shadow.CurrentSequence.IgnoreWorldTint ? TintModifiers.IgnoreWorldTint : TintModifiers.None; - return new IRenderable[] { new SpriteRenderable(shadow.Image, pos, info.ShadowOffset, info.ShadowZOffset, palette, shadow.CurrentSequence.Scale, true, tintModifiers) }; + var palette = wr.Palette(info.Palette); + var tintModifiers = shadow.CurrentSequence.IgnoreWorldTint ? TintModifiers.ReplaceColor | TintModifiers.IgnoreWorldTint : TintModifiers.ReplaceColor; + return new IRenderable[] { new SpriteRenderable(shadow.Image, pos, info.ShadowOffset, info.ShadowZOffset, palette, 1, shadowAlpha, shadowColor, tintModifiers, true) }; } IEnumerable IRender.ScreenBounds(Actor self, WorldRenderer wr) diff --git a/OpenRA.Mods.Common/Traits/Render/WithShadow.cs b/OpenRA.Mods.Common/Traits/Render/WithShadow.cs index d777c107ba..9db8e8ba2f 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithShadow.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithShadow.cs @@ -20,8 +20,8 @@ namespace OpenRA.Mods.Common.Traits.Render [Desc("Clones the actor sprite with another palette below it.")] public class WithShadowInfo : ConditionalTraitInfo { - [PaletteReference] - public readonly string Palette = "shadow"; + [Desc("Color to draw shadow.")] + public readonly Color ShadowColor = Color.FromArgb(140, 0, 0, 0); [Desc("Shadow position offset relative to actor position (ground level).")] public readonly WVec Offset = WVec.Zero; @@ -35,11 +35,15 @@ namespace OpenRA.Mods.Common.Traits.Render public class WithShadow : ConditionalTrait, IRenderModifier { readonly WithShadowInfo info; + readonly float3 shadowColor; + readonly float shadowAlpha; public WithShadow(WithShadowInfo info) : base(info) { this.info = info; + shadowColor = new float3(info.ShadowColor.R, info.ShadowColor.G, info.ShadowColor.B) / 255f; + shadowAlpha = info.ShadowColor.A / 255f; } IEnumerable IRenderModifier.ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) @@ -47,12 +51,12 @@ namespace OpenRA.Mods.Common.Traits.Render if (IsTraitDisabled) return r; - // Contrails shouldn't cast shadows var height = self.World.Map.DistanceAboveTerrain(self.CenterPosition).Length; - var shadowSprites = r.Where(s => !s.IsDecoration && s is IPalettedRenderable) - .Select(a => ((IPalettedRenderable)a).WithPalette(wr.Palette(info.Palette)) + var shadowSprites = r.Where(s => !s.IsDecoration && s is IModifyableRenderable) + .Select(ma => ((IModifyableRenderable)ma).WithTint(shadowColor, ((IModifyableRenderable)ma).TintModifiers | TintModifiers.ReplaceColor) + .WithAlpha(shadowAlpha) .OffsetBy(info.Offset - new WVec(0, 0, height)) - .WithZOffset(a.ZOffset + (height + info.ZOffset)) + .WithZOffset(ma.ZOffset + (height + info.ZOffset)) .AsDecoration()); return shadowSprites.Concat(r); diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20201213/ReplaceShadowPalette.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20201213/ReplaceShadowPalette.cs new file mode 100644 index 0000000000..6df0946baa --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20201213/ReplaceShadowPalette.cs @@ -0,0 +1,64 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class ReplaceShadowPalette : UpdateRule + { + public override string Name { get { return "Removed ShadowPalette from WithShadow and projectiles."; } } + + public override string Description + { + get + { + return "The ShadowPalette field has been replaced by ShadowColor on projectiles.\n" + + "The Palette field on WithShadow and ShadowPalette on WithParachute have similarly been replaced with ShadowColor."; + } + } + + readonly List locations = new List(); + + public override IEnumerable AfterUpdate(ModData modData) + { + if (locations.Any()) + yield return "The shadow palette overrides have been removed from the following locations:\n" + + UpdateUtils.FormatMessageList(locations) + "\n\n" + + "You may wish to inspect and change these."; + + locations.Clear(); + } + + public override IEnumerable UpdateWeaponNode(ModData modData, MiniYamlNode weaponNode) + { + foreach (var projectileNode in weaponNode.ChildrenMatching("Projectile")) + if (projectileNode.RemoveNodes("ShadowPalette") > 0) + locations.Add("{0}: {1} ({2})".F(weaponNode.Key, weaponNode.Key, weaponNode.Location.Filename)); + + yield break; + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var node in actorNode.ChildrenMatching("WithShadow")) + if (node.RemoveNodes("Palette") > 0) + locations.Add("{0}: {1} ({2})".F(actorNode.Key, node.Key, actorNode.Location.Filename)); + + foreach (var node in actorNode.ChildrenMatching("WithParachute")) + if (node.RemoveNodes("ShadowPalette") > 0) + locations.Add("{0}: {1} ({2})".F(actorNode.Key, node.Key, actorNode.Location.Filename)); + + yield break; + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index cfbb2b5122..9bff9b597a 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -89,6 +89,7 @@ namespace OpenRA.Mods.Common.UpdateRules new ReplaceWithColoredOverlayPalette(), new RemoveRenderSpritesScale(), new RemovePlaceBuildingPalette(), + new ReplaceShadowPalette(), }) };