
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
#include <SDL/SDL_ttf.h>

#define SCREENW 640
#define SCREENH 480
#define NUMSTAR 200
#define NUMENEMY 10
#define NUMMISSILE 50
#define NUMENEMYMISSILE 150


struct PLAYER
{
  int x;
  int y;
  int skor;
  int lives;
}player;

struct ENEMY
{
  int x;
  int y;
  //int lives;
  int i;
  int type;
};

struct MISSILE
{
  int i;
  int x;
  int y;
  int v;
};

struct STAR
{
  int x;
  int y;
  int v;
};


STAR stars[NUMSTAR];
ENEMY enemy[NUMENEMY];
MISSILE missile[NUMMISSILE];
MISSILE enemymissile[NUMENEMYMISSILE];

int now,oldticks;

int yonx,yony;
int menustate;
int gamestate;
int scroll;
int done;

char scoretext[10];

SDL_Surface *screen;
SDL_Surface *lborder;
SDL_Surface *rborder;
SDL_Surface *konsol;
SDL_Surface *bg;
SDL_Surface *newgame[2];
SDL_Surface *hiscore[2];
SDL_Surface *exitsrf[2];
SDL_Surface *oyuncu;
SDL_Surface *dusman[6];
SDL_Surface *missilesrf;
SDL_Surface *enemy_missile;
SDL_Surface *patlama[4];
SDL_Surface *score;

Mix_Music *music;

TTF_Font *font;
SDL_Color color;


void putpixel(SDL_Surface *surface, int x, int y,
Uint8 R, Uint8 G, Uint8 B)
{
Uint32 color = SDL_MapRGB(surface->format, R, G, B);
switch (surface->format->BytesPerPixel)
{
case 1: 
{
Uint8 *bufp;
bufp = (Uint8 *)surface->pixels + y*surface->pitch + x;
*bufp = color;
}
break;
case 2: 
{
Uint16 *bufp;
bufp = (Uint16 *)surface->pixels + y*surface->pitch/2 + x;
*bufp = color;
}
break;
case 3: 
{
Uint8 *bufp;
bufp = (Uint8 *)surface->pixels + y*surface->pitch + x * 3;
if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
{
bufp[0] = color;
bufp[1] = color >> 8;
bufp[2] = color >> 16;
} else {
bufp[2] = color;
bufp[1] = color >> 8;
bufp[0] = color >> 16;
}
}
break;
case 4: 
{
Uint32 *bufp;
bufp = (Uint32 *)surface->pixels + y*surface->pitch/4 + x;
*bufp = color;
}
break;
}
}

void putrect(int x, int y, int w, int h, Uint32 color)
{
SDL_Rect dest;
dest.x = x;
dest.y = y;
dest.w = w;
dest.h = h;
SDL_FillRect (screen, &dest, color);
}


void putimg(SDL_Surface *img, int x, int y)
{
SDL_Rect dest;
dest.x = x;
dest.y = y;
SDL_BlitSurface(img, NULL, screen, &dest);
}

void setbgcolor(SDL_Surface *surface, Uint8 R, Uint8 G, Uint8 B) 
{
Uint32 color;
color = SDL_MapRGB (surface->format, R, G, B);
SDL_FillRect (surface, NULL, color);
}


void cutimg(SDL_Surface *img, int x, int y, int w, int h, int x2, int y2)
{
SDL_Rect dest;
dest.x = x2;
dest.y = y2;
SDL_Rect dest2;
dest2.x = x;
dest2.y = y;
dest2.w = w;
dest2.h = h;
SDL_BlitSurface(img, &dest2, screen, &dest);
}

SDL_Surface * imageload(char *file)
{
SDL_Surface *temp1, *temp2;
temp1 = SDL_LoadBMP(file);
temp2 = SDL_DisplayFormat(temp1);
SDL_FreeSurface(temp1);
return temp2;
}

SDL_Surface * maskedimg(char *filename,Uint8 r, Uint8 g, Uint8 b)
{
SDL_Surface *temp;
SDL_Surface *temp2;
temp = SDL_LoadBMP(filename);
SDL_SetColorKey(temp, SDL_SRCCOLORKEY,SDL_MapRGB(temp->format, r, g, b));
temp2 = SDL_DisplayFormat(temp);
SDL_FreeSurface(temp);
return temp2;
}


int InitTTF() {
  if(TTF_Init()==-1) {
    fprintf(stderr, "Error: unable to initialize TTF_SDL, %s\n", TTF_GetError());
    return 0;
  }
  atexit(TTF_Quit);
  return 1;
}

int InitMixer() {
  //Load Audio Support
  if(SDL_Init(SDL_INIT_AUDIO) != 0) {
    fprintf(stderr, "Warning: unable to initialize audio: %s\n", SDL_GetError());
    return 0;
  }

  if (Mix_OpenAudio(44100, AUDIO_S16, 2, 1024) < 0) {
    fprintf(stderr, "Warning: Audio could not be setup for 11025 Hz 16-bit stereo.\nReason: %s\n", SDL_GetError());
    return 0;
  }
  return 1;
}

void initGameData()
{

  lborder=imageload("data/left.bmp");
  rborder=imageload("data/right.bmp");
  konsol=maskedimg("data/konsol.bmp",255,0,255);
  bg=maskedimg("data/bg.bmp",255,0,255);
  oyuncu=maskedimg("data/player.bmp",255,0,255);
  newgame[0]=imageload("data/newgame1.bmp");
  hiscore[0]=imageload("data/hiscore1.bmp");
  exitsrf[0]=imageload("data/exit1.bmp");
  newgame[1]=imageload("data/newgame2.bmp");
  hiscore[1]=imageload("data/hiscore2.bmp");
  exitsrf[1]=imageload("data/exit2.bmp");
  dusman[0]=maskedimg("data/dusman01.bmp", 255, 0, 255);
  dusman[1]=maskedimg("data/dusman02.bmp", 255, 0, 255);
  dusman[2]=maskedimg("data/dusman03.bmp", 255, 0, 255);
  dusman[3]=maskedimg("data/dusman04.bmp", 255, 0, 255);
  dusman[4]=maskedimg("data/dusman05.bmp", 255, 0, 255);
  missilesrf=maskedimg("data/missile.bmp", 255, 0, 255);
  enemy_missile=maskedimg("data/enemy_missile.bmp", 255, 0, 255);
  patlama[0]=maskedimg("data/patlama01.bmp", 255, 0, 255);
  patlama[1]=maskedimg("data/patlama03.bmp", 255, 0, 255);
  patlama[2]=maskedimg("data/patlama05.bmp", 255, 0, 255);
  patlama[3]=maskedimg("data/patlama07.bmp", 255, 0, 255);

  music=Mix_LoadMUS("data/drey-shootemup.mp3");

} 

int check_collision(int x0, int y0, int w0, int h0, int x1, int y1, int w1, int h1)
{
  return (x0 >= x1 && y0 >= y1 && x0 + w0 <= x1 + w1 && y0 + h0 <= y1 + h1);
}


void init_starfield()
{
  int i;
  for (i=0;i<NUMSTAR;i++)
  {
    stars[i].x=rand()%640;
    stars[i].y=0-rand()%480;
    stars[i].v=1+rand()%3;
  }
}

void draw_starfield()
{
  int i;
  for (i=0;i<NUMSTAR;i++)
  {
    if (stars[i].y>=0)
    {
      if (stars[i].v==1)
	putpixel(screen,stars[i].x,stars[i].y,55,55,55);
      else if (stars[i].v==2)
	putpixel(screen,stars[i].x,stars[i].y,150,150,150);
      else if (stars[i].v==3)
	putpixel(screen,stars[i].x,stars[i].y,255,255,255);
     
    }
  }
}

void update_starfield()
{
  int i;
  for (i=0;i<NUMSTAR;i++)
  {
    stars[i].y+=stars[i].v;
    if (stars[i].y>=480) 
    {
      //stars[i].x=rand()%640;
      stars[i].y=0-rand()%640;
      //stars[i].v=rand()%3;
    }
  }
}

void update_score()
{
    sprintf(scoretext,"%d", player.skor);
    score=NULL;
    score=TTF_RenderText_Solid(font, scoretext, color);
}


void set_player()
{
  player.x=280;
  player.y=350;
  player.skor=0;
  player.lives=4;
}

void update_player()
{
  int n; 
  player.x+=yonx;
  player.y+=yony;

  for (n=0;n<NUMENEMY;n++)
  {
    if (check_collision(enemy[n].x, enemy[n].y, 45, 45, player.x, player.y, 76, 50))
    {
	enemy[n].i=0;
	player.lives--;
	player.skor+=enemy[n].type*10;
	update_score();
    }
  }
  if (player.y<150) player.y=150;
  if (player.y>350) player.y=350;
  if (player.x<80) player.x=80;
  if (player.x>480) player.x=480;
}

void init_missile()
{
  int i;
  for (i=0;i<NUMMISSILE;i++)
  {
    missile[i].x=0;
    missile[i].y=0;
    missile[i].v=0;
    missile[i].i=0;
  }
}

void shoot_missile()
{
  int i;
  for (i=0;i<NUMMISSILE;i++)
  {
    if (missile[i].i==0)
    {
      missile[i].x=player.x+33;
      missile[i].y=player.y-15;
      missile[i].v=-1;
      missile[i].i=1;
      break;
    }
  }
  
}

void collide()
{
  int i,n;
  for (n=0;n<NUMENEMY;n++)
  {
    if (!enemy[n].i) continue;
    //player

    for (i=0;i<NUMMISSILE;i++)
    {
      if (!missile[i].i) continue;
      if (check_collision(missile[i].x, missile[i].y, 10, 16, enemy[n].x, enemy[n].y, 45, 40))
      {
	enemy[n].i=0;
	missile[i].i=0;
	player.skor+=enemy[n].type*10;
	update_score();
      }
    }
  }
}

void draw_missile()
{
  int i;
  for (i=0;i<NUMMISSILE;i++)
  {
    if (missile[i].i) putimg(missilesrf,missile[i].x,missile[i].y);
  }
}

void update_missile()
{
  int i;
  for (i=0;i<NUMMISSILE;i++)
  {
    if (missile[i].i)
    {
      missile[i].y+=missile[i].v;
    }
    if (missile[i].y<0) missile[i].i=0;
  }
}

void init_enemy()
{
  int i;
  for (i=0;i<NUMENEMY;i++)
  {
    enemy[i].x=(rand()%440)+82;
    enemy[i].y=0-rand()%480;
    enemy[i].i=1;
    enemy[i].type=rand()%5+1;
  }
}

void update_enemy()
{
  /*i'm all lost in the supermarket
    i can no longer shop happily */
  int i;
  for (i=0;i<NUMENEMY;i++)
  {
    enemy[i].y++;
    enemy[i].x+=0;
    
    if (enemy[i].x>480) //enemy[i].x=480;
    if (enemy[i].x<80) enemy[i].x=80;
    if (!enemy[i].i || enemy[i].y>480) 
    {
      enemy[i].x=(rand()%440)+82;
      enemy[i].y=0-rand()%480;
      enemy[i].i=1;
      enemy[i].type=rand()%5+1;
    }
  }
}

void draw_enemy()
{
  int i;
  for (i=0;i<NUMENEMY;i++)
  {
    if (enemy[i].i) putimg(dusman[enemy[i].type-1],enemy[i].x,enemy[i].y);
  }
}

void update_lives()
{
  if (player.lives<=0)
  {
    //game over
    gamestate=0;
  }
}

void draw_lives()
{
  switch(player.lives)
  {
  case 4:
    putrect(270,417,11,11,0xff1010);
  case 3:
    putrect(294,417,11,11,0xff1010);
  case 2:
    putrect(322,417,11,11,0xff1010);
  case 1:
    putrect(345,417,12,11,0xff1010);
    break;
  }
}

void draw_score()
{
    putimg(score,275,445);
}

void runmenu()
{
    switch(menustate)
    {
    case 0: //newgame
      //init_starfield();
      set_player();
      init_missile();
      init_enemy();
      Mix_HaltMusic();
      gamestate=1;   
      Mix_PlayMusic(music, -1);
      break;
    case 1: //hiscore 
      //init_starfield();
      //Mix_HaltMusic();
      //gamestate=2;   
      //Mix_PlayMusic(music, -1);
      break;
    case 2: //exit
      done=1;
      break;
    }
}


int draw()
{
  setbgcolor(screen, 0, 0, 0);
  //putimg(oyuncu,300,300);
  switch(gamestate)
  {
  case 0: //menu
    draw_starfield();
    putimg(score,283,212);
    if (now>oldticks)
    {
      scroll++;
      update_starfield();
      update_player();
      oldticks=now;
    }
    putimg(bg,0,0);
    switch(menustate)
    {
    case 0: //newgame
      putimg(newgame[1],275,260);
      putimg(hiscore[0],275,300);
      putimg(exitsrf[0],275,340);
      break;
    case 1: //hiscore
      putimg(newgame[0],275,260);
      putimg(hiscore[1],275,300);
      putimg(exitsrf[0],275,340);
      break;
    case 2: //exit
      putimg(newgame[0],275,260);
      putimg(hiscore[0],275,300);
      putimg(exitsrf[1],275,340);
      break;
    }
    break;
  case 1: //game
    draw_starfield();
    if (now>oldticks)
    {
      scroll++;
      update_starfield();
      update_player();
      update_missile();
      update_enemy();
      update_lives();
      //
      oldticks=now;
    }
    if (scroll>=lborder->h) scroll=0;
    //left
    putimg(lborder, 0, scroll);
    cutimg(lborder, 0,lborder->h-scroll,lborder->w,scroll-1,0,0);
    //right
    putimg(rborder, 558, scroll);
    cutimg(rborder, 0,rborder->h-scroll,rborder->w,scroll-1,558, 0);
    // konsol
    putimg(konsol,175,385);
    //player
    putimg(oyuncu,player.x,player.y);
    //
    draw_missile(); 
    draw_enemy();
    draw_lives();
    draw_score();
    collide();
    break;
  case 2: //highscore,
    draw_starfield();
    if (now>oldticks)
    {
      scroll++;
      update_starfield();
      oldticks=now;
    }
    putimg(bg,0,0);
    break;
  }

  SDL_Flip(screen);
}

int main(int argc, char *argv[])
{

    if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0)
    {
        fprintf (stderr, "Couldn't initialize SDL: %s\n", SDL_GetError ());
        exit (1);
    }
    atexit (SDL_Quit);

    screen = SDL_SetVideoMode (SCREENW, SCREENH, 16, SDL_SWSURFACE | SDL_FULLSCREEN);
    if (screen == NULL)
    {
        fprintf (stderr, "Couldn't set video mode: %s\n",
          SDL_GetError ());
        exit (2);
    }
    SDL_WM_SetCaption ("BlackstaR", NULL);
    SDL_EnableKeyRepeat(10,10);

    srand(time(NULL));

    
    InitTTF();
    InitMixer();

    if((font = TTF_OpenFont("data/arial.ttf", 12)) == NULL) {
      printf("TTF_OpenFont error: %s", TTF_GetError());
      exit (-1);
    }
    color.r=55; color.g=55; color.b=255;


    initGameData();
    init_starfield();
    init_missile();
    init_enemy();
    update_score();

    done = 0;

    gamestate=0;
    scroll=0;
    oldticks=0;

    int shootold = 0;

    Mix_PlayMusic(music, -1);

    while (!done)
    {
        SDL_Event event;

        while (SDL_PollEvent (&event))
        {
            switch (event.type)
            {
            case SDL_KEYDOWN:
                if(event.key.keysym.sym == SDLK_SPACE)
		{
		  if (gamestate==0) runmenu();
		  if (gamestate==1)
                  {
                    if(now - shootold > 300)
		    {
                      shoot_missile();
		      shootold = now;
                    }
                  }
                }
	      switch (event.key.keysym.sym){
	      case SDLK_ESCAPE:
		done=1;
		break;
	      case SDLK_UP:
		if (gamestate==1) yony=-1;
		if (gamestate==0)
		{
		  menustate--;
		  if (menustate<0) menustate=0;
		}
		break;
	      case SDLK_DOWN:
		if (gamestate==1) yony=+1;
		if (gamestate==0)
		{
		  menustate++;
		  if (menustate>2) menustate=2;
		}
		break;
	      case SDLK_LEFT:
		if (gamestate==1) yonx=-1;
		if (gamestate==2)
		{
		  Mix_HaltMusic();
		  gamestate=0;
		  Mix_PlayMusic(music, -1);
		}
		break;
	      case SDLK_RIGHT:
		if (gamestate==1) yonx=+1;
		if (gamestate==2)
		{
		  Mix_HaltMusic();
		  gamestate=0;
		  Mix_PlayMusic(music, -1);
		}
		break;
	      }
	      break;        
	    case SDL_KEYUP:
	      switch (event.key.keysym.sym){
	      case SDLK_ESCAPE:
		done=1;
		break;
	      case SDLK_UP:
		if (gamestate==1) yony=0;
		break;
	      case SDLK_DOWN:
		if (gamestate==1) yony=0;
		break;
	      case SDLK_LEFT:
		if (gamestate==1) yonx=0;
	      case SDLK_RIGHT:
		if (gamestate==1) yonx=0;
		break;
	      case SDLK_SPACE:
		break;
	      }
	      break;
            case SDL_QUIT:
                done = 1;
                break;
            default:
                break;
            }
        }
	now=SDL_GetTicks();
        draw ();
    }

    TTF_Quit();
    Mix_CloseAudio();
    SDL_Quit();

  return 0;
}
