From c428cad70c7eba4dd477c1214944da5ff8a866f7 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 10 Apr 2013 00:35:39 +1200 Subject: [PATCH 1/7] Refactor per-player shrouds & fix shellmap shroud. --- OpenRA.Game/Graphics/Minimap.cs | 11 +-- OpenRA.Game/Graphics/ShroudRenderer.cs | 99 +++++++++++-------- OpenRA.Game/Graphics/TerrainRenderer.cs | 4 +- OpenRA.Game/Graphics/Viewport.cs | 2 +- OpenRA.Game/Graphics/WorldRenderer.cs | 2 +- OpenRA.Game/Player.cs | 5 + OpenRA.Game/Traits/SelectionDecorations.cs | 6 +- OpenRA.Game/Traits/TraitsInterfaces.cs | 2 +- OpenRA.Game/Traits/World/ResourceLayer.cs | 2 +- OpenRA.Game/Traits/World/Shroud.cs | 27 +++-- .../WorldInteractionControllerWidget.cs | 2 +- OpenRA.Game/World.cs | 26 +++-- OpenRA.Game/WorldUtils.cs | 2 +- OpenRA.Mods.RA/Buildings/BaseProvider.cs | 4 +- OpenRA.Mods.RA/Buildings/BibLayer.cs | 2 +- OpenRA.Mods.RA/Cloak.cs | 13 +-- OpenRA.Mods.RA/Effects/Bullet.cs | 3 +- OpenRA.Mods.RA/Effects/Contrail.cs | 4 +- OpenRA.Mods.RA/Effects/GpsDot.cs | 2 +- OpenRA.Mods.RA/Effects/Missile.cs | 2 +- OpenRA.Mods.RA/MPStartLocations.cs | 9 +- OpenRA.Mods.RA/Modifiers/FrozenUnderFog.cs | 6 +- OpenRA.Mods.RA/Modifiers/HiddenUnderFog.cs | 6 +- OpenRA.Mods.RA/ProductionBar.cs | 2 +- OpenRA.Mods.RA/SmokeTrailWhenDamaged.cs | 2 +- .../Logic/ObserverShroudSelectorLogic.cs | 10 +- OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs | 2 +- OpenRA.Mods.RA/World/SmudgeLayer.cs | 4 +- mods/cnc-classic/rules/system.yaml | 1 - mods/cnc/rules/system.yaml | 1 - mods/d2k/rules/system.yaml | 1 - mods/ra-classic/rules/system.yaml | 1 - mods/ra/rules/system.yaml | 1 - 33 files changed, 146 insertions(+), 120 deletions(-) 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..0ee74d8378 100644 --- a/OpenRA.Game/Graphics/ShroudRenderer.cs +++ b/OpenRA.Game/Graphics/ShroudRenderer.cs @@ -15,21 +15,12 @@ namespace OpenRA.Graphics { public class ShroudRenderer { - World world; - Traits.Shroud shroud { - get { - return world.RenderedShroud; - } - } - + Map map; Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow"); Sprite[,] sprites, fogSprites; - Map map; - public ShroudRenderer(World world) { - this.world = world; this.map = world.Map; sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; @@ -56,58 +47,58 @@ namespace OpenRA.Graphics new byte[] { 46 }, }; - Sprite ChooseShroud(int i, int j) + Sprite ChooseShroud(Shroud s, int i, int j) { - 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.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; } + 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 (!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; - 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 ] ]; + return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; } - Sprite ChooseFog(int i, int j) + Sprite ChooseFog(Shroud s, int i, int j) { - if (!shroud.IsVisible(i,j)) return shadowBits[0xf]; - if (!shroud.IsExplored(i, j)) return shadowBits[0xf]; + 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 (!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.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 (!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.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]]; } bool initializePalettes = true; PaletteReference fogPalette, shroudPalette; - internal void Draw(WorldRenderer wr) + internal void Draw(WorldRenderer wr, Player renderPlayer) { if (initializePalettes) { @@ -116,18 +107,42 @@ namespace OpenRA.Graphics initializePalettes = false; } - if (shroud != null && shroud.dirty) + if (renderPlayer == null) { - 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); + // 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; - 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); + 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 + { + renderPlayer.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(renderPlayer.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(renderPlayer.Shroud, i, j); + } var clipRect = Game.viewport.WorldBounds(wr.world); DrawShroud(wr, clipRect, sprites, shroudPalette); if (wr.world.WorldActor.HasTrait()) 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..ddbbf0f9b5 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -127,7 +127,7 @@ namespace OpenRA.Graphics if (world.OrderGenerator != null) world.OrderGenerator.RenderAfterWorld(this, world); - shroudRenderer.Draw( this ); + shroudRenderer.Draw(this, world.RenderPlayer); Game.Renderer.DisableScissor(); foreach (var g in world.Selection.Actors.Where(a => !a.Destroyed) diff --git a/OpenRA.Game/Player.cs b/OpenRA.Game/Player.cs index 74c7853efb..95132cc81d 100644 --- a/OpenRA.Game/Player.cs +++ b/OpenRA.Game/Player.cs @@ -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/SelectionDecorations.cs b/OpenRA.Game/Traits/SelectionDecorations.cs index bd1111957a..85dac3c42c 100644 --- a/OpenRA.Game/Traits/SelectionDecorations.cs +++ b/OpenRA.Game/Traits/SelectionDecorations.cs @@ -54,7 +54,8 @@ namespace OpenRA.Traits void DrawPips(WorldRenderer wr, Actor self, float2 basePosition) { - if (self.Owner != self.World.RenderedPlayer) return; + if (self.Owner != self.World.RenderPlayer) + return; var pipSources = self.TraitsImplementing(); if (pipSources.Count() == 0) @@ -95,7 +96,8 @@ namespace OpenRA.Traits void DrawTags(WorldRenderer wr, Actor self, float2 basePosition) { - if (self.Owner != self.World.RenderedPlayer) return; + if (self.Owner != 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/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..8682ac9ef3 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -23,7 +23,6 @@ namespace OpenRA.Traits public class Shroud : ISync { Map map; - World world; [Sync] public Player Owner; public int[,] visibleCells; @@ -38,11 +37,6 @@ namespace OpenRA.Traits set { disabled = value; Dirty(); } } - public bool Observing - { - get { return world.IsShellmap || (world.LocalPlayer == null && Owner == null);; } - } - public Rectangle? Bounds { get { return Disabled ? null : exploredBounds; } @@ -52,7 +46,6 @@ namespace OpenRA.Traits 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]; @@ -274,16 +267,24 @@ namespace OpenRA.Traits if (!map.IsInMap(x, y)) return false; - if (Disabled || Observing) + if (Disabled) return true; return foggedCells[x,y]; } + public bool IsExplored(Actor a) + { + if (Owner == null) + return true; + + 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) + if (Disabled) return true; // Visibility is allowed to extend beyond the map cordon so that @@ -298,16 +299,14 @@ namespace OpenRA.Traits 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, Owner))) return false; - if(Owner == null) return true; - - return Disabled || Observing || a.Owner.Stances[Owner] == Stance.Ally || GetVisOrigins(a).Any(o => IsExplored(o)); + return Disabled || a.Owner.Stances[Owner] == Stance.Ally || IsExplored(a); } public bool IsTargetable(Actor a) { - if (a.TraitsImplementing().Any(t => !t.IsVisible(this, a))) + if (a.TraitsImplementing().Any(t => !t.IsVisible(a, 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..e9a8d17816 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,25 @@ 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 Player RenderPlayer + { + get { return renderPlayer; } + set + { + renderPlayer = value; + if (renderPlayer != null) + renderPlayer.Shroud.Dirty(); + } + } + + public Rectangle? VisibleBounds { get { return renderPlayer != null ? renderPlayer.Shroud.Bounds : null; } } + 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 void SetLocalPlayer(string pr) { @@ -52,7 +67,7 @@ namespace OpenRA return; LocalPlayer = Players.FirstOrDefault(p => p.InternalName == pr); - RenderedPlayer = LocalPlayer; + RenderPlayer = LocalPlayer; } public readonly Actor WorldActor; @@ -104,7 +119,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.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/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/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/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/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/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..b52b092474 100755 --- a/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs +++ b/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs @@ -33,7 +33,7 @@ namespace OpenRA.Mods.RA.Widgets var cell = Game.viewport.ViewToWorld(Viewport.LastMousePos); if (!world.Map.IsInMap(cell)) return; - if (world.LocalPlayer != null && !world.RenderedShroud.IsExplored(cell)) + if (world.LocalPlayer != null && 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..3e88c7bcd6 100644 --- a/mods/cnc-classic/rules/system.yaml +++ b/mods/cnc-classic/rules/system.yaml @@ -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..2f84a6608e 100644 --- a/mods/cnc/rules/system.yaml +++ b/mods/cnc/rules/system.yaml @@ -306,7 +306,6 @@ World: MPStartLocations: SpatialBins: BinSize: 4 - Shroud: Fog: CrateSpawner: Minimum: 1 diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index 4ae5a989c6..d79a233cbf 100644 --- a/mods/d2k/rules/system.yaml +++ b/mods/d2k/rules/system.yaml @@ -388,7 +388,6 @@ World: Faction: ordos SpatialBins: BinSize: 4 - Shroud: Fog: PathFinder: ValidateOrder: diff --git a/mods/ra-classic/rules/system.yaml b/mods/ra-classic/rules/system.yaml index 6eccd968ca..c3775aafc4 100644 --- a/mods/ra-classic/rules/system.yaml +++ b/mods/ra-classic/rules/system.yaml @@ -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..5553568e19 100644 --- a/mods/ra/rules/system.yaml +++ b/mods/ra/rules/system.yaml @@ -621,7 +621,6 @@ World: SpawnMPUnits: SpatialBins: BinSize: 4 - Shroud: Fog: PathFinder: ValidateOrder: From ca8dbce0eff1fbbb35a9a7f3174227e58ef8bb4e Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 10 Apr 2013 19:37:04 +1200 Subject: [PATCH 2/7] Display selection decorations to allies & observers. --- OpenRA.Game/Traits/SelectionDecorations.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/Traits/SelectionDecorations.cs b/OpenRA.Game/Traits/SelectionDecorations.cs index 85dac3c42c..0a28adde06 100644 --- a/OpenRA.Game/Traits/SelectionDecorations.cs +++ b/OpenRA.Game/Traits/SelectionDecorations.cs @@ -54,7 +54,7 @@ namespace OpenRA.Traits void DrawPips(WorldRenderer wr, Actor self, float2 basePosition) { - if (self.Owner != self.World.RenderPlayer) + if (!self.Owner.IsAlliedWith(self.World.RenderPlayer)) return; var pipSources = self.TraitsImplementing(); @@ -96,7 +96,7 @@ namespace OpenRA.Traits void DrawTags(WorldRenderer wr, Actor self, float2 basePosition) { - if (self.Owner != self.World.RenderPlayer) + 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 From 248e815d99941b6b23f8dfca2c3be73b505fc17b Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 10 Apr 2013 20:27:33 +1200 Subject: [PATCH 3/7] More shroud refactoring. This introduces a hash on Shroud which ShroudRenderer can observe, removing the need to explicitly twiddle a dirty flag between objects. Shroud disabling is now done via RenderPlayer, so enabling the cheat or winning/losing will now give vis equivalent to an observer. --- OpenRA.Game/Graphics/ShroudRenderer.cs | 104 ++++++----- OpenRA.Game/Graphics/WorldRenderer.cs | 3 +- OpenRA.Game/Player.cs | 2 +- OpenRA.Game/Traits/CreatesShroud.cs | 25 ++- OpenRA.Game/Traits/Player/DeveloperMode.cs | 2 +- OpenRA.Game/Traits/World/Shroud.cs | 169 +++++++++--------- OpenRA.Game/World.cs | 26 ++- OpenRA.Mods.RA/ConquestVictoryConditions.cs | 4 +- .../Widgets/Logic/IngameChatLogic.cs | 2 +- 9 files changed, 169 insertions(+), 168 deletions(-) diff --git a/OpenRA.Game/Graphics/ShroudRenderer.cs b/OpenRA.Game/Graphics/ShroudRenderer.cs index 0ee74d8378..af21f5cb69 100644 --- a/OpenRA.Game/Graphics/ShroudRenderer.cs +++ b/OpenRA.Game/Graphics/ShroudRenderer.cs @@ -18,14 +18,10 @@ namespace OpenRA.Graphics Map map; Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow"); Sprite[,] sprites, fogSprites; + int shroudHash; - public ShroudRenderer(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 = { @@ -47,6 +43,17 @@ namespace OpenRA.Graphics new byte[] { 46 }, }; + public ShroudRenderer(World world) + { + this.map = world.Map; + + sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; + fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y]; + + // Force update on first render + shroudHash = -1; + } + Sprite ChooseShroud(Shroud s, int i, int j) { if (!s.IsExplored(i, j)) @@ -96,9 +103,50 @@ namespace OpenRA.Graphics return shadowBits[SpecialShroudTiles[u ^ uSides][v]]; } - bool initializePalettes = true; - PaletteReference fogPalette, shroudPalette; - internal void Draw(WorldRenderer wr, Player renderPlayer) + 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) { @@ -107,42 +155,8 @@ namespace OpenRA.Graphics initializePalettes = false; } - if (renderPlayer == 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; + GenerateSprites(shroud); - 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 - { - renderPlayer.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(renderPlayer.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(renderPlayer.Shroud, i, j); - } var clipRect = Game.viewport.WorldBounds(wr.world); DrawShroud(wr, clipRect, sprites, shroudPalette); if (wr.world.WorldActor.HasTrait()) diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index ddbbf0f9b5..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, world.RenderPlayer); + 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/Player.cs b/OpenRA.Game/Player.cs index 95132cc81d..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) 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/World/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index 8682ac9ef3..2a98e97e19 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -12,62 +12,70 @@ 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 object Create(ActorInitializer init) { return new Shroud(init.self); } } - public class Shroud : ISync + public class Shroud { Map map; + Actor self; - [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) { - get { return disabled; } - set { disabled = value; Dirty(); } - } + this.self = self; + map = self.World.Map; - public Rectangle? Bounds - { - get { return Disabled ? null : exploredBounds; } - } - - public Action Dirty = () => { }; - - public Shroud(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; + } + + 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++) @@ -77,13 +85,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) { @@ -95,17 +102,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 { @@ -116,34 +122,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); } } @@ -159,6 +164,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 )) @@ -170,7 +176,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; } @@ -189,34 +196,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) @@ -227,10 +233,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) @@ -241,10 +246,9 @@ namespace OpenRA.Traits foggedCells[i, j] = true; } } - exploredBounds = world.Map.Bounds; + ExploredBounds = world.Map.Bounds; - if (!Disabled) - Dirty(); + Invalidate(); } public void ResetExploration() @@ -257,8 +261,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); } @@ -267,26 +270,17 @@ namespace OpenRA.Traits if (!map.IsInMap(x, y)) return false; - if (Disabled) - return true; - return foggedCells[x,y]; } public bool IsExplored(Actor a) { - if (Owner == null) - return true; - 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) - 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) @@ -298,15 +292,14 @@ namespace OpenRA.Traits // 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(a, Owner))) + if (a.TraitsImplementing().Any(t => !t.IsVisible(a, self.Owner))) return false; - return Disabled || a.Owner.Stances[Owner] == Stance.Ally || IsExplored(a); + return a.Owner.IsAlliedWith(self.Owner) || IsExplored(a); } public bool IsTargetable(Actor a) { - if (a.TraitsImplementing().Any(t => !t.IsVisible(a, Owner))) + if (a.TraitsImplementing().Any(t => !t.IsVisible(a, self.Owner))) return false; return GetVisOrigins(a).Any(o => IsVisible(o)); diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index e9a8d17816..7143784bff 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -41,26 +41,24 @@ namespace OpenRA public void AddPlayer(Player p) { Players.Add(p); } public Player LocalPlayer { get; private set; } - public bool Observer { get { return LocalPlayer == null; } } - Player renderPlayer; - public Player RenderPlayer + public Player RenderPlayer; + 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 { return renderPlayer; } - set + get { - renderPlayer = value; - if (renderPlayer != null) - renderPlayer.Shroud.Dirty(); + if (RenderPlayer == null) + return null; + + return RenderPlayer.Shroud.ExploredBounds; } } - public Rectangle? VisibleBounds { get { return renderPlayer != null ? renderPlayer.Shroud.Bounds : null; } } - 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 void SetLocalPlayer(string pr) { if (orderManager.Connection is ReplayConnection) diff --git a/OpenRA.Mods.RA/ConquestVictoryConditions.cs b/OpenRA.Mods.RA/ConquestVictoryConditions.cs index 0334fba8f8..975df3b842 100644 --- a/OpenRA.Mods.RA/ConquestVictoryConditions.cs +++ b/OpenRA.Mods.RA/ConquestVictoryConditions.cs @@ -62,9 +62,9 @@ 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) { + self.World.RenderPlayer = null; Game.RunAfterDelay(Info.NotificationDelay, () => { if (Game.IsCurrentWorld(self.World)) @@ -79,9 +79,9 @@ 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) { + self.World.RenderPlayer = null; Game.RunAfterDelay(Info.NotificationDelay, () => Sound.PlayNotification(self.Owner, "Speech", "Win", self.Owner.Country.Race)); } } 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; } } From 9b7bb532870dfb3a6dbe8d2de7973816ad331b97 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 10 Apr 2013 21:42:30 +1200 Subject: [PATCH 4/7] LocalPlayer.Shroud is never the right shroud. --- .../Widgets/CncWorldInteractionControllerWidget.cs | 2 +- OpenRA.Mods.RA/Move/Mobile.cs | 4 ++-- OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) 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/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/Widgets/WorldTooltipWidget.cs b/OpenRA.Mods.RA/Widgets/WorldTooltipWidget.cs index b52b092474..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.ShroudObscures(cell)) + if (world.ShroudObscures(cell)) { var utext = "Unexplored Terrain"; var usz = Game.Renderer.Fonts["Bold"].Measure(utext) + new int2(20, 24); From 707c86fbbbb3f0e30a31045ed59fa5d968c3460a Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 10 Apr 2013 22:12:51 +1200 Subject: [PATCH 5/7] Fix selection decorations being drawn behind fog. --- OpenRA.Game/Traits/SelectionDecorations.cs | 4 +++- OpenRA.Mods.RA/GainsExperience.cs | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/OpenRA.Game/Traits/SelectionDecorations.cs b/OpenRA.Game/Traits/SelectionDecorations.cs index 0a28adde06..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); 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); From 2c680a183148ceaed2887d1309cd2a1568acf9a8 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Wed, 10 Apr 2013 22:33:58 +1200 Subject: [PATCH 6/7] Fix shroud for observers observing a player after win/loss. --- OpenRA.Game/World.cs | 9 ++++++++- OpenRA.Mods.RA/ConquestVictoryConditions.cs | 14 ++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 7143784bff..0845bba5ff 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -42,7 +42,14 @@ namespace OpenRA public void AddPlayer(Player p) { Players.Add(p); } public Player LocalPlayer { get; private set; } - public Player RenderPlayer; + 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); } diff --git a/OpenRA.Mods.RA/ConquestVictoryConditions.cs b/OpenRA.Mods.RA/ConquestVictoryConditions.cs index 975df3b842..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) { @@ -63,14 +67,11 @@ namespace OpenRA.Mods.RA a.Kill(a); if (self.Owner == self.World.LocalPlayer) - { - self.World.RenderPlayer = null; Game.RunAfterDelay(Info.NotificationDelay, () => { if (Game.IsCurrentWorld(self.World)) Sound.PlayNotification(self.Owner, "Speech", "Lose", self.Owner.Country.Race); }); - } } public void Win(Actor self) @@ -80,10 +81,7 @@ namespace OpenRA.Mods.RA Game.Debug("{0} is victorious.".F(self.Owner.PlayerName)); if (self.Owner == self.World.LocalPlayer) - { - self.World.RenderPlayer = null; Game.RunAfterDelay(Info.NotificationDelay, () => Sound.PlayNotification(self.Owner, "Speech", "Win", self.Owner.Country.Race)); - } } } From 400ad49de00deb1917c23f7e9a1dda615d5cdb4f Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Thu, 11 Apr 2013 22:29:51 +1200 Subject: [PATCH 7/7] Allow maps/mods to properly disable fog or shroud (or both). --- OpenRA.Game/Graphics/ShroudRenderer.cs | 10 ++++-- OpenRA.Game/OpenRA.Game.csproj | 1 - OpenRA.Game/Traits/World/Fog.cs | 20 ----------- OpenRA.Game/Traits/World/Shroud.cs | 19 +++++++++-- OpenRA.Mods.RA/FogPalette.cs | 46 -------------------------- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 - OpenRA.Mods.RA/ShroudPalette.cs | 45 ++++++++++++++++++++----- mods/cnc-classic/rules/system.yaml | 2 +- mods/cnc/rules/system.yaml | 8 +++-- mods/d2k/rules/system.yaml | 8 +++-- mods/ra-classic/rules/system.yaml | 2 +- mods/ra/rules/system.yaml | 8 +++-- 12 files changed, 77 insertions(+), 93 deletions(-) delete mode 100644 OpenRA.Game/Traits/World/Fog.cs delete mode 100644 OpenRA.Mods.RA/FogPalette.cs diff --git a/OpenRA.Game/Graphics/ShroudRenderer.cs b/OpenRA.Game/Graphics/ShroudRenderer.cs index af21f5cb69..7abb76ffae 100644 --- a/OpenRA.Game/Graphics/ShroudRenderer.cs +++ b/OpenRA.Game/Graphics/ShroudRenderer.cs @@ -16,6 +16,7 @@ namespace OpenRA.Graphics public class ShroudRenderer { Map map; + ShroudInfo shroudInfo; Sprite[] shadowBits = Game.modData.SpriteLoader.LoadAllSprites("shadow"); Sprite[,] sprites, fogSprites; int shroudHash; @@ -46,6 +47,7 @@ namespace OpenRA.Graphics public ShroudRenderer(World world) { this.map = world.Map; + shroudInfo = Rules.Info["player"].Traits.Get(); sprites = new Sprite[map.MapSize.X, map.MapSize.Y]; fogSprites = new Sprite[map.MapSize.X, map.MapSize.Y]; @@ -150,7 +152,8 @@ namespace OpenRA.Graphics { if (initializePalettes) { - fogPalette = wr.Palette("fog"); + if (shroudInfo.Fog) + fogPalette = wr.Palette("fog"); shroudPalette = wr.Palette("shroud"); initializePalettes = false; } @@ -158,8 +161,11 @@ namespace OpenRA.Graphics 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/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/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/Shroud.cs b/OpenRA.Game/Traits/World/Shroud.cs index 2a98e97e19..bc7cf629fa 100644 --- a/OpenRA.Game/Traits/World/Shroud.cs +++ b/OpenRA.Game/Traits/World/Shroud.cs @@ -18,13 +18,16 @@ namespace OpenRA.Traits { public class ShroudInfo : ITraitInfo { - public object Create(ActorInitializer init) { return new Shroud(init.self); } + public readonly bool Shroud = true; + public readonly bool Fog = true; + public object Create(ActorInitializer init) { return new Shroud(init.self, this); } } public class Shroud { - Map map; + public ShroudInfo Info; Actor self; + Map map; int[,] visibleCells; bool[,] exploredCells; @@ -34,8 +37,9 @@ namespace OpenRA.Traits public int Hash { get; private set; } - public Shroud(Actor self) + public Shroud(Actor self, ShroudInfo info) { + Info = info; this.self = self; map = self.World.Map; @@ -44,6 +48,9 @@ namespace OpenRA.Traits foggedCells = new bool[map.MapSize.X, map.MapSize.Y]; self.World.ActorAdded += AddActor; self.World.ActorRemoved += RemoveActor; + + if (!info.Shroud) + ExploredBounds = map.Bounds; } void Invalidate() @@ -270,6 +277,9 @@ namespace OpenRA.Traits if (!map.IsInMap(x, y)) return false; + if (!Info.Shroud) + return true; + return foggedCells[x,y]; } @@ -286,6 +296,9 @@ namespace OpenRA.Traits 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; } 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/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 6909ff4a35..f794438910 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -416,7 +416,6 @@ - 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/mods/cnc-classic/rules/system.yaml b/mods/cnc-classic/rules/system.yaml index 3e88c7bcd6..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 diff --git a/mods/cnc/rules/system.yaml b/mods/cnc/rules/system.yaml index 2f84a6608e..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,7 +309,6 @@ World: MPStartLocations: SpatialBins: BinSize: 4 - Fog: CrateSpawner: Minimum: 1 Maximum: 6 diff --git a/mods/d2k/rules/system.yaml b/mods/d2k/rules/system.yaml index d79a233cbf..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,7 +391,6 @@ World: Faction: ordos SpatialBins: BinSize: 4 - Fog: PathFinder: ValidateOrder: DebugPauseState: diff --git a/mods/ra-classic/rules/system.yaml b/mods/ra-classic/rules/system.yaml index c3775aafc4..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 diff --git a/mods/ra/rules/system.yaml b/mods/ra/rules/system.yaml index 5553568e19..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,7 +624,6 @@ World: SpawnMPUnits: SpatialBins: BinSize: 4 - Fog: PathFinder: ValidateOrder: DebugPauseState: