/*********************************************/
/* 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 <errno.h>
#include <graph.h>
#include <malloc.h>
#include <dos.h>

#include "xbd.h"

#define	HEIGHT	16
#define	WIDTH	16

#define	MAXPGM	23


extern char    *getenv();


char *bitmap[MAXPGM];

struct videoconfig config;
int size;

char *makegc(char pgm[])
{
	char *ptr,c;
	int i,j;
	unsigned r1,r2,r3,r4;
	unsigned *uptr;
	
	ptr = (char *)malloc(size);
	uptr = (unsigned *)ptr;
	if (ptr == NULL) {
		printf ("Erreur allocation (pgms)\n");
		exit(1);
	}	

	*ptr = WIDTH;
	*(ptr+2) = HEIGHT;
	*(ptr+1) = *(ptr+3) = 0;

	for (i=0; i < HEIGHT;i++) {
		r1 = r2 = r3 = r4 = 0;
		for (j=0; j < WIDTH; j++) {
			c = pgm[(i*WIDTH)+j];
			if (c & 0x01)
				r1 |= (1 << ((WIDTH-1)-j));
			if (c & 0x02)
				r2 |= (1 << ((WIDTH-1)-j));
			if (c & 0x04)
				r3 |= (1 << ((WIDTH-1)-j));
			if (c & 0x08)
				r4 |= (1 << ((WIDTH-1)-j));
		}
		/*
			For compatibility with _putimage from Microsoft
			
		*(uptr+2+(i*4)) = r1;
		*(uptr+2+(i*4)+1) = r2;
		*(uptr+2+(i*4)+2) = r3;
		*(uptr+2+(i*4)+3) = r4;
		*/

		/*	Using my own _putimage (drawPgm)
		*/
		*(uptr+2+i) = r1;
		*(uptr+2+i+16) = r2;
		*(uptr+2+i+32) = r3;
		*(uptr+2+i+48) = r4;
	}
	for (i=4; i< size; i+=2) {
		c = *(ptr+i);
		*(ptr+i) = *(ptr+i+1);
		*(ptr+i+1) = c;
	}
	return (ptr);
}


void make_gcs()
{
	pgc = pgc1 = makegc(bitmap[0]);	/* player_pgms		*/
	pgc2 = makegc(bitmap[1]);			/* player2_pgms	*/
	wgc = Wgc = makegc(bitmap[2]);	/* wall_pgms		*/
	Wgc2 = makegc(bitmap[3]);			/* wall2_pgms		*/
	sgc = makegc(bitmap[4]);			/* space_pgms		*/
	ggc = makegc(bitmap[5]);			/* grass_pgms		*/
	dgc = dgc1 = makegc(bitmap[6]);	/* diamond_pgms	*/
	dgc2 = makegc(bitmap[7]);			/* diamond2_pgms	*/
	Sgc = makegc(bitmap[8]);			/* steel_pgms		*/
	bgc = makegc(bitmap[9]);			/* boulder_pgms	*/
	xgc = makegc(bitmap[10]);			/* explosion_pgms	*/
	lgc = lgc1 = makegc(bitmap[11]);	/* lmonster_pgms	*/
	lgc2 = makegc(bitmap[12]);			/* lmonster2_pgms	*/
	rgc = rgc1 = makegc(bitmap[13]);	/* rmonster_pgms	*/
	rgc2 = makegc(bitmap[14]);			/* rmonster2_pgms	*/
	egc = egc1 = makegc(bitmap[15]);	/* eater_pgms		*/
	egc2 = makegc(bitmap[16]);			/* eater2_pgms		*/
	Egc = Egc1 = makegc(bitmap[8]);	/* steel_pgms		*/
	Egc2 = makegc(bitmap[17]);			/* exit2_pgms		*/
	ngc = makegc(bitmap[18]);			/* nucbal_pgms		*/
	Bgc = Bgc1 = makegc(bitmap[19]);	/* blob_pgms		*/
	Bgc2 = makegc(bitmap[20]);			/* blob2_pgms		*/
	tgc = tgc1 = makegc(bitmap[2]);	/* wall_pgms		*/
	tgc2 = makegc(bitmap[21]);			/* tinkle1_pgms	*/
	tgc3 = makegc(bitmap[22]);			/* tinkle2_pgms	*/
}

void load()
{
	FILE *map;
	int i,j,k;
	char buf[300];
	int *ptr;
	char *aux;
	int color[WIDTH];
	
	if (aux = getenv("XBDLIB"))
		strcpy(buf, aux);
	else
		strcpy(buf, LIB);

	strcat(buf, "\\");
	strcat(buf,"bitmaps.dat");
	map = fopen(buf,"r");
	if (map == 0) {
		printf("Error opening bitmap file %s\n",buf);
		exit(-1);
	}
	else {
		for (i = 0;i < MAXPGM;i++) {
			fgets(buf,300,map);
			bitmap[i] = (char *)malloc(HEIGHT * WIDTH);
			for (j = 0;j < HEIGHT;j++) {
				ptr = color;
				fgets(buf,300,map);
				sscanf(buf,"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
					    ptr++,ptr++,ptr++,ptr++,ptr++,ptr++,ptr++,ptr++,ptr++,
						 ptr++,ptr++,ptr++,ptr++,ptr++,ptr++,ptr);
				for (k = 0; k < WIDTH;k++)
					bitmap[i][(j*WIDTH)+k] = (char)color[k];
			}
			fgets(buf,300,map);

		}
		fclose(map);
	}
}

void init_level(levelnum)
int levelnum;
{

	FILE           *levelfile;
	char           buf[300], *ptr;

	Egc = Egc1;			/* don't blink EXIT */
	blobcollapse = FALSE;
	blobcells = 0;
	scoreobs = TRUE;
	tinkact = FALSE;
	levincreased = FALSE;
	strcpy(levname, "No_name_for_this_level_yet");

	/* Manufaction the file name by starting with the world name and */
	/* appending the level number to it. */

	if (ptr = getenv("XBDLIB"))
		strcpy(filename, ptr);
	else
		strcpy(filename, LIB);

	strcat(filename, "\\");
	strcat(filename, LEVELPREFIX);
	sprintf(filename + strlen(filename), "%03d", levelnum);
	
	/* Open level file for reading */
	levelfile = fopen(filename, "r");
	
	/* If level file does not exist, use the default level file. */
	if (levelfile == NULL) {
		/* Build the default level name */

		if (ptr = getenv("XBDLIB"))
			strcpy(buf, ptr);
		else
			strcpy(buf, LIB);

		strcat(buf, "\\");
		strcat(buf, "\\default");
		/* Open default level file for reading */
		levelfile = fopen(buf, "r");
		if (levelfile == NULL) {
			perror(LEVELPREFIX);
			exit(1);
		}
	}
	
	/* Load the first line of the level file */
	if (fgets(buf, 300, levelfile) == NULL)	{
		x = w;
		y = h;
		speed = 15;
		diareq = 12;
		diapoints = 0;
		extradiapoints = 0;
		blobbreak = 200;
		curtime = 1000;
	} 
	else	{
		/* Extract the level parameters */
		sscanf(buf, "%d %d %d %d %d %d %d %d %d %s", &y, &x, &speed, 
			  &diareq, &diapoints, &extradiapoints, &blobbreak, 
			  &tinkdur, &curtime, levname);
	}

	if (xin && yin) {
		x = xin;
		y = yin;
	}				/* read in from editor command line */
/*
 * if (x > w) x = w; if (y > h) y = h; if (x < 2) x = 2; if (y < 1) y = 1;
 * 
 *
 * Iterate through each horizontal line
*/

	for (i = 0; i < y; ++i) {
		/* Load the next line from the file */
		if (fgets(buf, 300, levelfile) != NULL) {
			/* Go through each horizontal position and copy the data */
			/* into the level array. */
			for (j = 0; j < x; ++j) {
				/* Break out if line ends prematurely */
				if (buf[j] == '\n' || buf[j] == '\0')
					field[i][j].content = STEEL;	/* break; */
				field[i][j].content = buf[j];
				field[i][j].changed = TRUE;
				field[i][j].dir = N;
				field[i][j].speed = 0;
				field[i][j].stage = 0;
				field[i][j].caught = TRUE;
				field[i][j].checked = FALSE;
			}
		} 
		else
			j = 0;
		for (; j < x; ++j)
			field[i][j].content = STEEL;
	}
	
	/* Close the level file */
	fclose(levelfile);
}


/* Draw the score and level number */
void	draw_score()
{
	char            buf[200];
	
	/* Build the output string */
	sprintf(buf, "sc:%d lv:%d ls:%d ds:%d dp:%d ti:%d %s", score, levelnum,
		        lives, diareq, diapoints, curtime / 10, levname);
	strncat(buf,"                                         ", 80-strlen(buf));
	_settextposition(y+2,0);
	_outtext(buf);
	scoreobs = FALSE;
}

											
void xstart()
{
	_setvideomode(_MAXRESMODE);
	_getvideoconfig(&config);
	size = (unsigned int)_imagesize(0,0,WIDTH-1,HEIGHT-1);

}


void	xend()
{
	gamestop = TRUE;
	
	_setvideomode(_DEFAULTMODE);
}


void	draw_field(redrawall)
Bool	redrawall;
{
	char            c;
	
	/* Iterate through each horizontal line */
	for (i = y - 1; i >= 0; --i) {
		for (j = 0; j < x; ++j) {
			if (field[i][j].changed || redrawall) {	
				c = field[i][j].content;
				switch (c) {
					case GRASS:
						drawPgm((j << 1), (i << 4), ggc, _GPSET);
						break;
					case SPACE:
						drawPgm((j << 1), (i << 4), sgc, _GPSET);
						break;
					case PLAYER:
						drawPgm((j << 1), (i << 4), pgc, _GPSET);
						break;
					case WALL:
						drawPgm((j << 1), (i << 4), wgc, _GPSET);
						break;
					case MAGICWALL:
						drawPgm((j << 1), (i << 4), Wgc, _GPSET);
						break;
					case DIAMOND:
						drawPgm((j << 1), (i << 4), dgc, _GPSET);
						break;
					case BOULDER:
						drawPgm((j << 1), (i << 4), bgc, _GPSET);
						break;
					case EXPLOSION:
						drawPgm((j << 1), (i << 4), xgc, _GAND);
						break;
					case LMONSTER:
						drawPgm((j << 1), (i << 4), lgc, _GPSET);
						break;
					case RMONSTER:
						drawPgm((j << 1), (i << 4), rgc, _GPSET);
						break;
					case NUCBAL:
						drawPgm((j << 1), (i << 4), ngc, _GPSET);
						break;
					case BLOB:
						drawPgm((j << 1), (i << 4), Bgc, _GPSET);
						break;
					case TINKLE:
						drawPgm((j << 1), (i << 4), tgc, _GPSET);
						break;
					case EATER:
						drawPgm((j << 1), (i << 4), egc, _GPSET);
						break;
					case EXIT:
						drawPgm((j << 1), (i << 4), Egc, _GPSET);
						break;
					case STEEL:
					default:
						field[i][j].content = STEEL;
						drawPgm((j << 1), (i << 4), Sgc, _GPSET);
						break;
				}
				field[i][j].changed = FALSE;
			}
		}
	}
	if (scoreobs)
		draw_score();
}


void	set_cell(i, j, content)
int	i, j;
char	content;
{
	field[i][j].content = content;
	field[i][j].speed = 0;
	field[i][j].changed = TRUE;
	field[i][j].stage = 0;
	field[i][j].caught = TRUE;
	field[i][j].checked = FALSE;
}
