/*
  chicken.c

  Bill Kendrick
  bill@newbreedsoftware.com
  http://www.newbreedsoftware.com/

  September 5, 2003 - September 11, 2003
*/


#include <stdio.h>
#include <stdlib.h>
#include "SDL.h"
#include "SDL_image.h"
#include "SDL_mixer.h"


#define FALSE 0
#define TRUE  1

#define UP    0
#define DOWN  1
#define RIGHT 2
#define LEFT  3


/* Local function prototypes: */

SDL_Surface * my_IMG_Load(char * fname);
Mix_Chunk * my_Mix_LoadWAV(char * fname);


/* Types: */

typedef struct car_type {
  int x;
  int lane;
  int missing;
} car_type;

#define NUM_CARS 48

#define LANE_DIST 76


/* --- Main! --- */

int main(int argc, char * argv[])
{
  SDL_Surface * screen;
  SDL_Surface * chicken_image_left[2];
  SDL_Surface * chicken_image_right[2];
  SDL_Surface * chicken_image_hurt;
  SDL_Surface * car_image_left;
  SDL_Surface * car_image_right;
  Mix_Chunk * chicken_sound;
  Mix_Chunk * traffic_sound;
  Mix_Chunk * horn_sound;
  Mix_Chunk * score_sound;
  SDL_Rect dest;
  int i, done;
  Uint32 loop_start_time;
  Uint32 loop_end_time;
  SDL_Event event;
  SDLKey key;
  int key_pressed[4];
  int chicken_x, chicken_y, chicken_facing, anim_frame, chicken_hit_counter;
  int score;
  car_type cars[NUM_CARS];

  
  /* Initialize SDL Video and Audio: */
  
  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
  {
    fprintf(stderr, "Error init'ing SDL:  %s\n",
	    SDL_GetError());
    exit(1);
  }


  /* Open display: */

  screen = SDL_SetVideoMode(640, 480, 16, 0);

  if (screen == NULL)
  {
    fprintf(stderr, "Error: Can't open window!  %s\n",
	    SDL_GetError());
    exit(1);
  }


  /* Load graphics: */

  chicken_image_left[0] =  my_IMG_Load("chickenL1.png");
  chicken_image_left[1] =  my_IMG_Load("chickenL2.png");

  chicken_image_right[0] = my_IMG_Load("chickenR1.png");
  chicken_image_right[1] = my_IMG_Load("chickenR2.png");
  
  chicken_image_hurt = my_IMG_Load("chicken_hurt.png");

  car_image_left =  my_IMG_Load("carL.png");
  car_image_right = my_IMG_Load("carR.png");


  /* Open audio: */

  if (Mix_OpenAudio(44100, AUDIO_S16, 2, 256) < 0)
  {
    fprintf(stderr, "Error opening audio:  %s\n", Mix_GetError());
    exit(1);
  }


  /* Load sounds: */

  chicken_sound = my_Mix_LoadWAV("chicken.wav");
  traffic_sound = my_Mix_LoadWAV("traffic.wav");
  horn_sound    = my_Mix_LoadWAV("horn.wav");
  score_sound   = my_Mix_LoadWAV("score.wav");


  /* Clear keypress array: */

  for (i = 0; i < 4; i++)
    key_pressed[i] = FALSE;

  
  /* Reset chicken: */

  chicken_x = (640 - 32) / 2;
  chicken_y = (480 - 32);
  chicken_facing = LEFT;
  chicken_hit_counter = 0;
  anim_frame = 0;

  score = 0;


  /* Reset cars: */

  for (i = 0; i < 48; i++)
  {
    cars[i].x = (i % 8) * 80;
    cars[i].lane = (i / 8);

    if ((rand() % 10) < 3)
      cars[i].missing = TRUE;
    else
      cars[i].missing = FALSE;
  }


  /* MAIN LOOP! */

  done = FALSE;


  do
  {
    loop_start_time = SDL_GetTicks();


    /* Handle events: */
    
    while (SDL_PollEvent(&event) > 0)
    {
      if (event.type == SDL_QUIT)
      {
	/* Quit event!  (Window close, kill signal, etc.) */
	      
	done = TRUE;
      }
      else if (event.type == SDL_KEYDOWN)
      {
	/* Key press! */
	      
	key = event.key.keysym.sym;


	if (key == SDLK_q ||
	    key == SDLK_ESCAPE)
	{
	  done = TRUE;
	}
	else if (key == SDLK_UP ||
		 key == SDLK_DOWN ||
		 key == SDLK_RIGHT ||
		 key == SDLK_LEFT)
	{
	  key_pressed[(int) (key - SDLK_UP)] = TRUE;

	  if (key == SDLK_LEFT)
	    chicken_facing = LEFT;
	  else if (key == SDLK_RIGHT)
	    chicken_facing = RIGHT;
	}
      }
      else if (event.type == SDL_KEYUP)
      {
	/* Key release! */
	      
	key = event.key.keysym.sym;


	if (key == SDLK_UP ||
	    key == SDLK_DOWN ||
	    key == SDLK_RIGHT ||
	    key == SDLK_LEFT)
	{
	  key_pressed[(int) (key - SDLK_UP)] = FALSE;
	}
      }
    }


    /* Move chicken: */

    if (chicken_hit_counter == 0)
    {
      /* User is still in control of the chicken: */
	    
      if (key_pressed[UP])
      {
        chicken_y = chicken_y - 4;

	if (chicken_y < -32)  /* -32 because chicken is 32 pixels tall */
	{
	  /* Off the top of the screen! */

          score++;

	  chicken_y = 480 - 32;
	  chicken_x = (640 - 32) / 2;

	  Mix_PlayChannel(0, score_sound, 0);
	}
      }
      else if (key_pressed[DOWN])
      {
        chicken_y = chicken_y + 4;
      }

      if (key_pressed[RIGHT])
      {
        chicken_x = chicken_x + 4;

	if (chicken_x > 640 - 32)
	  chicken_x = 640 - 32;
      }
      else if (key_pressed[LEFT])
      {
        chicken_x = chicken_x - 4;

	if (chicken_x < 0)
	  chicken_x = 0;
      }


      /* Animate chicken: */

      if (key_pressed[UP] ||
	  key_pressed[DOWN] ||
	  key_pressed[RIGHT] ||
	  key_pressed[LEFT])
      {
        anim_frame = !anim_frame;
      }
    }
    else
    {
      /* Chicken was hit! */
	    
      if (chicken_hit_counter > 7)
      {
	/* For the first few moments, move down and shake about! */
	      
        chicken_y = chicken_y + 6;
        chicken_x = chicken_x + ((rand() % 8) - 4);
      }


      /* Count down, of course... */

      chicken_hit_counter--;
    }


    /* Keep chicken on the screen */
    /* (Done here because chicken could move down manually _or_ when hurt!) */

    if (chicken_y > 480 - 32)
      chicken_y = 480 - 32;


    /* Move cars: */

    for (i = 0; i < NUM_CARS; i++)
    {
      /* Which direction they go depends on the lane they're in! */
	    
      if (cars[i].lane < 3)
      {
	cars[i].x = cars[i].x - 4;

	if (cars[i].x < -64)   /* Note: -64 to keep it from 'popping' up! */
	{
	  cars[i].x = 640;     /* (the car image is 64 pixels wide) */

	  if ((rand() % 10) < 3)
	    cars[i].missing = TRUE;
          else
            cars[i].missing = FALSE;
	}
      }
      else
      {
	cars[i].x = cars[i].x + 4;

	if (cars[i].x > 640)
	{
	  cars[i].x = -64;
	  
          if ((rand() % 10) < 3)
            cars[i].missing = TRUE;
          else
            cars[i].missing = FALSE;
	}
      }
    }


    /* Check for collisions! */

    for (i = 0; i < NUM_CARS; i++)
    {
      if (cars[i].missing == FALSE)
      {
        if (cars[i].x + 64 >= chicken_x &&
            cars[i].x < chicken_x + 32 &&
	    (cars[i].lane * LANE_DIST) + 32 >= chicken_y &&
	    (cars[i].lane * LANE_DIST) < chicken_y + 32)
        {
	  chicken_hit_counter = 10;

	  Mix_PlayChannel(0, chicken_sound, 0);
        }
      }
    }


    /* Draw screen: */

    /* (Clear it first) */
    
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 128, 128, 128));


    /* (Draw the chicken) */
    
    dest.x = chicken_x;
    dest.y = chicken_y;

    if (chicken_hit_counter > 0)
      SDL_BlitSurface(chicken_image_hurt, NULL, screen, &dest);
    else if (chicken_facing == LEFT)
      SDL_BlitSurface(chicken_image_left[anim_frame], NULL, screen, &dest);
    else if (chicken_facing == RIGHT)
      SDL_BlitSurface(chicken_image_right[anim_frame], NULL, screen, &dest);


    /* (Draw the cars) */

    for (i = 0; i < 48; i++)
    {
      if (cars[i].missing == FALSE)
      {
        dest.x = cars[i].x;
        dest.y = cars[i].lane * LANE_DIST;


        /* Which direction it's facing depends on the lane it's in! */
      
        if (cars[i].lane < 3)
	  SDL_BlitSurface(car_image_left, NULL, screen, &dest);
        else
	  SDL_BlitSurface(car_image_right, NULL, screen, &dest);
      }
    }


    /* (Update the display) */

    SDL_Flip(screen);


    /* Play traffic sounds and random horn honks: */
  
    if (!Mix_Playing(1) && (rand() % 10) < 1)
    {
      /* Not playing anything; play something once in a while */

      if ((rand() % 10) < 5)
      {
	/* Half the time, traffic sounds: */

        Mix_PlayChannel(1, traffic_sound, 0);
      }
      else
      {
	/* The other half, honking sounds: */

        Mix_PlayChannel(1, horn_sound, 0);
      }
    }


    

    /* Pause at the end, if necessary: */
    
    loop_end_time = SDL_GetTicks();

    if (loop_end_time < loop_start_time + (1000 / 60))
    {
      SDL_Delay(loop_start_time + (1000 / 60) - loop_end_time);
    }
  }
  while (!done);


  /* Close up SDL! */

  Mix_CloseAudio();
  SDL_Quit();

  return(0);
}


/* Load an image; abort if an error: */

SDL_Surface * my_IMG_Load(char * fname)
{
  SDL_Surface * temp_surface;

  temp_surface = IMG_Load(fname);

  if (temp_surface == NULL)
  {
    fprintf(stderr, "Error loading image %s:  %s\n",
	    fname, IMG_GetError());
    exit(1);
  }

  return(temp_surface);
}


/* Load a sound; abort if an error: */

Mix_Chunk * my_Mix_LoadWAV(char * fname)
{
  Mix_Chunk * temp_chunk;

  temp_chunk = Mix_LoadWAV(fname);

  if (temp_chunk == NULL)
  {
    fprintf(stderr, "Error loading sound %s:  %s\n",
	    fname, Mix_GetError());
    exit(1);
  }

  return (temp_chunk);
}

