version 0.1
[zeRace] / zeRace.c
1 #include <dirent.h>
2 #include <signal.h>
3 #include <SDL.h>
4 #include <SDL_image.h>
5 #include <SDL_net.h>
6 #include <SDL_mixer.h>
7 #include <math.h>
8 #include "sdl.h"
9
10 #define MAXLINELENGTH 1000
11 #define VERSION "0.1"
12 #define WIDTH 1024
13 #define HEIGHT 768
14
15 /* global variables */
16
17 struct track
18 {
19   char *name;
20   char *title;
21   char *author;
22   char *version;
23   char *full;
24   char *function;
25   int x,y,a;
26   struct track *prev;
27   struct track *next;
28 } *tracklist=NULL;
29
30 int fullscreen=0;
31 int sound=0;
32 char pseudo[MAXLINELENGTH]="anonymous";
33 char url[MAXLINELENGTH]="";
34 SDL_Surface *screen;
35 SDL_Surface *cars[256];
36
37 void zeRace_exit()
38 {
39   printf("quit\n");
40   if (sound) Mix_CloseAudio();
41   SDLNet_Quit();
42   SDL_Quit();
43   /*
44   save_config();
45   zeRace_send_ghosts();
46   close_sdl();
47   */
48   exit(0);
49 }
50
51
52 void zeRace_read_config()
53 {
54   FILE *fic;
55   char line[MAXLINELENGTH];
56   char keyword[MAXLINELENGTH];
57   char value[MAXLINELENGTH];
58   int configlines=0;
59   
60   if ((fic=fopen("zeRace.cfg","rt"))==NULL)
61   {
62     fprintf(stderr,"can't open config file \"zeRace.cfg\"\n");
63     exit(1);
64   }
65
66   while (fgets(line,MAXLINELENGTH,fic))
67   {
68     configlines++;
69     if (*line!=';' && *line!='#' && *line!='/' && *line!='-' && *line!='\n')
70     {
71       if ((sscanf(line,"%s : %s\n",(char *)&keyword,(char *)&value))!=2) { fprintf(stderr,"error in config file : each line must have the format \"keyword : value\" (line %d)\n",configlines); exit(1); }
72       
73       if (strcmp("pseudo",keyword)==0)
74         strcpy(pseudo,value);
75       else
76       
77       if (strcmp("url",keyword)==0)
78         strcpy(url,value);
79       else
80       
81       if (strcmp("fullscreen",keyword)==0)
82       {
83         if (strcmp("no",value)==0) fullscreen=0;
84         else if (strcmp("yes",value)==0) fullscreen=1;
85         else { fprintf(stderr,"unknown value for \"fullscreen\" option, must be \"yes\" or \"no\"\n"); exit(1); }
86       }
87       else
88       
89       if (strcmp("sound",keyword)==0)
90       {
91         if (strcmp("no",value)==0) sound=0;
92         else if (strcmp("yes",value)==0) sound=1;
93         else { fprintf(stderr,"unknown value for \"sound\" option, must be \"yes\" or \"no\"\n"); exit(1); }
94       }
95       
96       else { fprintf(stderr,"error in config file : \"%s\" is an unknown keyword (line %d)\n",keyword,configlines); exit(1); }        
97     }
98   }
99 }
100
101
102 void zeRace_get_tracks()
103 {
104   struct dirent **namelist;
105   int i;
106   unsigned char ext[5];
107   FILE *fic;
108   char *shortname=NULL;
109   char line[MAXLINELENGTH];
110   int configlines;
111   struct track *tmp=NULL,*first=NULL;
112   DIR *dirp;
113   struct dirent *dp;
114
115   if ((dirp=opendir("tracks"))==NULL) { fprintf(stderr,"can't open \"tracks\" directory or no tracks\n"); return; }
116   
117   while (dp=readdir(dirp)) if (strlen(dp->d_name)>4)
118   {
119     shortname=(char *)realloc(shortname,strlen(dp->d_name)-3);
120     strncpy(shortname,dp->d_name,strlen(dp->d_name)-4);
121     shortname[strlen(dp->d_name)-4]='\0';
122     for (i=0;i<5;i++) ext[i]=tolower(dp->d_name[strlen(dp->d_name)-4+i]);
123     if (strcmp(".txt",ext)==0)
124     {
125       tmp=(struct track *)malloc(sizeof(struct track));
126       if (first==NULL) first=tmp;
127       tmp->name=(char *)malloc(strlen(shortname)+1);
128       strcpy(tmp->name,shortname);
129       tmp->title="";
130       tmp->author="";
131       tmp->version="";
132       tmp->x=10;
133       tmp->y=10;
134       tmp->a=0;
135       configlines=0;
136       sprintf(line,"tracks/%s.txt",shortname);
137       if ((fic=fopen(line,"rt"))==NULL)
138       {
139         fprintf(stderr,"can't open track file \"%s\"\n",line);
140         zeRace_exit();
141       }
142       while (fgets(line,MAXLINELENGTH,fic))
143       {
144         configlines++;
145         if (*line!=';' && *line!='#' && *line!='/' && *line!='-' && *line!='\n')
146         {
147           for (i=0;i<strlen(line)-2;i++) if (line[i]==' ' && line[i+1]==':' && line[i+2]==' ') break;
148           if (line[i]!=' ' || line[i+1]!=':' || line[i+2]!=' ')
149           {
150             fprintf(stderr,"error in track file \"%s\" : each line must have the format \"keyword : value\" (line %d)\n",shortname,configlines);
151             exit(1);
152           }
153           line[i]='\0';
154           
155           if (strcmp("title",line)==0)
156           {
157             tmp->title=(char *)malloc(strlen(line+i+3)+1);
158             strcpy(tmp->title,line+i+3);
159           }
160           else
161           
162           if (strcmp("author",line)==0)
163           {
164             tmp->author=(char *)malloc(strlen(line+i+3)+1);
165             strcpy(tmp->author,line+i+3);
166           }
167           else
168           
169           if (strcmp("x",line)==0)
170             tmp->x=atoi(line+i+3);
171           else
172           
173           if (strcmp("y",line)==0)
174             tmp->y=atoi(line+i+3);
175           else
176           
177           if (strcmp("a",line)==0)
178             tmp->a=atoi(line+i+3);
179           else
180           
181           if (strcmp("version",line)==0)
182           {
183             tmp->version=(char *)malloc(strlen(line+i+3)+1);
184             strcpy(tmp->version,line+i+3);
185           }
186           
187           else { fprintf(stderr,"error in track file \"%s\" : \"%s\" is an unknown keyword (line %d)\n",shortname,line,configlines); exit(1); }        
188         }
189       }
190       fclose(fic);
191       tmp->full=(char *)malloc(strlen(line)+20);
192       sprintf(tmp->full,"tracks/%s.png",shortname);
193       tmp->function=(char *)malloc(strlen(line)+30);
194       sprintf(tmp->function,"tracks/%s_function.png",shortname);
195       tmp->prev=tracklist;
196       if (tmp->prev) tmp->prev->next=tmp;
197       tracklist=tmp;
198     }
199   }
200   if (!tmp) { fprintf(stderr,"no circuits found !\n"); zeRace_exit(); }
201   while (tmp->prev) tmp=tmp->prev;
202   tmp->prev=tracklist;
203   tracklist->next=tmp;
204 }
205
206
207 void zeRace_init()
208 {
209   SDL_Surface *car;
210   int i,flags;
211   
212   signal(SIGINT,zeRace_exit);
213   signal(SIGTERM,zeRace_exit);
214   zeRace_read_config();
215   //zeRace_check_version();
216   zeRace_get_tracks();
217   //zeRace_get_ghosts();
218   
219   srand(time(NULL));
220   
221   if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0)
222   {
223     fprintf(stderr,"could not initialize SDL : %s\n",SDL_GetError());
224     zeRace_exit();
225   }
226   atexit(SDL_Quit);
227   
228   if(SDLNet_Init()==-1)
229   {
230     fprintf(stderr,"could not initialize SDLNet : %s\n",SDLNet_GetError());
231     zeRace_exit();
232   }
233
234   flags=SDL_HWSURFACE|SDL_ANYFORMAT;
235   if (fullscreen) flags|=SDL_FULLSCREEN;
236   
237   if ((screen=SDL_SetVideoMode(WIDTH,HEIGHT,32,flags))==NULL)
238   {
239     fprintf(stderr,"could not create a surface : %s\n",SDL_GetError());
240     zeRace_exit();
241   }
242   
243   SDL_WM_SetIcon(SDL_LoadBMP("icon.bmp"),NULL);
244   SDL_WM_SetCaption("zeRace " VERSION,"zeRace " VERSION);
245   SDL_ShowCursor(SDL_DISABLE);
246   
247   if (sound) if (Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,512)<0)
248   {
249     fprintf(stderr,"Mix_OpenAudio error\n");
250     zeRace_exit();
251   }
252
253   car=IMG_Load("sprites/car.png");
254   for (i=0;i<256;i++)
255   {
256     float x,y;
257     float tcos,tsin;
258     cars[i]=SDL_CreateRGBSurface(SDL_SWSURFACE,car->h*2,car->h*2,32,0x000000ff,0x0000ff00,0x00ff0000,0xff000000);
259     if(cars[i]==NULL)
260     {
261       fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
262       exit(1);
263     }
264     tcos=cos(2*M_PI*i/256);
265     tsin=sin(2*M_PI*i/256);
266     for (x=0;x<cars[i]->w;x++) for (y=0;y<cars[i]->h;y++)
267     {
268       int x2,y2;
269       Uint32 col;
270       x2=(x-cars[i]->w/2.0)*tcos+(y-cars[i]->h/2.0)*tsin+car->w/2.0;
271       y2=(x-cars[i]->w/2.0)*tsin-(y-cars[i]->h/2.0)*tcos+car->h/2.0;
272       if (x2>0 && x2<car->w && y2>0 && y2<car->h)
273         putpixel(cars[i],x,y,getpixel(car,x2,y2));
274     }
275   }
276 }
277
278
279 void zeRace_send_time(float x,float y,float speed,float angle,int btime,char *bkeys)
280 {
281   IPaddress ip;
282   TCPsocket tcpsock;
283   char *temp;
284   char *msg1=
285     "POST /zerace/time.php HTTP/1.1\n"
286     "Host: royale.zerezo.com\n"
287     "User-Agent: zeRace " VERSION "\n"
288     "Content-Type: application/x-www-form-urlencoded\n"
289     "Content-Length: 99999\n"
290     "\n"
291     "pseudo=";
292   char *msg2="&url=";
293   char *msg3="&track=";
294   char *msg4="&btime=";
295   char *msg5="&x=";
296   char *msg6="&y=";
297   char *msg7="&speed=";
298   char *msg8="&angle=";
299   char *msg9="&bkeys=";
300   int len,result;
301   
302   printf("sending time... ");
303   fflush(stdout);
304
305   if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
306   {
307     fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
308     return;
309   }
310   
311   tcpsock=SDLNet_TCP_Open(&ip);
312   if(!tcpsock)
313   {
314     fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
315     return;
316   }
317
318   temp=(char *)malloc(strlen(msg1)+strlen(pseudo)+strlen(msg2)+strlen(url)+strlen(msg3)+strlen(tracklist->name)+strlen(msg4)+10+strlen(msg5)+10+strlen(msg6)+10+strlen(msg7)+10+strlen(msg8)+10+strlen(msg9)+strlen(bkeys)+100);
319   sprintf(temp,"%s%s%s%s%s%s%s%d%s%f%s%f%s%f%s%f%s%s\n",msg1,pseudo,msg2,url,msg3,tracklist->name,msg4,btime,msg5,x,msg6,y,msg7,speed,msg8,angle,msg9,bkeys);
320   
321   len=strlen(temp);
322   result=SDLNet_TCP_Send(tcpsock,temp,len);
323   if(result<len)
324     fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
325   else
326     printf(" done\n");
327
328   SDLNet_TCP_Close(tcpsock);
329 }
330
331
332 void zeRace_launch()
333 {
334   SDL_Surface *cir,*fun;
335   SDL_Rect pos,size;
336   SDL_Event event;
337   int ku=0,kd=0,kl=0,kr=0;
338   int i,time=0,lastcheck=0,btime=10000;
339   float ox,oy;
340   float x,y,angle,speed;
341   float sx,sy,sangle,sspeed;
342   float bx,by,bangle,bspeed;
343   int c,r,v,b;
344   int temp;
345   char keys[10000];
346   char bkeys[10000];
347   char text[10];
348         Mix_Music *light,*engine,*crash,*slide;
349   int lastsound_time=-999,alltime=0,lastsound=0;
350
351   cir=IMG_Load(tracklist->full);
352   fun=IMG_Load(tracklist->function);
353   
354   sspeed=speed=0;
355   sangle=angle=(tracklist->a*2*M_PI/360);
356   sx=x=tracklist->x;
357   sy=y=tracklist->y;
358   lastcheck=0;
359   time=0;
360
361   if (sound) if (!(light=Mix_LoadMUS("sounds/light.wav")) || !(engine=Mix_LoadMUS("sounds/engine.wav")) || !(crash=Mix_LoadMUS("sounds/crash.wav")) || !(slide=Mix_LoadMUS("sounds/slide.wav")))
362   {
363     fprintf(stderr,"Mix_LoadMUS error\n");
364     zeRace_exit();
365   }
366   
367   for (i=4;i>=-1;i--)
368   {
369     char startup[15]="sprites/?.png";
370     SDL_Surface *temp;
371     startup[8]='0'+i;
372     pos.x=x;
373     pos.y=y;
374     SDL_BlitSurface(cir,NULL,screen,NULL);
375     SDL_BlitSurface(cars[(unsigned char)(256*angle/2.0/M_PI)%256],NULL,screen,&pos);
376     if (i!=4 && i!=-1)
377     {
378       temp=IMG_Load(startup);
379       pos.x=screen->w/2-temp->w/2;
380       pos.y=screen->h/2-temp->h/2;
381       SDL_BlitSurface(temp,NULL,screen,&pos);
382       SDL_FreeSurface(temp);
383     }
384     if (sound) if (i!=4) Mix_PlayMusic(light,1);
385     SDL_Flip(screen);
386     if (i!=-1) SDL_Delay(1000);
387   }
388   
389   for (;;)
390   {    
391     size.w=cars[0]->w;
392     size.h=cars[0]->h;
393     pos.x=x;
394     pos.y=y;
395     SDL_BlitSurface(cir,&pos,screen,&pos);
396     
397     ox=x;
398     oy=y;
399     speed*=0.995;
400     x=x-cos(angle)*speed;
401     y=y-sin(angle)*speed;
402     
403     if (x<0 || x>screen->w-cars[0]->w || y<0 || y>screen->h-cars[0]->h)
404     {
405       x=ox;
406       y=oy;
407       speed=0;
408     }
409     
410     pos.x=x;
411     pos.y=y;
412     i=(unsigned char)(256*angle/2.0/M_PI)%256;
413     SDL_BlitSurface(cars[i],NULL,screen,&pos);
414     SDL_UpdateRect(screen,ox,oy,cars[i]->w,cars[i]->h);
415     SDL_UpdateRect(screen,x,y,cars[i]->w,cars[i]->h);
416     
417     if (kl) angle-=0.01;
418     if (kr) angle+=0.01;
419     if (ku) speed+=0.01*2;
420     if (kd) speed-=0.01;
421
422     if (lastsound_time+100<alltime)
423     {
424       lastsound=0;
425       lastsound_time=alltime;
426       if (sound) Mix_PlayMusic(engine,1);
427     }
428     
429     if (kd && speed>0.5 || speed>2.0 && !ku)
430     {
431
432       if (lastsound_time+100<alltime || lastsound<1)
433       {
434         lastsound=1;
435         lastsound_time=alltime;
436         if (sound) Mix_PlayMusic(slide,1)==-1;
437       }
438
439       putpixel(cir,x+cars[i]->w/2+cos(angle)*cars[i]->w/3-sin(angle)*2,y+cars[i]->h/2+sin(angle)*cars[i]->h/3+cos(angle)*2,0);
440       putpixel(cir,x+cars[i]->w/2+cos(angle)*cars[i]->w/3+sin(angle)*5,y+cars[i]->h/2+sin(angle)*cars[i]->h/3-cos(angle)*5,0);
441       if (kd)
442       {
443         putpixel(cir,x+cars[i]->w/2+cos(angle)*cars[i]->w/3-sin(angle)*3,y+cars[i]->h/2+sin(angle)*cars[i]->h/3+cos(angle)*3,0);
444         putpixel(cir,x+cars[i]->w/2+cos(angle)*cars[i]->w/3+sin(angle)*4,y+cars[i]->h/2+sin(angle)*cars[i]->h/3-cos(angle)*4,0);
445       }
446     }
447     
448     c=getpixel(fun,x+cars[i]->w/2,y+cars[i]->h/2);
449     r=c&0x000000ff;
450     v=(c&0x0000ff00)>>8;
451
452     if (v==0)
453     {
454       x=ox;
455       y=oy;
456       if (lastsound_time+100<alltime || lastsound<2)
457       {
458         lastsound=2;
459         lastsound_time=alltime;
460         if (sound) Mix_PlayMusic(crash,1)==-1;
461       }
462     }
463     speed-=speed*(255-v)/1000;
464    
465     if (r/8==lastcheck+1) lastcheck++;
466     if (r/8==0 && lastcheck==31)
467     {
468       printf("time = %d\"%d\n",time*5/1000,time*5%1000);
469       if (btime==-1 || time<btime)
470       {
471         btime=time;
472         bx=sx;
473         by=sy;
474         bangle=sangle;
475         bspeed=sspeed;
476         keys[time]='\0';
477         memcpy(bkeys,keys,btime);
478       }
479       lastcheck=0;
480       time=0;
481       sx=x;
482       sy=y;
483       sangle=angle;
484       sspeed=speed;
485     }
486     
487     while (SDL_PollEvent(&event))
488     {
489       switch (event.type)
490       {
491         case SDL_QUIT:
492           zeRace_exit();
493           break;
494         case SDL_KEYDOWN:
495           switch (event.key.keysym.sym)
496           {
497             case SDLK_ESCAPE: // escape
498               Mix_FreeMusic(light);
499               Mix_FreeMusic(engine);
500               Mix_FreeMusic(crash);
501               Mix_FreeMusic(slide);
502               if (btime<10000) zeRace_send_time(bx,by,bspeed,bangle,btime,bkeys);
503               return;  
504             case SDLK_UP: //up
505               ku=1;
506               break;
507             case SDLK_DOWN: //down
508               kd=1;
509               break;
510             case SDLK_LEFT: //left
511               kl=1;
512               break;
513             case SDLK_RIGHT: //right
514               kr=1;
515               break;
516           }
517           break;
518         case SDL_KEYUP:
519           switch (event.key.keysym.sym)
520           {
521             case SDLK_UP: //up
522               ku=0;
523               break;
524             case SDLK_DOWN: //down
525               kd=0;
526               break;
527             case SDLK_LEFT: //left
528               kl=0;
529               break;
530             case SDLK_RIGHT: //right
531               kr=0;
532               break;
533           }
534           break;
535       }
536     }
537     
538     SDL_Delay(5);
539     if (time<btime) keys[time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
540     time++;
541     alltime++;
542   }
543 }
544
545
546 void zeRace_splash()
547 {
548   SDL_Surface *splash;
549   SDL_Rect pos;
550   int i;
551   char temp[20]="splashs/0.jpg";
552   
553   SDL_FillRect(screen,NULL,0x000000);
554   temp[8]=rand()%3+'1';
555   splash=IMG_Load(temp);
556   pos.x=screen->w/2-splash->w/2-1;
557   pos.w=splash->w+2;
558   pos.y=screen->h/2-splash->h/2-1;
559   pos.h=splash->h+2;
560   SDL_FillRect(screen,&pos,0xffffff);
561   pos.x=screen->w/2-splash->w/2;
562   pos.y=screen->h/2-splash->h/2;
563   SDL_BlitSurface(splash,NULL,screen,&pos);
564   print(screen,screen->w/2-strlen("zeRace " VERSION)*5,screen->h/2-splash->h/2-20,"zeRace " VERSION);
565   SDL_FreeSurface(splash);
566   SDL_Flip(screen);
567   SDL_Delay(2000);
568 }
569
570
571 void zeRace_menu()
572 {
573   SDL_Event event;
574   
575   void update()
576   {
577     SDL_Surface *full,*preview;
578     SDL_Rect pos;
579     SDL_FillRect(screen,NULL,0x000000);
580     print(screen,WIDTH/2-28*5,HEIGHT/6,"* Please choose your race *");
581     print(screen,WIDTH/2-strlen(tracklist->title)*5,5*HEIGHT/6-20,tracklist->title);
582     print(screen,WIDTH/2-(strlen(tracklist->author)+strlen("Author : "))*5,5*HEIGHT/6+0,"Author : ");
583     print(screen,WIDTH/2-(strlen(tracklist->author)-strlen("Author : "))*5,5*HEIGHT/6+0,tracklist->author);
584     print(screen,WIDTH/2-(strlen(tracklist->version)+strlen("Version : "))*5,5*HEIGHT/6+20,"Version : ");
585     print(screen,WIDTH/2-(strlen(tracklist->version)-strlen("Version : "))*5,5*HEIGHT/6+20,tracklist->version);
586     full=IMG_Load(tracklist->full);
587     preview=(SDL_Surface *)zoomSurface(full,0.5,0.5,1);
588     SDL_FreeSurface(full);
589     pos.x=WIDTH/2-preview->w/2-1;
590     pos.w=preview->w+2;
591     pos.y=screen->h/2-preview->h/2-1;
592     pos.h=preview->h+2;
593     SDL_FillRect(screen,&pos,0xffffff);
594     pos.x=WIDTH/2-preview->w/2;
595     pos.y=screen->h/2-preview->h/2;
596     SDL_BlitSurface(preview,NULL,screen,&pos);
597     SDL_FreeSurface(preview);
598     SDL_Flip(screen);
599   }
600   
601   update();
602   for (;;)
603   {
604     while (SDL_PollEvent(&event))
605     {
606       switch (event.type)
607       {
608         case SDL_QUIT:
609           zeRace_exit();
610           break;
611         case SDL_KEYDOWN:
612           switch (event.key.keysym.sym)
613           {
614             case SDLK_ESCAPE: // escape
615               zeRace_exit();
616               break;
617             case SDLK_RETURN: //enter
618             case SDLK_SPACE: //space
619               zeRace_launch();
620               update();
621               break;
622             case SDLK_LEFT: //left
623               tracklist=tracklist->next;
624               update();
625               break;
626             case SDLK_RIGHT: //right
627               tracklist=tracklist->prev;
628               update();
629               break;
630           }
631           break;
632       }
633     }
634     SDL_Delay(10);
635   }
636 }
637
638
639 int main(int argc,char *argv[])
640 {
641   zeRace_init();
642   zeRace_splash();
643   zeRace_menu();
644   zeRace_exit();
645   return 0;
646 }