/******************************************************************************
*									      *
*	(C) 1993 by K. Ballueder					      *
*									      *
*	See README and COPYING for details.				      *
*									      *
*	Please feel free to contact me:					      *
*		kballued@charon.physik.uni-osnabrueck.de		      *
*		kballued@jupiter.rz.uni-osnabrueck.de			      *
*									      *
******************************************************************************/



/******************************************************************************
**                                                                           **
** Boulder-Dash: Hauptprogramm                                               **
**                                                                           **
******************************************************************************/
#include "bdash.h"

#ifdef CC_TURBOC
#	include <graphics.h>
#else
#	include <unistd.h>
#	include <vga.h>
#	include <sys/types.h>
#	include <signal.h>
#	include <fcntl.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

#include "graphic.h"
#include "react.h"
#include "communic.h"
#include "io.h"
#include "sound.h"
#include "scores.h"
#include "movers.h"
#include "vconfig.h"


extern int controlling(void);  /* controlling.c */


long bdash_speed = MAX_SPEED-DEFAULT_SPEED;    /* Delay in msecs */
unsigned char player_x[2],player_y[2];
unsigned char **level_table;
unsigned level_x_size, level_y_size;
char level_name[LEVEL_NAME_MAXLEN+1];
unsigned long points_required = 0ul;

void 		*figur[NUM_OF_FIGURS]; /* Bildchen */

unsigned 	act_level 	= 1;
struct flagstype globale_flags 	= {0,0,0,0x2f8,SPEAKER};

unsigned char 	keys[2][4];	/* Schluessel */


struct memlist_node *mem_first_block = NULL;

void *k_alloc(size_t n, size_t size)
{
  struct memlist_node *mln = __malloc(sizeof(struct memlist_node));
  void *ptr = calloc(n, size);

  if((!mln) || (!ptr))
    return NULL;
  mln->address = ptr;
  mln->next = mem_first_block;
  return ptr;
}


vconf_parameter parameters[] =
{	{"starting_level","-l",VCONF_GLOBAL},
	{"monochrome","-m",VCONF_GLOBAL|VCONF_LOCAL|VCONF_CLINE},
	{"speed","-s",VCONF_GLOBAL},
	{"sound_device","-p",VCONF_GLOBAL},
	{"help","-h",VCONF_CLINE},
	{NULL}
};


void evaluate_parameters(vconf_parameter *vcp)
{
	if(vcp[0].set)
	{	act_level = atoi(vcp[0].value);
		printf("\tstarting on level %d\n",act_level);
	}
	if(vcp[1].set)
	{	globale_flags.monochrome = 1;
		puts("\tmonochrome activated.");
	}
	if(vcp[2].set)
	{	bdash_speed = atol(vcp[2].value);
		bdash_speed = bdash_speed > MAX_SPEED?0:MAX_SPEED-bdash_speed;
		printf("\tspeed set to %ld\n",MAX_SPEED-bdash_speed);
	}
	if(vcp[3].set)
	{	globale_flags.snd_dev = vcp[3].value;
		printf("writing sound data to: %s\n", globale_flags.snd_dev);
	}
	if(vcp[4].set)
	{	printf(HELPTEXT,MAX_SPEED,DEFAULT_SPEED);
		exit(EXIT_SUCCESS);
	}
}

		



/************** only for use by cleanup(): **/
static int vtflags;	/* is set in main() by fcntl() */

void cleanup(void)
{
	debug_printf("cleanup()\n");
#ifdef OS_LINUX
	/* make sure son is dead */
	if(globale_flags.son_pid)
		kill(globale_flags.son_pid, SIGTERM);

	fcntl(STDIN_FILENO,F_SETFL,vtflags);
#endif
#ifdef  CC_TURBOC
	closegraph();
#else
	if(geteuid() == 0 && graphics_initialized)	/* skip if no graphics available */
		debug_printf("restoring textmode\n"),vga_setmode(TEXT);
	printf("\n");	/* to restore testmode under linux */
#endif

#ifdef K_ALLOC
	while(mem_first_block) /* Speicher freigeben */
	{ free(mem_first_block->address);
	  mem_first_block = mem_first_block->next;
	}
#endif

	CLEAR_KEY_BUF
	debug_printf("cleanup complete\n");
}

int main(int argc, char **argv)
{
	int cont;	/* boolean */


	globale_flags.snd_dev = SND_DEVICE;
	
	SHOW_COPYRIGHT
	#ifdef DUMMY_VERSION
		puts("\n\t\tDUMMY_VERSION  --- no graphics\a!!!");
	#endif

	strcpy(vconf_global_prefix,DATAPATH);
	vconfig(CONFIGFILE,parameters,&argc, &argv, fatal_error);
	evaluate_parameters(parameters);
	atexit(cleanup);

	puts("\nType BDASH -h for help\n\nPress return key to proceed.");
#ifdef OS_UNIX
	if(geteuid() != 0)	/* not suid root! */
	{	puts("\aBDASH must be run as root or with suid root!");
		exit(1);
	}
#endif
	getch();

	if(globale_flags.twoplayer)
	{ 	InitComm();   /* COM2 initialisieren */
		globale_flags.slavemode = detect_mode(); /* Slavemode? */
	}
	if(globale_flags.soundport != NOSOUND)
	{	debug_printf("calling load_sounds");
		load_sounds();
	}
	debug_printf("calling load_graphics\n");
	if(load_graphics()<0)
		return 1;

	debug_printf("calling load_scores\n");
	(void) load_scores();

#ifdef 	OS_LINUX 
	debug_printf("setting console to O_NONBLOCK\n");
	vtflags = fcntl(STDIN_FILENO,F_GETFL,0);
	fcntl(0,F_SETFL,O_NONBLOCK);
#endif
	/************* MAIN LOOP ***************/
	debug_printf("entering main_loop\n");
	do
	{	debug_printf("In MAIN LOOP\n");
		init_react_stack();
		debug_printf("passed init_react_stack()\n");
		if(load_level(act_level) >= 0)
		{	display(player_x[0],player_y[0]);
			debug_printf("passed display()\n");
			display_message("Next Level:","",level_name);
			debug_printf("passed display_message()\n");
			act_level += cont = controlling();
			free_react_stack();
			debug_printf("passed free_react_stack()\n");
			movers_cleanup();
			debug_printf("passed kill_all_objects()\n");
			free_level();
			debug_printf("passed free_level()\n");
		}
		else
			cont = 0;
		debug_printf("at end of MAIN LOOP\n");
	}while(cont);
	debug_printf("passed MAIN LOOP\n");
	/***************************************/

	display_scoretable();
	debug_printf("passed display_scoretable()\n");
#ifdef  CC_TURBOC
	closegraph();
#else
	vga_setmode(TEXT);
#endif

	if(save_scores())
	      puts("cannot save scores\a");
	debug_printf("passed save_scores()\n");

	/* cleanup() is called via atexit() */
	return 0;
}
