#include <dos.h>
#include <stdio.h>
#include <string.h>
#include "globals.h"
#include "structur.h"

void my_main(void)
{
//	texture=(char *)install("datas\\testmap.bpp");
	texture=(char *)install("datas\\map1.pcd");
//	fade_to_col(1, 0x3f3f3f);					// flash to white

	fade_to_col(1, 0x000000);					// flash to black in 1 frame
	wait_fade();
     	fade_to_pal(63, &game_palette[0][0]);	// fade to game palette in 63 frames


	keydata->keymap[K_ESC] = 0;

	copydest = backscr;
	clr_screen();


	for (;;) {

		sync();
		read_joy();

#if DEBUGGING==1
		keydata->last_key = get_key();
		clear_keyb();
#endif

		ifkey(K_ESC)
			break;

		copysource = backscr;
		copydest = MCGA_RAM;
		dump_screen();

		read_mouse();

		clear_keyb();

		copydest = backscr;
		clr_screen();

		print(0, 0, "Mx:%d\nMy:%d\nMb:%d\n\nJ1x:%d\nJ1y:%d\nJ1f:%d\n\nJ2x:%d\nJ2y:%d\nJ2f:%d",
			mx, my, mbut,
			joy1_x, joy1_y, joy1_fire,
			joy2_x, joy2_y, joy2_fire);
		print(0, 100, "1xc:%d\n1yc:%d\n\n1ls:%d\n1rs:%d\n1us:%d\n1ds:%d",
			joy1_xcentre, joy1_ycentre,
			joy1_lscale, joy1_rscale, joy1_uscale, joy1_dscale);
		print(0, 160, "1lt:%d\n1rt:%d\n1ut:%d\n1dt:%d",
			joy1_lthresh, joy1_rthresh, joy1_uthresh, joy1_dthresh);
		print(0, 208, "Keys held: %d\nLast key:%d",
			keydata->keys_held, keydata->last_key);
		*(backscr+my*288+mx) = 2;
	}

	col=0;
  	for (copydest = backscr; copydest<(backscr+256); copydest++)
		{
		*copydest = col;						//put palette to screen top edge
		col++;
		col=col&255;
		}

 		drawtext(10,10);				//put text on screen scale 1-1
 		backtext(100,40);				//put text on screen scale 1-1
 		halftext(90,100);				//put text on screen scale 1/2

		copysource = backscr;
		copydest = MCGA_RAM;
		dump_screen();


		dotx=200;
		doty=150;
		col=200;

	for(;;)
		{
		clear_keyb();
		keydata->last_key = get_key();
		ifkey(K_SPACE)
			break;

		ifkey(K_UP)
			{
			col++;
			col=col&255;
			doty--;
			}
		ifkey(K_DOWN)
			{
			col++;
			col=col&255;
			doty++;
			}
		ifkey(K_LEFT)
			{
			col++;
			col=col&255;
			dotx--;
			}
		ifkey(K_RIGHT)
			{
			col++;
			col=col&255;
			dotx++;
			}


		linep.x1=100;
		linep.y1=100;
		linep.x2=dotx;
		linep.y2=doty;


		if (clipline())	//if clip returns non zero	(0=false)
			{
			if ( (linep.x1==linep.x2) && (linep.y1==linep.y2) )
				point();
			else
				drline();		//draw a line
			}


		copysource = backscr;
		copydest = MCGA_RAM;
		dump_screen();
		}

  
		dang=speed=0;
		mapx=-16*256+200;
		mapz=32*256+20;			//start pos = middle of map
		mapy=1600;
		viewrange=20;
		angle=40;
		altoff=300;

// ******************************************************
//	***************************** landscape routine
	col=254;

//	for(cnt=0;cnt<=253;cnt++)
//		game_palette[cnt][0]=63;
	fade_to_pal(1, &game_palette[0][0]);	// fade to game palette in 1 frame


	for(;;)
		{
		clear_keyb();
		keydata->last_key = get_key();
		ifkey(K_ESC)
			break;

	copydest = backscr;
	clr_screen();

		control();

		print(0, 0, "Mx:%d\nMy:%d\nMz:%d\n",mapx, mapy, mapz);
		print(0, 50, "xoff:%d\nzoff:%d\n",xoff, zoff);
		print(0, 74, "subx:%d\nsubz:%d\n",subx, subz);

		spinline();
		spinline2();
		drawmap(0,0,256);			// x,y,size

		copysource = backscr;
		copydest = MCGA_RAM;
		dump_screen();
		}

}
// ****************************************************************8


void	drawmap(int x, int z, int size)
{
	int half;

	process(x,z,size);
	if (perspec())
	{
	if (size <= rangesize(x+size/2,z+size/2))				//draw square size (small enough) ?
		{
//		if (faceon())
			{
				col=colr[size];
				drawblock(x,z,size);
			}
		}
	else							// else subdivide if not small enough yet to draw
		{
				half=size/2;
				drawmap(x,z,half);
				drawmap(x+half,z,half);
				drawmap(x,z+half,half);
				drawmap(x+half,z+half,half);
		}
	}
}


int	rangesize(int x, int z)
{
	int	dx,dz;
	dx=abs((-mapx>>8)-x);
	dz=abs((mapz>>8)-z);
	if	(dx>dz)
		return subsize[((dx+dz/2)>>3)];
	else
		return subsize[((dz+dx/2)>>3)];
}


void	drawblock(int x, int z, int size)				//draw one block of map
{
	int	xx,yy;

//	if (perspec());			//if no z clipping on perspective
//		{
		if((box.z1>120)&&(box.z2>120))
			{
			linep.x1=box.x1;
			linep.y1=box.y1;
			linep.x2=box.x2;
			linep.y2=box.y2;
			clipdraw();
			}

		if((box.z1>120)&&(box.z4>120))
			{
			linep.x1=box.x1;
			linep.y1=box.y1;
			linep.x2=box.x4;
			linep.y2=box.y4;
			clipdraw();
			}
//		}
}


int	process(int x, int z, int size)
{
	int xx,yy;
	xx=x-xblock;
	yy=z-zblock;
	

	box.x1= (xx*zvect)+(yy*xvect)+subx;
	box.z1= (yy*zvect)-(xx*xvect)+subz;

	box.x2= box.x1+(size*zvect);
	box.z2= box.z1-(size*xvect);

	box.x3= box.x2+(size*xvect);
	box.z3= box.z2+(size*zvect);

	box.x4= box.x1+(size*xvect);
	box.z4= box.z1+(size*zvect);


	box.y1= mapy+high(x,z);
	box.y2= mapy+high(x+size,z);
	box.y3= mapy+high(x+size,z+size);
	box.y4= mapy+high(x,z+size);

}



int	faceon()
{
	int a,b;
	
	a=(box.x3-box.x1)*(box.y2-box.y1);
	b=(box.y3-box.y1)*(box.x2-box.x1);
		
	if ((a-b)>=-2000)
		return -1;
	else
		return 0;				//return 0
}


int	closey()
{
	int zd,yd;
	zd=abs(box.z1);
	yd=box.y1;

 	if (abs(box.z2)<zd)
		{
		zd=box.z2;
		yd=box.y2;
		}
 	if (abs(box.z3)<zd)
		{
		zd=box.z3;
		yd=box.y3;
		}
 	if (abs(box.z4)<zd)
		{
		zd=box.z4;
		yd=box.y4;
		}
	return yd;
}

int	fary()
{
	int zd,yd;
	zd=abs(box.z1);
	yd=box.y1;

	if (abs(box.z2)>zd)
		{
		zd=box.z2;
		yd=box.y2;
		}
 	if (abs(box.z3)>zd)
		{
		zd=box.z3;
		yd=box.y3;
		}
 	if (abs(box.z4)>zd)
		{
		zd=box.z4;
		yd=box.y4;
		}
	return yd;
}


//		rotate 1st point in the line stucture line2
void	rotate(long angl)
{
		short	s,c;
		s=sin(angl);
		c=cos(angl);
		linepl.x2 = (linepl.x1*s + linepl.y1*c) >> 16;
		linepl.y2 = (linepl.x1*c - linepl.y1*s) >> 16;

//		linepl.x2 = (linepl.x1*c - linepl.y1*s) >> 16;
//		linepl.y2 = (linepl.x1*s + linepl.y1*c) >> 16;

}


int	high2(int x, int z)
{
	short	s,c,o;

	s=sin((x<<3)&2047);
	c=cos((z<<4)&2047);
	o=sin(((z+x)<<5)&2047);

//	return (int)((s-c+((o*o)>>17))>>4);					//HILLY MAP
	return (int)((s-c+((o*o)>>17))>>4+((o*s)>>24));	//MAD MAP
//	return 0;					//FLAT MAP
}


int	high(int x, int z)
{
			char	*source;
			int	zh;

	source = texture+4+(z/2)*128+(x/2);
	if (!(x&1) && !(z&1))
		{
		return -(*source)<<2;
		}
	else
		{
		if ((x&1) && (z&1))
			{
				zh= (*source+ *(source+1))  ;
				zh+= (*source+ *(source+128))  ;
				zh+= (*(source+128)+ *(source+129))  ;
				zh+= (*(source+1)+ *(source+129))  ;
		return -zh>>1;
			}
		
else
			if (x&1)
				return -(*source+*(source+1))<<1;
			else
				return -(*source+*(source+128))<<1;
		}
}


//	perspective routine on list of 4 x,y,z points in space (to centre of screen)
int	perspec()
{
	if (box.z1>70 && box.z2>70 && box.z3>70 && box.z4>70)
		{
		box.x1 = (box.x1 << 8)/box.z1+144;
		box.x2 = (box.x2 << 8)/box.z2+144;
		box.x3 = (box.x3 << 8)/box.z3+144;
		box.x4 = (box.x4 << 8)/box.z4+144;

		box.y1 = (box.y1 << 8)/box.z1+110;
		box.y2 = (box.y2 << 8)/box.z2+110;
		box.y3 = (box.y3 << 8)/box.z3+110;
		box.y4 = (box.y4 << 8)/box.z4+110;
		return -1;			//ok no z clipping
		}
	else
		return 0;
}


//	perspective routine on list of 4 x,y,z points in space (to centre of screen)
int	perspec2()
{
		box.x1 = (box.x1 >> 7)+144;
		box.x2 = (box.x2 >> 7)+144;
		box.x3 = (box.x3 >> 7)+144;
		box.x4 = (box.x4 >> 7)+144;

		box.y1 = (box.z1 >> 7)+100;
		box.y2 = (box.z2 >> 7)+100;
		box.y3 = (box.z3 >> 7)+100;
		box.y4 = (box.z4 >> 7)+100;
		return -1;			//ok no z clipping
}


// clipdraw	:clips a line and draws it
void	clipdraw()
{
		if (clipline())	//if clip returns non zero	(0=false)
			{
			if ( (linep.x1==linep.x2) && (linep.y1==linep.y2) )
				point();
			else
				drline();		//draw a line
			}
}


// ********************************************************************8
void	spinline()
{
		linep.x1=20;
		linep.y1=20;
		linep.x2=20+(sin(angle)>>9);
		linep.y2=20+(cos(angle)>>9);


		if (clipline())	//if clip returns non zero	(0=false)
			{
			if ( (linep.x1==linep.x2) && (linep.y1==linep.y2) )
				point();
			else
				drline();		//draw a line
			}
}

void	spinline2()
{
		box.z3=box.z4=20;


		linep.y1=20;

		box.x1=0;
		box.z1=400;
		box.y1=-100;

		box.x2=(sin(angle)>>7);
		box.z2=400+(cos(angle)>>7);
		box.y2=-100;

		perspec();

		linep.x1=box.x1;
		linep.y1=box.y1;
		linep.x2=box.x2;
		linep.y2=box.y2;


		if (clipline())	//if clip returns non zero	(0=false)
			{
			if ( (linep.x1==linep.x2) && (linep.y1==linep.y2) )
				point();
			else
				drline();		//draw a line
			}
}


void	control()
{
	int	ang;
		ifkey(K_A)
			altoff+=25;
		ifkey(K_Z)
			altoff-=25;
		ifkey(K_LEFT)
			dang--;
		ifkey(K_RIGHT)
			dang++;
		ifkey(K_SPACE)
			dang=0;
		ifkey(K_UP)
			{
			mapx +=(sin((angle+512)&2047) >> 7);
			mapz +=(cos((angle+512)&2047) >> 7);
			}
		ifkey(K_DOWN)
			{
			mapx -=(sin((angle+512)&2047) >> 7);
			mapz -=(cos((angle+512)&2047) >> 7);
			}

		mapz=mapz&65535;
		if (mapx>0)
			mapx=0;
		if	(mapx<-65535)
			mapx=-65535;

		ifkey(K_I)
			mapz+=64;
		ifkey(K_J)
			mapx+=64;
		ifkey(K_K)
			mapx-=64;
		ifkey(K_M)
			mapz-=64;

		angle = (angle+dang)&2047;
		xoff = mapx & 255;
		zoff = mapz & 255;

		ang = (angle+512)&2047;				//512=90 degs
		xvect = sin(ang) >> 8;		//vector of 1 block from my heading
		zvect = cos(ang) >> 8;		//   >>7
		
		xblock = abs(mapx >> 8);
		zblock = abs(mapz >> 8);

		linepl.x1=xoff;
		linepl.y1=zoff;
		rotate((angle)&2047);
		subx = linepl.x2;
		subz = linepl.y2;
		follow();
}
		
		
//		follow height contour of the land
void	follow()
{
	int	y1,y2,y3,y4;
	int	xb,zb;
	int	h1,h2;
		xb = -mapx >> 8;
		zb = mapz >> 8;
		
	y1= high(xb,zb);
	y2= high(xb+1,zb);
	y3= high(xb+1,zb+1);
	y4= high(xb,zb+1);

	h1 = y1 + (((y2-y1) * (256-xoff)) >> 8);
	h2 = y4 + (((y3-y4) * (256-xoff)) >> 8);
	mapy=altoff - h1+ (((h2-h1) * (256-zoff)) >> 8);
}




	



		
		//clipline clips a line , stored in structure linep
int	clipline()
{
	int	i,swap;
	if (linep.x2 < linep.x1)
		swapinx();

	if ((linep.x1>287) || (linep.x2<0))
		return 0;				//no draw if both points to right of screen
	else
		{
		clipright();
		clipleft();

		if (linep.y2 < linep.y1)
			{
			swapinx();				//swap points so y1<y2
			}

		if ((linep.y1>223) || (linep.y2<0))
			return 0;				//no draw if both points to right of screen
		else
			{
			clipup();
			clipdown();
			return -1;
			}
		}
}




void	clipright()
{
		int	dx,dy,ex,ey;

	if (linep.x2>287)				//is clip required ?
		{
		dx=linep.x2-linep.x1;
		dy=linep.y2-linep.y1;
		ex=288-linep.x1;
		ey=(dy*ex)/dx;
		linep.y2=linep.y1+ey;
		linep.x2=287;
		}
}


void	clipleft()
{
		int	dx,dy,ex,ey;

	if (linep.x1 < 0)				//is clip required ?
		{
		dx=linep.x2-linep.x1;
		dy=linep.y2-linep.y1;
		ex= -(linep.x1);
		ey=(dy*ex)/dx;
 		linep.y1 += ey;
		linep.x1=0;
		}
}


void	clipup()
{
		int	dx,dy,ex,ey;

	if (linep.y1<0)				//is clip required ?
		{
		dx=linep.x2-linep.x1;
		dy=linep.y2-linep.y1;
		ey=-(linep.y1);
		ex=(dx*ey)/dy;
		linep.y1=0;
		linep.x1+=ex;
		}
}



void	clipdown()
{
		int	dx,dy,ex,ey;

	if (linep.y2>223)				//is clip required ?
		{
		dx=linep.x2-linep.x1;
		dy=linep.y2-linep.y1;
		ey=224-linep.y1;
		ex=(dx*ey)/dy;
		linep.x2=linep.x1+ex;
		linep.y2=223;
		}
}


void	swapinx()
{
		int	swap;
		swap=linep.x2;
		linep.x2=linep.x1;
		linep.x1=swap;

		swap=linep.y2;
		linep.y2=linep.y1;
		linep.y1=swap;
}



void	point()
{
			char	*start;
			start = backscr + 288 * linep.y1 + linep.x1;
			*start = col;				//set colour
}

		/* drline	:routine to draw a line  */
void	drline()
{
			int	i,st,dx,dy,ax,ay;
			int	x1,y1,x2,y2;
			int	yy,end,ab;
			char	*start;
			x1=linep.x1;
			y1=linep.y1;
			x2=linep.x2;
			y2=linep.y2;

			st=0;
			start = backscr + 288 * y1 + x1;
			ax = sgn(x2-x1);
			ay = sgn(y2-y1);
			yy=288*ay;


			if (abs(x2-x1) < abs(y2-y1))
				{
				end = abs(y2-y1);
				dx=256*(x2-x1)/(y2-y1);
				ab = abs(dx);
				for(i=0; i<end; i++)
					{
					*start = col;				//set colour
					start +=yy;
					st += ab;
					if (st>255)
						{
						start +=ax;
						st -= 256;
						}
					}
				}
			else
				{
				end = abs(x2-x1);
				dy=256*(y2-y1)/(x2-x1);
				ab = abs(dy);
				for(i=0; i<end; i++)
					{
					*start = col;				//set colour
					start+=ax;
					st += ab;
					if (st>255)
						{
						start +=yy;
						st -= 256;
						}
					}
				}
}


int	sgn(int val)
{
	if (val!=0)
		val=val/abs(val);
	else
		val=1;

	return (val);
}

	 
	 	/*	drawtext routine to stick texture onto screen */
int	drawtext(int xx,int yy)
{
			int	wid,hig,x,y;
			char	*source;

			x = y = 0;
			wid = 128;
			hig = 128;

			copydest = backscr + 288 * yy + xx;
			source = texture;

			for (y=hig ;y>0 ;y-- )
				{
				for (x=wid ;x>0 ; x--)
					{
					*copydest++ = *source++;
					}
					copydest += 288-wid;
				}

		return 0;
}




		/*	drawtext routine to stick texture onto screen backwards*/
int	backtext(int xx,int yy)
{
			int	wid,hig,x,y;
			char	*source;

			x = y = 0;
			wid = 128;
			hig = 128;

			copydest = backscr + 288 * yy + xx + wid;
			source = texture;

			for (y=hig ;y>0 ;y-- )
				{
				for (x=wid ;x>0 ; x--)
					{
					*copydest-- = *source++;
					}
					copydest += 288+wid;
				}

			return 0;
		}



		/*	drawtext routine to stick texture onto screen half size*/
int	halftext(int xx,int yy)
{
			int	wid,hig,x,y;
			char	*source;

			x = y = 0;
			wid = 128;
			hig = 128;

			copydest = backscr + 288 * yy + xx;
			source = texture;

			for (y=hig ;y>0 ;y-=2 )
				{
				for (x=wid ;x>0 ; x-=2)
					{
					*copydest++ = *source++;
					source++;
					}
					copydest += 288-wid/2;
					source +=wid;
				}

			return 0;
}


				 
