public EditorActorBrush(EditorViewportControllerWidget editorWidget, ActorInfo actor, PlayerReference owner, WorldRenderer wr) { this.editorWidget = editorWidget; worldRenderer = wr; world = wr.World; editorLayer = world.WorldActor.Trait<EditorActorLayer>(); Actor = actor; this.owner = owner; preview = editorWidget.Get<ActorPreviewWidget>("DRAG_ACTOR_PREVIEW"); preview.GetScale = () => worldRenderer.Viewport.Zoom; preview.IsVisible = () => editorWidget.CurrentBrush == this; var buildingInfo = actor.Traits.GetOrDefault<BuildingInfo>(); if (buildingInfo != null) { locationOffset = -FootprintUtils.AdjustForBuildingSize(buildingInfo); previewOffset = FootprintUtils.CenterOffset(world, buildingInfo); } var td = new TypeDictionary(); td.Add(new FacingInit(facing)); td.Add(new TurretFacingInit(facing)); td.Add(new OwnerInit(owner.Name)); td.Add(new RaceInit(owner.Race)); preview.SetPreview(actor, td); // The preview widget may be rendered by the higher-level code before it is ticked. // Force a manual tick to ensure the bounds are set correctly for this first draw. Tick(); }
public override void Tick(Actor self) { base.Tick(self); if (!dirty) return; // Update connection to neighbours var vec = new CVec(1, 1); var adjacentActors = self.World.FindActorsInBox(self.Location - vec, self.Location + vec); adjacent = 0; foreach (var a in adjacentActors) { var rb = a.TraitOrDefault<RenderBuildingWall>(); if (rb == null || rb.info.Type != info.Type) continue; var location = self.Location; var otherLocation = a.Location; if (otherLocation == location + new CVec(0, -1)) adjacent |= 1; else if (otherLocation == location + new CVec(+1, 0)) adjacent |= 2; else if (otherLocation == location + new CVec(0, +1)) adjacent |= 4; else if (otherLocation == location + new CVec(-1, 0)) adjacent |= 8; } dirty = false; }
bool RampExists(Actor self, CVec offset) { var neighbour = bridgeLayer[self.Location + offset]; if (neighbour == null) return false; return bridgeInfo.RampActors.Contains(neighbour.Info.Name); }
static CPos FindEdge(Surface s, CPos p, CVec d, TerrainTile replace) { for (;;) { var q = p + d; if (!s.Map.Contains(q)) return p; if (s.Map.MapTiles.Value[q].Type != replace.Type) return p; p = q; } }
public void Do([NotNull] CVec input) { ThrowIfDisposed(); if (input == null) { throw new ArgumentNullException(nameof(input)); } NativeMethods.aubio_spectral_whitening_do(this, input); }
static IEnumerable<CVec> TilesWhere(string name, CVec dim, char[] footprint, Func<char, bool> cond) { if( footprint.Length != dim.X * dim.Y ) throw new InvalidOperationException( "Invalid footprint for " + name ); int index = 0; for( int y = 0 ; y < dim.Y ; y++ ) for( int x = 0 ; x < dim.X ; x++ ) if( cond( footprint[ index++ ] ) ) yield return new CVec(x, y); }
int GetCostToNode(CPos destNode, CVec direction) { var movementCost = locomotor.MovementCostToEnterCell(Actor, destNode, checkConditions, IgnoreActor); if (movementCost != short.MaxValue && !(CustomBlock != null && CustomBlock(destNode))) { return(CalculateCellCost(destNode, direction, movementCost)); } return(CostForInvalidCell); }
int GetPathCostToNode(CPos srcNode, CPos destNode, CVec direction) { var movementCost = locomotor.MovementCostToEnterCell(Actor, srcNode, destNode, checkConditions, IgnoreActor); if (movementCost != MovementCostForUnreachableCell && !(CustomBlock != null && CustomBlock(destNode))) { return(CalculateCellPathCost(destNode, direction, movementCost)); } return(PathCostForInvalidPath); }
int GetPathCostToNode(CPos srcNode, CPos destNode, CVec direction) { var movementCost = locomotor.MovementCostToEnterCell(actor, srcNode, destNode, check, ignoreActor); if (movementCost != PathGraph.MovementCostForUnreachableCell) { return(CalculateCellPathCost(destNode, direction, movementCost)); } return(PathGraph.PathCostForInvalidPath); }
int GetCostToNode(CPos destNode, CVec direction) { var movementCost = locomotorInfo.MovementCostToEnterCell(worldMovementInfo, Actor, destNode, IgnoreActor, checkConditions); if (movementCost != int.MaxValue && !(CustomBlock != null && CustomBlock(destNode))) { return(CalculateCellCost(destNode, direction, movementCost)); } return(Constants.InvalidNode); }
bool RampExists(Actor self, CVec offset) { var neighbour = bridgeLayer[self.Location + offset]; if (neighbour == null) { return(false); } return(bridgeInfo.RampActors.Contains(neighbour.Info.Name)); }
public bool IsCloseEnoughToBase(World world, Player p, string buildingName, CPos topLeft) { if (p.PlayerActor.Trait <DeveloperMode>().BuildAnywhere) { return(true); } if (RequiresBaseProvider && FindBaseProvider(world, p, topLeft) == null) { return(false); } var buildingMaxBounds = (CVec)Dimensions; var buildingTraits = world.Map.Rules.Actors[buildingName].Traits; if (buildingTraits.Contains <BibInfo>() && !(buildingTraits.Get <BibInfo>().HasMinibib)) { buildingMaxBounds += new CVec(0, 1); } var scanStart = world.ClampToWorld(topLeft - new CVec(Adjacent, Adjacent)); var scanEnd = world.ClampToWorld(topLeft + buildingMaxBounds + new CVec(Adjacent, Adjacent)); var nearnessCandidates = new List <CPos>(); var bi = world.WorldActor.Trait <BuildingInfluence>(); var allyBuildRadius = world.LobbyInfo.GlobalSettings.AllyBuildRadius; for (var y = scanStart.Y; y < scanEnd.Y; y++) { for (var x = scanStart.X; x < scanEnd.X; x++) { var pos = new CPos(x, y); var at = bi.GetBuildingAt(pos); if (at == null || !at.IsInWorld || !at.HasTrait <GivesBuildableArea>()) { continue; } if (at.Owner == p || (allyBuildRadius && at.Owner.Stances[p] == Stance.Ally)) { nearnessCandidates.Add(pos); } } } var buildingTiles = FootprintUtils.Tiles(world.Map.Rules, buildingName, this, topLeft).ToList(); return(nearnessCandidates .Any(a => buildingTiles .Any(b => Math.Abs(a.X - b.X) <= Adjacent && Math.Abs(a.Y - b.Y) <= Adjacent))); }
public override CPos ParseActorLocation(string input, int loc) { var newLoc = new CPos(loc % MapSize, loc / MapSize); var vectorDown = new CVec(0, 1); if (input == "obli" || input == "atwr" || input == "weap" || input == "hand" || input == "tmpl" || input == "split2" || input == "split3") { newLoc += vectorDown; } return(newLoc); }
bool NeighbourIsDestroyed(CVec offset) { var neighbour = bridgeLayer[self.Location + offset]; if (neighbour == null) return false; var segment = neighbour.TraitOrDefault<IBridgeSegment>(); if (segment == null) return false; return segment.DamageState == DamageState.Dead; }
public override CPos ParseActorLocation(string input, int loc) { var newLoc = new CPos(loc % MapSize, loc / MapSize); var vectorDown = new CVec(0, 1); if (input == "tsla" || input == "agun" || input == "gap" || input == "apwr" || input == "iron") { newLoc += vectorDown; } return(newLoc); }
public IEnumerable <IActorPreview> RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { if (init.Contains <HideBibPreviewInit>() && init.Get <HideBibPreviewInit, bool>()) { yield break; } if (Palette != null) { p = init.WorldRenderer.Palette(Palette); } var bi = init.Actor.TraitInfo <BuildingInfo>(); var rows = HasMinibib ? 1 : 2; var width = bi.Dimensions.X; var bibOffset = bi.Dimensions.Y - rows; var centerOffset = bi.CenterOffset(init.World); var map = init.World.Map; var location = CPos.Zero; if (init.Contains <LocationInit>()) { location = init.Get <LocationInit, CPos>(); } for (var i = 0; i < rows * width; i++) { var index = i; var anim = new Animation(init.World, image); var cellOffset = new CVec(i % width, i / width + bibOffset); var cell = location + cellOffset; // Some mods may define terrain-specific bibs var sequence = Sequence; if (map.Tiles.Contains(cell)) { var terrain = map.GetTerrainInfo(cell).Type; var testSequence = Sequence + "-" + terrain; if (anim.HasSequence(testSequence)) { sequence = testSequence; } } anim.PlayFetchIndex(sequence, () => index); anim.IsDecoration = true; // Z-order is one set to the top of the footprint var offset = map.CenterOfCell(cell) - map.CenterOfCell(location) - centerOffset; yield return(new SpriteActorPreview(anim, () => offset, () => - (offset.Y + centerOffset.Y + 512), p, rs.Scale)); } }
static void UpdateNeighbours(Actor self) { var vec = new CVec(1, 1); var neighbours = self.World.FindActorsInBox(self.Location - vec, self.Location + vec) .Select(a => a.TraitOrDefault <RenderBuildingWall>()) .Where(a => a != null); foreach (var rb in neighbours) { rb.dirty = true; } }
public static void GetSpectrum([NotNull] FVec compspec, [NotNull] CVec spectrum) { if (compspec == null) { throw new ArgumentNullException(nameof(compspec)); } if (spectrum == null) { throw new ArgumentNullException(nameof(spectrum)); } NativeMethods.aubio_fft_get_spectrum(compspec, spectrum); }
static IEnumerable<CPos> RandomWalk(CPos p, MersenneTwister r) { for (;;) { var dx = r.Next(-1, 2); var dy = r.Next(-1, 2); if (dx == 0 && dy == 0) continue; p += new CVec(dx, dy); yield return p; } }
public static IEnumerable<CPos> Tiles(string name, BuildingInfo buildingInfo, CPos topLeft) { var dim = (CVec)buildingInfo.Dimensions; var footprint = buildingInfo.Footprint.Where(x => !char.IsWhiteSpace(x)); if (Rules.Info[ name ].Traits.Contains<BibInfo>()) { dim += new CVec(0, 1); footprint = footprint.Concat(new char[dim.X]); } return TilesWhere( name, dim, footprint.ToArray(), a => a != '_' ).Select( t => t + topLeft ); }
public static IEnumerable <CPos> Tiles(string name, BuildingInfo buildingInfo, CPos topLeft) { var dim = (CVec)buildingInfo.Dimensions; var footprint = buildingInfo.Footprint.Where(x => !char.IsWhiteSpace(x)); if (Rules.Info[name].Traits.Contains <BibInfo>()) { dim += new CVec(0, 1); footprint = footprint.Concat(new char[dim.X]); } return(TilesWhere(name, dim, footprint.ToArray(), a => a != '_').Select(t => t + topLeft)); }
public static void GetRealImag([NotNull] CVec spectrum, [NotNull] FVec compspec) { if (spectrum == null) { throw new ArgumentNullException(nameof(spectrum)); } if (compspec == null) { throw new ArgumentNullException(nameof(compspec)); } NativeMethods.aubio_fft_get_realimag(spectrum, compspec); }
int CalculateCellCost(CPos neighborCPos, CVec direction, int movementCost) { var cellCost = movementCost; if (direction.X * direction.Y != 0) { cellCost = (cellCost * 34) / 24; } if (CustomCost != null) { var customCost = CustomCost(neighborCPos); if (customCost == Constants.InvalidNode) { return(Constants.InvalidNode); } cellCost += customCost; } // Prevent units from jumping over height discontinuities if (checkTerrainHeight && neighborCPos.Layer == 0) { var from = neighborCPos - direction; if (Math.Abs(World.Map.Height[neighborCPos] - World.Map.Height[from]) > 1) { return(Constants.InvalidNode); } } // Directional bonuses for smoother flow! if (LaneBias != 0) { var ux = neighborCPos.X + (InReverse ? 1 : 0) & 1; var uy = neighborCPos.Y + (InReverse ? 1 : 0) & 1; if ((ux == 0 && direction.Y < 0) || (ux == 1 && direction.Y > 0)) { cellCost += LaneBias; } if ((uy == 0 && direction.X < 0) || (uy == 1 && direction.X > 0)) { cellCost += LaneBias; } } return(cellCost); }
public static IEnumerable<CPos> Tiles(Ruleset rules, string name, BuildingInfo buildingInfo, CPos topLeft) { var dim = (CVec)buildingInfo.Dimensions; var footprint = buildingInfo.Footprint.Where(x => !char.IsWhiteSpace(x)); var bibInfo = rules.Actors[name].TraitInfoOrDefault<BibInfo>(); if (bibInfo != null && !bibInfo.HasMinibib) { dim += new CVec(0, 1); footprint = footprint.Concat(new char[dim.X]); } return TilesWhere(name, dim, footprint.ToArray(), a => a != '_').Select(t => t + topLeft); }
public SelectConditionTarget(World world, string order, SupportPowerManager manager, GrantExternalConditionPowerCA power) { // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) { manager.Self.World.Selection.Clear(); } this.manager = manager; this.order = order; this.power = power; footprint = power.info.Footprint.Where(c => !char.IsWhiteSpace(c)).ToArray(); dimensions = power.info.Dimensions; tile = world.Map.Rules.Sequences.GetSequence("overlay", "target-select").GetSprite(0); }
void Copy(CellRegion source, CVec offset) { var gridType = worldRenderer.World.Map.Grid.Type; var mapTiles = worldRenderer.World.Map.Tiles; var mapHeight = worldRenderer.World.Map.Height; var mapResources = worldRenderer.World.Map.Resources; var dest = new CellRegion(gridType, source.TopLeft + offset, source.BottomRight + offset); var previews = new Dictionary <string, ActorReference>(); var tiles = new Dictionary <CPos, (TerrainTile, ResourceTile, byte)>(); var copyFilters = getCopyFilters(); foreach (var cell in source) { if (!mapTiles.Contains(cell) || !mapTiles.Contains(cell + offset)) { continue; } tiles.Add(cell + offset, (mapTiles[cell], mapResources[cell], mapHeight[cell])); if (copyFilters.HasFlag(MapCopyFilters.Actors)) { foreach (var preview in editorLayer.PreviewsAt(cell)) { if (previews.ContainsKey(preview.ID)) { continue; } var copy = preview.Export(); var locationInit = copy.GetOrDefault <LocationInit>(); if (locationInit != null) { copy.RemoveAll <LocationInit>(); copy.Add(new LocationInit(locationInit.Value + offset)); } previews.Add(preview.ID, copy); } } } var action = new CopyPasteEditorAction(copyFilters, worldRenderer.World.Map, tiles, previews, editorLayer, dest); editorActionManager.Add(action); }
CPos?ChooseMcvDeployLocation(string actorType, CVec offset, bool distanceToBaseIsImportant) { var actorInfo = world.Map.Rules.Actors[actorType]; var bi = actorInfo.TraitInfoOrDefault <BuildingInfo>(); if (bi == null) { return(null); } // Find the buildable cell that is closest to pos and centered around center Func <CPos, CPos, int, int, CPos?> findPos = (center, target, minRange, maxRange) => { var cells = world.Map.FindTilesInAnnulus(center, minRange, maxRange); // Sort by distance to target if we have one if (center != target) { cells = cells.OrderBy(c => (c - target).LengthSquared); } else { cells = cells.Shuffle(world.LocalRandom); } foreach (var cell in cells) { if (!world.CanPlaceBuilding(cell + offset, actorInfo, bi, null)) { continue; } if (distanceToBaseIsImportant && !bi.IsCloseEnoughToBase(world, player, actorInfo, cell)) { continue; } return(cell); } return(null); }; var baseCenter = GetRandomBaseCenter(); return(findPos(baseCenter, baseCenter, Info.MinBaseRadius, distanceToBaseIsImportant ? Info.MaxBaseRadius : world.Map.Grid.MaximumTileSearchRange)); }
static CPos FindEdge(Surface s, CPos p, CVec d, TileReference <ushort, byte> replace) { for (;;) { var q = p + d; if (!s.Map.IsInMap(q)) { return(p); } if (s.Map.MapTiles.Value[q.X, q.Y].Type != replace.Type) { return(p); } p = q; } }
public void Do([NotNull] FVec input, [NotNull] CVec fftGrain) { ThrowIfDisposed(); if (input == null) { throw new ArgumentNullException(nameof(input)); } if (fftGrain == null) { throw new ArgumentNullException(nameof(fftGrain)); } NativeMethods.aubio_pvoc_do(this, input, fftGrain); }
public void Rdo([NotNull] CVec fftGrain, [NotNull] FVec output) { ThrowIfDisposed(); if (fftGrain == null) { throw new ArgumentNullException(nameof(fftGrain)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } NativeMethods.aubio_pvoc_rdo(this, fftGrain, output); }
static IEnumerable <CPos> RandomWalk(CPos p, Thirdparty.Random r) { for (; ;) { var dx = r.Next(-1, 2); var dy = r.Next(-1, 2); if (dx == 0 && dy == 0) { continue; } p += new CVec(dx, dy); yield return(p); } }
public static IEnumerable <CPos> Tiles(Ruleset rules, string name, BuildingInfo buildingInfo, CPos topLeft) { var dim = buildingInfo.Dimensions; var footprint = buildingInfo.Footprint.Where(x => !char.IsWhiteSpace(x)); var bibInfo = rules.Actors[name].TraitInfoOrDefault <BibInfo>(); if (bibInfo != null && !bibInfo.HasMinibib) { dim += new CVec(0, 1); footprint = footprint.Concat(new char[dim.X]); } return(TilesWhere(name, dim, footprint.ToArray(), a => a != '_').Select(t => t + topLeft)); }
public static IEnumerable <CPos> RandomWalk(CPos p, MersenneTwister r) { while (true) { var dx = r.Next(-1, 2); var dy = r.Next(-1, 2); if (dx == 0 && dy == 0) { continue; } p += new CVec(dx, dy); yield return(p); } }
public void Do([NotNull] CVec input, [NotNull] FVec output) { ThrowIfDisposed(); if (input == null) { throw new ArgumentNullException(nameof(input)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } NativeMethods.aubio_filterbank_do(this, input, output); }
public void Do([NotNull] CVec fftGrain, [NotNull] FVec description) { ThrowIfDisposed(); if (fftGrain == null) { throw new ArgumentNullException(nameof(fftGrain)); } if (description == null) { throw new ArgumentNullException(nameof(description)); } NativeMethods.aubio_specdesc_do(this, fftGrain, description); }
public void Rdo([NotNull] CVec spectrum, [NotNull] FVec output) { ThrowIfDisposed(); if (spectrum == null) { throw new ArgumentNullException(nameof(spectrum)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } NativeMethods.aubio_fft_rdo(this, spectrum, output); }
public void Do([NotNull] FVec input, [NotNull] CVec spectrum) { ThrowIfDisposed(); if (input == null) { throw new ArgumentNullException(nameof(input)); } if (spectrum == null) { throw new ArgumentNullException(nameof(spectrum)); } NativeMethods.aubio_fft_do(this, input, spectrum); }
static CPos FindEdge(Surface s, CPos p, CVec d, TerrainTile replace) { for (;;) { var q = p + d; if (!s.Map.Contains(q)) { return(p); } if (s.Map.MapTiles.Value[q].Type != replace.Type) { return(p); } p = q; } }
void UpdateNeighbour(CVec offset) { var neighbour = bridgeLayer[self.Location + offset]; if (neighbour == null) { return; } var body = neighbour.TraitOrDefault <WithBridgeSpriteBody>(); if (body != null && body.bridgeInfo.Type == bridgeInfo.Type) { body.SetDirty(); } }
public override void Tick(Actor self) { base.Tick(self); if (!hasTicked) { var vec = new CVec(1, 1); var adjWalls = self.World.FindActorsInBox(self.Location - vec, self.Location + vec) .Where(a => a.Info == self.Info && a != self); foreach (var w in adjWalls) { w.Trait<RenderBuildingWall>().AddAdjacentWall(w.Location, self.Location); AddAdjacentWall(self.Location, w.Location); } hasTicked = true; } }
static CPos FindEdge(Surface s, CPos p, CVec d, TileReference<ushort, byte> replace) { for (;;) { var q = p + d; if (!s.Map.IsInMap(q)) return p; if (s.Map.MapTiles.Value[q.X, q.Y].Type != replace.Type) return p; p = q; } }
internal static void ModifyCPos(ref string input, CVec vector) { var oldCPos = FieldLoader.GetValue<CPos>("(value)", input); var newCPos = oldCPos + vector; input = newCPos.ToString(); }
void Copy(CellRegion source, CVec offset) { var gridType = worldRenderer.World.Map.Grid.Type; var mapTiles = worldRenderer.World.Map.Tiles; var mapHeight = worldRenderer.World.Map.Height; var mapResources = worldRenderer.World.Map.Resources; var dest = new CellRegion(gridType, source.TopLeft + offset, source.BottomRight + offset); var previews = new Dictionary<string, ActorReference>(); var tiles = new Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>>(); foreach (var cell in source) { if (!mapTiles.Contains(cell) || !mapTiles.Contains(cell + offset)) continue; tiles.Add(cell + offset, Tuple.Create(mapTiles[cell], mapResources[cell], mapHeight[cell])); foreach (var preview in editorLayer.PreviewsAt(cell)) { if (previews.ContainsKey(preview.ID)) continue; var copy = preview.Export(); if (copy.InitDict.Contains<LocationInit>()) { var location = copy.InitDict.Get<LocationInit>(); copy.InitDict.Remove(location); copy.InitDict.Add(new LocationInit(location.Value(worldRenderer.World) + offset)); } previews.Add(preview.ID, copy); } } foreach (var kv in tiles) { mapTiles[kv.Key] = kv.Value.Item1; mapResources[kv.Key] = kv.Value.Item2; mapHeight[kv.Key] = kv.Value.Item3; } var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList(); foreach (var preview in removeActors) editorLayer.Remove(preview); foreach (var kv in previews) editorLayer.Add(kv.Value); }
void UpdateNeighbour(CVec offset) { var neighbour = bridgeLayer[self.Location + offset]; if (neighbour == null) return; var body = neighbour.TraitOrDefault<WithBridgeSpriteBody>(); if (body != null && body.bridgeInfo.Type == bridgeInfo.Type) body.SetDirty(); }
public override CPos ParseActorLocation(string input, int loc) { var newLoc = new CPos(loc % MapSize, loc / MapSize); var vectorDown = new CVec(0, 1); if (input == "obli" || input == "atwr" || input == "weap" || input == "hand" || input == "tmpl" || input == "split2" || input == "split3") newLoc += vectorDown; return newLoc; }
static void UpdateNeighbours(Actor self) { var vec = new CVec(1, 1); var neighbours = self.World.FindActorsInBox(self.Location - vec, self.Location + vec) .Select(a => a.TraitOrDefault<RenderBuildingWall>()) .Where(a => a != null); foreach (var rb in neighbours) rb.dirty = true; }
int2 CellToMinimapPixel(CPos p) { var mapOrigin = new CVec(world.Map.Bounds.Left, world.Map.Bounds.Top); var mapOffset = Map.CellToMap(world.Map.TileShape, p) - mapOrigin; return new int2(mapRect.X, mapRect.Y) + (previewScale * new float2(mapOffset.X, mapOffset.Y)).ToInt2(); }
public static Bitmap ShroudBitmap(World world) { var map = world.Map; var b = map.Bounds; var size = Exts.NextPowerOf2(Math.Max(b.Width, b.Height)); var bitmap = new Bitmap(size, size); if (world.RenderPlayer == null) return bitmap; var bitmapData = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); var shroud = Color.Black.ToArgb(); var fog = Color.FromArgb(128, Color.Black).ToArgb(); var offset = new CVec(b.Left, b.Top); unsafe { var colors = (int*)bitmapData.Scan0; var stride = bitmapData.Stride / 4; var shroudObscured = world.ShroudObscuresTest(map.Cells); var fogObscured = world.FogObscuresTest(map.Cells); foreach (var cell in map.Cells) { var uv = Map.CellToMap(map.TileShape, cell) - offset; if (shroudObscured(cell)) colors[uv.Y * stride + uv.X] = shroud; else if (fogObscured(cell)) colors[uv.Y * stride + uv.X] = fog; } } bitmap.UnlockBits(bitmapData); return bitmap; }