/*********************************************/
/* you just keep on pushing my luck over the */
/*		   BOULDER	   DASH			*/
/*									*/
/*	  Jeroen Houttuin, ETH Zurich, 1990	*/
/*									*/
/*									*/
/*	  PC-VGA version from :				*/
/*									*/
/*		Herve SOULARD, Paris, 1990		*/
/*									*/
/*********************************************/

#include <stdio.h>
#include <graph.h>

#include "xbd.h"

#define	HEIGHT	16
#define	WIDTH	16

#define	MAXPGM	23

char	curchar;

char	allPgms[NB_EDIT_PGM];


Bool kbdHit(void)
{ 
	if (*kbdPtrRead == *kbdPtrWrite)
		return(FALSE);
	else
		return(TRUE);
}

void getKbd(byte *TT,byte *T)
{ 
	*T = *(kbdBuffer + *kbdPtrRead);
	if (*T == 0x00 || *T == 0xE0) {
		*T = *(kbdBuffer + *kbdPtrRead + 1);
		*TT = 'F';
	}
	else
		*TT = 'T';
	*kbdPtrRead += 2;
	if (*kbdPtrRead == 0x3E)
		*kbdPtrRead = 0x1E;
}


void init_vars()
{
	levelnum = -1;
	xin = 0;
	yin = 0;
}


/* Save the current level back into a file.	The global variable */
/* filename is used to determine the file name. */

void save_level()
{
	FILE		  *levelfile;
	char		   buf[300];
	register int	   i, j;

	/* Open the data file */
	levelfile = fopen(filename, "w");
	if (levelfile == NULL) {
		exit(1);
	}
	
	/* Write out the size of the level.  Normal text is used so that */
	/* levels can be easily copied across architectures. */
	fprintf(levelfile, "%d %d %d %d %d %d %d %d %d %s\n", y, x,
			speed, diareq, diapoints, extradiapoints, blobbreak, 
			tinkdur, curtime, levname);
	
	/* Terminate the lines for writing out the horizontal level lines */
	buf[x] = '\n';
	buf[x + 1] = '\0';
	
	/* Iterate through each vertical position */
	for (i = 0; i < y; ++i) {

		/* Copy each horizontal line into the output buffer */
		for (j = 0; j < x; ++j)
			buf[j] = field[i][j].content;
		
		/* Write the line out to the file */
		fputs(buf, levelfile);
	}
	
	/* Close the data file */
	fclose(levelfile);
}

int getIndex(char c)
{
	int i=0;
	
	while (allPgms[i] != c && i < NB_EDIT_PGM)
		i++;
	if (i == NB_EDIT_PGM)
		return (-1);
	else
		return(i);
}

void setCursor(xC,yC)
int xC,yC;
{
	int x,y;

	_setcolor(15);
	y = yC * HEIGHT;
	x = xC * WIDTH;
	_rectangle(_GBORDER, x, y, x + WIDTH -1, y + HEIGHT-1);
	_setcolor(0);
	_rectangle(_GBORDER, x+1, y+1, x + WIDTH-2, y + HEIGHT-2);

}


void unsetCursor(xC,yC)
int xC,yC;
{
	switch (field[yC][xC].content) {
		case GRASS:
			drawPgm((xC << 1), (yC << 4), ggc, _GPSET);
			break;
		case	SPACE:
			drawPgm((xC << 1), (yC << 4), sgc, _GPSET);
			break;
		case PLAYER:
			drawPgm((xC << 1), (yC << 4), pgc, _GPSET);
			break;
		case WALL:
			drawPgm((xC << 1), (yC << 4), wgc, _GPSET);
			break;
		case MAGICWALL:
			drawPgm((xC << 1), (yC << 4), Wgc, _GPSET);
			break;
		case DIAMOND:
			drawPgm((xC << 1), (yC << 4), dgc, _GPSET);
			break;
		case BOULDER:
			drawPgm((xC << 1), (yC << 4), bgc, _GPSET);
			break;
		case EXPLOSION:
			drawPgm((xC << 1), (yC << 4), xgc, _GPSET);
			break;
		case LMONSTER:
			drawPgm((xC << 1), (yC << 4), lgc, _GPSET);
			break;
		case RMONSTER:
			drawPgm((xC << 1), (yC << 4), rgc, _GPSET);
			break;
		case NUCBAL:
			drawPgm((xC << 1), (yC << 4), ngc, _GPSET);
			break;
		case BLOB:
			drawPgm((xC << 1), (yC << 4), Bgc, _GPSET);
			break;
		case TINKLE:
			drawPgm((xC << 1), (yC << 4), tgc, _GPSET);
			break;
		case EATER:
			drawPgm((xC << 1), (yC << 4), egc, _GPSET);
			break;
		case EXIT:
			drawPgm((xC << 1), (yC << 4), Egc, _GPSET);
			break;
		case STEEL:
			drawPgm((xC << 1), (yC << 4), Sgc, _GPSET);
			break;
	}
}

void showLocPgm(int xC, int yC)
{
	char c;
	int i;
	
	c = field[yC][xC].content;
	i = getIndex(c);
	_setcolor(15);
	_rectangle(_GFILLINTERIOR, 625, 22+(i*20), 635, 26+(i*20));
}

void unShowLocPgm(int xC, int yC)
{
	char c;
	int i;
	
	c = field[yC][xC].content;
	i = getIndex(c);
	_setcolor(0);
	_rectangle(_GFILLINTERIOR, 625, 22+(i*20), 635, 26+(i*20));
}

void drawAllPgm()
{
	drawPgm(75, 16, pgc, _GPSET); allPgms[0] = PLAYER;
	drawPgm(75, 36, sgc, _GPSET); allPgms[1] = SPACE;
	drawPgm(75, 56, lgc, _GPSET); allPgms[2] = LMONSTER;
	drawPgm(75, 76, rgc, _GPSET); allPgms[3] = RMONSTER;
	drawPgm(75, 96, ggc, _GPSET); allPgms[4] = GRASS;
	drawPgm(75,116, wgc, _GPSET);	allPgms[5] = WALL;
	drawPgm(75,136, Wgc, _GPSET);	allPgms[6] = MAGICWALL;
	drawPgm(75,156, dgc, _GPSET);	allPgms[7] = DIAMOND;
	drawPgm(75,176, Sgc, _GPSET);	allPgms[8] = STEEL;
	drawPgm(75,196, bgc, _GPSET);	allPgms[9] = BOULDER;
	drawPgm(75,216, xgc, _GPSET);	allPgms[10] = EXPLOSION;
	drawPgm(75,236, Egc, _GPSET);	allPgms[11] = EXIT;
	drawPgm(75,256, egc, _GPSET);	allPgms[12] = EATER;
	drawPgm(75,276, ngc, _GPSET);	allPgms[13] = NUCBAL;
	drawPgm(75,296, Bgc, _GPSET);	allPgms[14] = BLOB;
	drawPgm(75,316, tgc, _GPSET);	allPgms[15] = TINKLE;
}


/* Main routine for editing levels */
void main(argc, argv)
int	argc;
char	**argv;
{
	register int		i, j;
	int	tmp;
	char	buf[50];
	int	pX = 0,
		pY = 0;

	int curPgm = 0;
	
	Bool end = FALSE;
	byte	keyhit;
	byte	keytype;

	init_vars();

	/* Read in command line options */
	for (i = 1; i < argc; ++i) {
		if (argv[i][0] == '-') {
			
			/* -w sets the level width */
			if (argv[i][1] == 'w') {
				if (argv[i][2] == '\0' && i + 1 < argc) {
					sscanf(argv[i + 1], "%d", &xin);
					i++;
				} 
				else
					sscanf(argv[i] + 2, "%d", &xin);
			}
			
			/* -h sets the level height */
			else 
				if (argv[i][1] == 'h') {
					if (argv[i][2] == '\0' && i + 1 < argc) {
						sscanf(argv[i + 1], "%d", &yin);
						i++;
					} 
					else
						sscanf(argv[i] + 2, "%d", &yin);
				}
				
				/* -l sets the level number */
				else 
					if (argv[i][1] == 'l') {
						if (argv[i][2] == '\0' && i + 1 < argc) {
							sscanf(argv[i + 1], "%d", &levelnum);
							i++;
						} 
						else
							sscanf(argv[i] + 2, "%d", &levelnum);
					} 
					else	{
						printf("usage: xbde [-h <height>] [-w <width>] -l <level> \n");
						exit(1);
					}
		}
	}
	
	/* Make sure some value was chosen for the level number.	This */
	/* discourages everybody editing the same level all the time. */
	if (levelnum == -1) {
		printf("usage: xbde [-h <height>] [-w <width>] -l <level> \n");
		exit(1);
	}
	
	/* Load in level data from file. */
	init_level(levelnum);
	
	/* Start up X windows and create all graphics cursors */
	xstart();

	load();
	
	make_gcs();
	Egc = Egc2;
	Wgc = Wgc2;
	tgc = tgc3;
	draw_field(TRUE);


	drawAllPgm();
	_setcolor(15);
	_rectangle(_GFILLINTERIOR, 580, 22+(curPgm*20), 590, 26+(curPgm*20));
	showLocPgm(pX,pY);

	
	/* Main event loop */
	while (!end) {
		setCursor(pX, pY);
		if (kbdHit()) {
			getKbd(&keytype,&keyhit);
			if (keytype == 'T') {
				switch (keyhit) {
					/* C erases the entire level */
					case K_C :
					case K_c :
						/* Replace level contents with space */
						for (i = 0; i < y; ++i)
							for (j = 0; j < x; ++j)
								if ((i == 0) || (i == y - 1) 
									|| (j == 0) || (j == x - 1))
									set_cell(i, j, STEEL);
								else
									set_cell(i, j, SPACE);
						/* Redraw empty level */
						draw_field(FALSE);
						showLocPgm(pX,pY);
						break;

					case K_U :
					case K_u :
						save_level();
						break;

					case K_ESC :
						end = TRUE;
						break;
						
					case K_SPACE :
						unShowLocPgm(pX,pY);
						set_cell(pY, pX, allPgms[curPgm]);
						showLocPgm(pX,pY);
						break;
						
					default :
						curchar = keyhit;
						break;
				}
			}
			else {
				switch (keyhit) {
					case K_PGUP :
						_setcolor(0);
						_rectangle(_GFILLINTERIOR, 580, 22+(curPgm*20),
							      590, 26+(curPgm*20));
						if (--curPgm < 0)
							curPgm = NB_EDIT_PGM - 1;
						_setcolor(15);
						_rectangle(_GFILLINTERIOR, 580, 22+(curPgm*20),
							      590, 26+(curPgm*20));
						break;

					case K_PGDOWN :
						_setcolor(0);
						_rectangle(_GFILLINTERIOR, 580, 22+(curPgm*20),
							      590, 26+(curPgm*20));
						if (++curPgm >= NB_EDIT_PGM)
							curPgm = 0;
						_setcolor(15);
						_rectangle(_GFILLINTERIOR, 580, 22+(curPgm*20),
							      590, 26+(curPgm*20));
						break;

					case K_LEFT :
						unsetCursor(pX,pY);
						unShowLocPgm(pX,pY);
						if (--pX < 0)
							pX = x-1;
						setCursor(pX,pY);
						showLocPgm(pX,pY);
						break;

					case K_RIGHT :
						unsetCursor(pX,pY);
						unShowLocPgm(pX,pY);
						if (++pX >= x)
							pX = 0;
						setCursor(pX,pY);
						showLocPgm(pX,pY);
						break;

					case K_UP :
						unsetCursor(pX,pY);
						unShowLocPgm(pX,pY);
						if (--pY < 0)
							pY = y-1;
						setCursor(pX,pY);
						showLocPgm(pX,pY);
						break;
						
					case K_DOWN :
						unShowLocPgm(pX,pY);
						unsetCursor(pX,pY);
						if (++pY >= y)
							pY = 0;
						showLocPgm(pX,pY);
						setCursor(pX,pY);
						break;
				}
			}
		}
		unsetCursor(pX, pY);
			
		/* If the mouse moves with the button pressed, or the button is */
		/* pressed, draw the current block at that position */
		
		/*
		else 
			if (xev.type == MotionNotify) {
				if (xev.xmotion.state & Button3Mask)
					set_cell(xev.xmotion.y >> 5, xev.xmotion.x >> 5, SPACE);
				else 
					if (xev.xmotion.state & Button1Mask)
						set_cell(xev.xmotion.y >> 5, xev.xmotion.x >> 5, curchar);
			} 
			else 
				if (xev.type == ButtonPress) {
					if (xev.xbutton.button == Button3)
						set_cell(xev.xbutton.y >> 5, xev.xbutton.x >> 5, SPACE);
					else
						set_cell(xev.xbutton.y >> 5, xev.xbutton.x >> 5, curchar);
				}
			draw_field(FALSE);
			XFlush(disp);
			
		*/
		
	} 
	  
	xend();
	exit(0);
}
