/*
 *  snake.cc
 *  
 *  main implementation file of the snake game
 *  
 *  allegro Speedhack competition november 1999
 *
 *  Hein Zelle
 *
 */

#include "snake.h"

int init(int color_depth)
{
    if (allegro_init() < 0)
    {
	cerr << "failed to initialize allegro." << endl;
	return 0;
    }

    if (install_timer() < 0)
    {
	cerr << "failed to install timer." << endl;
	return 0;
    }
	
    if (install_mouse() < 0)
    {
	cerr << "failed to install mouse." << endl;
	return 0;
    }

    if (install_keyboard() < 0)
    {
	cerr << "failed to install keyboard." << endl;
	return 0;
    }

    reserve_voices(4, 0);
    if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, 0) < 0)
    {
	cerr << "failed to install sound." << endl;
	return 0;
    }
    
    set_color_depth(color_depth);

    if (set_gfx_mode(GFX_AUTODETECT, 800, 600, 0, 0) < 0)
    {
	cerr << "failed to set graphics mode." << endl;
	cerr << allegro_error << endl;
	return 0;
    }

    // load the datafile after the graphics mode has been set
    if (!(data = load_datafile("snake.dat")))
    {
	cerr << "failed to load data file 'snake.dat'" << endl;
	return 0;
    }
    
    // initialize timers
    if (init_timers() < 0)
    {
	cerr << "failed to initialize timers." << endl;
	return 0;
    }
    
    return 1;
}

void usage()
{
    cerr << "Usage: " << progname << " [options]" << endl;
    cerr << "where [options] is one of" << endl;
    cerr << "\t-h or --help\tprint this message" << endl;
    cerr << "\t-8b         \tuse  8 bit color depth" << endl;
    cerr << "\t-16b        \tuse 16 bit color depth" << endl;
    cerr << "\t-24b        \tuse 24 bit color depth" << endl;
    cerr << "\t-29b        \tuse 29 bit color depth" << endl;
    cerr << "\t-32b        \tuse 32 bit color depth" << endl;
    cerr << "\t-1p         \tone player" << endl;
    cerr << "\t-2p         \ttwo players" << endl;
    cerr << "\t-3p         \tthree players" << endl;
    cerr << "\t-4p         \tfour players (requires 3-button mouse)" << endl;
    
    exit(1);
}

int parse_options(int argc, char **argv, int &color_depth)
{
    for (int i = 1; i < argc; i++)
    {
	if (argv[i][0] == '-')
	{
	    if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
		usage();
	    else
	    if (!strcmp(argv[i], "-8b"))
		color_depth = 8;
	    else
	    if (!strcmp(argv[i], "-16b"))
		color_depth = 16;
	    else
	    if (!strcmp(argv[i], "-24b"))
		color_depth = 24;
	    else
	    if (!strcmp(argv[i], "-32b"))
		color_depth = 32;
	    else
	    if (!strcmp(argv[i], "-29b"))
	    {
		cerr << "Sorry, your video card does not seem to support this"
		     << " color depth." << endl;
		exit(0);
	    }
	    else
	    if (!strcmp(argv[i], "-1p"))
		nr_players = 1;
	    else
	    if (!strcmp(argv[i], "-2p"))
		nr_players = 2;
	    else
	    if (!strcmp(argv[i], "-3p"))
		nr_players = 3;
	    else
	    if (!strcmp(argv[i], "-4p"))
		nr_players = 4;
	    else
		usage();
	}
	else
	{
	    usage();
	}
    }

    return 1;
}

void init_graphics(int color_depth)
{
    text_mode(-1);
    init_colors(color_depth);
    
    scratch = create_bitmap(MAP_SIZE_X, MAP_SIZE_Y);
    clear_to_color(scratch, black);
    clear_to_color(screen, gray);
}

void init_sound()
{
    sample_chainsaw = (SAMPLE *)data[CHAINSAW].dat;
    sample_burrow = (SAMPLE *)data[BURROW].dat;
    sample_pling = (SAMPLE *)data[PLING].dat;
    sample_tick = (SAMPLE *)data[TICK].dat;

    if (!sample_chainsaw || !sample_burrow || !sample_pling || !sample_tick)
    {
	cerr << "error loading samples" << endl;
    }
}

void init_players()
{
    for (int i = 0; i < MAX_PLAYERS; i++)
    {
	bodies[i] = new body(20);
	players[i] = new player;

	// first do common initialization
	// afterwards do the viewport stuff, this is different for
	// each player and for the total number of players
	// this will be ugly and big, but what the heck.
	if (i < nr_players)
	{
	    bodies[i]->alive = 1;
	    players[i]->alive = 1;
	    players[i]->color_offset = 100 + 20 * i;
	}
	else
	{
	    bodies[i]->alive = 0;
	    players[i]->alive = 0;
	}
    }

    // set the keys and the mouse (non-configurable, sorry)
    // set the position of the head, and the map_view offset
    players[0]->key_left = KEY_LEFT;
    players[0]->key_right = KEY_RIGHT;
    players[0]->key_action = KEY_ENTER_PAD;
    players[0]->uses_mouse = 0;

    bodies[0]->init_pos(MAP_SIZE_X / 4, MAP_SIZE_Y / 4, 315);
    players[0]->init_map(MAP_SIZE_X / 4, MAP_SIZE_Y / 4);
    
    players[1]->key_left = KEY_Z;
    players[1]->key_right = KEY_X;
    players[1]->key_action = KEY_Q;
    players[1]->uses_mouse = 0;

    bodies[1]->init_pos(MAP_SIZE_X * 3 / 4, MAP_SIZE_Y / 4, 225);
    players[1]->init_map(MAP_SIZE_X * 3 / 4, MAP_SIZE_Y / 4);

    players[2]->key_left = KEY_COMMA;
    players[2]->key_right = KEY_STOP;          // i hope that is the period?
    players[2]->key_action = KEY_SPACE;
    players[2]->uses_mouse = 0;

    bodies[2]->init_pos(MAP_SIZE_X / 4, MAP_SIZE_Y * 3 / 4, 45);
    players[2]->init_map(MAP_SIZE_X / 4, MAP_SIZE_Y * 3 / 4);

    players[3]->key_left = 0;
    players[3]->key_right = 0;
    players[3]->key_action = 0;
    players[3]->uses_mouse = 1;

    bodies[3]->init_pos(MAP_SIZE_X * 3 / 4, MAP_SIZE_Y * 3 / 4, 135);
    players[3]->init_map(MAP_SIZE_X * 3 / 4, MAP_SIZE_Y * 3 / 4);

    switch (nr_players)
    {
	case 1:
	    players[0]->set_viewport(0, SCREEN_H - 1, 0, SCREEN_W - 1);
	    break;
	case 2:
	    players[0]->set_viewport(0, SCREEN_H - 1, 0, SCREEN_W / 2 - 2);
	    players[1]->set_viewport(0, SCREEN_H - 1,
				     SCREEN_W / 2 + 1, SCREEN_W - 1);
	    break;
	case 3:
	    players[0]->set_viewport(0, SCREEN_H / 2 - 2,
				     0, SCREEN_W / 2 - 2);
	    players[1]->set_viewport(0, SCREEN_H / 2 - 2,
				     SCREEN_W / 2 + 1, SCREEN_W - 1);
	    players[2]->set_viewport(SCREEN_H / 2 + 1, SCREEN_H - 1,
				     0, SCREEN_W - 1);
	    break;
	case 4:
	    players[0]->set_viewport(0, SCREEN_H / 2 - 2,
				     0, SCREEN_W / 2 - 2);
	    players[1]->set_viewport(0, SCREEN_H / 2 - 2,
				     SCREEN_W / 2 + 1, SCREEN_W - 1);
	    players[2]->set_viewport(SCREEN_H / 2 + 1, SCREEN_H - 1,
				     0, SCREEN_W / 2 - 2);
	    players[3]->set_viewport(SCREEN_H / 2 + 1, SCREEN_H - 1,
				     SCREEN_W / 2 + 1, SCREEN_W - 1);
	    break;
	default:
	    cerr << "invalid number of players: " << nr_players << endl;
	    exit(1);
    }
    
}

int main(int argc, char **argv, char **envp)
{
    int	color_depth = 8;    // 8 is default value
    
    // get color depth before allegro starts: now we still have
    // the normal output routines available

    progname = argv[0];

    nr_players = 1;
    parse_options(argc, argv, color_depth);

    // initialize allegro, timers, keyboard, mouse, graphics mode
    if (!init(color_depth))
    {
	cerr << "initialization failed, shutting down." << endl;
	return 0;
    }

    // initialize sound
    init_sound();
    
    // play a fancy sound :P
    int handle;

    handle = allocate_voice(sample_burrow);
    if (handle >= 0)
    {
	voice_start(handle);
	release_voice(handle);
    }

    // show the intro bitmap;

    BITMAP *intro;
    if (color_depth == 8)
    {
	clear_to_color(screen, 1);
	set_palette(*((PALETTE *)data[INTROPAL].dat));
	intro = (BITMAP *)data[INTRO8].dat;
    }
    else
	intro = (BITMAP *)data[INTRO].dat;
    
    blit(intro, screen, 0, 0,
	 (SCREEN_W - intro->w) / 2, (SCREEN_H - intro->h) / 2,
	 intro->w, intro->h);

    readkey();

    
    handle = allocate_voice(sample_pling);
    if (handle >= 0)
    {
	voice_start(handle);
	release_voice(handle);
    }

    // initialize scratch and screen bitmaps, and colors
    init_graphics(color_depth);

    // initialize players
    init_players();

    // initialize dirty rectangle lists
    init_dirty();

    // initialize bonus lists
    // allow 5 'real' bonusses at the same time
    init_bonus(25);

    // start the game loop
    while (game_loop());
    
    return 0;
}

END_OF_MAIN();
 
