/*
	CT2 graph routines 
	Made by Ismo Horppu on 1996 - 1997
		
	new enhancements - these will boost display updating a lot
*/

#include "types.h"
#include "m320x200.h"
#include "ct2defs.h"
#include "line3d.h"

#include <go32.h>
#include <stdio.h>
#include "ct2grx.h"

int CheckDraw (int mx, int my, int mz)
{
	if (endz - 1 == curz) return 1;
	if (endz - 1 == mz) return 1;
	if (mz == Zlevels - 1) return 1;

	/*
	if (Map[mx][my][mz + 1] != 255 && Map[mx][my + 1][mz + 1] != 255 &&
	Map[mx + 1][my][mz + 1] != 255 && Map[mx + 1][my + 1][mz + 1] != 255){
		return 0;
	}*/

	if (Map[mx][my][mz + 1] != 255 &&
	Map[mx - 1][my - 1][mz + 1] != 255 &&
	Map[mx][my - 1][mz + 1] != 255 &&
	Map[mx + 1][my - 1][mz + 1] != 255 &&
	Map[mx - 1][my][mz + 1] != 255 &&
	Map[mx][my][mz + 1] != 255 &&
	Map[mx + 1][my][mz + 1] != 255 &&
	Map[mx - 1][my + 1][mz + 1] != 255 &&
	Map[mx][my + 1][mz + 1] != 255 &&
	Map[mx + 1][my + 1][mz + 1] != 255){
		return 0;
	}
	
	else return 1;
}

/*
	initializes selector for conventional memory addressing...
*/
void InitGraphPointer (void)
{
	dos_seg = _go32_conventional_mem_selector ();
}

/*
	initializes mode 320x200
*/
void InitGraph (void)
{
	asm ("
		movw $0x13, %ax
		int $0x10
	");

	// put here check was the mode set succesful...
	minx = miny = 0;
	maxx = 319;
	maxy = 199;
}

void CloseGraph (void)
{
	asm ("
		movw $0x3, %ax
		int $0x10
	");
}

void DrawImage (BYTE *imagePTR, long block, int x, int y)
{
	BYTE value;
	int sx, sy;
	long off = 0;

	off = block * BlockWidth * BlockHeight;

	for (sy = y; sy < y + BlockHeight; sy++){
		for (sx = x; sx < x + BlockWidth; sx++){
			value = imagePTR[off];
			off++;

			if (value != 0){
				if (sx >= minx && sy >= miny &&
				sx <= maxx && sy <= maxy){
					PutPixel (sx, sy, value, VB);
				}
			}
		}
	}
}

long team (long x, long y, long z)
{
	register long c;
	register int xc;

	if (x == manX && y == manY && z == manZ){
		return player;
	}
	
	for (c = 0; c < default_players; c++){
		for (xc = 0; xc < MAX_START; xc++){
			if (x == PlayerStartX[xc][c] &&
			y == PlayerStartY[xc][c] &&
			z == PlayerStartZ[xc][c]){
				return c;
			}
		}
	}

	return 255;	// unknown team ???, weird...
}

long xsoldier (long x, long y, long z)
{
	register long c;
	register int xc;

	if (x == manX && y == manY && z == manZ){
		return soldier;
	}
	
	for (c = 0; c < default_players; c++){
		for (xc = 0; xc < MAX_START; xc++){
			if (x == PlayerStartX[xc][c] &&
			y == PlayerStartY[xc][c] &&
			z == PlayerStartZ[xc][c]){
				return xc;
			}
		}
	}

	return 255;	// unknown team ???, weird...
}

/*
	only Play_AI_Turn should call this...
	useful routine for seek/hide/fire AI code
*/
void CheckVisibleEnemies (void)
{
	int xc;
	int zsoldier, visible;
	
	enemies = 0;
	
	/*
		new visible check code
		
	*/
	for (xc = 0; xc < default_players; xc++){
		// own team, visible always...
		
		if (xc == player){
		}
		
		// check if visible
		else{
			for (zsoldier = 0; zsoldier < MAX_START; zsoldier++){
				visible = CheckLine3D (manX, manY, manZ, 
				PlayerStartX[zsoldier][xc], PlayerStartY[zsoldier][xc],
				PlayerStartZ[zsoldier][xc]);

				if (visible == 0){
					if (health[xc][zsoldier] > 0){
						if (Object[PlayerStartX[zsoldier][xc]][PlayerStartY[zsoldier][xc]][PlayerStartZ[zsoldier][xc]] != 254){
							enemyX[enemies] = PlayerStartX[zsoldier][xc];
							enemyY[enemies] = PlayerStartY[zsoldier][xc];
							enemyZ[enemies] = PlayerStartZ[zsoldier][xc];
							enemyR[enemies] = linerange;
							enemies++;
						}
					}
					
				}
				
				else{
				}
			}
		}
	}
}

/*
	visibility check has been totally enhanced, now works a lot better/longer
*/
void ShowMap (void)
{
	int sx, sy = 0;
	int x, y, z;
	int blks = 1;
	int msy;
	int ADJ = 16;
	int spy;
	int yadj;
	long blk;
	long obj, xobj, tobj;
	int cblk;
	int visible;
	int xc, zsoldier;
	int clipX, clipY;
	BYTE fastclip;

	// floor start

	// first draw upper part
	sx = 320 / 2 - (BlockWidth / 2);
	sy = -12 - 128;
	enemies = 0;
	
	/*
		new visible check code
		
	*/
	for (xc = 0; xc < default_players; xc++){
		// own team, visible always...
		if (xc == player){
			/*
			for (zsoldier = 0; zsoldier < MAX_START; zsoldier++){
			}*/
		}
	
		// check if visible
		else{
			for (zsoldier = 0; zsoldier < MAX_START; zsoldier++){
				visible = CheckLine3D (manX, manY, manZ, 
				PlayerStartX[zsoldier][xc], PlayerStartY[zsoldier][xc],
				PlayerStartZ[zsoldier][xc]);

				if (visible == 0){
					if (health[xc][zsoldier] > 0){
						if (Object[PlayerStartX[zsoldier][xc]][PlayerStartY[zsoldier][xc]][PlayerStartZ[zsoldier][xc]] != 254){
							enemyX[enemies] = PlayerStartX[zsoldier][xc];
							enemyY[enemies] = PlayerStartY[zsoldier][xc];
							enemyZ[enemies] = PlayerStartZ[zsoldier][xc];
							enemyR[enemies] = linerange;
							enemies++;
						}
					}
				}
				
				else{
				}
			}
		}
	}
	
	blks += 4;
	sx -= BlockWidth / 2 * 4;
	sy += BlockWidth / 2 * 4;
	
	for (y = 4; y < 16; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;

			clipX = sx + x * BlockWidth;
			clipY = sy - BlockHeight - yadj;
			fastclip = 0;
			if (clipX <= -32 || clipX >= 320) fastclip = 1;
			if (clipY <= -64 || clipY >= 200) fastclip = 1;
		
			for (z = 0; z < 1; z++){
				if (CheckDraw (mx + x, my - x + y + 1, z) == 1 && fastclip == 0){
					blk = Map[mx + x][my - x + y + 1][z];

					if (z == 0){
						blk = (LightLevel[mx + x][my - x + y + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, sx + x * BlockWidth, sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					else if (blk != 255){
						blk = (LightLevel[mx + x][my - x + y + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, sx + x * BlockWidth, sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					obj = Object[mx + x][my - x + y + 1][z];
					xobj = obj;
					
					if (obj != 255){
						visible = CheckLine3D (manX, manY, manZ, mx + x, my - x + y + 1, z);
						
						if (visible == 0){
							obj = (LightLevel[mx + x][my - x + y + 1][z] * RealSprites) + obj;
						
							// alive soldier !!!
							if (xobj != 254){
								tobj = team (mx + x, my - x + y + 1, z);
								
								if (tobj != 255){
									obj += tobj * 448L;
									PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, sx + x * BlockWidth + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
									
									// select
									if (manX == mx + x && manY == my - x + y + 1 && manZ == z){
										PutClippedInvImage16 (&selectPTR[0][0], sx + x * BlockWidth + adjX, sy - BlockHeight - yadj + adjY, 16, 16, VB);
									}
									
									// target
									if (mx + x == enemyX[target] && 
									my - x + y + 1 == enemyY[target] && 
									z == enemyZ[target] && 
									team (manX, manY, manZ) != 
									team (mx + x, my - x + y + 1, z)){
										PutClippedInvImage16 (&targetPTR[0][0], sx + x * BlockWidth + adjX + 8, sy - BlockHeight - yadj + adjY + 16, 16, 16, VB);
									}
								}
							}
						
							// draw dead soldier
							else{
								obj = 1792 + LightLevel[mx + x][my - x + y + 1][z];	// first dead frame
								PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, sx + x * BlockWidth + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
							}
						}
					}
				}

				yadj += zadj;
			}
		}

		blks++;
		sx -= BlockWidth / 2;
		sy += BlockWidth / 2;
	}
	
	// draw bottom part
	spy = sy;

	for (y = 0; y < 12; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;

			clipX = (320 - BlockWidth) - (sx + x * BlockWidth);
			clipY = sy - BlockHeight - yadj;
			fastclip = 0;
			if (clipX <= -32 || clipX >= 320) fastclip = 1;
			if (clipY <= -64 || clipY >= 200) fastclip = 1;
			
			for (z = 0; z < 1; z++){
				if (CheckDraw (mx + ADJ - x, my + ADJ - (ADJ - y) + x + 1, z) == 1 && fastclip == 0){
					blk = Map[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];

					if (z == 0){
						blk = (LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth), sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					else if (blk != 255){
						blk = (LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth), sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					obj = Object[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];
					xobj = obj;
					
					if (obj != 255){
						visible = CheckLine3D (manX, manY, manZ, mx + ADJ - x, my + ADJ - (ADJ - y) + x + 1, z);
						
						if (visible == 0){
							obj = (LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z] * RealSprites) + obj;
							
							// alive !!!
							if (xobj != 254){
								tobj = team (mx + ADJ - x, my + ADJ - (ADJ - y) + x + 1, z);
								
								if (tobj != 255){
									obj += tobj * 448L;
									PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth) + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
									
									// select
									if (manX == mx + ADJ - x && manY == my + y + x + 1 && manZ == z){
										PutClippedInvImage16 (&selectPTR[0][0], (320 - BlockWidth) - (sx + x * BlockWidth) + adjX, sy - BlockHeight - yadj + adjY, 16, 16, VB);
									}
									
									if (mx + ADJ - x == enemyX[target] && 
									my + y + x + 1 == enemyY[target] &&
									z == enemyZ[target] &&
									team (manX, manY, manZ) !=
									team (mx + ADJ - x, my + y + x + 1, z)){
										PutClippedInvImage16 (&targetPTR[0][0], (320 - BlockWidth) - (sx + x * BlockWidth) + adjX + 8, sy - BlockHeight - yadj + adjY + 16, 16, 16, VB);
									}
								}
							}
							
							// dead....
							else{
								obj = 1792 + LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];
								PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth) + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
							}
						}
					}
				}

				yadj += zadj;
			}
		}


		blks--;
		sx += BlockWidth / 2;
		sy += BlockWidth / 2;
	}
	// floor end

	// first draw upper part
	sx = 320 / 2 - (BlockWidth / 2);
	sy = -12 - 128;

	blks += 4;
	sx -= BlockWidth / 2 * 4;
	sy += BlockWidth / 2 * 4;

	for (y = 4; y < 16; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;

			for (z = 1; z < endz; z++){
				clipX = sx + x * BlockWidth;
				clipY = sy - BlockHeight - yadj;
				fastclip = 0;
				if (clipX <= -32 || clipX >= 320) fastclip = 1;
				if (clipY <= -64 || clipY >= 200) fastclip = 1;
				
				if (CheckDraw (mx + x, my - x + y + 1, z) == 1 && fastclip == 0){
					blk = Map[mx + x][my - x + y + 1][z];

					if (z == 0){
						blk = (LightLevel[mx + x][my - x + y + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, sx + x * BlockWidth, sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					else if (blk != 255){
						blk = (LightLevel[mx + x][my - x + y + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, sx + x * BlockWidth, sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					obj = Object[mx + x][my - x + y + 1][z];
					xobj = obj;
					
					if (obj != 255){
						visible = CheckLine3D (manX, manY, manZ, mx + x, my - x + y + 1, z);
						
						if (visible == 0){
							obj = (LightLevel[mx + x][my - x + y + 1][z] * RealSprites) + obj;
							
							if (xobj != 254){
								tobj = team (mx + x, my - x + y + 1, z);
								
								if (tobj != 255){
									obj += tobj * 448L;
									PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, sx + x * BlockWidth + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
									
									// select
									if (manX == mx + x && manY == my - y + x + 1 && manZ == z){
										PutClippedInvImage16 (&selectPTR[0][0], sx + x * BlockWidth + adjX, sy - BlockHeight - yadj + adjY, 16, 16, VB);
									}
									
									if (mx + x == enemyX[target] && 
									my - y + x + 1 == enemyY[target] && 
									z == enemyZ[target] &&
									team (manX, manY, manZ) != 
									team (mx + x, my - y + x + 1, z)){
										PutClippedInvImage16 (&targetPTR[0][0], sx + x * BlockWidth + adjX + 8, sy - BlockHeight - yadj + adjY + 16, 16, 16, VB);
									}
								}
							}
							
							else{
								obj = 1792 + LightLevel[mx + x][my - x + y + 1][z];
								PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, sx + x * BlockWidth + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
							}
						}
					}
				}

				yadj += zadj;
			}
		}

		blks++;
		sx -= BlockWidth / 2;
		sy += BlockWidth / 2;
	}

	// draw bottom part
	spy = sy;

	for (y = 0; y < 12; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;

			for (z = 1; z < endz; z++){
				clipX = (320 - BlockWidth) - (sx + x * BlockWidth);
				clipY = sy - BlockHeight - yadj;
				fastclip = 0;
				if (clipX <= -32 || clipX >= 320) fastclip = 1;
				if (clipY <= -64 || clipY >= 200) fastclip = 1;
				
				if (CheckDraw (mx + ADJ - x, my + ADJ - (ADJ - y) + x + 1, z) == 1 && fastclip == 0){
					blk = Map[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];

					if (z == 0){
						blk = (LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth), sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					else if (blk != 255){
						blk = (LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z] * RealBlocks) + blk;
						PutClippedInvImage16 (blockPTR + blk * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth), sy - BlockHeight - yadj, BlockWidth, BlockHeight, VB);
					}

					obj = Object[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];
					xobj = obj;
					
					if (obj != 255){
						visible = CheckLine3D (manX, manY, manZ, mx + ADJ - x, my + ADJ - (ADJ - y) + x + 1, z);
						
						if (visible == 0){
							obj = (LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z] * RealSprites) + obj;
							
							if (xobj != 254){
								tobj = team (mx + ADJ - x, my + ADJ - (ADJ - y) + x + 1, z);
								
								if (tobj != 255){
									obj += tobj * 448L;
									PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth) + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
									
									// select
									if (manX == mx + ADJ - x && manY == my + y + x + 1 && manZ == z){
										PutClippedInvImage16 (&selectPTR[0][0], (320 - BlockWidth) - (sx + x * BlockWidth) + adjX, sy - BlockHeight - yadj + adjY, 16, 16, VB);
									}
									
									if (mx + ADJ - x == enemyX[target] && 
									my + y + x + 1 == enemyY[target] && 
									z == enemyZ[target] &&
									team (manX, manY, manZ) != 
									team (mx + ADJ - x, my + y + x + 1, z)){
										PutClippedInvImage16 (&targetPTR[0][0], (320 - BlockWidth) - (sx + x * BlockWidth) + adjX + 8, sy - BlockHeight - yadj + adjY + 16, 16, 16, VB);
									}
								}
							}
							
							else{
								obj = 1792 + LightLevel[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];
								PutClippedInvImage16 (spritePTR + obj * BlockWidth * BlockHeight, (320 - BlockWidth) - (sx + x * BlockWidth) + adjX, sy - BlockHeight - yadj + adjY, BlockWidth, BlockHeight, VB);
							}
						}
					}
				}

				yadj += zadj;
			}
		}


		blks--;
		sx += BlockWidth / 2;
		sy += BlockWidth / 2;
	}
}

int zInArea (int xp, int yp, int sx, int sy)
{
	if (xp >= sx && xp <= sx + 32 - 1 &&
	yp >= sy && yp <= sy + 64 - 1){
		return 1;
	}

	return 0;
}

// returns -1 if not in any area !
int GetMapXY (int xp, int yp)
{
	int x, y, z;
	int sx, sy = 0;
	int blks = 1;
	int ADJ = 16;
	int spy;
	int yadj;
	long blk;
	int clipX, clipY;
	int ready;
	
	// floor start

	// first draw upper part
	sx = 320 / 2 - (BlockWidth / 2);
	sy = -12 - 128;
	yadj = 0;
	
	for (y = 0; y < 16; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;
			clipX = sx + x * BlockWidth;
			clipY = sy - BlockHeight - yadj;
			ready = zInArea (xp, yp, clipX, clipY);
			
			if (ready){
				GlobalMapXPosition = mx + x;
				GlobalMapYPosition = my - x + y + 1;
				GlobalMapZPosition = z;
				//blk = Map[mx + x][my - x + y + 1][z];

				if (CheckMove (GlobalMapXPosition, GlobalMapYPosition, GlobalMapZPosition) != 1){
					return -2;
				}
				
				return 0;
			}
		}

		blks++;
		sx -= BlockWidth / 2;
		sy += BlockWidth / 2;
	}
	
	// draw bottom part
	spy = sy;

	for (y = 0; y < 16; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;
			clipX = (320 - BlockWidth) - (sx + x * BlockWidth);
			clipY = sy - BlockHeight - yadj;
			ready = zInArea (xp, yp, clipX, clipY);
			
			if (ready){
				GlobalMapXPosition = mx + ADJ - x;
				GlobalMapYPosition = my + ADJ - (ADJ - y) + x + 1;
				GlobalMapZPosition = z;
				//blk = Map[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];
				
				if (CheckMove (GlobalMapXPosition, GlobalMapYPosition, GlobalMapZPosition) != 1){
					return -2;
				}

				return 0;
			}
		}

		blks--;
		sx += BlockWidth / 2;
		sy += BlockWidth / 2;
	}
	// floor end

	// first draw upper part
	sx = 320 / 2 - (BlockWidth / 2);
	sy = -12 - 128;

	for (y = 0; y < 16; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;

			for (z = 1; z < endz; z++){
				clipX = sx + x * BlockWidth;
				clipY = sy - BlockHeight - yadj;
				yadj += zadj;
				ready = zInArea (xp, yp, clipX, clipY);
				
				if (ready){
					GlobalMapXPosition = mx + x;
					GlobalMapYPosition = my - x + y + 1;
					GlobalMapZPosition = z;
					//blk = Map[mx + x][my - x + y + 1][z];
					
					if (CheckMove (GlobalMapXPosition, GlobalMapYPosition, GlobalMapZPosition) != 1){
						return -2;
					}

					return 0;
				}
			}
		}

		blks++;
		sx -= BlockWidth / 2;
		sy += BlockWidth / 2;
	}

	// draw bottom part
	spy = sy;

	for (y = 0; y < 16; y++){
		for (x = 0; x < blks; x++){
			yadj = 0;

			for (z = 1; z < endz; z++){
				clipX = (320 - BlockWidth) - (sx + x * BlockWidth);
				clipY = sy - BlockHeight - yadj;
				yadj += zadj;
				ready = zInArea (xp, yp, clipX, clipY);

				if (ready){
					GlobalMapXPosition = mx + ADJ - x;
					GlobalMapYPosition = my + ADJ - (ADJ - y) + x + 1;
					GlobalMapZPosition = z;
					//blk = Map[mx + ADJ - x][my + ADJ - (ADJ - y) + x + 1][z];
					
					if (CheckMove (GlobalMapXPosition, GlobalMapYPosition, GlobalMapZPosition) != 1){
						return -2;
					}

					return 0;
				}
			}
		}

		blks--;
		sx += BlockWidth / 2;
		sy += BlockWidth / 2;
	}
}