public static HashSet <Point> ComputeFOVFor(Rules rules, Actor actor, WorldTime time, Weather weather) { Location fromLocation = actor.Location; HashSet <Point> visibleSet = new HashSet <Point>(); Point from = fromLocation.Position; Map map = fromLocation.Map; int maxRange = rules.ActorFOV(actor, time, weather); ////////////////////////////////////////////// // Brute force ray-casting with wall fix pass ////////////////////////////////////////////// int xmin = from.X - maxRange; int xmax = from.X + maxRange; int ymin = from.Y - maxRange; int ymax = from.Y + maxRange; map.TrimToBounds(ref xmin, ref ymin); map.TrimToBounds(ref xmax, ref ymax); Point to = new Point(); List <Point> wallsToFix = new List <Point>(); // 1st pass : trace line and remember walls that are not visible for 2nd pass. for (int x = xmin; x <= xmax; x++) { to.X = x; for (int y = ymin; y <= ymax; y++) { to.Y = y; // Distance check. if (rules.LOSDistance(from, to) > maxRange) { continue; } // If we already know tile is visible, pass. if (visibleSet.Contains(to)) { continue; } // Trace line. if (!FOVSub(fromLocation, to, maxRange, ref visibleSet)) { // if its a wall (in FoV terms), remember. bool isFovWall = false; Tile tile = map.GetTileAt(x, y); MapObject mapObj = map.GetMapObjectAt(x, y); if (!tile.Model.IsTransparent && !tile.Model.IsWalkable) { isFovWall = true; } else if (mapObj != null) { isFovWall = true; } if (isFovWall) { wallsToFix.Add(to); } // next. continue; } // Visible. visibleSet.Add(to); } } // 2nd pass : wall fix. List <Point> fixedWalls = new List <Point>(wallsToFix.Count); foreach (Point wallP in wallsToFix) { int count = 0; foreach (Direction d in Direction.COMPASS) { Point next = wallP + d; if (visibleSet.Contains(next)) { Tile tile = map.GetTileAt(next.X, next.Y); if (tile.Model.IsTransparent && tile.Model.IsWalkable) { ++count; } } } if (count >= 3) { fixedWalls.Add(wallP); } } foreach (Point fixedWall in fixedWalls) { visibleSet.Add(fixedWall); } return(visibleSet); }