diff --git a/OpenRA.Game/Graphics/Minimap.cs b/OpenRA.Game/Graphics/Minimap.cs index 38c23a069d..c3487d3877 100644 --- a/OpenRA.Game/Graphics/Minimap.cs +++ b/OpenRA.Game/Graphics/Minimap.cs @@ -139,7 +139,7 @@ namespace OpenRA.Graphics foreach (var t in world.ActorsWithTrait()) { - if (!world.RenderedShroud.IsVisible(t.Actor)) + if (world.ShroudObscures(t.Actor)) continue; var color = t.Trait.RadarSignatureColor(t.Actor); @@ -158,7 +158,7 @@ namespace OpenRA.Graphics var map = world.Map; var size = Exts.NextPowerOf2(Math.Max(map.Bounds.Width, map.Bounds.Height)); var bitmap = new Bitmap(size, size); - if (world.RenderedShroud.Disabled) + if (world.RenderPlayer == null) return bitmap; var bitmapData = bitmap.LockBits(bitmap.Bounds(), @@ -174,11 +174,10 @@ namespace OpenRA.Graphics for (var x = 0; x < map.Bounds.Width; x++) for (var y = 0; y < map.Bounds.Height; y++) { - var mapX = x + map.Bounds.Left; - var mapY = y + map.Bounds.Top; - if (!world.RenderedShroud.IsExplored(mapX, mapY)) + var p = new CPos(x + map.Bounds.Left, y + map.Bounds.Top); + if (world.ShroudObscures(p)) *(c + (y * bitmapData.Stride >> 2) + x) = shroud; - else if (!world.RenderedShroud.IsVisible(mapX,mapY)) + else if (world.FogObscures(p)) *(c + (y * bitmapData.Stride >> 2) + x) = fog; } } diff --git a/OpenRA.Game/Graphics/ShroudRenderer.cs b/OpenRA.Game/Graphics/ShroudRenderer.cs index 592a5af055..7abb76ffae 100644 --- a/OpenRA.Game/Graphics/ShroudRenderer.cs +++ b/OpenRA.Game/Graphics/ShroudRenderer.cs @@ -15,26 +15,14 @@ namespace OpenRA.Graphics { public class ShroudRenderer { - World world; - Traits.Shroud shroud { - get { - return world.RenderedShroud; - } - } - + Map map; + ShroudInfo shroudInfo; Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow"); Sprite[,] sprites, fogSprites; + int shroudHash; - Map map; - - public ShroudRenderer(World world) - { - this.world = world; - this.map = world.Map; - - sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; - fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y]; - } + bool initializePalettes = true; + PaletteReference fogPalette, shroudPalette; static readonly byte[][] SpecialShroudTiles = { @@ -56,81 +44,128 @@ namespace OpenRA.Graphics new byte[] { 46 }, }; - Sprite ChooseShroud(int i, int j) + public ShroudRenderer(World world) { - if( !shroud.IsExplored( i, j ) ) return shadowBits[ 0xf ]; + this.map = world.Map; + shroudInfo = Rules.Info["player"].Traits.Get(); - // bits are for unexploredness: up, right, down, left - var v = 0; - // bits are for unexploredness: TL, TR, BR, BL - var u = 0; + sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; + fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y]; - if( !shroud.IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; } - if( !shroud.IsExplored( i + 1, j ) ) { v |= 2; u |= 6; } - if( !shroud.IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; } - if( !shroud.IsExplored( i - 1, j ) ) { v |= 8; u |= 9; } - - var uSides = u; - - if( !shroud.IsExplored( i - 1, j - 1 ) ) u |= 1; - if( !shroud.IsExplored( i + 1, j - 1 ) ) u |= 2; - if( !shroud.IsExplored( i + 1, j + 1 ) ) u |= 4; - if( !shroud.IsExplored( i - 1, j + 1 ) ) u |= 8; - - return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ]; + // Force update on first render + shroudHash = -1; } - Sprite ChooseFog(int i, int j) + Sprite ChooseShroud(Shroud s, int i, int j) { - if (!shroud.IsVisible(i,j)) return shadowBits[0xf]; - if (!shroud.IsExplored(i, j)) return shadowBits[0xf]; + if (!s.IsExplored(i, j)) + return shadowBits[0xf]; // bits are for unexploredness: up, right, down, left var v = 0; // bits are for unexploredness: TL, TR, BR, BL var u = 0; - if (!shroud.IsVisible(i, j - 1)) { v |= 1; u |= 3; } - if (!shroud.IsVisible(i + 1, j)) { v |= 2; u |= 6; } - if (!shroud.IsVisible(i, j + 1)) { v |= 4; u |= 12; } - if (!shroud.IsVisible(i - 1, j)) { v |= 8; u |= 9; } + if (!s.IsExplored(i, j - 1)) { v |= 1; u |= 3; } + if (!s.IsExplored(i + 1, j)) { v |= 2; u |= 6; } + if (!s.IsExplored(i, j + 1)) { v |= 4; u |= 12; } + if (!s.IsExplored(i - 1, j)) { v |= 8; u |= 9; } var uSides = u; - - if (!shroud.IsVisible(i - 1, j - 1)) u |= 1; - if (!shroud.IsVisible(i + 1, j - 1)) u |= 2; - if (!shroud.IsVisible(i + 1, j + 1)) u |= 4; - if (!shroud.IsVisible(i - 1, j + 1)) u |= 8; + if (!s.IsExplored(i - 1, j - 1)) u |= 1; + if (!s.IsExplored(i + 1, j - 1)) u |= 2; + if (!s.IsExplored(i + 1, j + 1)) u |= 4; + if (!s.IsExplored(i - 1, j + 1)) u |= 8; return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; } - bool initializePalettes = true; - PaletteReference fogPalette, shroudPalette; - internal void Draw(WorldRenderer wr) + Sprite ChooseFog(Shroud s, int i, int j) + { + if (!s.IsVisible(i, j)) return shadowBits[0xf]; + if (!s.IsExplored(i, j)) return shadowBits[0xf]; + + // bits are for unexploredness: up, right, down, left + var v = 0; + // bits are for unexploredness: TL, TR, BR, BL + var u = 0; + + if (!s.IsVisible(i, j - 1)) { v |= 1; u |= 3; } + if (!s.IsVisible(i + 1, j)) { v |= 2; u |= 6; } + if (!s.IsVisible(i, j + 1)) { v |= 4; u |= 12; } + if (!s.IsVisible(i - 1, j)) { v |= 8; u |= 9; } + + var uSides = u; + + if (!s.IsVisible(i - 1, j - 1)) u |= 1; + if (!s.IsVisible(i + 1, j - 1)) u |= 2; + if (!s.IsVisible(i + 1, j + 1)) u |= 4; + if (!s.IsVisible(i - 1, j + 1)) u |= 8; + + return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; + } + + void GenerateSprites(Shroud shroud) + { + var hash = shroud != null ? shroud.Hash : 0; + if (shroudHash == hash) + return; + + shroudHash = hash; + if (shroud == null) + { + // Players with no shroud see the whole map so we only need to set the edges + var b = map.Bounds; + for (int i = b.Left; i < b.Right; i++) + for (int j = b.Top; j < b.Bottom; j++) + { + var v = 0; + var u = 0; + + if (j == b.Top) { v |= 1; u |= 3; } + if (i == b.Right - 1) { v |= 2; u |= 6; } + if (j == b.Bottom - 1) { v |= 4; u |= 12; } + if (i == b.Left) { v |= 8; u |= 9; } + + var uSides = u; + if (i == b.Left && j == b.Top) u |= 1; + if (i == b.Right - 1 && j == b.Top) u |= 2; + if (i == b.Right - 1 && j == b.Bottom - 1) u |= 4; + if (i == b.Left && j == b.Bottom - 1) u |= 8; + + sprites[i, j] = fogSprites[i, j] = shadowBits[SpecialShroudTiles[u ^ uSides][v]]; + } + } + else + { + for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) + for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) + sprites[i, j] = ChooseShroud(shroud, i, j); + + for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) + for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) + fogSprites[i, j] = ChooseFog(shroud, i, j); + } + } + + internal void Draw(WorldRenderer wr, Shroud shroud) { if (initializePalettes) { - fogPalette = wr.Palette("fog"); + if (shroudInfo.Fog) + fogPalette = wr.Palette("fog"); shroudPalette = wr.Palette("shroud"); initializePalettes = false; } - if (shroud != null && shroud.dirty) - { - shroud.dirty = false; - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - sprites[i, j] = ChooseShroud(i, j); - - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - fogSprites[i, j] = ChooseFog(i, j); - } + GenerateSprites(shroud); var clipRect = Game.viewport.WorldBounds(wr.world); + + // We draw the shroud when disabled to hide the sharp map edges DrawShroud(wr, clipRect, sprites, shroudPalette); - if (wr.world.WorldActor.HasTrait()) + + if (shroudInfo.Fog) DrawShroud(wr, clipRect, fogSprites, fogPalette); } diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 1e17aac0a2..08882935e3 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -72,9 +72,9 @@ namespace OpenRA.Graphics if (firstRow < 0) firstRow = 0; if (lastRow > map.Bounds.Height) lastRow = map.Bounds.Height; - if (world.RenderedPlayer != null && !world.RenderedShroud.Disabled && world.RenderedShroud.Bounds.HasValue) + if (world.VisibleBounds.HasValue) { - var r = world.RenderedShroud.Bounds.Value; + var r = world.VisibleBounds.Value; if (firstRow < r.Top - map.Bounds.Top) firstRow = r.Top - map.Bounds.Top; diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index b3add5a4d4..e7623d5697 100755 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -196,7 +196,7 @@ namespace OpenRA.Graphics cachedScroll = scrollPosition; } - var b = world.RenderedShroud.Bounds; + var b = world.VisibleBounds; return (b.HasValue) ? Rectangle.Intersect(cachedRect, b.Value) : cachedRect; } } diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index c0f19ef77a..b3dd017af4 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -127,7 +127,8 @@ namespace OpenRA.Graphics if (world.OrderGenerator != null) world.OrderGenerator.RenderAfterWorld(this, world); - shroudRenderer.Draw( this ); + var renderShroud = world.RenderPlayer != null ? world.RenderPlayer.Shroud : null; + shroudRenderer.Draw(this, renderShroud); Game.Renderer.DisableScissor(); foreach (var g in world.Selection.Actors.Where(a => !a.Destroyed) diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 3f30d687e7..670708792d 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -182,7 +182,6 @@ - diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs index 74c7853efb..f22b003e3a 100644 --- a/OpenRA.Game/Player.cs +++ b/OpenRA.Game/Player.cs @@ -77,7 +77,7 @@ namespace OpenRA } PlayerActor = world.CreateActor("Player", new TypeDictionary { new OwnerInit(this) }); Shroud = PlayerActor.Trait(); - Shroud.Owner = this; + // Enable the bot logic on the host IsBot = botType != null; if (IsBot && Game.IsHost) @@ -92,5 +92,10 @@ namespace OpenRA } public Dictionary Stances = new Dictionary(); + public bool IsAlliedWith(Player p) + { + // Observers are considered as allies + return p == null || Stances[p] == Stance.Ally; + } } } diff --git a/OpenRA.Game/Traits/CreatesShroud.cs b/OpenRA.Game/Traits/CreatesShroud.cs index da5b644cbf..7cef8baa06 100644 --- a/OpenRA.Game/Traits/CreatesShroud.cs +++ b/OpenRA.Game/Traits/CreatesShroud.cs @@ -32,29 +32,24 @@ namespace OpenRA.Traits public void Tick(Actor self) { // TODO: don't tick all the time. - if(self.Owner == null) return; + if (self.Owner == null) + return; - if (previousLocation != self.Location && v != null) { + var shrouds = self.World.ActorsWithTrait().Select(s => s.Actor.Owner.Shroud); + if (previousLocation != self.Location && v != null) + { previousLocation = self.Location; - var shrouds = self.World.ActorsWithTrait().Select(s => s.Actor.Owner.Shroud); - foreach (var shroud in shrouds) { + foreach (var shroud in shrouds) shroud.UnhideActor(self, v, Info.Range); - } } - if (!self.TraitsImplementing().Any(d => d.Disabled)) { - var shrouds = self.World.ActorsWithTrait().Select(s => s.Actor.Owner.Shroud); - foreach (var shroud in shrouds) { + if (!self.TraitsImplementing().Any(d => d.Disabled)) + foreach (var shroud in shrouds) shroud.HideActor(self, Info.Range); - } - } - else { - var shrouds = self.World.ActorsWithTrait().Select(s => s.Actor.Owner.Shroud); - foreach (var shroud in shrouds) { + else + foreach (var shroud in shrouds) shroud.UnhideActor(self, v, Info.Range); - } - } v = new Shroud.ActorVisibility { vis = Shroud.GetVisOrigins(self).ToArray() diff --git a/OpenRA.Game/Traits/Player/DeveloperMode.cs b/OpenRA.Game/Traits/Player/DeveloperMode.cs index f6492a58af..e432474eaa 100644 --- a/OpenRA.Game/Traits/Player/DeveloperMode.cs +++ b/OpenRA.Game/Traits/Player/DeveloperMode.cs @@ -81,7 +81,7 @@ namespace OpenRA.Traits case "DevShroudDisable": { DisableShroud ^= true; - self.Owner.Shroud.Disabled = DisableShroud; + self.World.RenderPlayer = DisableShroud ? null : self.Owner; break; } case "DevPathDebug": diff --git a/OpenRA.Game/Traits/SelectionDecorations.cs b/OpenRA.Game/Traits/SelectionDecorations.cs index bd1111957a..ab9293d688 100644 --- a/OpenRA.Game/Traits/SelectionDecorations.cs +++ b/OpenRA.Game/Traits/SelectionDecorations.cs @@ -31,8 +31,10 @@ namespace OpenRA.Traits public void RenderAfterWorld(WorldRenderer wr) { - var bounds = self.Bounds.Value; + if (self.World.FogObscures(self)) + return; + var bounds = self.Bounds.Value; var xy = new float2(bounds.Left, bounds.Top); var xY = new float2(bounds.Left, bounds.Bottom); @@ -54,7 +56,8 @@ namespace OpenRA.Traits void DrawPips(WorldRenderer wr, Actor self, float2 basePosition) { - if (self.Owner != self.World.RenderedPlayer) return; + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) + return; var pipSources = self.TraitsImplementing(); if (pipSources.Count() == 0) @@ -95,7 +98,8 @@ namespace OpenRA.Traits void DrawTags(WorldRenderer wr, Actor self, float2 basePosition) { - if (self.Owner != self.World.RenderedPlayer) return; + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) + return; // If a mod wants to implement a unit with multiple tags, then they are placed on multiple rows var tagxyBase = basePosition + new float2(-16, 2); // Correct for the offset in the shp file diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index d04f5d5bde..437bf80096 100755 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -86,7 +86,7 @@ namespace OpenRA.Traits Color RadarSignatureColor(Actor self); } - public interface IVisibilityModifier { bool IsVisible(Shroud s, Actor self); } + public interface IVisibilityModifier { bool IsVisible(Actor self, Player byPlayer); } public interface IRadarColorModifier { Color RadarColorOverride(Actor self); } public interface IHasLocation { PPos PxPosition { get; } } diff --git a/OpenRA.Game/Traits/World/Fog.cs b/OpenRA.Game/Traits/World/Fog.cs deleted file mode 100644 index 3fae8b6bcf..0000000000 --- a/OpenRA.Game/Traits/World/Fog.cs +++ /dev/null @@ -1,20 +0,0 @@ -#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 OpenRA.FileFormats; - -namespace OpenRA.Traits -{ - [Desc("This tag trait will enable fog of war in ShroudRenderer.", - "Don't forget about HiddenUnderFog and FrozenUnderFog.")] - public class FogInfo : TraitInfo { } - - public class Fog { } -} \ No newline at end of file diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs index a9ab4f2bea..4b10b173fc 100644 --- a/OpenRA.Game/Traits/World/ResourceLayer.cs +++ b/OpenRA.Game/Traits/World/ResourceLayer.cs @@ -40,7 +40,7 @@ namespace OpenRA.Traits for (int x = clip.Left; x < clip.Right; x++) for (int y = clip.Top; y < clip.Bottom; y++) { - if (!world.RenderedShroud.IsExplored(new CPos(x, y))) + if (world.ShroudObscures(new CPos(x, y))) continue; var c = content[x, y]; diff --git a/OpenRA.Game/Traits/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index 7089d9c09e..bc7cf629fa 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -12,69 +12,77 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Linq; +using OpenRA.Graphics; namespace OpenRA.Traits { public class ShroudInfo : ITraitInfo { - public object Create(ActorInitializer init) { return new Shroud(init.world); } + public readonly bool Shroud = true; + public readonly bool Fog = true; + public object Create(ActorInitializer init) { return new Shroud(init.self, this); } } - public class Shroud : ISync + public class Shroud { + public ShroudInfo Info; + Actor self; Map map; - World world; - [Sync] public Player Owner; - public int[,] visibleCells; - public bool[,] exploredCells; - public bool[,] foggedCells; - public Rectangle? exploredBounds; - bool disabled = false; - public bool dirty = true; - [Sync] public bool Disabled + int[,] visibleCells; + bool[,] exploredCells; + bool[,] foggedCells; + + public Rectangle ExploredBounds { get; private set; } + + public int Hash { get; private set; } + + public Shroud(Actor self, ShroudInfo info) { - get { return disabled; } - set { disabled = value; Dirty(); } - } + Info = info; + this.self = self; + map = self.World.Map; - public bool Observing - { - get { return world.IsShellmap || (world.LocalPlayer == null && Owner == null);; } - } - - public Rectangle? Bounds - { - get { return Disabled ? null : exploredBounds; } - } - - public Action Dirty = () => { }; - - public Shroud(World world) - { - this.world = world; - map = world.Map; visibleCells = new int[map.MapSize.X, map.MapSize.Y]; exploredCells = new bool[map.MapSize.X, map.MapSize.Y]; foggedCells = new bool[map.MapSize.X, map.MapSize.Y]; - world.ActorAdded += AddActor; - world.ActorRemoved += RemoveActor; - Dirty += () => dirty = true; + self.World.ActorAdded += AddActor; + self.World.ActorRemoved += RemoveActor; + + if (!info.Shroud) + ExploredBounds = map.Bounds; + } + + void Invalidate() + { + Hash = Sync.hash_player(self.Owner) + self.World.FrameNumber * 3; } // cache of positions that were added, so no matter what crazy trait code does, it // can't make us invalid. - public class ActorVisibility { [Sync] public int range; [Sync] public CPos[] vis; } + public class ActorVisibility + { + [Sync] public int range; + [Sync] public CPos[] vis; + } + public Dictionary vis = new Dictionary(); static IEnumerable FindVisibleTiles(World world, CPos a, int r) { var min = a - new CVec(r, r); var max = a + new CVec(r, r); - if (min.X < world.Map.Bounds.Left - 1) min = new CPos(world.Map.Bounds.Left - 1, min.Y); - if (min.Y < world.Map.Bounds.Top - 1) min = new CPos(min.X, world.Map.Bounds.Top - 1); - if (max.X > world.Map.Bounds.Right) max = new CPos(world.Map.Bounds.Right, max.Y); - if (max.Y > world.Map.Bounds.Bottom) max = new CPos(max.X, world.Map.Bounds.Bottom); + if (min.X < world.Map.Bounds.Left - 1) + min = new CPos(world.Map.Bounds.Left - 1, min.Y); + + if (min.Y < world.Map.Bounds.Top - 1) + min = new CPos(min.X, world.Map.Bounds.Top - 1); + + if (max.X > world.Map.Bounds.Right) + max = new CPos(world.Map.Bounds.Right, max.Y); + + if (max.Y > world.Map.Bounds.Bottom) + max = new CPos(max.X, world.Map.Bounds.Bottom); for (var j = min.Y; j <= max.Y; j++) for (var i = min.X; i <= max.X; i++) @@ -84,13 +92,12 @@ namespace OpenRA.Traits public void AddActor(Actor a) { - if (!a.HasTrait()) return; - if (a.Owner == null || Owner == null) return; - if(a.Owner.Stances[Owner] != Stance.Ally) return; + if (!a.HasTrait() || !a.Owner.IsAlliedWith(self.Owner)) + return; ActorVisibility v = a.Sight; - - if (v.range == 0) return; // don't bother for things that can't see + if (v.range == 0) + return; foreach (var p in v.vis) { @@ -102,17 +109,16 @@ namespace OpenRA.Traits } var box = new Rectangle(p.X - v.range, p.Y - v.range, 2 * v.range + 1, 2 * v.range + 1); - exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box; + ExploredBounds = Rectangle.Union(ExploredBounds, box); } - if (!Disabled) - Dirty(); + Invalidate(); } public void HideActor(Actor a, int range) { - if (a.Owner.World.LocalPlayer == null - || a.Owner.Stances[a.Owner.World.LocalPlayer] == Stance.Ally) return; + if (a.Owner.IsAlliedWith(self.Owner)) + return; var v = new ActorVisibility { @@ -123,34 +129,33 @@ namespace OpenRA.Traits foreach (var q in FindVisibleTiles(a.World, p, range)) foggedCells[q.X, q.Y] = visibleCells[q.X, q.Y] > 0; - if (!Disabled) - Dirty(); + Invalidate(); } - public void UnhideActor(Actor a, ActorVisibility v, int range) { - if (a.Owner.World.LocalPlayer == null - || a.Owner.Stances[a.Owner.World.LocalPlayer] == Stance.Ally) return; - - if (v == null) + public void UnhideActor(Actor a, ActorVisibility v, int range) + { + if (a.Owner.IsAlliedWith(self.Owner) || v == null) return; foreach (var p in v.vis) foreach (var q in FindVisibleTiles(a.World, p, range)) foggedCells[q.X, q.Y] = exploredCells[q.X, q.Y]; - if (!Disabled) - Dirty(); + Invalidate(); } - public void MergeShroud(Shroud s) { - for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) { - for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) { + public void MergeShroud(Shroud s) + { + for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) + { + for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) + { if (s.exploredCells[i,j] == true) exploredCells[i, j] = true; if (s.foggedCells[i,j] == true) foggedCells[i, j] = true; } - exploredBounds = Rectangle.Union(exploredBounds.Value, s.exploredBounds.Value); + ExploredBounds = Rectangle.Union(ExploredBounds, s.ExploredBounds); } } @@ -166,6 +171,7 @@ namespace OpenRA.Traits foreach (var a in toRemove) RemoveActor(a); } + // Is now our ally; add unit vis if (newStance == Stance.Ally) foreach (var a in w.Actors.Where( a => a.Owner == player )) @@ -177,7 +183,8 @@ namespace OpenRA.Traits int seen = 0; for (int i = map.Bounds.Left; i < map.Bounds.Right; i++) for (int j = map.Bounds.Top; j < map.Bounds.Bottom; j++) - if(foggedCells[i, j]) seen++; + if (foggedCells[i, j]) + seen++; return seen; } @@ -196,34 +203,33 @@ namespace OpenRA.Traits public void RemoveActor(Actor a) { - if (!a.HasTrait())return; - if (a.Owner == null || Owner == null) return; - ActorVisibility v = a.Sight; - - if(a.Owner.Stances[Owner] != Stance.Ally) { - if (a.HasTrait()) { + if (!a.Owner.IsAlliedWith(self.Owner)) + { + if (a.HasTrait()) foreach (var p in v.vis) foreach (var q in FindVisibleTiles(a.World, p, v.range)) foggedCells[q.X, q.Y] = exploredCells[q.X, q.Y]; - } return; } + if (!a.HasTrait()) + return; + foreach (var p in v.vis) foreach (var q in FindVisibleTiles(a.World, p, v.range)) --visibleCells[q.X, q.Y]; - if (!Disabled) - Dirty(); + Invalidate(); } public void UpdateActor(Actor a) { - if (a.Owner.World.LocalPlayer == null - || a.Owner.Stances[a.Owner.World.LocalPlayer] != Stance.Ally) return; + if (!a.Owner.IsAlliedWith(self.Owner)) + return; - RemoveActor(a); AddActor(a); + RemoveActor(a); + AddActor(a); } public void Explore(World world, CPos center, int range) @@ -234,10 +240,9 @@ namespace OpenRA.Traits } var box = new Rectangle(center.X - range, center.Y - range, 2 * range + 1, 2 * range + 1); - exploredBounds = (exploredBounds.HasValue) ? Rectangle.Union(exploredBounds.Value, box) : box; + ExploredBounds = Rectangle.Union(ExploredBounds, box); - if (!Disabled) - Dirty(); + Invalidate(); } public void ExploreAll(World world) @@ -248,10 +253,9 @@ namespace OpenRA.Traits foggedCells[i, j] = true; } } - exploredBounds = world.Map.Bounds; + ExploredBounds = world.Map.Bounds; - if (!Disabled) - Dirty(); + Invalidate(); } public void ResetExploration() @@ -264,8 +268,7 @@ namespace OpenRA.Traits for (var i = 0; i <= foggedCells.GetUpperBound(0); i++) foggedCells[i, j] = visibleCells[i, j] > 0; - if (!Disabled) - Dirty(); + Invalidate(); } public bool IsExplored(CPos xy) { return IsExplored(xy.X, xy.Y); } @@ -274,40 +277,42 @@ namespace OpenRA.Traits if (!map.IsInMap(x, y)) return false; - if (Disabled || Observing) + if (!Info.Shroud) return true; return foggedCells[x,y]; } + public bool IsExplored(Actor a) + { + return GetVisOrigins(a).Any(o => IsExplored(o)); + } + public bool IsVisible(CPos xy) { return IsVisible(xy.X, xy.Y); } public bool IsVisible(int x, int y) { - if (Disabled || Observing) - return true; - // Visibility is allowed to extend beyond the map cordon so that // the fog tiles are not visible at the edge of the world if (x < 0 || x >= map.MapSize.X || y < 0 || y >= map.MapSize.Y) return false; + if (!Info.Fog) + return true; + return visibleCells[x,y] != 0; } // Actors are hidden under shroud, but not under fog by default public bool IsVisible(Actor a) { - // I need to pass in the current shroud, otherwise we're just checking that true==true - if (a.TraitsImplementing().Any(t => !t.IsVisible(this, a))) + if (a.TraitsImplementing().Any(t => !t.IsVisible(a, self.Owner))) return false; - if(Owner == null) return true; - - return Disabled || Observing || a.Owner.Stances[Owner] == Stance.Ally || GetVisOrigins(a).Any(o => IsExplored(o)); + return a.Owner.IsAlliedWith(self.Owner) || IsExplored(a); } public bool IsTargetable(Actor a) { - if (a.TraitsImplementing().Any(t => !t.IsVisible(this, a))) + if (a.TraitsImplementing().Any(t => !t.IsVisible(a, self.Owner))) return false; return GetVisOrigins(a).Any(o => IsVisible(o)); diff --git a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs index da73e51725..b58609031b 100644 --- a/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs +++ b/OpenRA.Game/Widgets/WorldInteractionControllerWidget.cs @@ -184,7 +184,7 @@ namespace OpenRA.Widgets IEnumerable SelectActorsInBox(World world, PPos a, PPos b, Func cond) { return world.FindUnits(a, b) - .Where(x => x.HasTrait() && world.RenderedShroud.IsVisible(x) && cond(x)) + .Where(x => x.HasTrait() && !world.FogObscures(x) && cond(x)) .GroupBy(x => x.GetSelectionPriority()) .OrderByDescending(g => g.Key) .Select(g => g.AsEnumerable()) diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 4d7647a1c1..0845bba5ff 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -10,6 +10,7 @@ using System; using System.Collections.Generic; +using System.Drawing; using System.Linq; using OpenRA.Effects; using OpenRA.FileFormats; @@ -40,11 +41,30 @@ namespace OpenRA public void AddPlayer(Player p) { Players.Add(p); } public Player LocalPlayer { get; private set; } - public readonly Shroud LocalShroud; - public bool Observer { get { return LocalPlayer == null; } } - public Player RenderedPlayer; - public Shroud RenderedShroud { get { return RenderedPlayer != null ? RenderedPlayer.Shroud : LocalShroud; } } - + + Player renderPlayer; + public bool ObserveAfterWinOrLose; + public Player RenderPlayer + { + get { return renderPlayer == null || (ObserveAfterWinOrLose && renderPlayer.WinState != WinState.Undefined)? null : renderPlayer; } + set { renderPlayer = value; } + } + + public bool FogObscures(Actor a) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(a); } + public bool FogObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(p); } + public bool ShroudObscures(Actor a) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(a); } + public bool ShroudObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p); } + + public Rectangle? VisibleBounds + { + get + { + if (RenderPlayer == null) + return null; + + return RenderPlayer.Shroud.ExploredBounds; + } + } public void SetLocalPlayer(string pr) { @@ -52,7 +72,7 @@ namespace OpenRA return; LocalPlayer = Players.FirstOrDefault(p => p.InternalName == pr); - RenderedPlayer = LocalPlayer; + RenderPlayer = LocalPlayer; } public readonly Actor WorldActor; @@ -104,7 +124,6 @@ namespace OpenRA SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed); WorldActor = CreateActor( "World", new TypeDictionary() ); - LocalShroud = WorldActor.Trait(); ActorMap = new ActorMap(this); // Add players diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs index 3fb087a324..0c43535154 100755 --- a/OpenRA.Game/WorldUtils.cs +++ b/OpenRA.Game/WorldUtils.cs @@ -24,7 +24,7 @@ namespace OpenRA public static IEnumerable FindUnitsAtMouse(this World world, int2 mouseLocation) { var loc = Game.viewport.ViewToWorldPx(mouseLocation); - return FindUnits(world, loc, loc).Where(a => world.RenderedShroud.IsVisible(a)); + return FindUnits(world, loc, loc).Where(a => !world.FogObscures(a)); } public static IEnumerable FindUnits(this World world, PPos a, PPos b) diff --git a/OpenRA.Mods.Cnc/Widgets/CncWorldInteractionControllerWidget.cs b/OpenRA.Mods.Cnc/Widgets/CncWorldInteractionControllerWidget.cs index 10a0f5ec7c..107d1768c5 100644 --- a/OpenRA.Mods.Cnc/Widgets/CncWorldInteractionControllerWidget.cs +++ b/OpenRA.Mods.Cnc/Widgets/CncWorldInteractionControllerWidget.cs @@ -66,7 +66,7 @@ namespace OpenRA.Mods.Cnc.Widgets if (!world.Map.IsInMap(cell)) return; - if (world.LocalPlayer != null && !world.LocalPlayer.Shroud.IsExplored(cell)) + if (world.ShroudObscures(cell)) { TooltipType = WorldTooltipType.Unexplored; return; diff --git a/OpenRA.Mods.RA/Buildings/BaseProvider.cs b/OpenRA.Mods.RA/Buildings/BaseProvider.cs index 8278d74744..0622f5a441 100755 --- a/OpenRA.Mods.RA/Buildings/BaseProvider.cs +++ b/OpenRA.Mods.RA/Buildings/BaseProvider.cs @@ -60,7 +60,7 @@ namespace OpenRA.Mods.RA.Buildings public void RenderBeforeWorld(WorldRenderer wr, Actor self) { // Visible to player and allies - if (self.World.RenderedPlayer != null && self.Owner.Stances[self.World.RenderedPlayer] != Stance.Ally) + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) return; wr.DrawRangeCircleWithContrast( @@ -73,7 +73,7 @@ namespace OpenRA.Mods.RA.Buildings public float GetValue() { // Visible to player and allies - if (self.World.RenderedPlayer != null && self.Owner.Stances[self.World.RenderedPlayer] != Stance.Ally) + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) return 0f; // Ready or delay disabled diff --git a/OpenRA.Mods.RA/Buildings/BibLayer.cs b/OpenRA.Mods.RA/Buildings/BibLayer.cs index efa1d48742..d5f33a2243 100755 --- a/OpenRA.Mods.RA/Buildings/BibLayer.cs +++ b/OpenRA.Mods.RA/Buildings/BibLayer.cs @@ -78,7 +78,7 @@ namespace OpenRA.Mods.RA.Buildings { if (!cliprect.Contains(kv.Key.X, kv.Key.Y)) continue; - if (!world.RenderedShroud.IsExplored(kv.Key)) + if (world.ShroudObscures(kv.Key)) continue; bibSprites[kv.Value.type - 1][kv.Value.index].DrawAt(wr, kv.Key.ToPPos().ToFloat2(), "terrain"); diff --git a/OpenRA.Mods.RA/Cloak.cs b/OpenRA.Mods.RA/Cloak.cs index 3bef1e3b8d..ea823c9a23 100644 --- a/OpenRA.Mods.RA/Cloak.cs +++ b/OpenRA.Mods.RA/Cloak.cs @@ -73,7 +73,7 @@ namespace OpenRA.Mods.RA if (remainingTime > 0) return r; - if (Cloaked && IsVisible(self.World.RenderedShroud, self)) + if (Cloaked && IsVisible(self, self.World.RenderPlayer)) if (string.IsNullOrEmpty(info.Palette)) return r; else @@ -97,17 +97,12 @@ namespace OpenRA.Mods.RA } } - public bool IsVisible(Shroud s, Actor self) + public bool IsVisible(Actor self, Player byPlayer) { - if (!Cloaked) + if (!Cloaked || self.Owner.IsAlliedWith(byPlayer)) return true; - if (s.Observing) - return true; - if (s.Owner != null) - if (self.Owner == s.Owner || self.Owner.Stances[s.Owner] == Stance.Ally) - return true; - + // TODO: Change this to be per-player? A cloak detector revealing to everyone is dumb return self.World.ActorsWithTrait().Any(a => a.Actor.Owner.Stances[self.Owner] != Stance.Ally && (self.Location - a.Actor.Location).Length < a.Actor.Info.Traits.Get().Range); diff --git a/OpenRA.Mods.RA/ConquestVictoryConditions.cs b/OpenRA.Mods.RA/ConquestVictoryConditions.cs index 0334fba8f8..f37020a031 100644 --- a/OpenRA.Mods.RA/ConquestVictoryConditions.cs +++ b/OpenRA.Mods.RA/ConquestVictoryConditions.cs @@ -19,13 +19,17 @@ namespace OpenRA.Mods.RA [Desc("Milliseconds")] public int NotificationDelay = 1500; - public object Create(ActorInitializer init) { return new ConquestVictoryConditions(this); } + public object Create(ActorInitializer init) { return new ConquestVictoryConditions(init.world, this); } } public class ConquestVictoryConditions : ITick, IResolveOrder { ConquestVictoryConditionsInfo Info; - public ConquestVictoryConditions(ConquestVictoryConditionsInfo info) { Info = info; } + public ConquestVictoryConditions(World world, ConquestVictoryConditionsInfo info) + { + world.ObserveAfterWinOrLose = true; + Info = info; + } public void Tick(Actor self) { @@ -62,15 +66,12 @@ namespace OpenRA.Mods.RA foreach (var a in self.World.Actors.Where(a => a.Owner == self.Owner)) a.Kill(a); - self.Owner.Shroud.Disabled = true; if (self.Owner == self.World.LocalPlayer) - { Game.RunAfterDelay(Info.NotificationDelay, () => { if (Game.IsCurrentWorld(self.World)) Sound.PlayNotification(self.Owner, "Speech", "Lose", self.Owner.Country.Race); }); - } } public void Win(Actor self) @@ -79,11 +80,8 @@ namespace OpenRA.Mods.RA self.Owner.WinState = WinState.Won; Game.Debug("{0} is victorious.".F(self.Owner.PlayerName)); - self.Owner.Shroud.Disabled = true; if (self.Owner == self.World.LocalPlayer) - { Game.RunAfterDelay(Info.NotificationDelay, () => Sound.PlayNotification(self.Owner, "Speech", "Win", self.Owner.Country.Race)); - } } } diff --git a/OpenRA.Mods.RA/Effects/Bullet.cs b/OpenRA.Mods.RA/Effects/Bullet.cs index 5939ed008a..0850180d61 100755 --- a/OpenRA.Mods.RA/Effects/Bullet.cs +++ b/OpenRA.Mods.RA/Effects/Bullet.cs @@ -160,7 +160,8 @@ namespace OpenRA.Mods.RA.Effects var altitude = float2.Lerp(Args.srcAltitude, Args.destAltitude, at); var pos = float2.Lerp(Args.src.ToFloat2(), Args.dest.ToFloat2(), at) - new float2(0, altitude); - if (Args.firedBy.World.RenderedShroud.IsVisible(((PPos) pos.ToInt2()).ToCPos())) + var cell = ((PPos)pos.ToInt2()).ToCPos(); + if (!Args.firedBy.World.FogObscures(cell)) { if (Info.High || Info.Angle > 0) { diff --git a/OpenRA.Mods.RA/Effects/Contrail.cs b/OpenRA.Mods.RA/Effects/Contrail.cs index 4c0b3ffb4a..6776b2db00 100755 --- a/OpenRA.Mods.RA/Effects/Contrail.cs +++ b/OpenRA.Mods.RA/Effects/Contrail.cs @@ -93,8 +93,8 @@ namespace OpenRA.Mods.RA var conPos = WPos.Average(positions[i], positions[i-1], positions[i-2], positions[i-3]); var nextPos = WPos.Average(positions[i-1], positions[i-2], positions[i-3], positions[i-4]); - if (self.World.RenderedShroud.IsVisible(new CPos(conPos)) || - self.World.RenderedShroud.IsVisible(new CPos(nextPos))) + if (!self.World.FogObscures(new CPos(conPos)) && + !self.World.FogObscures(new CPos(nextPos))) { Game.Renderer.WorldLineRenderer.DrawLine(wr.ScreenPosition(conPos), wr.ScreenPosition(nextPos), trailStart, trailEnd); diff --git a/OpenRA.Mods.RA/Effects/GpsDot.cs b/OpenRA.Mods.RA/Effects/GpsDot.cs index 7b63f440dc..c9da29dc8b 100644 --- a/OpenRA.Mods.RA/Effects/GpsDot.cs +++ b/OpenRA.Mods.RA/Effects/GpsDot.cs @@ -69,7 +69,7 @@ namespace OpenRA.Mods.RA.Effects } var hasGps = (watcher != null && (watcher.Granted || watcher.GrantedAllies)); - var hasDot = (huf != null && !huf.IsVisible(self.World.RenderedShroud, self)); // WRONG (why?) + var hasDot = (huf != null && !huf.IsVisible(self, self.World.RenderPlayer)); var dotHidden = (cloak != null && cloak.Cloaked) || (spy != null && spy.Disguised); show = hasGps && hasDot && !dotHidden; diff --git a/OpenRA.Mods.RA/Effects/Missile.cs b/OpenRA.Mods.RA/Effects/Missile.cs index f04ec2cecd..88bedf524a 100755 --- a/OpenRA.Mods.RA/Effects/Missile.cs +++ b/OpenRA.Mods.RA/Effects/Missile.cs @@ -158,7 +158,7 @@ namespace OpenRA.Mods.RA.Effects public IEnumerable Render(WorldRenderer wr) { - if (Args.firedBy.World.RenderedShroud.IsVisible(PxPosition.ToCPos())) + if (!Args.firedBy.World.FogObscures(PxPosition.ToCPos())) yield return new Renderable(anim.Image, PxPosition.ToFloat2() - 0.5f * anim.Image.size - new float2(0, Altitude), wr.Palette(Args.weapon.Underwater ? "shadow" : "effect"), PxPosition.Y); diff --git a/OpenRA.Mods.RA/FogPalette.cs b/OpenRA.Mods.RA/FogPalette.cs deleted file mode 100644 index 92ee39cee6..0000000000 --- a/OpenRA.Mods.RA/FogPalette.cs +++ /dev/null @@ -1,46 +0,0 @@ -#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.Drawing; -using OpenRA.FileFormats; -using OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.RA -{ - [Desc("Adds the hard-coded fog palette to the game")] - class FogPaletteInfo : ITraitInfo - { - [Desc("internal palette name")] - public readonly string Name = "fog"; - public object Create(ActorInitializer init) { return new FogPalette(this); } - } - - class FogPalette : IPalette - { - readonly FogPaletteInfo info; - - public FogPalette(FogPaletteInfo info) { this.info = info; } - - public void InitPalette(WorldRenderer wr) - { - var c = new[] { - Color.Transparent, Color.Green, - Color.Blue, Color.Yellow, - Color.FromArgb(128,0,0,0), - Color.FromArgb(128,0,0,0), - Color.FromArgb(128,0,0,0), - Color.FromArgb(64,0,0,0) - }; - - wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (uint)c[i % 8].ToArgb())), false); - } - } -} diff --git a/OpenRA.Mods.RA/GainsExperience.cs b/OpenRA.Mods.RA/GainsExperience.cs index 1674c9aa31..6ac2ff50cd 100644 --- a/OpenRA.Mods.RA/GainsExperience.cs +++ b/OpenRA.Mods.RA/GainsExperience.cs @@ -100,6 +100,7 @@ namespace OpenRA.Mods.RA public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { + // TODO: Make this consistent with everything else that adds animations to RenderSimple. if ((self.Owner == self.World.LocalPlayer || self.World.LocalPlayer == null) && Level > 0) return InnerModifyRender(self, wr, r); else @@ -112,6 +113,10 @@ namespace OpenRA.Mods.RA yield return rs; RankAnim.Tick(); // HACK + + if (self.World.FogObscures(self)) + yield break; + var bounds = self.Bounds.Value; yield return new Renderable(RankAnim.Image, new float2(bounds.Right - 6, bounds.Bottom - 8), wr.Palette("effect"), self.CenterLocation.Y); diff --git a/OpenRA.Mods.RA/MPStartLocations.cs b/OpenRA.Mods.RA/MPStartLocations.cs index 64fa49e993..a64af630f4 100755 --- a/OpenRA.Mods.RA/MPStartLocations.cs +++ b/OpenRA.Mods.RA/MPStartLocations.cs @@ -47,10 +47,11 @@ namespace OpenRA.Mods.RA } // Explore allied shroud - foreach (var p in Start) - if ((world.LocalPlayer != null ) &&(p.Key == world.LocalPlayer || p.Key.Stances[world.LocalPlayer] == Stance.Ally)) - world.WorldActor.Trait().Explore(world, p.Value, - world.WorldActor.Info.Traits.Get().InitialExploreRange); + var explore = world.WorldActor.Info.Traits.Get().InitialExploreRange; + foreach (var p in Start.Keys) + foreach (var q in world.Players) + if (p.IsAlliedWith(q)) + q.Shroud.Explore(world, Start[p], explore); // Set viewport if (world.LocalPlayer != null && Start.ContainsKey(world.LocalPlayer)) diff --git a/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs b/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs index c4f823be48..22b207ade7 100644 --- a/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs +++ b/OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs @@ -19,15 +19,15 @@ namespace OpenRA.Mods.RA class FrozenUnderFog : IRenderModifier, IVisibilityModifier { - public bool IsVisible(Shroud s, Actor self) + public bool IsVisible(Actor self, Player byPlayer) { - return Shroud.GetVisOrigins(self).Any(o => s.IsVisible(o)); + return byPlayer == null || Shroud.GetVisOrigins(self).Any(o => byPlayer.Shroud.IsVisible(o)); } Renderable[] cache = { }; public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { - if (IsVisible(self.World.RenderedShroud, self)) + if (IsVisible(self, self.World.RenderPlayer)) cache = r.ToArray(); return cache; } diff --git a/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs b/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs index cba548f4e4..0686b0941a 100644 --- a/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs +++ b/OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs @@ -19,15 +19,15 @@ namespace OpenRA.Mods.RA class HiddenUnderFog : IRenderModifier, IVisibilityModifier { - public bool IsVisible(Shroud s, Actor self) + public bool IsVisible(Actor self, Player byPlayer) { - return Shroud.GetVisOrigins(self).Any(o => s.IsVisible(o)); + return byPlayer == null || Shroud.GetVisOrigins(self).Any(o => byPlayer.Shroud.IsVisible(o)); } static Renderable[] Nothing = { }; public IEnumerable ModifyRender(Actor self, WorldRenderer wr, IEnumerable r) { - return IsVisible(self.World.RenderedShroud, self) ? r : Nothing; + return IsVisible(self, self.World.RenderPlayer) ? r : Nothing; } } } diff --git a/OpenRA.Mods.RA/Move/Mobile.cs b/OpenRA.Mods.RA/Move/Mobile.cs index 63744d9776..86b1757737 100755 --- a/OpenRA.Mods.RA/Move/Mobile.cs +++ b/OpenRA.Mods.RA/Move/Mobile.cs @@ -485,10 +485,10 @@ namespace OpenRA.Mods.RA.Move IsQueued = forceQueued; cursor = "move"; - if (self.World.LocalPlayer.Shroud.IsExplored(location)) + if (self.Owner.Shroud.IsExplored(location)) cursor = self.World.GetTerrainInfo(location).CustomCursor ?? cursor; - if (!self.World.Map.IsInMap(location) || (self.World.LocalPlayer.Shroud.IsExplored(location) && + if (!self.World.Map.IsInMap(location) || (self.Owner.Shroud.IsExplored(location) && unitType.MovementCostForCell(self.World, location) == int.MaxValue)) cursor = "move-blocked"; diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 12509ac1d7..b9a2febadd 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -417,7 +417,6 @@ - diff --git a/OpenRA.Mods.RA/ProductionBar.cs b/OpenRA.Mods.RA/ProductionBar.cs index 840b0c0153..198f82bcf5 100644 --- a/OpenRA.Mods.RA/ProductionBar.cs +++ b/OpenRA.Mods.RA/ProductionBar.cs @@ -29,7 +29,7 @@ namespace OpenRA.Mods.RA public float GetValue() { // only people we like should see our production status. - if (self.World.RenderedPlayer != null && self.Owner.Stances[self.World.RenderedPlayer] != Stance.Ally) + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) return 0; var queue = self.TraitsImplementing().FirstOrDefault(q => q.CurrentItem() != null); diff --git a/OpenRA.Mods.RA/ShroudPalette.cs b/OpenRA.Mods.RA/ShroudPalette.cs index 3fed81a6eb..247a87986e 100644 --- a/OpenRA.Mods.RA/ShroudPalette.cs +++ b/OpenRA.Mods.RA/ShroudPalette.cs @@ -15,11 +15,17 @@ using OpenRA.Traits; namespace OpenRA.Mods.RA { + public enum ShroudPaletteType { Shroud, Fog, Combined }; + [Desc("Adds the hard-coded shroud palette to the game")] class ShroudPaletteInfo : ITraitInfo { - [Desc("internal palette name")] + [Desc("Internal palette name")] public readonly string Name = "shroud"; + + [Desc("Palette type")] + public readonly ShroudPaletteType Type = ShroudPaletteType.Combined; + public object Create(ActorInitializer init) { return new ShroudPalette(this); } } @@ -31,16 +37,37 @@ namespace OpenRA.Mods.RA public void InitPalette(WorldRenderer wr) { - var c = new[] { - Color.Transparent, Color.Green, - Color.Blue, Color.Yellow, - Color.Black, - Color.FromArgb(128,0,0,0), - Color.Transparent, - Color.Transparent - }; + var c = info.Type == ShroudPaletteType.Shroud ? Shroud : + info.Type == ShroudPaletteType.Fog ? Fog : Combined; wr.AddPalette(info.Name, new Palette(Exts.MakeArray(256, i => (uint)c[i % 8].ToArgb())), false); } + + static Color[] Shroud = new[] { + Color.Transparent, Color.Green, + Color.Blue, Color.Yellow, + Color.Black, + Color.FromArgb(128,0,0,0), + Color.Transparent, + Color.Transparent + }; + + static Color[] Fog = new[] { + Color.Transparent, Color.Green, + Color.Blue, Color.Yellow, + Color.FromArgb(128,0,0,0), + Color.FromArgb(128,0,0,0), + Color.FromArgb(128,0,0,0), + Color.FromArgb(64,0,0,0) + }; + + static Color[] Combined = new[] { + Color.Transparent, Color.Green, + Color.Blue, Color.Yellow, + Color.Black, + Color.FromArgb(192,0,0,0), + Color.FromArgb(128,0,0,0), + Color.FromArgb(64,0,0,0) + }; } } diff --git a/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs b/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs index 229b329f59..a6d9ac9668 100644 --- a/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs +++ b/OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs @@ -41,7 +41,7 @@ namespace OpenRA.Mods.RA { var position = self.CenterPosition; if (position.Z > 0 && self.GetDamageState() >= DamageState.Heavy && - self.World.RenderedShroud.IsVisible(new CPos(position))) + !self.World.FogObscures(new CPos(position))) { var offset = info.Offset.Rotate(coords.QuantizeOrientation(self, self.Orientation)); var pos = PPos.FromWPosHackZ(position + coords.LocalToWorld(offset)); diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs index 8ef9c850cd..9dfbf91184 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs @@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic private bool teamChat = false; internal bool TeamChat { - get { return World.Observer ? false : teamChat; } + get { return World.LocalPlayer == null ? false : teamChat; } set { teamChat = value; } } diff --git a/OpenRA.Mods.RA/Widgets/Logic/ObserverShroudSelectorLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ObserverShroudSelectorLogic.cs index ba2b14c402..0e2d3e3636 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/ObserverShroudSelectorLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/ObserverShroudSelectorLogic.cs @@ -40,16 +40,16 @@ namespace OpenRA.Mods.RA.Widgets.Logic { var views = world.Players.Where(p => !p.NonCombatant).ToDictionary(p => p.PlayerName, p => new CameraOption("{0}'s view".F(p.PlayerName), - () => world.RenderedPlayer == p, - () => { world.RenderedPlayer = p; world.RenderedShroud.Dirty(); } + () => world.RenderPlayer == p, + () => world.RenderPlayer = p )); views.Add("", new CameraOption("World view", - () => world.RenderedPlayer == null, - () => { world.RenderedPlayer = null; world.RenderedShroud.Dirty(); } + () => world.RenderPlayer == null, + () => world.RenderPlayer = null )); var shroudSelector = widget.Get("SHROUD_SELECTOR"); - shroudSelector.GetText = () => views[world.RenderedPlayer == null ? "" : world.RenderedPlayer.PlayerName].Label; + shroudSelector.GetText = () => views[world.RenderPlayer == null ? "" : world.RenderPlayer.PlayerName].Label; shroudSelector.OnMouseDown = _ => { Func setupItem = (option, template) => diff --git a/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs b/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs index b81810dbe1..4326041e09 100755 --- a/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs +++ b/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs @@ -31,9 +31,10 @@ namespace OpenRA.Mods.RA.Widgets return; var cell = Game.viewport.ViewToWorld(Viewport.LastMousePos); - if (!world.Map.IsInMap(cell)) return; + if (!world.Map.IsInMap(cell)) + return; - if (world.LocalPlayer != null && !world.RenderedShroud.IsExplored(cell)) + if (world.ShroudObscures(cell)) { var utext = "Unexplored Terrain"; var usz = Game.Renderer.Fonts["Bold"].Measure(utext) + new int2(20, 24); diff --git a/OpenRA.Mods.RA/World/SmudgeLayer.cs b/OpenRA.Mods.RA/World/SmudgeLayer.cs index 440560d7c6..61b62ef802 100755 --- a/OpenRA.Mods.RA/World/SmudgeLayer.cs +++ b/OpenRA.Mods.RA/World/SmudgeLayer.cs @@ -78,12 +78,12 @@ namespace OpenRA.Mods.RA public void Render( WorldRenderer wr ) { var cliprect = Game.viewport.WorldBounds(world); - var localPlayer = world.LocalPlayer; foreach (var kv in tiles) { if (!cliprect.Contains(kv.Key.X,kv.Key.Y)) continue; - if (localPlayer != null && !world.RenderedShroud.IsExplored(kv.Key)) + + if (world.ShroudObscures(kv.Key)) continue; smudgeSprites[kv.Value.type- 1][kv.Value.index].DrawAt(wr, kv.Key.ToPPos().ToFloat2(), "terrain"); diff --git a/mods/cnc-classic/rules/system.yaml b/mods/cnc-classic/rules/system.yaml index 35a79a5e8a..58e6ffcf31 100644 --- a/mods/cnc-classic/rules/system.yaml +++ b/mods/cnc-classic/rules/system.yaml @@ -95,6 +95,7 @@ Player: DebugResourceOre: DebugResourceOreCapacity: Shroud: + Fog: false BaseAttackNotifier: PlayerStatistics: @@ -159,7 +160,6 @@ World: B: 0 A: 180 ShroudPalette: - FogPalette: Country@gdi: Name: GDI Race: gdi @@ -204,7 +204,6 @@ World: SpawnMPUnits: SpatialBins: BinSize: 4 - Shroud: PathFinder: ValidateOrder: DebugPauseState: diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index 737f98935f..c327250b94 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -257,8 +257,11 @@ World: G: 0 B: 0 A: 180 - ShroudPalette: - FogPalette: + ShroudPalette@shroud: + Type: Shroud + ShroudPalette@fog: + Name: fog + Type: Fog Country@gdi: Name: GDI Race: gdi @@ -306,8 +309,6 @@ World: MPStartLocations: SpatialBins: BinSize: 4 - Shroud: - Fog: CrateSpawner: Minimum: 1 Maximum: 6 diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 4ae5a989c6..e223d9b035 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -340,8 +340,11 @@ World: G: 0 B: 0 A: 180 - ShroudPalette: - FogPalette: + ShroudPalette@shroud: + Type: Shroud + ShroudPalette@fog: + Name: fog + Type: Fog Country@Atreides: Name: Atreides Race: atreides @@ -388,8 +391,6 @@ World: Faction: ordos SpatialBins: BinSize: 4 - Shroud: - Fog: PathFinder: ValidateOrder: DebugPauseState: diff --git a/mods/ra-classic/rules/system.yaml b/mods/ra-classic/rules/system.yaml index 6eccd968ca..60f22de31f 100644 --- a/mods/ra-classic/rules/system.yaml +++ b/mods/ra-classic/rules/system.yaml @@ -122,6 +122,7 @@ Player: DebugResourceOreCapacity: GpsWatcher: Shroud: + Fog: false BaseAttackNotifier: PlayerStatistics: @@ -193,7 +194,6 @@ World: B: 0 A: 180 ShroudPalette: - FogPalette: Country@0: Name: Allies Race: allies @@ -236,7 +236,6 @@ World: SpawnMPUnits: SpatialBins: BinSize: 4 - Shroud: PathFinder: ValidateOrder: DebugPauseState: diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index 03c595e238..3d946f1952 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -574,8 +574,11 @@ World: G: 0 B: 0 A: 180 - ShroudPalette: - FogPalette: + ShroudPalette@shroud: + Type: Shroud + ShroudPalette@fog: + Name: fog + Type: Fog Country@0: Name: Allies Race: allies @@ -621,8 +624,6 @@ World: SpawnMPUnits: SpatialBins: BinSize: 4 - Shroud: - Fog: PathFinder: ValidateOrder: DebugPauseState: