///<summary>Returns true if cell is lit from any direction.</summary> public bool IsLit(Point cell) { if (MagicalLightState == MagicalLightState.MagicalLight) { return(true); } else if (MagicalLightState == MagicalLightState.MagicalDarkness) { return(false); } else { if (TileDefinition.IsOpaque(Map.Tiles[cell])) { foreach (Point neighbor in cell.EnumeratePointsAtChebyshevDistance(1, false, false)) { if (!neighbor.ExistsBetweenMapEdges()) { continue; } if (cellBrightness[neighbor] > 0 && !TileDefinition.IsOpaque(Map.Tiles[neighbor])) { return(true); } } return(false); } else { return(cellBrightness[cell] > 0); } } }
public bool CellIsOpaque(Point p) { TileType type = Tiles[p]; if (TileDefinition.IsOpaque(type)) { return(true); } if (Features[p].IsOpaque()) { return(true); } return(false); }
private void UpdateBrightnessWithinRadius(Point sourceCell, int radius, int increment) { for (int i = sourceCell.Y - radius; i <= sourceCell.Y + radius; ++i) { for (int j = sourceCell.X - radius; j <= sourceCell.X + radius; ++j) { Point p = new Point(j, i); if (!p.ExistsBetweenMapEdges()) { continue; } if (!TileDefinition.IsOpaque(Map.Tiles[p]) && sourceCell.CheckReciprocalBresenhamLineOfSight(p, Map.Tiles)) { cellBrightness[p] += increment; } } } }
///<summary>Returns true if cell is lit AND (for opaque cells) if the observer is on the right side to see the light.</summary> public bool CellAppearsLitToObserver(Point cell, Point observer) { if (MagicalLightState == MagicalLightState.MagicalLight) { return(true); } else if (!IsLit(cell)) { return(false); // If it isn't lit at all, stop here. } else { if (TileDefinition.IsOpaque(Map.Tiles[cell])) { // Light for opaque cells must be done carefully so light sources aren't visible through walls. // If the observer has LOS to any adjacent lit nonopaque cell, that observer knows this wall is lit. for (int i = 0; i < 8; ++i) { Dir8 dir = EightDirections.Eight[i]; Point neighbor = cell.PointInDir(dir); if (!neighbor.ExistsBetweenMapEdges()) { continue; } if (cellBrightness[neighbor] == 0) { continue; } if (observer.CheckReciprocalBresenhamLineOfSight(neighbor, Map.Tiles)) { return(true); } } return(false); } else { return(true); // Cell is lit and not opaque, so it appears lit from anywhere. } } }
public static bool HasLOS(this Point source, Point destination, PointArray <TileType> map) //todo, move this, to use NeverInLOS from DungeonMap { if (TileDefinition.IsOpaque(map[destination])) { Point[] neighbors = GetNeighborsBetween(destination, source); for (int i = 0; i < neighbors.Length; ++i) { if (TileDefinition.IsOpaque(map[neighbors[i]])) { continue; } if (CheckReciprocalBresenhamLineOfSight(source, neighbors[i], map)) { return(true); } } return(false); } else { return(CheckReciprocalBresenhamLineOfSight(source, destination, map)); } }
public static bool CheckReciprocalBresenhamLineOfSight(this Point source, Point destination, PointArray <TileType> map) //todo, what to do with map? { int x1 = source.X; int y1 = source.Y; int x2 = destination.X; int y2 = destination.Y; int dx = Math.Abs(x2 - x1); int dy = Math.Abs(y2 - y1); int incrementX = x1 == x2? 0 : x1 < x2? 1 : -1; int incrementY = y1 == y2? 0 : y1 < y2? 1 : -1; if (dx <= 1 && dy <= 1) { return(true); // Automatically pass the check for anything in the same or adjacent cells. } // Next, handle simple cases that don't need Bresenham at all. These cases correspond to straight lines in the 8 directions: if (dx == 0 || dy == 0 || (y1 + x1 == y2 + x2) || (y1 - x1 == y2 - x2)) // (if slope is undefined, 0, -1, or 1) { do { x1 += incrementX; // Increment first, so that the opacity of 'source' is ignored. y1 += incrementY; if (TileDefinition.IsOpaque(map[x1, y1])) { return(false); } } while(x1 != x2 || y1 != y2); return(true); } // If it wasn't a simple case, move on to reciprocal Bresenham: bool xMajor = (dx > dy); int er = 0; // error accumulator bool blockedA = false; // These 2 are used to track whether each of the 2 possible paths per line is blocked or not. bool blockedB = false; // (The result is equivalent to calculating 2 regular Bresenham lines, source->dest and dest->source.) if (xMajor) { do { x1 += incrementX; er += dy; if (er << 1 > dx) { y1 += incrementY; er -= dx; } if (TileDefinition.IsOpaque(map[x1, y1])) { if (blockedB || er << 1 != dx) { return(false); } blockedA = true; } if (er << 1 == dx) // This is the part that makes this reciprocal, by checking both options while crossing a corner. { y1 += incrementY; // Increment Y, then check the new position: if (TileDefinition.IsOpaque(map[x1, y1])) { if (blockedA || er << 1 != dx) { return(false); } blockedB = true; } er -= dx; } } while(x1 != x2); } else // Y-major { do { y1 += incrementY; er += dx; if (er << 1 > dy) { x1 += incrementX; er -= dy; } if (TileDefinition.IsOpaque(map[x1, y1])) { if (blockedB || er << 1 != dy) { return(false); } blockedA = true; } if (er << 1 == dy) { x1 += incrementX; if (TileDefinition.IsOpaque(map[x1, y1])) { if (blockedA || er << 1 != dy) { return(false); } blockedB = true; } er -= dy; } } while(y1 != y2); } return(true); }