public BuildingInfluence(World world) { map = world.Map; influence = new CellLayer<Actor>(map); world.ActorAdded += a => { var b = a.Info.TraitInfoOrDefault<BuildingInfo>(); if (b == null) return; foreach (var u in FootprintUtils.Tiles(map.Rules, a.Info.Name, b, a.Location)) if (influence.Contains(u) && influence[u] == null) influence[u] = a; }; world.ActorRemoved += a => { var b = a.Info.TraitInfoOrDefault<BuildingInfo>(); if (b == null) return; foreach (var u in FootprintUtils.Tiles(map.Rules, a.Info.Name, b, a.Location)) if (influence.Contains(u) && influence[u] == a) influence[u] = null; }; }
void IRenderShroud.RenderShroud(Shroud shroud, WorldRenderer wr) { if (currentShroud != shroud) { if (currentShroud != null) { currentShroud.CellsChanged -= DirtyCells; } if (shroud != null) { shroud.CellsChanged += DirtyCells; } // Needs the anonymous function to ensure the correct overload is chosen if (shroud != null) { visibleUnderShroud = puv => currentShroud.IsExplored(puv); } else { visibleUnderShroud = puv => map.Contains(puv); } if (shroud != null) { visibleUnderFog = puv => currentShroud.IsVisible(puv); } else { visibleUnderFog = puv => map.Contains(puv); } currentShroud = shroud; DirtyCells(map.ProjectedCellBounds); } // We need to update newly dirtied areas of the shroud. // Expand the dirty area to cover the neighboring cells, since shroud is affected by neighboring cells. foreach (var uv in cellsDirty) { cellsAndNeighborsDirty.Add(uv); var cell = ((MPos)uv).ToCPos(map); foreach (var direction in CVec.Directions) { cellsAndNeighborsDirty.Add((PPos)(cell + direction).ToMPos(map)); } } foreach (var puv in cellsAndNeighborsDirty) { var uv = (MPos)puv; if (!tileInfos.Contains(uv)) { continue; } var tileInfo = tileInfos[uv]; var shroudSprite = GetSprite(shroudSprites, GetEdges(puv, visibleUnderShroud), tileInfo.Variant); var shroudPos = tileInfo.ScreenPosition; if (shroudSprite != null) { shroudPos += shroudSprite.Offset - 0.5f * shroudSprite.Size; } var fogSprite = GetSprite(fogSprites, GetEdges(puv, visibleUnderFog), tileInfo.Variant); var fogPos = tileInfo.ScreenPosition; if (fogSprite != null) { fogPos += fogSprite.Offset - 0.5f * fogSprite.Size; } shroudLayer.Update(uv, shroudSprite, shroudPos); fogLayer.Update(uv, fogSprite, fogPos); } cellsDirty.Clear(); cellsAndNeighborsDirty.Clear(); fogLayer.Draw(wr.Viewport); shroudLayer.Draw(wr.Viewport); }
public Player GetOwnerAt(CPos cell) { return(owners.Contains(cell) ? owners[cell] : null); }
void BuildDomains(World world) { ushort domain = 1; var visited = new CellLayer <bool>(map); var toProcess = new Queue <CPos>(); toProcess.Enqueue(MPos.Zero.ToCPos(map)); // Flood-fill over each domain. while (toProcess.Count != 0) { var start = toProcess.Dequeue(); // Technically redundant with the check in the inner loop, but prevents // ballooning the domain counter. if (visited[start]) { continue; } var domainQueue = new Queue <CPos>(); domainQueue.Enqueue(start); var currentPassable = CanTraverseTile(world, start); // Add all contiguous cells to our domain, and make a note of // any non-contiguous cells for future domains. while (domainQueue.Count != 0) { var n = domainQueue.Dequeue(); if (visited[n]) { continue; } var candidatePassable = CanTraverseTile(world, n); if (candidatePassable != currentPassable) { toProcess.Enqueue(n); continue; } visited[n] = true; domains[n] = domain; // PERF: Avoid LINQ. foreach (var direction in CVec.Directions) { // Don't crawl off the map, or add already-visited cells. var neighbor = direction + n; if (visited.Contains(neighbor) && !visited[neighbor]) { domainQueue.Enqueue(neighbor); } } } domain += 1; } Log.Write("debug", "Found {0} domains for movement class {1} on map {2}.", domain - 1, movementClass, map.Title); }
public void UpdateCell(CPos cell) { var uv = cell.ToMPos(Map); if (!Map.Resources.Contains(uv)) { return; } var tile = Map.Resources[uv]; var t = Tiles[uv]; ResourceType type; var newTile = ResourceLayerContents.Empty; var newTerrain = byte.MaxValue; if (Resources.TryGetValue(tile.Type, out type)) { newTile = new ResourceLayerContents { Type = type, Density = CalculateCellDensity(type, cell) }; newTerrain = Tileset.GetTerrainIndex(type.Info.TerrainType); } // Nothing has changed if (newTile.Type == t.Type && newTile.Density == t.Density) { return; } UpdateNetWorth(t.Type, t.Density, newTile.Type, newTile.Density); Tiles[uv] = newTile; Map.CustomTerrain[uv] = newTerrain; if (CellChanged != null) { CellChanged(cell, type); } // Neighbouring cell density depends on this cell foreach (var d in CVec.Directions) { var neighbouringCell = cell + d; if (!Tiles.Contains(neighbouringCell)) { continue; } var neighbouringTile = Tiles[neighbouringCell]; var density = CalculateCellDensity(neighbouringTile.Type, neighbouringCell); if (neighbouringTile.Density == density) { continue; } UpdateNetWorth(neighbouringTile.Type, neighbouringTile.Density, neighbouringTile.Type, density); neighbouringTile.Density = density; Tiles[neighbouringCell] = neighbouringTile; if (CellChanged != null) { CellChanged(neighbouringCell, type); } } }
ResourceLayerContents IResourceLayer.GetResource(CPos cell) { return(Tiles.Contains(cell) ? Tiles[cell] : default);
public bool Contains(PPos uv) { // Check that uv is inside the map area. There is nothing special // about explored here: any of the CellLayers would have been suitable. return(explored.Contains((MPos)uv)); }
public Actor GetBuildingAt(CPos cell) { return(influence.Contains(cell) ? influence[cell] : null); }
/// <summary> /// Builds the domains. /// 构建域 /// </summary> /// <param name="world">World.</param> void BuildDomains(World world) { ushort domain = 1; var visited = new CellLayer <bool>(map); var toProcess = new Queue <CPos>(); toProcess.Enqueue(MPos.Zero.ToCPos(map)); //Flood-fill over each domain. //填充每个域 while (toProcess.Count != 0) { var start = toProcess.Dequeue(); //Technically redundant with the check in the inner loop, //but prevents ballooning the domain counter //技术上在内部循环检查冗余,防止膨胀域计数器 if (visited[start]) { continue; } var domainQueue = new Queue <CPos>(); domainQueue.Enqueue(start); var currentPassable = CanTraverseTile(world, start); //Add all contiguous cells to our domain,and make a not of an non-contiguous cells for future domain. //将所有连续的单元格添加到我们的域,并记录下未来域的非连续单元格 while (domainQueue.Count != 0) { var n = domainQueue.Dequeue(); if (visited[n]) { continue; } var candidatePassable = CanTraverseTile(world, n); if (candidatePassable != currentPassable) { toProcess.Enqueue(n); continue; } visited[n] = true; domains[n] = domain; //PERF:Avoid LINQ foreach (var direction in CVec.Directions) { //Don't crawl off the map ,or add already-visited cells. //不要抓取地图,或添加已经访问的单元格 var neighbor = direction + n; if (visited.Contains(neighbor) && !visited[neighbor]) { domainQueue.Enqueue(neighbor); } } } domain += 1; } }