Perimeter-based visibility.
[roguelike.git] / level.py
index e6ec9ff..66259ea 100644 (file)
--- a/level.py
+++ b/level.py
@@ -452,37 +452,38 @@ class Level (object):
         return (pl for pl in __main__.AppUI.instance.players if pl.level() == self)
 
     def visible_path(self, py, px, oy, ox):
+        """Returns a list of coordinates that can be seen by (py,px) when
+        looking at (oy,ox)."""
         (dy, dx) = (oy-py, ox-px)
-        if abs(dy) <= 1 and abs(dx) <= 1:
-            return True
-        flipped = False
+        if abs(dy) < 1 and abs(dx) < 1:
+            return (py, px)
+
+        path = []
+
         # Go in the direction of the longer axis
-        if abs(dy) > abs(dx):
-            flipped = True
+        flipped = abs(dy) > abs(dx)
+        if flipped:
             (dy, dx) = (dx, dy)
             (py, px) = (px, py)
             (oy, ox) = (ox, oy)
 
         xinc = 1 if dx >= 0 else -1
-        yinc = 1 if dy >= 0 else -1
-        
-        einc = abs(float(dy)/dx)
-        err = einc - 1.0
 
-        y = py + (yinc if einc >= 0.5 else 0)
+        # For each long-axis coordinate between p and o (inclusive):
+        for x in xrange(px, ox + xinc, xinc):
+            # Find the corresponding short-axis coordinate.
+            y = int(round(py + (x - px)*(float(dy)/dx)))
 
-        for x in xrange(px + xinc, ox, xinc):
+            # Convert to real coordinates
             (ly, lx) = (x, y) if flipped else (y, x)
 
-            if not self.loc(ly, lx).transparent():
-                return False
-
-            err += einc
-            if err >= 0.5:
-                y += yinc
-                err -= 1.0
+            # This cell can be seen.
+            path.append((ly, lx))
 
-        return True
+            # If it is opaque, no more cells can be seen.
+            if not self.loc(ly, lx).transparent():
+                break
+        return path
 
     # TODO: use dynamic programming: if we can't see a near tile, there is
     # no reason to test the tiles behind it.
@@ -493,7 +494,7 @@ class Level (object):
         vis = set()
         
         for pl in self.players():
-            vis |= set(pl.visibles())
+            vis |= pl.visibles()
 
         vis &= (self.invalid_tiles | self.active_tiles)
         vis |= self.important_repaints