+static void vis_visit(struct player *p, int cx, int cy, int *cvis)
+{
+ int i, j, nx, ny, dx, dy;
+ struct level *lvl = p->lvl;
+ struct cell *cell;
+
+ if(cx < 0 || cx >= lvl->width || cy < 0 || cy >= lvl->height) {
+ return;
+ }
+ cell = lvl->cells + cy * lvl->width + cx;
+
+ /* stop when we encounter a solid cell */
+ if(cell->type == CELL_SOLID) {
+ return;
+ }
+
+ dx = cx - p->cx;
+ dy = cy - p->cy;
+ /* stop beyond the maximum visibility distance (manhattan) */
+ if(abs(dx) > lvl->visdist || abs(dy) > lvl->visdist) {
+ return;
+ }
+
+ /* dot product */
+ if(step[p->dir][0] * dx + step[p->dir][1] * dy < 0) {
+ return; /* cell is behind the player */
+ }
+
+ cvis[cy * lvl->width + cx] = 1; /* mark as visited before recursing */
+
+ /* visit neighboring nodes before adding current cell */
+ for(i=0; i<3; i++) {
+ ny = cy - 1 + i;
+ if(ny < 0) continue;
+ if(ny >= lvl->height) break;
+
+ for(j=0; j<3; j++) {
+ if(i == 1 && j == 1) continue;
+ nx = cx - 1 + j;
+ if(nx < 0) continue;
+ if(nx >= lvl->width) break;
+
+ if(!cvis[ny * lvl->width + nx]) {
+ vis_visit(p, nx, ny, cvis);
+ }
+ }
+ }
+
+ /* then add this cell to the visible list */
+ cell->next = p->vis;
+ p->vis = cell;
+}
+