/*
 *    SPEED - by Shawn Hargreaves, 1999
 *
 *    Main program body, setup, action pump, etc.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <allegro.h>

#include "speed.h"



/* are we cheating? */
int cheat = FALSE;


/* how many points did we get? */
int score = 0;



/* draws text with a dropshadow */
void textout_shadow(char *msg, int x, int y, int c)
{
   textout_centre(screen, font, msg, x+1, y+1, makecol(0, 0, 0));
   textout_centre(screen, font, msg, x, y, c);
}



/* display the title screen */
int title_screen()
{
   BITMAP *b;
   int i;

   if (bitmap_color_depth(screen) > 8) {
      for (i=0; i<SCREEN_H/2; i++) {
	 hline(screen, 0, i, SCREEN_W, makecol(0, 0, i*255/(SCREEN_H/2)));
	 hline(screen, 0, SCREEN_H-i-1, SCREEN_W, makecol(0, 0, i*255/(SCREEN_H/2)));
      }
   }
   else
      clear_to_color(screen, makecol(0, 0, 128));

   b = create_bitmap(40, 8);
   clear_to_color(b, bitmap_mask_color(screen));

   textout(b, font, "SPEED", 0, 0, makecol(0, 0, 0));
   stretch_sprite(screen, b, 8, 8, SCREEN_W, SCREEN_H);

   textout(b, font, "SPEED", 0, 0, makecol(0, 0, 64));
   stretch_sprite(screen, b, 0, 0, SCREEN_W, SCREEN_H);

   destroy_bitmap(b);

   textout_shadow("Simultaneous Projections", SCREEN_W/2, SCREEN_H/2-80, makecol(255, 255, 255));
   textout_shadow("Employing an Ensemble of Displays", SCREEN_W/2, SCREEN_H/2-64, makecol(255, 255, 255));

   textout_shadow("Or alternatively: Stupid Pointless", SCREEN_W/2, SCREEN_H/2-32, makecol(255, 255, 255));
   textout_shadow("Effort at Establishing a Dumb Acronym", SCREEN_W/2, SCREEN_H/2-16, makecol(255, 255, 255));

   textout_shadow("By Shawn Hargreaves, 1999", SCREEN_W/2, SCREEN_H/2+16, makecol(255, 255, 255));
   textout_shadow("Written for the Allegro", SCREEN_W/2, SCREEN_H/2+48, makecol(255, 255, 255));
   textout_shadow("SpeedHack competition", SCREEN_W/2, SCREEN_H/2+64, makecol(255, 255, 255));

   while (joy_b1)
      poll_joystick();

   while ((key[KEY_SPACE]) || (key[KEY_ESC]))
      poll_keyboard();

   while ((!key[KEY_SPACE]) && (!key[KEY_ESC]) && (!joy_b1)) {
      poll_joystick();
      poll_keyboard();
   }

   if (key[KEY_ESC])
      return FALSE;

   return TRUE;
}



/* display the results screen */
void show_results()
{
   char buf[80];
   BITMAP *b;
   int i;

   if (bitmap_color_depth(screen) > 8) {
      for (i=0; i<SCREEN_H/2; i++) {
	 hline(screen, 0, SCREEN_H/2-i-1, SCREEN_W, makecol(i*255/(SCREEN_H/2), 0, 0));
	 hline(screen, 0, SCREEN_H/2+i, SCREEN_W, makecol(i*255/(SCREEN_H/2), 0, 0));
      }
   }
   else
      clear_to_color(screen, makecol(128, 0, 0));

   b = create_bitmap(72, 8);
   clear_to_color(b, bitmap_mask_color(screen));

   textout(b, font, "GAME OVER", 0, 0, makecol(0, 0, 0));
   stretch_sprite(screen, b, 4, SCREEN_H/3+4, SCREEN_W, SCREEN_H/3);

   textout(b, font, "GAME OVER", 0, 0, makecol(64, 0, 0));
   stretch_sprite(screen, b, 0, SCREEN_H/3, SCREEN_W, SCREEN_H/3);

   destroy_bitmap(b);

   sprintf(buf, "Score: %d", score);
   textout_shadow(buf, SCREEN_W/2, SCREEN_H*3/4, makecol(255, 255, 255));

   while (joy_b1)
      poll_joystick();

   while ((key[KEY_SPACE]) || (key[KEY_ESC]))
      poll_keyboard();

   while ((!key[KEY_SPACE]) && (!key[KEY_ESC]) && (!joy_b1)) {
      poll_joystick();
      poll_keyboard();
   }
}



/* the main game function */
int play_game()
{ 
   return TRUE;
}



/* for generating the 8 bit additive color lookup table */
void add_blender8(PALETTE pal, int x, int y, RGB *rgb)
{
   int r, g, b;

   r = (int)pal[x].r + (int)pal[y].r;
   g = (int)pal[x].g + (int)pal[y].g;
   b = (int)pal[x].b + (int)pal[y].b;

   rgb->r = MIN(r, 63);
   rgb->g = MIN(g, 63);
   rgb->b = MIN(b, 63);
}



/* 15 bit additive color blender */
unsigned long add_blender15(unsigned long x, unsigned long y, unsigned long n)
{
   int r = getr15(x) + getr15(y);
   int g = getg15(x) + getg15(y);
   int b = getb15(x) + getb15(y);

   r = MIN(r, 255);
   g = MIN(g, 255);
   b = MIN(b, 255);

   return makecol15(r, g, b);
}



/* 16 bit additive color blender */
unsigned long add_blender16(unsigned long x, unsigned long y, unsigned long n)
{
   int r = getr16(x) + getr16(y);
   int g = getg16(x) + getg16(y);
   int b = getb16(x) + getb16(y);

   r = MIN(r, 255);
   g = MIN(g, 255);
   b = MIN(b, 255);

   return makecol16(r, g, b);
}



/* 24 bit additive color blender */
unsigned long add_blender24(unsigned long x, unsigned long y, unsigned long n)
{
   int r = getr24(x) + getr24(y);
   int g = getg24(x) + getg24(y);
   int b = getb24(x) + getb24(y);

   r = MIN(r, 255);
   g = MIN(g, 255);
   b = MIN(b, 255);

   return makecol24(r, g, b);
}



/* display a commandline usage message */
void usage()
{
   allegro_message(
      "\n"
      "SPEED - by Shawn Hargreaves, 1999\n"
      "\n"
      "Usage: speed w h bpp [options]\n"
      "\n"
      "The w and h values set your desired screen resolution\n"
      "(available modes will depend on your hardware)\n"
      "\n"
      "The bpp value sets the color depth: 8, 15, 16, 24, or 32\n"
      "\n"
      "Available options:\n"
      "\n"
      "\t-cheat makes you invulnerable\n"
      "\t-www invokes the built-in web browser\n"
      "\n"
      "Example usage:\n"
      "\n"
      "\tspeed 640 480 8\n"
   );
}



/* print the shutdown message */
void goodbye()
{
   static int data1[] =
   {
      0, 2, 0, 1, 2, 3, 0, 3, 5, 3, 4, 6, 0, 2, 0, 1, 2,
      3, 0, 3, 7, 3, 5, 6, 0, 2, 0, 1, 12, 3, 9, 3, 5, 3,
      4, 3, 2, 3, 10, 2, 10, 1, 9, 3, 5, 3, 7, 3, 5, 9

   };

   static int data2[] =
   {
      12, 3, 7, 1, 6, 1, 7, 1, 8, 3, 7, 3
   };

   SAMPLE *s1, *s2;
   BITMAP *b;
   int i;

   install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL);

   if (digi_driver->id == DIGI_NONE) {
      set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
      allegro_message("Couldn't install a digital sound driver, so no closing tune is available.\n");
      return;
   }

   s1 = create_sample(8, FALSE, 44100, 256);
   s2 = create_sample(8, FALSE, 44100, 256);

   for (i=0; i<256; i++) {
      ((char *)s1->data)[i] = i;
      ((char *)s2->data)[i] = (i < 128) ? 255 : 0;
   }

   b = create_bitmap(176, 40);
   clear(b);

   for (i=0; i<=b->w; i++)
      line(b, 0, 0, i, b->h, makecol(255-i*255/b->w, i*255/b->w, 0));

   for (i=0; i<=b->h; i++)
      line(b, 0, 0, b->w, i, makecol(0, i*255/b->h, 255-i*255/b->h));

   textout(b, font, "Happy birthday Arron!", 5, 17, makecol(0, 0, 0));
   textout(b, font, "Happy birthday Arron!", 4, 16, makecol(255, 255, 255));
   stretch_blit(b, screen, 0, 0, b->w, b->h, 0, 0, SCREEN_W, SCREEN_H);
   destroy_bitmap(b);

   while ((key[KEY_SPACE]) || (key[KEY_ESC]))
      poll_keyboard();

   clear_keybuf();

   for (i=0; i < (int)(sizeof(data1)/sizeof(int)); i += 2) {
      play_sample(s1, 255, 128, 1000 * pow(2.0, (float)data1[i]/12.0), TRUE);
      rest(100*data1[i+1]);
      stop_sample(s1);
      rest(50*data1[i+1]);

      if (keypressed())
	 return;
   }

   rest(500);

   clear(screen);
   set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
   allegro_message("\nAnd thanks for organising this most excellent competition...\n");

   for (i=0; i < (int)(sizeof(data2)/sizeof(int)); i += 2) {
      play_sample(s2, 255, 128, 1000 * pow(2.0, (float)data2[i]/12.0), TRUE);
      rest(75*data2[i+1]);
      stop_sample(s2);
      rest(25*data2[i+1]);

      if (keypressed())
	 return;
   }

   rest(300);
   printf("\007"); fflush(stdout);
   rest(300);
   printf("\007"); fflush(stdout);

   destroy_sample(s1);
   destroy_sample(s2);
}



/* the main program body */
int main(int argc, char *argv[])
{
   int w=0, h=0, bpp=0;
   int www = FALSE;
   PALETTE pal;
   int i, n;

   allegro_init();

   /* parse the commandline */
   for (i=1; i<argc; i++) {
      if (stricmp(argv[i], "-cheat") == 0) {
	 cheat = TRUE;
      }
      else if (stricmp(argv[i], "-www") == 0) {
	 www = TRUE;
      }
      else {
	 n = atoi(argv[i]);

	 if (!n) {
	    usage();
	    return 1;
	 }

	 if (!w) {
	    w = n;
	 }
	 else if (!h) {
	    h = n;
	 }
	 else if (!bpp) {
	    bpp = n;
	 }
	 else {
	    usage();
	    return 1;
	 }
      }
   }

   /* it's a real shame that I had to take this out! */
   if (www) {
      allegro_message(
	 "\n"
	 "Unfortunately the built-in web browser feature had to be removed.\n"
	 "\n"
	 "I did get it more or less working as of Saturday evening (forms and\n"
	 "Java were unsupported, but tables and images were mostly rendering ok),\n"
	 "but the US Department of Justice felt that this was an unacceptable\n"
	 "monopolistic attempt to tie in web browsing functionality to an\n"
	 "unrelated product, so they threatened me with being sniped at from\n"
	 "the top of tall buildings by guys with high powered rifles unless I\n"
	 "agreed to disable this code.\n"
	 "\n"
	 "We apologise for any inconvenience that this may cause you.\n"
      );

      return 1;
   }

   if ((!w) || (!h) || (!bpp)) {
      usage();
      return 1;
   }

   /* set the screen mode */
   set_color_depth(bpp);

   if (set_gfx_mode(GFX_AUTODETECT, w, h, 0, 0) != 0) {
      allegro_message("Error setting %dx%d %d bpp display mode:\n%s\n",
		      w, h, bpp, allegro_error);
      return 1;
   }

   /* set up everything else */
   install_timer();
   install_keyboard();
   install_joystick(JOY_TYPE_AUTODETECT);

   /* additive color is cool */
   if (bpp == 8) {
      generate_332_palette(pal);

      pal[0].r = 0;
      pal[0].g = 0;
      pal[0].b = 0;

      set_palette(pal);

      rgb_map = malloc(sizeof(RGB_MAP));
      create_rgb_table(rgb_map, pal, NULL);

      color_map = malloc(sizeof(COLOR_MAP));
      create_color_table(color_map, pal, add_blender8, NULL);
   }
   else {
      set_blender_mode(add_blender15, add_blender16, add_blender24, 0, 0, 0, 0);
   }

   text_mode(-1);

   /* the main program body */
   while (title_screen()) {
      if (play_game())
	 show_results();
   }

   /* time to go away now */
   goodbye();

   if (rgb_map) {
      free(rgb_map);
      rgb_map = NULL;
   }

   if (color_map) {
      free(color_map);
      color_map = NULL;
   }

   return 0;
}

END_OF_MAIN();
