diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs index 3b0a3c9504..f54bc40cbf 100644 --- a/OpenRA.Game/Player.cs +++ b/OpenRA.Game/Player.cs @@ -154,12 +154,7 @@ namespace OpenRA if (a.TraitsImplementing().Any(t => !t.IsVisible(a, this))) return false; - if (a.Owner.IsAlliedWith(this)) - return true; - - // Actors are hidden under shroud, but not under fog by default - // TODO: Shroud exploration should be implemented as an IVisibility modifier! - return Shroud.GetVisOrigins(a).Any(Shroud.IsExplored); + return a.Trait().IsVisible(a, this); } #region Scripting interface diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index c2e7e154df..e4d4ff7deb 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -167,6 +167,8 @@ namespace OpenRA.Traits IEnumerable> RadarSignatureCells(Actor self); } + public interface IDefaultVisibilityInfo { } + public interface IDefaultVisibility { bool IsVisible(Actor self, Player byPlayer); } public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); } public interface IFogVisibilityModifier { bool HasFogVisibility(Player byPlayer); } diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 44e8c69a92..6fedf82187 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -676,6 +676,8 @@ + + diff --git a/OpenRA.Mods.Common/Traits/Modifiers/AlwaysVisible.cs b/OpenRA.Mods.Common/Traits/Modifiers/AlwaysVisible.cs new file mode 100644 index 0000000000..74c798070c --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Modifiers/AlwaysVisible.cs @@ -0,0 +1,24 @@ +#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 OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("The actor is always considered visible for targeting and rendering purposes.")] + public class AlwaysVisibleInfo : TraitInfo, IDefaultVisibilityInfo { } + public class AlwaysVisible : IDefaultVisibility + { + public bool IsVisible(Actor self, Player byPlayer) + { + return true; + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs index 154c852257..cdee1d2959 100644 --- a/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.Common/Traits/Modifiers/FrozenUnderFog.cs @@ -17,17 +17,21 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("This actor will remain visible (but not updated visually) under fog, once discovered.")] - public class FrozenUnderFogInfo : ITraitInfo, Requires + public class FrozenUnderFogInfo : ITraitInfo, Requires, IDefaultVisibilityInfo { public readonly bool StartsRevealed = false; + [Desc("Players with these stances can always see the actor.")] + public readonly Stance AlwaysVisibleStances = Stance.Ally; + public object Create(ActorInitializer init) { return new FrozenUnderFog(init, this); } } - public class FrozenUnderFog : IRenderModifier, IVisibilityModifier, ITick, ISync + public class FrozenUnderFog : IRenderModifier, IDefaultVisibility, ITick, ISync { [Sync] public int VisibilityHash; + readonly FrozenUnderFogInfo info; readonly bool startsRevealed; readonly MPos[] footprint; @@ -41,6 +45,8 @@ namespace OpenRA.Mods.Common.Traits public FrozenUnderFog(ActorInitializer init, FrozenUnderFogInfo info) { + this.info = info; + // Spawned actors (e.g. building husks) shouldn't be revealed startsRevealed = info.StartsRevealed && !init.Contains(); var footprintCells = FootprintUtils.Tiles(init.Self).ToList(); @@ -54,7 +60,11 @@ namespace OpenRA.Mods.Common.Traits public bool IsVisible(Actor self, Player byPlayer) { - return byPlayer == null || visible[byPlayer]; + if (byPlayer == null) + return true; + + var stance = self.Owner.Stances[byPlayer]; + return info.AlwaysVisibleStances.HasFlag(stance) || visible[byPlayer]; } public void Tick(Actor self) diff --git a/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderFog.cs b/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderFog.cs index fa2a44dbb6..a9438fcf8b 100644 --- a/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderFog.cs +++ b/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderFog.cs @@ -16,18 +16,22 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("The actor stays invisible under fog of war.")] - public class HiddenUnderFogInfo : TraitInfo { } - - public class HiddenUnderFog : IRenderModifier, IVisibilityModifier + public class HiddenUnderFogInfo : HiddenUnderShroudInfo { - public bool IsVisible(Actor self, Player byPlayer) - { - return byPlayer == null || Shroud.GetVisOrigins(self).Any(byPlayer.Shroud.IsVisible); - } + public override object Create(ActorInitializer init) { return new HiddenUnderFog(this); } + } - public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) + public class HiddenUnderFog : HiddenUnderShroud + { + public HiddenUnderFog(HiddenUnderFogInfo info) + : base(info) { } + + protected override bool IsVisibleInner(Actor self, Player byPlayer) { - return IsVisible(self, self.World.RenderPlayer) ? r : SpriteRenderable.None; + if (!VisibilityFootprint(self).Any(byPlayer.Shroud.IsVisible)) + return false; + + return base.IsVisibleInner(self, byPlayer); } } } diff --git a/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderShroud.cs b/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderShroud.cs new file mode 100644 index 0000000000..3882bfa5ce --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Modifiers/HiddenUnderShroud.cs @@ -0,0 +1,60 @@ +#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.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("The actor stays invisible under the shroud.")] + public class HiddenUnderShroudInfo : ITraitInfo, IDefaultVisibilityInfo + { + [Desc("Players with these stances can always see the actor.")] + public readonly Stance AlwaysVisibleStances = Stance.Ally; + + public virtual object Create(ActorInitializer init) { return new HiddenUnderShroud(this); } + } + + public class HiddenUnderShroud : IDefaultVisibility, IRenderModifier + { + readonly HiddenUnderShroudInfo info; + + public HiddenUnderShroud(HiddenUnderShroudInfo info) + { + this.info = info; + } + + protected IEnumerable VisibilityFootprint(Actor self) + { + return Shroud.GetVisOrigins(self); + } + + protected virtual bool IsVisibleInner(Actor self, Player byPlayer) + { + return VisibilityFootprint(self).Any(byPlayer.Shroud.IsExplored); + } + + public bool IsVisible(Actor self, Player byPlayer) + { + if (byPlayer == null) + return true; + + var stance = self.Owner.Stances[byPlayer]; + return info.AlwaysVisibleStances.HasFlag(stance) || IsVisibleInner(self, byPlayer); + } + + public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) + { + return IsVisible(self, self.World.RenderPlayer) ? r : SpriteRenderable.None; + } + } +}