Skip to content
Snippets Groups Projects
line_of_sight.cpp 2 KiB
Newer Older
Jake Feddersen's avatar
Jake Feddersen committed
#include <cstdlib>

#include "line_of_sight.h"
#include "util.h"

// Bresenham's line drawing algorithm
// Based on pseudocode from Wikipedia
// https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm

// Not perfect, but does a decent job of line of sight

static uint8_t plot_line_low(int x0, int y0, int x1, int y1, dungeon &d) {
	int dx = x1 - x0;
  int dy = y1 - y0;
  int yi = 1;
  if (dy < 0) {
    yi = -1;
    dy = -dy;
	}
  int D = 2*dy - dx;
  int y = y0;

	int x;
	for (x = x0; x != x1; x += sign(x1-x0)) {
    if (d.hardness[y][x]) return 0;
    if (D > 0) {
       y = y + yi;
       D = D - 2*dx;
		}
    D = D + 2*dy;
	}
	return 1;
}

static uint8_t plot_line_high(int x0, int y0, int x1, int y1, dungeon &d) {
  int dx = x1 - x0;
  int dy = y1 - y0;
  int xi = 1;
  if (dx < 0) {
    xi = -1;
    dx = -dx;
	}
	
  int D = 2*dx - dy;
  int x = x0;

	int y;
	for (y = y0; y != y1; y += sign(y1-y0)) {
    if (d.hardness[y][x]) return 0;
    if (D > 0) {
       x = x + xi;
       D = D - 2*dy;
		}
    D = D + 2*dx;
	}
	return 1;
}

static uint8_t test_line(int x0, int y0, int x1, int y1, dungeon &d) {
	int i;
	
	// Vertical line
	if (x0 == x1) {
		for (i = y0; i != y1; i += sign(y1-y0)) {
			if (d.hardness[i][x1]) return 0;
		}
		return 1;
	}

  if (abs(y1 - y0) < abs(x1 - x0)) {
    if (x0 > x1) {
      return plot_line_low(x1, y1, x0, y0, d);
		} else {
      return plot_line_low(x0, y0, x1, y1, d);
		}
	} else {
    if (y0 > y1) {
      return plot_line_high(x1, y1, x0, y0, d);
		} else {
      return plot_line_high(x0, y0, x1, y1, d);
		}
	}
	return 1;
}

void calc_line_of_sight(dungeon &d) {
	int i, j;
	
	int x = d.player_pos.x;
	int y = d.player_pos.y;
	
	for (i = 0; i < MAP_HEIGHT; i++) {
		for (j = 0; j < MAP_WIDTH; j++) {
			d.pc_sight[i][j] = 0;
		}
	}

	for (i = std::max(0, y-VIEW_DIST); i < std::min(MAP_HEIGHT, y+VIEW_DIST+1); i++) {
		for (j = std::max(0, x-VIEW_DIST); j <  std::min(MAP_WIDTH, x+VIEW_DIST+1); j++) {
			d.pc_sight[i][j] = test_line(j, i, x, y, d);
		}
	}
	
	d.update_fog_of_war();
}