/***************************************************************************
                           main.c  -  description
                             -------------------
    begin                : Sat Aug 24 00:00:00 EEST 2002
    copyright            : (C) 2002 Markus Kettunen
    email                : makegho@mbnet.fi
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL.h"

#ifndef WIN32
	#include <unistd.h>
	#include <dirent.h>
#else
	#include <io.h>
	#include <windows.h>
	#define rint int
#endif

#define fps 50
#define gravity 9.81
#define pi 3.14159265358979

  SDL_Surface *back;
  SDL_Surface *TMP;
  SDL_Surface *kp1;
  SDL_Surface *kp1b;
  SDL_Surface *kp2;
  SDL_Surface *kp2b;
  SDL_Surface *num3;
  SDL_Surface *num2;
  SDL_Surface *num1;
  SDL_Surface *num0;
  SDL_Surface *numv;
  SDL_Surface *font;
  SDL_Surface *font2;
  SDL_Surface *screen;
  SDL_Surface *menu;
  SDL_Surface *menu_onoff;
  SDL_Surface *blobtrox;
  SDL_Surface *blursurface;
  SDL_Surface *blursurface2;
  SDL_Surface *balloonchase;
  SDL_Surface *arrow[2];
  SDL_Event event;

// long status[3][10];


struct dirent *currentfile;

#ifdef WIN32
	double rint(double roundable){return roundable;}	// 'cos windows doesn't have rint(), we'll not use it.
#endif

  Uint8* keys;
  Uint32 oldtime;
  Uint32 newtime;
  Uint32 frames;
  Uint32 stime;
  Uint32 pausetime;
  Uint32 decorback[1500];
  Uint32 rfps;
  int winsneeded=2;

  char p1keys[20];
  char p2keys[20];

  double decoration[4500][10];
  long decorused;

  int gametype=0;

  int mypos=0;
  int mxpos=0;

  int option_ai=0;
  int option_wave_effect=1;

int exittexts()
{
  fprintf (stderr, "Comments to: Blobtrox@sunpoint.net\n");

  fprintf(stderr, "\nBalloon Chase\n");

  SDL_FreeSurface (back);
  SDL_FreeSurface (TMP);
  SDL_FreeSurface (kp1);
  SDL_FreeSurface (kp1b);
  SDL_FreeSurface (kp2);
  SDL_FreeSurface (kp2b);
  SDL_FreeSurface (num3);
  SDL_FreeSurface (num2);
  SDL_FreeSurface (num1);
  SDL_FreeSurface (num0);
  SDL_FreeSurface (numv);
  SDL_FreeSurface (font);
  SDL_FreeSurface (blobtrox);
  SDL_FreeSurface (blursurface);
  SDL_FreeSurface (blursurface2);
  SDL_FreeSurface (balloonchase);
  SDL_FreeSurface (menu);
  SDL_FreeSurface (menu_onoff);
//  SDL_FreeSurface (*arrow);
  exit (1);
}


void emergencyexit()
{
	fprintf (stderr, "Close window pressed! Quitting program!\n\n\n");
	exittexts();
	exit (1);
}

void Slock(SDL_Surface *screen)
{
	if ( SDL_MUSTLOCK(screen) )
		{
		if ( SDL_LockSurface(screen) < 0 )
			{
			return;
			}
		}
}

void Sulock(SDL_Surface *screen)
{
	if ( SDL_MUSTLOCK(screen) )
		{
		SDL_UnlockSurface(screen);
		}
}

inline void DrawPixel (SDL_Surface *screen, int x, int y, Uint8 R, Uint8 G, Uint8 B)
{
  Uint32 color = SDL_MapRGB(screen->format, R, G, B);
  /*switch (screen->format->BytesPerPixel)
	{
	case 2: {
		Uint32 *bufp;
		bufp = (Uint32 *)screen->pixels + y*screen->pitch/2+x;
		*bufp = color;
		}
	break;
	case 4: {*/
		Uint32 *bufp;
	        bufp = (Uint32 *)screen->pixels + y*screen->pitch/4+x;
 	        *bufp = color;/*
		break;
		}
	break;


	}*/
}

Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to retrieve */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        return *p;

    case 2:
        return *(Uint16 *)p;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;

    case 4:
        return *(Uint32 *)p;

    default:
        return 0;       /* shouldn't happen, but avoids warnings */
    }
}


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

void ToTMP( int x, int y, int w, int h)
{
SDL_Rect dest;
SDL_Rect dest2;
dest.x = 0;
dest.y = 0;
dest2.x = x;
dest2.y = y;
dest2.w = w;
dest2.h = h;
SDL_BlitSurface(screen, &dest2, TMP, &dest);
}

void FromTMP( int x, int y, int w, int h)
{
SDL_Rect dest;
SDL_Rect dest2;
dest.x = x;
dest.y = y;
dest2.x = 0;
dest2.y = 0;
dest2.w = w;
dest2.h = h;
SDL_BlitSurface(TMP, &dest2, screen, &dest);
}

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


void line (SDL_Surface *screen, int x0, int y0, int x1, int y1, Uint8 R, Uint8 G, Uint8 B)
    {
        int dy;
        int dx;
        int stepx, stepy;
	int fraction;

 	dy = y1 - y0;
	dx = x1 - x0;

        if (dy < 0) { dy = -dy;  stepy = -1; } else { stepy = 1; }
        if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; }
        dy <<= 1;                                                  // dy is now 2*dy
        dx <<= 1;                                                  // dx is now 2*dx

	if (x0 > 0 && x0 < 639 && y0 > 0 && y0 < 479) DrawPixel(screen, x0, y0, R, G, B);
        if (dx > dy) {
            fraction = dy - (dx >> 1);                         // same as 2*dy - dx
            while (x0 != x1) {
                if (fraction >= 0) {
                    y0 += stepy;
                    fraction -= dx;                                // same as fraction -= 2*dx
                }
                x0 += stepx;
                fraction += dy;                                    // same as fraction -= 2*dy
		if (x0 > 0 && x0 < 639 && y0 > 0 && y0 < 479) DrawPixel(screen, x0, y0, R, G, B);
            }
        } else {
            fraction = dx - (dy >> 1);
            while (y0 != y1) {
                if (fraction >= 0) {
                    x0 += stepx;
                    fraction -= dy;
                }
                y0 += stepy;
                fraction += dx;
		if (x0 > 0 && x0 < 639 && y0 > 0 && y0 < 479) DrawPixel(screen, x0, y0, R, G, B);
            }
        }
    }


void movedeco()
{
int a, b, c=0, d=0;
	Slock(screen);
	for (c=1;c<=decorused;c++)
		{
			if (decoration[c][3]>=1)
				{
					if (decoration[c][9]<=2) DrawPartOfIMG(back, screen, (int)rint(decoration[c][1]),
							(int)rint(decoration[c][2]),1,1,(int)rint(decoration[c][1]), (int)rint(decoration[c][2]));
					decoration[c][1]+=decoration[c][4];
					decoration[c][2]+=decoration[c][5];
					if (decoration[c][9]!=3) decoration[c][6]-=1.0;
					if (decoration[c][9]==3) decoration[c][5]+=gravity/fps;

					if (decoration[c][3]==2)
						{
							decoration[c][3]=0;
						}

					if (decoration[c][9]<=2 && decoration[c][3]!=0)
						{


							if (decoration[c][1] < 0 || decoration[c][1] > 639 || decoration[c][2]>479 ||
									decoration[c][2]<0 || decoration[c][6] <=0)
								{
									decoration[c][3]=0;
								}
							else
								{
									if (decoration[c][9]==1) DrawPixel(screen, (int)rint(decoration[c][1]),
													(int)rint(decoration[c][2]),	255,100,0);
									if (decoration[c][9]==2) DrawPixel(screen, (int)rint(decoration[c][1]),
													(int)rint(decoration[c][2]),	63,0,16);
								}
						}
					d=c;
				}
		}
	decorused=d;
	Sulock(screen);
}

int InitImages()
{
	back = SDL_LoadBMP("<BalloonC$Dir>/images/back.bmp");

	num3 = SDL_LoadBMP("<BalloonC$Dir>/images/num3.bmp");
	SDL_SetColorKey(num3, SDL_SRCCOLORKEY, SDL_MapRGB(num3->format, 0xFF, 0xFF, 0xFF));
	num2 = SDL_LoadBMP("<BalloonC$Dir>/images/num2.bmp");
	SDL_SetColorKey(num2, SDL_SRCCOLORKEY, SDL_MapRGB(num2->format, 0xFF, 0xFF, 0xFF));
	num1 = SDL_LoadBMP("<BalloonC$Dir>/images/num1.bmp");
	SDL_SetColorKey(num1, SDL_SRCCOLORKEY, SDL_MapRGB(num1->format, 0xFF, 0xFF, 0xFF));
	num0 = SDL_LoadBMP("<BalloonC$Dir>/images/num0.bmp");
	SDL_SetColorKey(num0, SDL_SRCCOLORKEY, SDL_MapRGB(num0->format, 0xFF, 0xFF, 0xFF));
	numv = SDL_LoadBMP("<BalloonC$Dir>/images/num-.bmp");
	SDL_SetColorKey(numv, SDL_SRCCOLORKEY, SDL_MapRGB(numv->format, 0xFF, 0xFF, 0xFF));

	menu = SDL_LoadBMP("<BalloonC$Dir>/images/menu.bmp");
	menu_onoff = SDL_LoadBMP("<BalloonC$Dir>/images/menu_onoff.bmp");


//	arrow[0] = SDL_LoadBMP("<BalloonC$Dir>/images/down.bmp");
//	SDL_SetColorKey(arrow[0], SDL_SRCCOLORKEY, SDL_MapRGB(arrow[0]->format, 0x00, 0x00, 0x00));
//	arrow[1] = SDL_LoadBMP("<BalloonC$Dir>/images/down.bmp");
//	SDL_SetColorKey(arrow[1], SDL_SRCCOLORKEY, SDL_MapRGB(arrow[1]->format, 0x00, 0x00, 0x00));

	kp1 = SDL_LoadBMP("<BalloonC$Dir>/images/kp1.bmp");
	SDL_SetColorKey(kp1, SDL_SRCCOLORKEY, SDL_MapRGB(kp1->format, 0xFF, 0xFF, 0xFF));
	kp1b = SDL_LoadBMP("<BalloonC$Dir>/images/kp1b.bmp");
	SDL_SetColorKey(kp1b, SDL_SRCCOLORKEY, SDL_MapRGB(kp1b->format, 0xFF, 0xFF, 0xFF));

	kp2 = SDL_LoadBMP("<BalloonC$Dir>/images/kp2.bmp");
	SDL_SetColorKey(kp2, SDL_SRCCOLORKEY, SDL_MapRGB(kp2->format, 0xFF, 0xFF, 0xFF));
	kp2b = SDL_LoadBMP("<BalloonC$Dir>/images/kp2b.bmp");
	SDL_SetColorKey(kp2b, SDL_SRCCOLORKEY, SDL_MapRGB(kp2b->format, 0xFF, 0xFF, 0xFF));

	font2 = SDL_LoadBMP("<BalloonC$Dir>/images/font.bmp");
	font = SDL_CreateRGBSurface(SDL_SWSURFACE, 1288, 100, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
	SDL_SetColorKey(font, SDL_SRCCOLORKEY, SDL_MapRGB(font->format, 0x00, 0x00, 0x00));
	DrawIMG (font, font2, 0, 0);

	blobtrox = SDL_LoadBMP("<BalloonC$Dir>/images/blobtrox.bmp");
	//SDL_SetColorKey(blobtrox, SDL_SRCCOLORKEY, SDL_MapRGB(blobtrox->format, 0x01, 0x01, 0x01));

	balloonchase = SDL_LoadBMP("<BalloonC$Dir>/images/balloonchase.bmp");

	TMP = SDL_CreateRGBSurface(SDL_SWSURFACE, 259, 200, 32, 		0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
	blursurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 32, 0x00000000, 0x00000000, 0x00000000, 0x00000000);
	blursurface2 = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 32, 0x00000000, 0x00000000, 0x00000000, 0x00000000);

	return 0;
}

int chkkeys()
{
int enter=0;
	while ( SDL_PollEvent(&event) )
		{
			if ( event.type == SDL_QUIT ) emergencyexit();
			if ( event.type == SDL_KEYDOWN )
			{
				if ( event.key.keysym.sym == SDLK_KP_ENTER || event.key.keysym.sym == SDLK_SPACE
						|| event.key.keysym.sym == SDLK_RETURN) enter=1;
				if ( event.key.keysym.sym == SDLK_ESCAPE) enter=2;
			}
		}
	return enter;
}

int WaitSec(int wait)
{
int skipped=0;
	oldtime=SDL_GetTicks();
	newtime=SDL_GetTicks();
	while (newtime-oldtime < wait && skipped==0)
		{
			newtime=SDL_GetTicks();
			skipped=chkkeys();
		}
	return skipped;
}


int Calculate()
{
int skipped=0;

	ToTMP(245, 170, 150, 200);
	DrawIMG (screen, num3, 245, 170);
	SDL_Flip(screen);
	if (WaitSec(1000)!=0) skipped=1;

	if (skipped!=1)
		{
			FromTMP(245, 170, 150, 200);
			DrawIMG (screen, num2, 245, 170);
			SDL_Flip(screen);
			if (WaitSec(1000)!=0) skipped=1;
		}

	if (skipped!=1)
		{
			FromTMP(245, 170, 150, 200);
			DrawIMG (screen, num1, 245, 170);
			SDL_Flip(screen);
			if (WaitSec(1000)!=0) skipped=1;
		}

	if (skipped!=1)
		{
			FromTMP(245, 170, 150, 200);
			DrawIMG (screen, num0, 245, 170);
			SDL_Flip(screen);
			if (WaitSec(500)!=0) skipped=1;
		}

	FromTMP(245, 170, 150, 200);
	SDL_Flip(screen);

	newtime=SDL_GetTicks();
	return 0;
}

//Uint32 random32 (int x1, int x2){return x1+(Uint32)( rand() / (RAND_MAX*labs(x1-x2)+1.0));}
double randomd (double x1, double x2){return x1+rand()/(RAND_MAX/(x2-x1)+1.0);}

void LaunchDeco	(double x1, double y1, double gx, double gy, double tandir, double owner, double power, double sprite)
{
int b=0, found=0;
	while (!found)
		{
			b++;
			if (b==4500) found=1;
			if (decoration[b][3]==0)
			{
				decoration[b][1]=x1;
				decoration[b][2]=y1;
				decoration[b][3]=1;
				decoration[b][4]=randomd (-1.5, 1.5)+gx/1.5-sin(tandir);
				decoration[b][5]=randomd (-1.5, 1.5)+gy/1.5-cos(tandir);
				//if (sprite!=3)decoration[b][4]=200*rand()/(RAND_MAX+1.0)+gx/1.5-sin(tandir);
		//			else	decoration[b][4]=gx+sin(tandir);
				//if (sprite!=3)decoration[b][5]=200*rand()/(RAND_MAX+1.0)+gy/1.5-cos(tandir);
		//			else	decoration[b][5]=gy+cos(tandir);
				if (sprite!=3)decoration[b][6]=rand()/(RAND_MAX/200.0)+1.0;
					else decoration[b][6]=0;
				decoration[b][7]=owner;
				decoration[b][8]=power;
				decoration[b][9]=sprite;
				if (b > decorused) decorused=b;
				found=1;
			}
	}
}

int fadein(SDL_Surface *screen, SDL_Surface *blursurface)
{
  int x,y,skpd;
  int bpp = screen->format->BytesPerPixel;
  Uint16 blurpitch = (Uint16)blursurface->pitch;
  Uint32 stime, etime;
  Uint32 i;
  i=1;
  stime=SDL_GetTicks();
	while (i>0 && i<34)
		{
				for (y=0;y<480;y++)
				{
					for (x=0;x<640;x++)
						{
								Uint8 *p = (Uint8 *)blursurface->pixels + y * blurpitch + (x*bpp) ;
								Uint32 *bufp = (Uint32 *)screen->pixels + y*blurpitch/4+x;
								*bufp = int( (p[0]*i>>5) ) + int( (p[1]*i>>5)<<8 ) + int ( (p[2]*i>>5)<<16);
						}
				}
			SDL_Flip(screen);
			skpd=chkkeys();
			etime=SDL_GetTicks();
			i = 32-int((stime+1000-etime)*32/1000);
		}
  return skpd;
}

int fadeout(SDL_Surface *screen, SDL_Surface *blursurface)
{
  int x,y,skpd;
  int bpp = screen->format->BytesPerPixel;
  Uint16 blurpitch = (Uint16)blursurface->pitch;
  Uint32 stime, etime;
  Uint32 i;
  i=32;
  stime=SDL_GetTicks();
	while (i>0 && i<34)
		{
				for (y=0;y<480;y++)
				{
					for (x=0;x<640;x++)
						{
								Uint8 *p = (Uint8 *)blursurface->pixels + y * blurpitch + (x*bpp) ;
								Uint32 *bufp = (Uint32 *)screen->pixels + y*blurpitch/4+x;
								*bufp = int( (p[0]*i>>5) ) + int( (p[1]*i>>5)<<8 ) + int ( (p[2]*i>>5)<<16);
						}
				}
			SDL_Flip(screen);
			skpd=chkkeys();
			etime=SDL_GetTicks();
			i = int((stime+1000-etime)*32/1000);

		}
  return skpd;
}


int crossfade (SDL_Surface *screen, SDL_Surface *tmp1, SDL_Surface *tmp2)
{
  int x,y,j,skpd;
  Uint16 blurpitch = (Uint16)blursurface->pitch;
  Uint32 stime, etime, i;
  int bpp1 = tmp1->format->BytesPerPixel;
  int bpp2 = tmp2->format->BytesPerPixel;

  Uint32 color;

  stime=SDL_GetTicks();
	i=32;
	while(i>0 && i < 40) //for (i=32;i>=1;i--)
		{
			SDL_Flip (screen);
			skpd=chkkeys();
			for (y=0;y<480;y++)
				{
					for (x=0;x<640;x++)
						{
							j=32-i;
							Uint8 *p1 = (Uint8 *)tmp1->pixels + y * blurpitch+x*bpp1;
							Uint8 *p2 = (Uint8 *)tmp2->pixels + y * blurpitch+x*bpp2;
							Uint32 *bufp = (Uint32 *)screen->pixels + y*blurpitch/4+x;
							*bufp = int( (p1[0]*i>>5) ) + ((p1[1]*i>>5)<<8) + ( (p1[2]*i>>5)<<16) +
									(( (p2[0]*j>>5) ) + ( (p2[1]*j>>5)<<8 ) + ( (p2[2]*j>>5)<<16));
						}
				}
			etime=SDL_GetTicks();
			i=int( 				(stime+1000-etime) *32/1000);
		}
  return skpd;
}

void createdat(int winsneed, int option_wave_effect)
{
  FILE *OPTFILE=fopen ("<BalloonC$Dir>/balloonchase.dat", "w+");
  char datmsg[60];
  sprintf (datmsg, "Balloon Chase settings file -- Do not edit manually!");
  char tmp2;
  for (tmp2=0;tmp2<=strlen(datmsg);tmp2++)
	{
		fputc(datmsg[tmp2],OPTFILE);
	}
  fputc (winsneed, OPTFILE);
  fputc (option_wave_effect+2, OPTFILE);
  fprintf (stderr, "Saved configuration to balloonchase.dat\n");
  fclose (OPTFILE);
}

void checkfiles()
{
  char found=0;
  #ifdef WIN32
	WIN32_FIND_DATA  fileinfo;
	BOOL rc = 0;
	HANDLE hFile;
	hFile = FindFirstFile("*", &fileinfo);
	while(rc)
		{
			rc = FindNextFile(hFile, &fileinfo);
			if (strcmp (fileinfo.cFileName, "balloonchase.dat")==0)
		{
	fprintf(stderr, "Found balloonchase.dat\n");
	found = 1;
	_findclose(hFile);
  #endif
  #ifndef WIN32
	struct dirent *filelist[255];
	int i=0;
	int j=0;
	DIR *dp;
	dp=opendir("./");
	int filenum=0;
	while( filelist[filenum]=readdir(dp) )
 	 	filenum++;
	closedir(dp);
	if (filenum>=2)
		for (i=0;i<filenum;i++)
			{
				if (strcmp(filelist[i]->d_name,"balloonchase.dat")==0)
						{
							fprintf (stderr, "Found balloonchase.dat\n");
							found=1;
						}
			}
  #endif
	if (found==0)
		{
			fprintf (stderr, "Balloonchase.dat not found!\nCreating new...\n");
			if (found==0) createdat(2, 1);
		}
}

Uint32 rgb(Uint8 r, Uint8 g, Uint8 b)
{
	return (b)+(g<<8)+(r<<16);
}

void DrawBG(SDL_Surface *screen)
{
	DrawIMG(screen, balloonchase, 0, 0);
}


void blobprintf(SDL_Surface *screen, char msg[60], int x, int y, Uint8 r, Uint8 g, Uint8 b, int effect)
{
int str, cpx, fx, fy, px, py;
Uint32 fpitch = (Uint16)font->pitch;
Uint32 color;
//Uint32 color;
	for (str=0;str<strlen(msg);str++)
		{
			cpx = str*18;
			fx = (msg[str]-33)*28;
			fy = 0;
			while (fx>=1286)
				{
					fx-=1286;
					fy+=32;
				}
			if (msg[str]!=' ')
				{
					for (px=0; px<=27;px++)
						for (py=0;py<32;py++)
							{
								Uint8 *p = (Uint8 *)font->pixels + (fy+py) * fpitch + ((px+fx)<<2);
								if (effect==0 || effect >= 31337)
									{
										Uint32 *bufp = (Uint32 *)screen->pixels + (y+py) * screen->pitch/4+(px+x+cpx);
										if (effect==31337)
											{
												Uint32 col;
										col=(int)(fabs(255/pi*atan2(strlen(msg)*9-px, 16-py)));
												r=col; g=col;
												b=col;
											}
										if ( rgb(p[3],p[2],p[1]) != 0) *bufp = rgb(r, g, b);

									}
								if (effect>0 && effect < 31337)
									{
										Uint32 *bufp = (Uint32 *)screen->pixels + (y+py) * screen->pitch/4+(px+x+cpx);
										Uint8 *p2 = (Uint8 *)blursurface->pixels + (y+py) *
											blursurface->pitch + ((px+x+cpx)<<2);
										Uint16 r2 = (p2[2]+effect);
										Uint16 g2 = (p2[1]+effect);
										Uint16 b2 = (p2[0]+effect);
										if (r2 > 255) r2=255;
										if (g2 > 255) g2=255;
										if (b2 > 255) b2=255;
										if (p[2]!=0) *bufp = rgb(r2,g2,b2);
									}
							}
				}
		}
}

void blur(SDL_Surface *screen, SDL_Surface *blursurface, int x1, int y1, int x2, int y2)
{
int x, y, xx, yy;
Uint32 r, g, b;
int range=1;
int colors;

	DrawPartOfIMG(screen, blursurface, x1-range, y1-range, x2-x1+(range<<1), y2-y1+(range<<1), x1-range, y1-range);

	for (y=y1; y<=y2; y++)
		for (x=x1; x<=x2; x++)
			{
				r=0;
				g=0;
				b=0;
				colors=0;
				for (yy=-range;yy<=range;yy++)
					for (xx=-range;xx<=range;xx++)
						{
									colors++;
									Uint8 *p = (Uint8 *)blursurface->pixels + (y+yy) * blursurface->pitch + ((x+xx)<<2);
									r+=p[0];
									g+=p[1];
									b+=p[2];
						}
				r/=colors;
				g/=colors;
				b/=colors;
				Uint32 *bufp = (Uint32 *)screen->pixels + (y) * screen->pitch/4+(x);
				*bufp=(b<<16)+(g<<8)+(r);
			}
}

void box(SDL_Surface *screen, int x, int y, int x2, int y2, Uint8 R, Uint8 G, Uint8 B)
{
	line (screen, x,   y,  x2,   y,   R, G, B);
	line (screen, x,   y,   x,  y2,   R, G, B);
	line (screen, x,  y2,  x2,  y2,   R, G, B);
	line (screen, x2,  y,  x2,  y2,   R, G, B);
}


void player_chk_if_deco_hit (double x, double y, double *gx, double *gy, int player)
{
int a;
	for (a=1;a<decorused;a++)
		{
			if (decoration[a][1] > x && decoration[a][1] < x+37 && decoration[a][2] > y &&
					decoration[a][2] < y+78 && decoration[a][7]!=player && decoration[a][3]==1)
						{
							*gx += decoration[a][4]/decoration[a][8];
							*gy += decoration[a][5]/decoration[a][8];
							decoration[a][3]=0;
						}
		}
}

void player_chk_if_balloons_hit_each_other (double x, double y, double x2, double y2, char *broken)
{
		if (x+36 > x2 && x < x2+36 && y+36 > y2 && y < y2+78)
			{
				if (*broken == 0) *broken=1;
			}
}

void player_handleplayer (char broken, int *viive, short key_up, short key_down, short key_left, short key_right, short key_shoot,
			double *gx, double *gy, double tandir, int player, double x, double y)
{
int shot=0;
	if (!broken)
		{
			if (*viive>0) *viive--;
			keys = SDL_GetKeyState(NULL);
			if (keys[key_up]) {*gy-=0.2;shot=1;}
			if (keys[key_down]) {*gy+=0.2;shot=1;}
			if (keys[key_left]) {*gx-=0.2;shot=1;}
			if (keys[key_right]) {*gx+=0.2;shot=1;}
			if (keys[key_shoot] && *viive<=0)
				{
					LaunchDeco(x+20,y+73,*gx+sin(tandir)*5,*gy+cos(tandir)*5,tandir,player,8,2);*viive++;
				}
			if (shot==1) LaunchDeco(x+20,y+72,*gx,*gy,tandir,player,13,1);
		}
}

void player_slowmovement (double *gx, double *gy)
{
	*gx/=1.05;
	*gy/=1.05;
}

void player_draw_balloon(double x, double y, double tandir, char broken, int player)
{
		if (!broken)								// if player is not broken, draw it
				{
					line (screen, (int)rint(x+20+sin(tandir)*20), (int)rint(y+71+cos(tandir)*20),
						(int)rint(x+20+sin(tandir)*60), (int)rint(y+71+cos(tandir)*60), 255, 255, 255);
					if (player==1) DrawIMG(screen, kp1, (int)rint(x), (int)rint(y));
					if (player==2) DrawIMG(screen, kp2, (int)rint(x), (int)rint(y));
				}
			else								// if it is, draw the broken ballon
				{
					if (player==1) DrawIMG(screen, kp1b, (int)rint(x), (int)rint(y));
					if (player==2) DrawIMG(screen, kp2b, (int)rint(x), (int)rint(y));
				}
}

void player_gravitydeadballoon (double *gy, char broken)
{
	if (broken > 0) *gy+=gravity/fps;
}

void player_moveplayer (double *x, double *y, double gx, double gy)
{
*x+=gx;
*y+=gy;
}

void player_checkborders (double x, double y, char *broken)
{
		if (x < 16 && *broken < 1) *broken=1;
		if (x > 639-36-16 && *broken < 1) *broken=1;
		if (y < 15 && *broken < 1) *broken=1;
		if (y > 385 && *broken < 1) *broken=1;
		if (y >= 479) *broken+=1;
}

void player_clean_screen_below_balloon (double x, double y)
{
	DrawPartOfIMG(back, screen, (int)rint(x)+20-60, (int)rint(y), 122, 133, (int)rint(x)+20-60, (int)rint(y));
}

void player_waveplayer(int i, int direction, double *gy)
{
	if (direction==1) *gy += sin(pi/100*i)/10;
	if (direction==0) *gy -= sin(pi/100*i)/10;
}
int box_x=320, box_y=240;

double ai_target (double x, double y, double x2, double y2)
{
	box_x=(int)(x2+x); box_y=(int)(y+y2);
	return ( atan2(x,y) );
}

int MainLoop(SDL_Surface *screen)
{
	int a=0;
	double x1=520, y1=200, gx1=0,gy1=0;
	double x2=120, y2=200, gx2=0,gy2=0;

	double ai_straight, ai_distance;

	int shot=0;
	int i=0;
	int p1viive=0, p2viive=0;

	double tandir, tandir2;
	int found=0;
	char BFinished=0;

	char p1broken=0, p2broken=0;

	char ai_shoot;

	int b=0;
	char ESC=0;

	frames=0;
	int winner=0;

	SDL_Flip(screen);
	stime=SDL_GetTicks();
	decorused=0;
	i=50;
	double ai_speed;
	while (ESC<2 && BFinished==0)
	{
		oldtime=SDL_GetTicks();							// used for slowing the game up
		if (option_wave_effect==1)						// waving balloons
			{
				i++;
				if (i>200) i-=200;
				player_waveplayer(i,1, &gy1);
				player_waveplayer(i,0, &gy2);
			}

											// I'm gonna move this to another function:
		if (option_ai==1 && p2broken==0)
			{
				if (p1broken == 0)
					{
						ai_speed=0.2;
						if (	(y2-y1 < 0 || (x2-x1 < -80 || x2-x1 > 80+40)	)	)
							{
								ai_straight= ai_target ( x1-x2, y1-y2-80 ,x2,y2);
							}

						ai_distance = sqrt ( pow (x1-x2, 2)+ pow(y1-y2, 2) );
						ai_shoot=0;
						shot=0;

						if ( y2 < 80 ||y2 > 300 || x2 < 80 || x2 > 520 )
							{
								ai_speed=0.2;
								ai_straight = ai_target (320-x2, 240-y2,x2,y2);
							}
						if ( y1 < 80 ||y1 > 300 || x1 < 80 || x1 > 520 )
							{
								ai_shoot=1;
							}
					}
				else
					{
						ai_straight = ai_target(320-x2, 240-y2,x2,y2);
					}

				gx2+=sin(ai_straight)*ai_speed;
				gy2+=cos(ai_straight)*ai_speed;
				shot=1;
				if (p2viive>=0) p2viive--;
				if (ai_shoot && p2viive<=0)
					{
						LaunchDeco(x2+20,y2+73,gx2+sin(tandir2)*5,gy2+cos(tandir2)*5,tandir2,2,8,2);
						p2viive++;
					}
				if (shot==1) LaunchDeco(x2+20,y2+72,gx2,gy2,tandir2,2,13,1);
			}

		player_moveplayer(&x1,&y1,gx1,gy1);					// move balloons
		player_moveplayer(&x2,&y2,gx2,gy2);

		player_chk_if_deco_hit (x1, y1, &gx1, &gy1, 1);				// checking if "wind" hits players
		player_chk_if_deco_hit (x2, y2, &gx2, &gy2, 2);

		if (decorused > 0) movedeco();

		tandir = atan2(gx1, gy1);
		tandir2 = atan2(gx2, gy2);

		player_gravitydeadballoon(&gy1, p1broken);
		player_gravitydeadballoon(&gy2, p2broken);

		player_chk_if_balloons_hit_each_other (x1, y1, x2, y2, &p1broken);	// kill player 1 if needed (hit p2 or walls)
		player_checkborders (x1, y1, &p1broken);

		player_chk_if_balloons_hit_each_other (x2, y2, x1, y1, &p2broken);	// kill player 2 if needed (hit p1 or walls)
		player_checkborders (x2, y2, &p2broken);

		player_draw_balloon (x1, y1, tandir, p1broken, 1);
		player_draw_balloon (x2, y2, tandir2, p2broken, 2);

/*		box (screen, box_x-5, box_y-5, box_x+5, box_y+5, 128, 255, 63);		// used for tracking AI
		line (screen, 320, 240, box_x, box_y, 128, 255, 63);*/
		SDL_Flip(screen);

		player_clean_screen_below_balloon (x1,y1);
		player_clean_screen_below_balloon (x2,y2);

		player_handleplayer (p1broken, &p1viive, SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT, SDLK_RSHIFT, &gx1, &gy1, tandir, 1, x1, y1);
		if (!option_ai) player_handleplayer (p2broken, &p2viive, SDLK_w, SDLK_s, SDLK_a, SDLK_d, SDLK_TAB, &gx2, &gy2, tandir2, 2, x2, y2);

		player_slowmovement (&gx1, &gy1);
		player_slowmovement (&gx2, &gy2);


		ESC=chkkeys();
		if (p1broken > 20 || p2broken > 20) BFinished=1;

		newtime=SDL_GetTicks();
		while (newtime-oldtime < 1000/fps && ESC<2 && BFinished==0)
			{
				newtime=SDL_GetTicks();
				ESC=chkkeys();
			}
	}
	if (p1broken==0 && p2broken !=0) winner=1;
	if (p1broken!=0 && p2broken ==0) winner=2;
	if (p1broken!=0 && p2broken !=0) winner=3;
	return (winner);
}

int GameLoop(SDL_Surface *screen)
{
int p1score=0, p2score=0, winner=4, i, escape=0, totalwinner=0;
	SDL_ShowCursor(0);
	DrawIMG(blursurface2, back,0,0);
//	DrawBG(blursurface2);
//	DrawIMG (blursurface2, screen,0,0);
	crossfade (screen, blursurface, blursurface2);
	while ((totalwinner==0) && (escape<2))
		{
			escape=0;
			for (i=0;i<4500;i++) decoration[i][3]=0;
			DrawIMG(screen, back,0,0);
			if (p2score == 0) DrawIMG (screen, num0, 95, 140);
			if (p2score == 1) DrawIMG (screen, num1, 95, 140);
			if (p2score == 2) DrawIMG (screen, num2, 95, 140);
			if (p2score == 3) DrawIMG (screen, num3, 95, 140);
			DrawIMG(screen, numv, 245, 140);
			if (p1score == 0) DrawIMG (screen, num0, 395, 140);
			if (p1score == 1) DrawIMG (screen, num1, 395, 140);
			if (p1score == 2) DrawIMG (screen, num2, 395, 140);
			if (p1score == 3) DrawIMG (screen, num3, 395, 140);
			SDL_Flip(screen);
				escape=WaitSec(2000);
			DrawIMG(screen, back,0,0);
			SDL_Flip(screen);
			if (escape<2)
				{
					Calculate();
					winner = MainLoop(screen);
				}
			DrawIMG (blursurface2, screen, 0, 0);
			if (winner==0) ;
			if (winner==1) p1score+=1;
			if (winner==2) p2score+=1;
			if (winner==3) fprintf (stderr, "Draw!\n");
			if (p1score>=winsneeded) totalwinner=1;
			if (p2score>=winsneeded) totalwinner=2;
			chkkeys();
		}
	SDL_ShowCursor(1);
	DrawIMG (blursurface, screen, 0, 0);
	return (totalwinner);
}

int menuy=220-68;
int menuy2=67;
int menus[2];

void drawblock(SDL_Surface *screen, char msg[50], int size, int y)
{
	if (size==0)
		{
			DrawIMG(screen, menu, 226, y);
			blobprintf (screen, msg, 320-(strlen(msg)*9), y+16, 255, 255, 0, 0);
			blur (screen, blursurface2, 320-strlen(msg)*9, y+18, 321+strlen(msg)*9,y+44);
			box (screen, 226,y,226+186,y+menuy2, 0, 0,   0);
		}
	if (size==1);
}

void drawblocks(SDL_Surface *screen, int menuno)
{
int i, j;
char messages[5][15];
	DrawBG(screen);
	if (menuno==1)
		{
			i=3;
			drawblock (screen, "New Game", 0, menuy+menuy2);
			drawblock (screen, "Options", 0, menuy+2*menuy2);
			drawblock (screen, "Quit Game", 0, menuy+3*menuy2);
		}
	if (menuno==2)
		{
			i=3;
			drawblock (screen, "Rounds", 0, menuy+menuy2);
			drawblock (screen, "Wave fx", 0, menuy+2*menuy2);
			drawblock (screen, "Main Menu", 0, menuy+3*menuy2);
		}
}

void MenuLoop(SDL_Surface *screen)
{
int menuing=0, number=1, quit=0, enter=0;
char msg[60];
int totalwinner=0;
int mviive=-1;
int menuno=1;
int j;
char clicked[3];
char escape=0;
menus[1]=3;
menus[2]=3;

	drawblocks(blursurface2,1);
	crossfade (screen, blursurface, blursurface2);
	drawblocks (screen, 1);
	while (escape==0 && quit==0)
		{
			if (mviive>=0) mviive--;
			keys = SDL_GetKeyState(NULL);

			escape=chkkeys();
			if (escape<2) escape=0;

			if (mviive==0)
				{
					DrawPartOfIMG (blursurface2, screen, 320-strlen(msg)*9, 40, strlen(msg)*18, 32, 320-strlen(msg)*9, 40);
				}

			if (mviive>1)
				{
					int a;
					a = mviive*2;
					blobprintf (screen, msg, 320-strlen(msg)*9, 40, 255,255,255, a);
				}

			clicked[2]=clicked[1];

			if (SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(1)) clicked[1]=1;
				else
					if (SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(2)) clicked[1]=2;
						else
							if (SDL_GetMouseState(NULL, NULL)&SDL_BUTTON(3)) clicked[1]=3;
								else
									clicked[1]=0;
			SDL_GetMouseState(&mxpos, &mypos);

			for (j=1;j<=menus[menuno];j++)
				{
					if (mxpos >= 226 && mxpos <= 226+186 && mypos >= menuy+j*menuy2 && mypos <menuy+(j+1)*menuy2+67) number=j;
				}


			if (number<1) number=menus[menuno];
			if (number>menus[menuno]) number=1;

			box (screen, 226,menuy+number*menuy2,226+186,menuy+(number+1)*menuy2, 255, 255,   0);
			SDL_Flip(screen);
			box (screen, 226,menuy+number*menuy2,226+186,menuy+(number+1)*menuy2, 0, 0,   0);

			if (menuno == 1)											// main menu
				{
					if (clicked[1]==0 && clicked[2]==1)
						{
							if (number==1)
								{
									DrawBG(screen);
									DrawIMG (blursurface, screen, 0, 0);
									totalwinner=GameLoop(screen);
									if (totalwinner!=0) sprintf (msg, "Player %d wins the game!", totalwinner);
										else
											sprintf (msg,      "---  Game  skipped  ---");
									totalwinner=0;
									enter=0;
									number=1;
									drawblocks(blursurface2,1);
									blobprintf (blursurface2, msg, 130, 40, 255,255,255,0);
									crossfade (screen, blursurface, blursurface2);
									DrawBG (blursurface2);
								}
							if (number==2)
								{
									menuno=2;
									drawblocks(screen, menuno);
								}
							if (number==3) quit=1;
							clicked[2]=0;
						}
				}
			if (menuno == 2)											// options
				{
					if (clicked[2]!=0 && clicked[1]==0)
						{
							if (number==1)
								{
									if (clicked[2]==1)winsneeded++;
									if (clicked[2]==3)winsneeded--;
									if (winsneeded <1) winsneeded=4;
									if (winsneeded >4) winsneeded=1;
									mviive=250;
									sprintf (msg, "Rounds per game changed to %d", winsneeded);
									DrawPartOfIMG (blursurface2, screen, 0, 40, 639, 32, 0, 40);
									blobprintf (screen, msg, 320-(strlen(msg)*9),  40, 255,255,255,0);
								}
							if (number==2)
								{
									if (clicked[2]==1) option_wave_effect*=-1;
									if (clicked[2]==2) option_wave_effect=1;
									if (clicked[2]==3) option_wave_effect=-1;
									mviive=250;
									sprintf (msg, "Wave effect turned ");
									if (option_wave_effect==-1) sprintf (msg, "%soff", msg);
									if (option_wave_effect==1) sprintf (msg, "%son", msg);
									DrawPartOfIMG (blursurface2, screen, 0, 40, 639, 32, 0, 40);
								}
							if (number==3) menuno=1;drawblocks(screen, menuno);
							clicked[2]=0;
						}
				}

			newtime=SDL_GetTicks();
			while (newtime-oldtime < 1000/fps && escape==0)
			{
					newtime=SDL_GetTicks();
					enter=chkkeys();
					if (enter>1) escape=1;
			}
		}
}


void DrawBlobtroxLogo(SDL_Surface *screen, SDL_Surface *blobtrox)
{
/*	int x, y;
	Uint16 scrpitch = (Uint16)screen->pitch;
	for (y=0;y<480;y++)
		for (x=0;x<640;x++)
			{
					Uint32 *bufp = (Uint32 *)screen->pixels + y* ((int)scrpitch/4) +x;
					*bufp = int( (255*sin(pi*x/640) + 255*sin(pi*y/480))/2 );
			}*/
	int x, y,i;
	Uint16 scrpitch = (Uint16)screen->pitch;
	for (y=0;y<480;y++)
		for (x=0;x<640;x++)
			{
					Uint32 *bufp = (Uint32 *)screen->pixels + y* ((int)scrpitch/4) +x;
					*bufp = 0;
			}
	DrawIMG(screen, blobtrox, 49, 100);
	blobprintf (screen, "Make", 280, 270, 255,255,255,31337);
}

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

  int skpd;
  Uint8 R, G, B;
  atexit(SDL_Quit);
  if ( SDL_Init(SDL_INIT_VIDEO) < 0) {
      fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
      exit(1);
  }

  rand();

  if (argc>1)
	{
		int t;
		for (t=1;t<argc;t++)
			{
				if (*argv[t]=='f' || *argv[t]=='F')
					{
						screen = SDL_SetVideoMode(640, 480, 32, SDL_FULLSCREEN);
						if (screen==NULL) fprintf (stderr, "Couldn't set fullscreen mode, running in window!\n");
					}
				if (*argv[t]=='c' || *argv[t]=='C')
					{
						option_ai=1;
						fprintf (stderr, "Turning AI on\n");
					}
			}

	}
  if (screen==NULL) screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);//SWSURFACE); //SDL_FULLSCREEN);
  if (screen==NULL) {
	fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
	exit(1);
	}

  SDL_WM_SetCaption ("Balloon Chase", 0);
  checkfiles();

  FILE *OPTFILE=fopen ("<BalloonC$Dir>/balloonchase.dat", "r");
  char datmsg[60];
  char varmistus[60];

  sprintf (datmsg, "Balloon Chase settings file -- Do not edit manually!");

  char tmp2;
  for (tmp2=0;tmp2<=strlen(datmsg);tmp2++)
	{
		varmistus[tmp2]=fgetc(OPTFILE);
	}

  varmistus[strlen(datmsg)]='\0';

  if ( strcmp(varmistus, datmsg)==0)
	{
		winsneeded=fgetc(OPTFILE);
		option_wave_effect=fgetc(OPTFILE)-2;
		fprintf (stderr, "Successfully loaded balloonchase.dat\n");
	}
		else
	{
		createdat(2, 1);
	}
  fclose (OPTFILE);

  InitImages();

  Slock(blursurface2);
  Slock(blursurface);
  Slock(screen);


  Uint8 *pixels = (Uint8 *)screen->pixels;
  Uint16 blurpitch = (Uint16)blursurface->pitch;

  DrawBlobtroxLogo (blursurface, blobtrox);
  skpd=fadein (screen, blursurface);
  if (skpd==0) skpd=WaitSec(1400);

  DrawIMG(blursurface2, balloonchase, 0,0);

  crossfade(screen, blursurface, blursurface2);		// Crossfade between the logo and balloon chase-screen
  DrawIMG(screen, blursurface2,0,0);
  SDL_Flip (screen);

  DrawIMG(blursurface, balloonchase, 0, 0);		// Put the balloon chase-screen to blursurface
  if (skpd==0) skpd=WaitSec(1200);

  Sulock(screen);
  Sulock(blursurface);
  Sulock(blursurface2);


//  DrawBG();

  MenuLoop (screen);
  DrawIMG (blursurface, screen, 0, 0);
  fadeout (screen, blursurface);
  createdat(winsneeded, (char)option_wave_effect);
  exittexts();
	/* Program should never get here :) */
  return(0);
}
