/*
	3D line routine 0.11
	made by Ismo Horppu on 1996 - 1997
*/

#include <math.h>
#include <stdio.h>
#include <dpmi.h>
#include <stdlib.h>
#include "ct2egen.h"
#include "ct2line.h"

/*
	returns zero if there is a line of vision between
	these 2 points else returns -1
	
	This routine contains a major bug, it won't work
	if start Z != end Z, (I have included a code that
	returns always blocked, 'cause this code won't work
	on most cases...)
*/
int CheckLine3D (int sx, int sy, int sz, int ex, int ey, int ez)
{
	register int cx, cy, cz;
	int ox, oy, oz;
	register int cnt;
	int xs, ys, zs;
	int xr, yr, zr;
	int range;
	int rx, ry, rz;

	if (sz != ez) return -1;
	
	// active soldier always visible :)
	if (sx == ex && sy == ey && sz == ez){
		return 0;	
	}
	
	// if current team's soldier then visible always...
	if (team (sx, sy, sz) == team (ex, ey, ez)) return 0;

	cx = sx << SHL;
	cy = sy << SHL;
	cz = sz << SHL;

	xr = abs (sx - ex);
	yr = abs (sy - ey);
	zr = abs (sz - ez);

	if (xr >= yr && xr >= zr){
		range = xr;
		xs = MUL;

		if (xr != 0){
			ys = (yr << SHL) / xr;
			zs = (zr << SHL) / xr;
		}

		else{
			ys = zs = 0;
		}
	}

	else if (yr >= xr && yr >= zr){
		range = yr;
		ys = MUL;

		if (yr != 0){
			xs = (xr << SHL) / yr;
			zs = (zr << SHL) / yr;
		}

		else{
			xs = zs = 0;
		}
	}

	else if (zr >= xr && zr >= yr){
		range = zr;
		zs = MUL;

		if (zr != 0){
			xs = (xr << SHL) / zr;
			ys = (yr << SHL) / zr;
		}

		else{
			xs = ys = 0;
		}
	}

	if (ex < sx) xs = -xs;
	if (ey < sy) ys = -ys;
	if (ez < sz) zs = -zs;
	
	if (sprdir == 0 && xs < 0) return -1;
	else if (sprdir == 1 && ys < 0) return -1;
	else if (sprdir == 2 && xs > 0) return -1;
	else if (sprdir == 3 && ys > 0) return -1;
	
	linerange = 0;

	for (cnt = 0; cnt < range; cnt++){
		linerange++;
		ox = cx;
		oy = cy;
		oz = cz;
		cx += xs;
		cy += ys;
		cz += zs;
		rx = cx >> SHL;
		ry = cy >> SHL;
		rz = cz >> SHL;

		// entering to new Z level, one level up
		if (rz == (oz >> SHL) + 1){
			// there must be 255 (= noblock)
			if (Map[rx][ry][rz] != 255){
				if (rx != ex && ry != ey && rz != ez){
					return -1;
				}
			}
		}

		// 1 level down
		else if (rz == (oz >> SHL) - 1){
			if (BlockFlags[Map[(ox >> SHL)][(oy >> SHL)][(oz >> SHL)]] != 255){
				return -1;
			}
		}

		// block must be seeable
		else if (BlockFlags[Map[rx][ry][rz]] != Seeable
		&& BlockFlags[Map[rx][ry][rz]] != SWable &&
		Map[rx][ry][rz] != 255 &&
		BlockFlags[Map[rx][ry][rz]] != RWable &&
		BlockFlags[Map[rx][ry][rz]] != Riseable &&
		BlockFlags[Map[rx][ry][rz]] != Walkable){
			return -1;
		}
		
		if (Soldier (rx, ry, rz) == 0 &&
		(range - cnt) > 1) return -1;
	}

	return 0;
}