Git

1 /*
2  * zeRace 0.7, a funny retro racing game
3  * http://royale.zerezo.com/zerace/
4  * 
5  * Copyright (C) 2004  Antoine Jacquet <royale@zerezo.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
22 #include <stdlib.h>
23 #include <time.h>
24 #include <signal.h>
25 #include <math.h>
26 #include <string.h>
27 #include <SDL.h>
28 #include <SDL_image.h>
29 #include <SDL_net.h>
30 #include <SDL_mixer.h>
31 #include <SDL_rotozoom.h>
32 #include "sdl.h"
33 #include "car.h"
34 #include "tracklist.h"
35 #include "network.h"
36 #include <sys/stat.h>
38 /* configuration constants */
39 #define COEFF 1
40 #define DELAY 7
41 #define WIDTH 1024
42 #define HEIGHT 768
43 #define MAXRECORDKEYS 9999
44 #define NB_CARS 16
46 /* some usefull colors */
47 #define C_BLACK SDL_MapRGB(screen->format,0,0,0)
48 #define C_WHITE SDL_MapRGB(screen->format,255,255,255)
49 #define C_RED SDL_MapRGB(screen->format,255,0,0)
50 #define C_ORANGE SDL_MapRGB(screen->format,255,200,0)
51 #define C_YELLOW SDL_MapRGB(screen->format,255,255,100)
52 #define T_BLACK SDL_MapRGB(cir->format,0,0,0)
54 /* tracklist */
55 struct _tracklist *tracklist;
57 /* user setup */
58 struct _config
59 {
60   char pseudo[MAXLINELENGTH];
61   char url[MAXLINELENGTH];
62   int fullscreen;
63   int sound;
64   int tire;
65   SDLKey up;
66   SDLKey down;
67   SDLKey left;
68   SDLKey right;
69   int color;
70   SDLKey boss;
71   int bynight;
72   int internet;
73 } config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6,SDLK_b,0,1};
75 /* full script for a lap */
76 struct _record
77 {
78   float x,y,angle,speed;
79   char keys[MAXRECORDKEYS];
80   int time;
81 };
83 /* display and all directions for the car */
84 SDL_Surface *screen;
85 SDL_Surface *cars[NB_CARS][256];
87 /* network stuff */
88 UDPsocket udpsock=NULL;
89 UDPpacket *packet;
90 int network_speed=1;
93 /* read the user configuration file */
94 void zeRace_read_config()
95 {
96   FILE *fic;
97   if ((fic=fopen("zeRace.cfg","rb"))==NULL)
98   {
99     fprintf(stderr,"can't open config file \"zeRace.cfg\"\n");
100     return;
101   }
102   fread(&config,sizeof(struct _config),1,fic);
103   fclose(fic);
107 /* save the user configuration file */
108 void zeRace_save_config()
110   FILE *fic;
111   if ((fic=fopen("zeRace.cfg","wb"))==NULL)
112   {
113     fprintf(stderr,"can't create config file \"zeRace.cfg\"\n");
114     return;
115   }
116   fwrite(&config,sizeof(struct _config),1,fic);
117   fclose(fic);
121 /* exit the game and clean */
122 void zeRace_exit()
124   printf("quit\n");
125   if (config.sound) Mix_CloseAudio();
126   SDLNet_Quit();
127   SDL_Quit();
128   zeRace_save_config();
129   exit(0);
133 /* check for a newer version online to warn the user */
134 void zeRace_check_version()
136   IPaddress ip;
137   TCPsocket tcpsock;
138   char *request=
139     "GET /zerace/version.php HTTP/1.0\n"
140     "Host: royale.zerezo.com\n"
141     "User-Agent: zeRace " VERSION "\n"
142     "\n";
143   char response[1024],*tmp,*version;
144   int len,result;
145   
146   if (!config.internet) return;
147   
148   printf("checking version... ");
149   fflush(stdout);
151   if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
152   {
153     fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
154     return;
155   }
156   
157   tcpsock=SDLNet_TCP_Open(&ip);
158   if (!tcpsock)
159   {
160     fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
161     return;
162   }
164   len=strlen(request);
165   result=SDLNet_TCP_Send(tcpsock,request,len);
166   if (result<len)
167     fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
168   else
169     printf("done\n");
170   
171   len=SDLNet_TCP_Recv(tcpsock,response,1024);
172   if (len<0)
173     fprintf(stderr,"SDLNet_TCP_Recv: %s\n",SDLNet_GetError());
174   else
175   {
176     tmp=response;
177     while (*tmp++!='\0') if (strncmp(tmp,"version=",8)==0)
178     {
179       version=tmp+8;
180       while (*tmp!='\n') tmp++;
181       *tmp='\0';
182       if (strcmp(version,VERSION)>0) printf("new version available !\nhttp://royale.zerezo.com/zerace/\n");
183     }
184   }
186   SDLNet_TCP_Close(tcpsock);
190 /* get remote list of tracks */
191 void zeRace_update_tracks()
193   IPaddress ip;
194   TCPsocket tcpsock;
195   char *request=
196     "GET /zerace/tracks.php HTTP/1.0\n"
197     "Host: royale.zerezo.com\n"
198     "User-Agent: zeRace " VERSION "\n"
199     "\n";
200   char response[10240],*tmp;
201   int len,result;
202   FILE *fic;
203   
204   if (!config.internet) return;
205   
206   printf("checking version and updating tracks... ");
207   fflush(stdout);
209   if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
210   {
211     fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
212     return;
213   }
214   
215   tcpsock=SDLNet_TCP_Open(&ip);
216   if (!tcpsock)
217   {
218     fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
219     return;
220   }
222   len=strlen(request);
223   result=SDLNet_TCP_Send(tcpsock,request,len);
224   if (result<len)
225     fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
226   else
227   {
228     if ((fic=fopen("tracks/list.txt","wt"))==NULL)
229     {
230       fprintf(stderr,"can't create track list\n");
231       zeRace_exit();
232     }
233     len=SDLNet_TCP_Recv(tcpsock,response,10240);
234     tmp=response;
235     while (*tmp!='\n' || *(tmp+1)!='\r') tmp++;
236     tmp+=3;
237     fwrite(tmp,1,len+response-tmp,fic);
238     fclose(fic);
239     printf("done\n");
240   }
241   
242   SDLNet_TCP_Close(tcpsock);
246 /* download the file if it is missing */
247 void zeRace_download_file(char *file)
249   IPaddress ip;
250   TCPsocket tcpsock;
251   char request[1024];
252   char response[10240],*tmp;
253   int len,result;
254   FILE *fic;
255   struct stat buf;
257   if (!config.internet) return;
258   
259   if (stat(file,&buf)<0)
260   {
261     printf("downloading file \"%s\" : ",file);
262     fflush(stdout);
263     
264     if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
265     {
266       fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
267       return;
268     }
269     
270     tcpsock=SDLNet_TCP_Open(&ip);
271     if (!tcpsock)
272     {
273       fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
274       return;
275     }
276   
277     sprintf(request,
278       "GET /zerace/%s HTTP/1.0\n"
279       "Host: royale.zerezo.com\n"
280       "User-Agent: zeRace " VERSION "\n"
281       "\n",file);
282     len=strlen(request);
283     result=SDLNet_TCP_Send(tcpsock,request,len);
284     if (result<len)
285       fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
286     else
287     {
288       if ((fic=fopen(file,"wb"))==NULL)
289       {
290         fprintf(stderr,"can't create \"%s\" file\n",file);
291         zeRace_exit();
292       }
293       len=SDLNet_TCP_Recv(tcpsock,response,10240);
294       tmp=response;
295       while (*tmp!='\n' || *(tmp+1)!='\r') tmp++;
296       tmp+=3;
297       fwrite(tmp,1,len+response-tmp,fic);
298       while ((len=SDLNet_TCP_Recv(tcpsock,response,10240))) fwrite(response,1,len,fic);
299       fclose(fic);
300       printf("done\n");
301     }
302     
303     SDLNet_TCP_Close(tcpsock);
304   }
308 /* load the car sprite and rotate it for every angles */
309 void zeRace_generate_cars()
311   int i,j;
312   SDL_Surface *car;
313   char temp[20]="sprites/carX.png";
314   for (i=0;i<NB_CARS;i++)
315   {
316     temp[11]='A'+i;
317     /* load the car sprite */
318     car=IMG_Load(temp);
319     /* and rotate it for all available angles */
320     for (j=0;j<256;j++)
321     {
322       float x,y;
323       float tcos,tsin;
324       if ((cars[i][j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,RMASK,GMASK,BMASK,AMASK))==NULL)
325       {
326         fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
327         zeRace_exit();
328       };
329       tcos=cos(2*M_PI*j/256);
330       tsin=sin(2*M_PI*j/256);
331       for (x=0;x<cars[i][j]->w;x++) for (y=0;y<cars[i][j]->h;y++)
332       {
333         int x2,y2;
334         x2=(x-cars[i][j]->w/2.0)*tcos+(y-cars[i][j]->h/2.0)*tsin+car->w/2.0;
335         y2=(x-cars[i][j]->w/2.0)*tsin-(y-cars[i][j]->h/2.0)*tcos+car->h/2.0;
336         if (x2>0 && x2<car->w && y2>0 && y2<car->h)
337           putpixel(cars[i][j],x,y,getpixel(car,x2,y2));
338       }
339     }
340     SDL_FreeSurface(car);
341   }
345 /* initialize the game */
346 void zeRace_init()
348   int flags;
349   struct _tracklist *loopcheck;
350   
351   /* do a clean exit in case of emergency */
352   signal(SIGINT,zeRace_exit);
353   signal(SIGTERM,zeRace_exit);
355   /* initialize SDL */
356   if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0)
357   {
358     fprintf(stderr,"could not initialize SDL : %s\n",SDL_GetError());
359     zeRace_exit();
360   }
361   atexit(SDL_Quit);
362   
363   /* initialize SDLNet */
364   if (SDLNet_Init()==-1)
365   {
366     fprintf(stderr,"could not initialize SDLNet : %s\n",SDLNet_GetError());
367     zeRace_exit();
368   }
370   /* read the user configuration file */
371   zeRace_read_config();
373   /* check for a newer available version */
374   zeRace_check_version();
375   
376   /* update the list of tracks */
377   zeRace_update_tracks();
378   
379   /* get the list of local tracks */
380   if (!zeRace_get_tracks(&tracklist)) zeRace_exit();
381   
382   /* download missing files */
383   loopcheck=tracklist;
384   do
385   {
386     zeRace_download_file(tracklist->full);
387     zeRace_download_file(tracklist->function);
388     tracklist=tracklist->next;
389   } while (tracklist!=loopcheck);
390   
391   srand(time(NULL));
392   
393   packet=SDLNet_AllocPacket(1024);
394   if (!packet)
395   {
396     fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
397     zeRace_exit();
398   }
400   SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL);
402   flags=SDL_HWSURFACE|SDL_ANYFORMAT;
403   if (config.fullscreen) flags|=SDL_FULLSCREEN;
404   
405   if ((screen=SDL_SetVideoMode(WIDTH,HEIGHT,32,flags))==NULL)
406   {
407     fprintf(stderr,"could not create a surface : %s\n",SDL_GetError());
408     zeRace_exit();
409   }
410   
411   SDL_WM_SetIcon(SDL_LoadBMP("icon.bmp"),NULL);
412   SDL_WM_SetCaption("zeRace " VERSION,"zeRace " VERSION);
413   SDL_ShowCursor(SDL_DISABLE);
414   
415   if (config.sound) if (Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,512)<0)
416   {
417     fprintf(stderr,"Mix_OpenAudio error\n");
418     zeRace_exit();
419   }
421   /* pre-calculate car sprites */
422   zeRace_generate_cars();
426 /* send the best time for this race to the web server */
427 void zeRace_send_time(struct _record *record)
429   IPaddress ip;
430   TCPsocket tcpsock;
431   char *temp;
432   char *msg1=
433     "POST /zerace/time.php HTTP/1.0\n"
434     "Host: royale.zerezo.com\n"
435     "User-Agent: zeRace " VERSION "\n"
436     "Content-Type: application/x-www-form-urlencoded\n"
437     "Content-Length: 99999\n"
438     "\n"
439     "pseudo=";
440   char *msg2="&url=";
441   char *msg3="&track=";
442   char *msg4="&btime=";
443   char *msg5="&x=";
444   char *msg6="&y=";
445   char *msg7="&speed=";
446   char *msg8="&angle=";
447   char *msg9="&bkeys=";
448   int len,result;
449   
450   if (!config.internet) return;
451   
452   /* if the best time is small enought to save all keys, send it */
453   if (record->time>=MAXRECORDKEYS) return;
455   printf("sending time... ");
456   fflush(stdout);
458   if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
459   {
460     fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
461     return;
462   }
463   
464   tcpsock=SDLNet_TCP_Open(&ip);
465   if (!tcpsock)
466   {
467     fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
468     return;
469   }
471   temp=(char *)malloc(strlen(msg1)+strlen(config.pseudo)+strlen(msg2)+strlen(config.url)+strlen(msg3)+strlen(tracklist->name)+strlen(msg4)+10+strlen(msg5)+10+strlen(msg6)+10+strlen(msg7)+10+strlen(msg8)+10+strlen(msg9)+strlen(record->keys)+100);
472   sprintf(temp,"%s%s%s%s%s%s%s%d%s%f%s%f%s%f%s%f%s%s\n",msg1,config.pseudo,msg2,config.url,msg3,tracklist->name,msg4,record->time,msg5,record->x,msg6,record->y,msg7,record->speed,msg8,record->angle,msg9,record->keys);
473   
474   len=strlen(temp);
475   result=SDLNet_TCP_Send(tcpsock,temp,len);
476   if (result<len)
477     fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
478   else
479     printf("done\n");
481   SDLNet_TCP_Close(tcpsock);
485 /* print a time for a lap */
486 void print_time(int x,int y,int time)
488   char temp[20];
489   int q,r;
490   time*=DELAY;
491   q=(time/1000);
492   r=(time%1000);
493   if (q>100) return;
494   temp[0]=q/10+'0';
495   temp[1]=q%10+'0';
496   temp[2]='"';
497   temp[3]=r/100+'0';
498   temp[4]=r%100/10+'0';
499   temp[5]=r%10+'0';
500   temp[6]='\0';
501   print(screen,x,y,temp);
505 /* car lights */
506 void lights(int x,int y,int r,Uint32 pixel)
508   putpixel(screen,x,y,pixel);
509   if (r>1)
510   {
511     putpixel(screen,x-1,y,pixel);
512     putpixel(screen,x+1,y,pixel);
513     putpixel(screen,x,y-1,pixel);
514     putpixel(screen,x,y+1,pixel);
515   }
516   if (r>2)
517   {
518     putpixel(screen,x-2,y,pixel);
519     putpixel(screen,x+2,y,pixel);
520     putpixel(screen,x,y-2,pixel);
521     putpixel(screen,x,y+2,pixel);
522     putpixel(screen,x-1,y-1,pixel);
523     putpixel(screen,x-1,y+1,pixel);
524     putpixel(screen,x+1,y-1,pixel);
525     putpixel(screen,x+1,y+1,pixel);
526   }
530 /* launch a new race */
531 void zeRace_launch(int alltime,int go)
533   SDL_Surface *cir,*fun,*hilight;
534   SDL_Rect pos;
535   SDL_Event event;
536   int ku=0,kd=0,kl=0,kr=0,i;
537   struct _car car;
538   struct _record current,best;
539   Mix_Music *light,*engine,*crash,*slide;
540   int lastsound_time=-999,lastsound=0;
541   int delay=DELAY;
542   int lastack=alltime;
543   struct _record net;
544   struct _car oldnetpos[MAX_CLIENTS],newnetpos[MAX_CLIENTS];
545   int l=80,o=15;
546   
547   /* free memory */
548   void free_mem()
549   {
550     SDL_FreeSurface(cir);
551     SDL_FreeSurface(fun);
552     if (config.sound)
553     {
554       Mix_FreeMusic(light);
555       Mix_FreeMusic(engine);
556       Mix_FreeMusic(crash);
557       Mix_FreeMusic(slide);
558     }
559     return;
560   }
562   cir=IMG_Load(tracklist->full);
563   /* dark the track if it is night */
564   if (config.bynight)
565   {
566     for (pos.x=0;pos.x<screen->w;pos.x++)
567       for (pos.y=0;pos.y<screen->h;pos.y++)
568       {
569         Uint32 c;
570         Uint8 r,g,b;
571         c=getpixel(cir,pos.x,pos.y);
572         SDL_GetRGB(c,cir->format,&r,&g,&b);
573         r*=0.3;
574         g*=0.3;
575         b*=0.3;
576         putpixel(cir,pos.x,pos.y,SDL_MapRGB(cir->format,r,g,b));
577       }
578   }
579   fun=IMG_Load(tracklist->function);
580   hilight=IMG_Load("sprites/light.png");
581   
582   current.speed=car.speed=0;
583   current.angle=car.angle=tracklist->a*2*M_PI/360;
584   current.x=car.ox=car.x=tracklist->x;
585   current.y=car.oy=car.y=tracklist->y;
586   car.lastcheck=0;
587   car.lapflag=0;
588   car.w=cars[0][0]->w;
589   car.h=cars[0][0]->h;
590   current.time=0;
591   best.time=MAXRECORDKEYS;
592   net.time=0;
593   memset(oldnetpos,0,MAX_CLIENTS*sizeof(struct _car));
594   memset(newnetpos,0,MAX_CLIENTS*sizeof(struct _car));
596   if (config.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")))
597   {
598     fprintf(stderr,"Mix_LoadMUS error\n");
599     zeRace_exit();
600   }
601   
602   /* startup countdown */
603   for (i=4;i>=-1;i--)
604   {
605     char startup[15]="sprites/?.png";
606     SDL_Surface *temp;
607     startup[8]='0'+i;
608     pos.x=car.x-car.w/2;
609     pos.y=car.y-car.h/2;
610     SDL_BlitSurface(cir,NULL,screen,NULL);
611     SDL_BlitSurface(cars[config.color][(unsigned char)(256*car.angle/2.0/M_PI)%256],NULL,screen,&pos);
612     if (i!=4 && i!=-1)
613     {
614       temp=IMG_Load(startup);
615       pos.x=screen->w/2-temp->w/2;
616       pos.y=screen->h/2-temp->h/2;
617       SDL_BlitSurface(temp,NULL,screen,&pos);
618       SDL_FreeSurface(temp);
619     }
620     if (config.sound) if (i!=4) Mix_PlayMusic(light,1);
621     SDL_Flip(screen);
622     if (!go) break;
623     if (i!=-1) SDL_Delay(1000);
624   }
625   
626   /* main loop */
627   for (;;)
628   {
629     /* look for user interaction */
630     while (SDL_PollEvent(&event))
631     {
632       switch (event.type)
633       {
634         case SDL_QUIT:
635           zeRace_exit();
636           break;
637         case SDL_KEYDOWN:
638           switch (event.key.keysym.sym)
639           {
640             case SDLK_ESCAPE:
641               if (udpsock)
642               {
643                 print(screen,WIDTH/2-strlen("Disconnecting !")*5,HEIGHT/2-10,"Disconnecting !");
644                 strcpy(packet->data,"disconnect");
645                 packet->len=strlen(packet->data)+1;
646                 SDLNet_UDP_Send(udpsock,-1,packet);
647                 SDL_Flip(screen);
648               }
649               zeRace_send_time(&best);
650               free_mem();
651               return;  
652             default:
653               i=event.key.keysym.sym;
654               if (i==config.up) ku=1;
655               if (i==config.down) kd=1;
656               if (i==config.left) kl=1;
657               if (i==config.right) kr=1;
658               if (i==config.boss)
659               {
660                 /* display the boss screen */
661                 SDL_Surface *boss;
662                 boss=IMG_Load("sprites/boss.png");
663                 SDL_BlitSurface(boss,NULL,screen,NULL);
664                 SDL_FreeSurface(boss);
665                 SDL_Flip(screen);
666                 /* and wait until the user press another key */
667                 for (;;) if (SDL_PollEvent(&event)) { if (event.type==SDL_KEYDOWN) break; } else SDL_Delay(10);
668                 SDL_BlitSurface(cir,NULL,screen,NULL);
669                 SDL_Flip(screen);
670               }
671               break;
672           }
673           break;
674         case SDL_KEYUP:
675           i=event.key.keysym.sym;
676           if (i==config.up) ku=0;
677           if (i==config.down) kd=0;
678           if (i==config.left) kl=0;
679           if (i==config.right) kr=0;
680           break;
681       }
682     }
683     
684     /* save pressed keys to validate best time */
685     if (current.time<MAXRECORDKEYS) current.keys[current.time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
686     current.keys[current.time+1]='\0';
687     /* and to send to server if needed */
688     if (udpsock)
689     {
690       net.keys[net.time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
691       net.keys[net.time+1]='\0';
692     }
694     /* move the car */
695     move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
697     delay=DELAY;
698     /* if we are in network mode */
699     if (udpsock!=NULL)
700     {
701       char *tmp;
702       while (SDLNet_UDP_Recv(udpsock,packet)) if (strcmp(packet->data,"positions")==0)
703       {
704         int servertime,clienttime,nb;
705         servertime=SDLNet_Read32(packet->data+strlen("positions")+1);
706         clienttime=SDLNet_Read32(packet->data+strlen("positions")+1+4);
707         nb=SDLNet_Read16(packet->data+strlen("positions")+1+4+4);
708         if (clienttime>lastack)
709         {
710           memcpy(net.keys,net.keys+clienttime-lastack,net.time+1);
711           net.time-=clienttime-lastack;
712           if (clienttime>servertime+5) delay+=DELAY;
713           if (clienttime<servertime-5) delay-=DELAY;
714           if (delay<0) delay=0;
715           for (i=0;i<MAX_CLIENTS;i++) newnetpos[i].w=0;
716           for (i=0;i<nb;i++)
717           {
718             newnetpos[i].w=newnetpos[i].h=30;
719             newnetpos[i].x=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14);
720             newnetpos[i].y=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2);
721             newnetpos[i].angle=(float)SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2)/1000;
722             newnetpos[i].color=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2);
723             newnetpos[i].lights_brake=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2);
724             newnetpos[i].lights_backwards=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2+2);
725             newnetpos[i].lights_warning=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2+2+2);
726           }
727           lastack=clienttime;
728         }
729       }
730       else if (strcmp(packet->data,"collision")==0)
731       {
732         net.time=-1;
733         net.keys[0]='\0';
734         lastack=SDLNet_Read32(packet->data+strlen("collision")+1);
735         car.x=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4)/65536-100;
736         car.y=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4)/65536-100;
737         car.speed=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4)/65536-100;
738         car.angle=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4+4)/65536-100;
739       }
740       else /* end of this network race */
741       {
742         zeRace_send_time(&best);
743         free_mem();
744         return;
745       }
746       if (strlen(net.keys)!=0)
747       {
748         tmp=packet->data;
749         strcpy(tmp,"keys");
750         tmp+=strlen(tmp)+1;
751         SDLNet_Write32(lastack,tmp);
752         tmp+=4;
753         SDLNet_Write32(car.x,tmp);
754         tmp+=4;
755         SDLNet_Write32(car.y,tmp);
756         tmp+=4;
757         strcpy(tmp,net.keys);
758         tmp+=strlen(tmp)+1;
759         packet->len=(void *)tmp-(void *)packet->data+10;
760         if (net.time%network_speed==0) if (!SDLNet_UDP_Send(udpsock,-1,packet))
761         {
762           fprintf(stderr,"SDLNet_UDP_Send: %s\n",SDLNet_GetError());
763           exit(2);
764         };
765       }
766     }
768     /* clear the old network position */
769     if (udpsock) for (i=0;i<MAX_CLIENTS;i++) if (oldnetpos[i].w)
770     {
771       pos.x=oldnetpos[i].x-car.w/2;
772       pos.y=oldnetpos[i].y-car.h/2;
773       pos.w=car.w;
774       pos.h=car.h;
775       SDL_BlitSurface(cir,&pos,screen,&pos);
776     }
777     
778     /* clear the old position */
779     pos.x=car.ox-car.w/2;
780     pos.y=car.oy-car.h/2;
781     pos.w=car.w;
782     pos.h=car.h;
783     SDL_BlitSurface(cir,&pos,screen,&pos);
784     
785     /* clear the lights */
786     if (config.bynight)
787     {
788       pos.x=car.ox-cos(car.angle)*l-sin(car.angle)*o;
789       pos.y=car.oy-sin(car.angle)*l+cos(car.angle)*o;
790       pos.x-=60;
791       pos.y-=60;
792       pos.w=120;
793       pos.h=120;
794       SDL_BlitSurface(cir,&pos,screen,&pos);
795       pos.x=car.ox-cos(car.angle)*l+sin(car.angle)*o;
796       pos.y=car.oy-sin(car.angle)*l-cos(car.angle)*o;
797       pos.x-=60;
798       pos.y-=60;
799       pos.w=120;
800       pos.h=120;
801       SDL_BlitSurface(cir,&pos,screen,&pos);
802     }
804     /* display the network car at the new position */
805     if (udpsock) for (i=0;i<MAX_CLIENTS;i++) if (newnetpos[i].w)
806     {
807       pos.x=newnetpos[i].x-car.w/2;
808       pos.y=newnetpos[i].y-car.h/2;
809       pos.w=car.w;
810       pos.h=car.h;
811       SDL_BlitSurface(cars[newnetpos[i].color][(unsigned char)(256*newnetpos[i].angle/2.0/M_PI)%256],NULL,screen,&pos);
812       
813       /* if the car is braking, display red lights */
814       if (newnetpos[i].lights_brake)
815       {
816         lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*4,3,C_RED);
817         lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*4,3,C_RED);
818       }
819       
820       /* if the car is going backwards, display white lights */
821       if (newnetpos[i].lights_backwards)
822       {
823         lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*4,3,C_WHITE);
824         lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*4,3,C_WHITE);
825       }
826       
827       /* if the car is stopped, then warning */
828       if (newnetpos[i].lights_warning && alltime/75%2)
829       {
830         lights(newnetpos[i].x-cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*5,newnetpos[i].y-sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*5,2,C_ORANGE);
831         lights(newnetpos[i].x-cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*5,newnetpos[i].y-sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*5,2,C_ORANGE);
832         lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*5,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*5,2,C_ORANGE);
833         lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*5,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*5,2,C_ORANGE);
834       }
835     }
836     
837     /* display the car at the new position */
838     pos.x=car.x-car.w/2;
839     pos.y=car.y-car.h/2;
840     pos.w=car.w;
841     pos.h=car.h;
842     SDL_BlitSurface(cars[config.color][(unsigned char)(256*car.angle/2.0/M_PI)%256],NULL,screen,&pos);
843     
844     /* if the car is braking, display red lights */
845     if (car.lights_brake)
846     {
847       lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*4,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,3,C_RED);
848       lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*4,car.y+sin(car.angle)*car.h/3-cos(car.angle)*4,3,C_RED);
849     }
850     
851     /* if the car is going backwards, display white lights */
852     if (car.lights_backwards)
853     {
854       lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*4,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,3,C_WHITE);
855       lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*4,car.y+sin(car.angle)*car.h/3-cos(car.angle)*4,3,C_WHITE);
856     }
857     
858     /* if the car is stopped, then warning */
859     if (car.lights_warning && alltime/75%2)
860     {
861       lights(car.x-cos(car.angle)*car.w/3-sin(car.angle)*5,car.y-sin(car.angle)*car.h/3+cos(car.angle)*5,2,C_ORANGE);
862       lights(car.x-cos(car.angle)*car.w/3+sin(car.angle)*5,car.y-sin(car.angle)*car.h/3-cos(car.angle)*5,2,C_ORANGE);
863       lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*5,car.y+sin(car.angle)*car.h/3+cos(car.angle)*5,2,C_ORANGE);
864       lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*5,car.y+sin(car.angle)*car.h/3-cos(car.angle)*5,2,C_ORANGE);
865     }
866     
867     /* display the lights */
868     if (config.bynight)
869     {
870       lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*3,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,2,C_RED);
871       lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*3,car.y+sin(car.angle)*car.h/3-cos(car.angle)*4,2,C_RED);
872       lights(car.x-cos(car.angle)*car.w/3-sin(car.angle)*4,car.y-sin(car.angle)*car.h/3+cos(car.angle)*4,3,C_YELLOW);
873       lights(car.x-cos(car.angle)*car.w/3+sin(car.angle)*4,car.y-sin(car.angle)*car.h/3-cos(car.angle)*4,3,C_YELLOW);
874       pos.x=car.x-cos(car.angle)*l-sin(car.angle)*o;
875       pos.y=car.y-sin(car.angle)*l+cos(car.angle)*o;
876       pos.x-=50;
877       pos.y-=50;
878       pos.w=100;
879       pos.h=100;
880       SDL_BlitSurface(hilight,NULL,screen,&pos);
881       pos.x=car.x-cos(car.angle)*l+sin(car.angle)*o;
882       pos.y=car.y-sin(car.angle)*l-cos(car.angle)*o;
883       pos.x-=50;
884       pos.y-=50;
885       pos.w=100;
886       pos.h=100;
887       SDL_BlitSurface(hilight,NULL,screen,&pos);
888     }
889     
890     /* update display */
891     if (udpsock)
892     {
893       for (i=0;i<MAX_CLIENTS;i++)
894       {
895         if (oldnetpos[i].w) SDL_UpdateRect(screen,oldnetpos[i].x-car.w/2,oldnetpos[i].y-car.h/2,car.w,car.h);
896         if (newnetpos[i].w) SDL_UpdateRect(screen,newnetpos[i].x-car.w/2,newnetpos[i].y-car.h/2,car.w,car.h);
897       }
898       memcpy(oldnetpos,newnetpos,MAX_CLIENTS*sizeof(struct _car));
899     }
900     SDL_UpdateRect(screen,car.ox-car.w/2,car.oy-car.h/2,car.w,car.h);
901     SDL_UpdateRect(screen,car.x-car.w/2,car.y-car.h/2,car.w,car.h);
902     
903     /* update the lights by night */
904     if (config.bynight)
905     {
906       pos.x=car.x-cos(car.angle)*l-sin(car.angle)*15;
907       pos.y=car.y-sin(car.angle)*l+cos(car.angle)*15;
908       pos.x-=60;
909       pos.y-=60;
910       pos.w=120;
911       pos.h=120;
912       if (pos.x<0) pos.x=0;
913       if (pos.y<0) pos.y=0;
914       if (pos.x+pos.w>screen->w) pos.w=screen->w-pos.x;
915       if (pos.y+pos.h>screen->h) pos.h=screen->h-pos.y;
916       SDL_UpdateRect(screen,pos.x,pos.y,pos.w,pos.h);
917       pos.x=car.x-cos(car.angle)*l+sin(car.angle)*15;
918       pos.y=car.y-sin(car.angle)*l-cos(car.angle)*15;
919       pos.x-=60;
920       pos.y-=60;
921       pos.w=120;
922       pos.h=120;
923       if (pos.x<0) pos.x=0;
924       if (pos.y<0) pos.y=0;
925       if (pos.x+pos.w>screen->w) pos.w=screen->w-pos.x;
926       if (pos.y+pos.h>screen->h) pos.h=screen->h-pos.y;
927       SDL_UpdateRect(screen,pos.x,pos.y,pos.w,pos.h);
928     }
929     
930     memcpy(oldnetpos,newnetpos,MAX_CLIENTS*sizeof(struct _car));
931     
932     /* play engine sound if no sound is currently playing */
933     if (lastsound_time+100<alltime)
934     {
935       lastsound=0;
936       lastsound_time=alltime;
937       if (config.sound) Mix_PlayMusic(engine,1);
938     }
939     
940     /* if the car is fast or braking, it slides */
941     if ((kd && car.speed>0.5) || (car.speed>2.0 && !ku))
942     {
943       /* if the only sound is the engine, play the slide sound */
944       if (lastsound_time+100<alltime || lastsound<1)
945       {
946         lastsound=1;
947         lastsound_time=alltime;
948         if (config.sound) Mix_PlayMusic(slide,1)==-1;
949       }
951       /* display tires slide */
952       if (config.tire)
953       {
954         putpixel(cir,car.x+cos(car.angle)*car.w/3-sin(car.angle)*4,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,T_BLACK);
955         putpixel(cir,car.x+cos(car.angle)*car.w/3+sin(car.angle)*4,car.y+sin(car.angle)*car.h/3-cos(car.angle)*4,T_BLACK);
956         /* if we are braking the slide is larger */
957         if (kd)
958         {
959           putpixel(cir,car.x+cos(car.angle)*car.w/3-sin(car.angle)*3,car.y+sin(car.angle)*car.h/3+cos(car.angle)*3,T_BLACK);
960           putpixel(cir,car.x+cos(car.angle)*car.w/3+sin(car.angle)*3,car.y+sin(car.angle)*car.h/3-cos(car.angle)*3,T_BLACK);
961         }
962       }
963     }
964    
965     /* if we crashed */
966     if (car.crashflag && (lastsound_time+100<alltime || lastsound<2))
967     {
968       lastsound=2;
969       lastsound_time=alltime;
970       if (config.sound) Mix_PlayMusic(crash,1)==-1;
971     }
972    
973     /* game time */
974     current.time++;
975     net.time++;
976     if (udpsock && net.time>MAX_LAG)
977     {
978       print(screen,WIDTH/2-strlen("Timeout !")*5,HEIGHT/2-10,"Timeout !");
979       SDL_Flip(screen);
980       zeRace_send_time(&best);
981       free_mem();
982       return;
983     }
984     alltime++;
986     switch (car.lapflag)
987     {
988       /* if we completed a lap */
989       case 1:
990         printf("time = %d\"%d\n",current.time*DELAY/1000,current.time*DELAY%1000);
991         print(screen,0,0,"Last lap :          ");
992         print_time(110,0,current.time);
993         SDL_UpdateRect(screen,0,0,200,19);
994         /* if it is the first turn of the best turn, save it */
995         if (best.time==-1 || current.time<best.time)
996           memcpy(&best,&current,sizeof(struct _record));
997         /* reset turn variables */
998         current.time=0;
999         current.x=car.x;
1000         current.y=car.y;
1001         current.angle=car.angle;
1002         current.speed=car.speed;
1003         car.lapflag=0;
1004         break;
1005       /* if we completed an incomplete lap */
1006       case 2:
1007         print(screen,0,0,"Last lap : CANCELED ");
1008         SDL_UpdateRect(screen,0,0,200,19);
1009         /* reset turn variables */
1010         current.time=0;
1011         car.lapflag=0;
1012         break;
1013       /* if we miss a checkpoint */
1014       case 3:
1015         print(screen,0,0,"Checkpoint missed ! ");
1016         SDL_UpdateRect(screen,0,0,200,19);
1017         break;
1018       /* if we validate a missed checkpoint */
1019       case 4:
1020         print(screen,0,0,"Checkpoint missed OK");
1021         SDL_UpdateRect(screen,0,0,200,19);
1022         break;
1023       /* nothing */
1024       default:
1025         break;
1026     }
1027     
1028     /* let the system breath */
1029     SDL_Delay(delay);
1030   }
1034 /* display a random splash screen at startup */
1035 void zeRace_splash()
1037   SDL_Surface *splash;
1038   SDL_Rect pos;
1039   char temp[20]="splashs/0.jpg";
1040   
1041   SDL_FillRect(screen,NULL,C_BLACK);
1042   temp[8]=rand()%5+'1';
1043   splash=IMG_Load(temp);
1044   pos.x=screen->w/2-splash->w/2-1;
1045   pos.w=splash->w+2;
1046   pos.y=screen->h/2-splash->h/2-1;
1047   pos.h=splash->h+2;
1048   SDL_FillRect(screen,&pos,C_WHITE);
1049   pos.x=screen->w/2-splash->w/2;
1050   pos.y=screen->h/2-splash->h/2;
1051   SDL_BlitSurface(splash,NULL,screen,&pos);
1052   print(screen,screen->w/2-strlen("zeRace " VERSION)*5,screen->h/2-splash->h/2-20,"zeRace " VERSION);
1053   SDL_FreeSurface(splash);
1054   SDL_Flip(screen);
1055   SDL_Delay(2000);
1059 /* menu loop to select track */
1060 void zeRace_local()
1062   SDL_Event event;
1063   
1064   void update()
1065   {
1066     SDL_Surface *full,*preview;
1067     SDL_Rect pos;
1068     SDL_FillRect(screen,NULL,C_BLACK);
1069     print(screen,WIDTH/2-28*5,HEIGHT/6,"* Please choose your race *");
1070     print(screen,WIDTH/2-strlen(tracklist->title)*5,5*HEIGHT/6-20,tracklist->title);
1071     print(screen,WIDTH/2-(strlen(tracklist->author)+strlen("Author : "))*5,5*HEIGHT/6+0,"Author : ");
1072     print(screen,WIDTH/2-(strlen(tracklist->author)-strlen("Author : "))*5,5*HEIGHT/6+0,tracklist->author);
1073     print(screen,WIDTH/2-( strlen("Version : ")+strlen(tracklist->version))*5,5*HEIGHT/6+20,"Version : ");
1074     print(screen,WIDTH/2-(-strlen("Version : ")+strlen(tracklist->version))*5,5*HEIGHT/6+20,tracklist->version);
1075     print(screen,WIDTH/2-( strlen("Best time : ")+6+strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40,"Best time : ");
1076     print_time  (WIDTH/2-(-strlen("Best time : ")+6+strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40,tracklist->best_time);
1077     print(screen,WIDTH/2-(-strlen("Best time : ")-6+strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40," by ");
1078     print(screen,WIDTH/2-(-strlen("Best time : ")-6-strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40,tracklist->best_pseudo);
1079     full=IMG_Load(tracklist->full);
1080     preview=(SDL_Surface *)zoomSurface(full,0.5,0.5,1);
1081     SDL_FreeSurface(full);
1082     pos.x=WIDTH/2-preview->w/2-1;
1083     pos.w=preview->w+2;
1084     pos.y=screen->h/2-preview->h/2-1;
1085     pos.h=preview->h+2;
1086     SDL_FillRect(screen,&pos,C_WHITE);
1087     pos.x=WIDTH/2-preview->w/2;
1088     pos.y=screen->h/2-preview->h/2;
1089     SDL_BlitSurface(preview,NULL,screen,&pos);
1090     SDL_FreeSurface(preview);
1091     SDL_Flip(screen);
1092   }
1093   
1094   update();
1095   for (;;)
1096   {
1097     while (SDL_PollEvent(&event))
1098     {
1099       switch (event.type)
1100       {
1101         case SDL_QUIT:
1102           zeRace_exit();
1103           break;
1104         case SDL_KEYDOWN:
1105           switch (event.key.keysym.sym)
1106           {
1107             case SDLK_ESCAPE:
1108               return;
1109             case SDLK_RETURN:
1110             case SDLK_SPACE:
1111               zeRace_launch(0,1);
1112               update();
1113               break;
1114             case SDLK_LEFT:
1115               tracklist=tracklist->next;
1116               update();
1117               break;
1118             case SDLK_RIGHT:
1119               tracklist=tracklist->prev;
1120               update();
1121               break;
1122             default:
1123               break;
1124           }
1125           break;
1126       }
1127     }
1128     SDL_Delay(10);
1129   }
1133 /* top 10 screen */
1134 void zeRace_top10(char *buf)
1136   int i,nb,tmp;
1137   SDL_Rect pos;
1138   SDL_FillRect(screen,NULL,C_BLACK);
1139   nb=SDLNet_Read16(buf);
1140   buf+=2;
1141   print(screen,WIDTH/2-16*5,HEIGHT/14,"* Race results *");
1142   for (i=0;i<nb;i++)
1143   {
1144     print(screen,150,(i+3)*HEIGHT/14,buf);
1145     buf+=strlen(buf)+1;
1146     tmp=SDLNet_Read16(buf);
1147     buf+=2;
1148     pos.x=110;
1149     pos.y=(i+3)*HEIGHT/14-8;
1150     SDL_BlitSurface(cars[tmp][0],NULL,screen,&pos);
1151   }
1152   SDL_Flip(screen);
1153   SDL_Delay(5000);
1157 /* connect to a server */
1158 void zeRace_connect(char *host,int port)
1160   char *tmp;
1161   int lag=0;
1162   udpsock=SDLNet_UDP_Open(0);
1163   if (udpsock==NULL)
1164   {
1165     fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
1166     zeRace_exit();
1167   }
1168   SDLNet_ResolveHost(&packet->address,host,port);
1169   tmp=packet->data;
1170   strcpy(tmp,"connect");
1171   tmp+=strlen(tmp)+1;
1172   strcpy(tmp,config.pseudo);
1173   tmp+=strlen(tmp)+1;
1174   SDLNet_Write16(config.color,tmp);
1175   tmp+=2;
1176   packet->len=(void *)tmp-(void *)packet->data;
1177   SDLNet_UDP_Send(udpsock,-1,packet);
1178   /* network loop */
1179   while (SDLNet_UDP_Recv(udpsock,packet) || lag<MAX_LAG)
1180   {
1181     tmp=packet->data;
1182     if (strcmp(tmp,"track")==0)
1183     {
1184       struct _tracklist *loopcheck=tracklist;
1185       int time;
1186       char go;
1187       tmp+=strlen(tmp)+1;
1188       go=*tmp++;
1189       printf("server asked for track : %s\n",tmp);
1190       do if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next; while (tracklist!=loopcheck);
1191       if (strcmp(tracklist->name,tmp)!=0)
1192       {
1193         fprintf(stderr,"unknown track : %s\n",tmp);
1194         zeRace_exit();
1195       }
1196       tmp+=strlen(tmp)+1;
1197       time=SDLNet_Read32(tmp);
1198       tmp+=4;
1199       network_speed=SDLNet_Read32(tmp);
1200       zeRace_launch(time,go);
1201       if (strcmp(packet->data,"finish")==0) zeRace_top10(packet->data+strlen(packet->data)+1);
1202       lag=0;
1203     }
1204     SDL_Delay(7);
1205     lag++;
1206   }
1207   SDLNet_UDP_Close(udpsock);
1208   udpsock=NULL;
1212 /* network game */
1213 void zeRace_network()
1215   SDL_Event event;
1216   int active=0;
1217   char server[MAXLINELENGTH]="localhost";
1218   char port[6]=PORT;
1219   #define NETWORK_OPTIONS 4
1221   void update()
1222   {
1223     SDL_FillRect(screen,NULL,C_BLACK);
1224     print(screen,380,HEIGHT/(NETWORK_OPTIONS+4)*(3+active),">");
1225     print(screen,WIDTH/2-18*5,HEIGHT/(NETWORK_OPTIONS+4),"* Network screen *");
1226     print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*3,"Server : ");
1227     print(screen,400+10*strlen("Server : "),HEIGHT/(NETWORK_OPTIONS+4)*3,server);
1228     print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*4,"Port : ");
1229     print(screen,400+10*strlen("Port : "),HEIGHT/(NETWORK_OPTIONS+4)*4,port);
1230     print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*(NETWORK_OPTIONS+1),"Connect");
1231     print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*(NETWORK_OPTIONS+2),"Back to main menu");
1232     SDL_Flip(screen);
1233   }
1235   update();
1236   for (;;)
1237   {
1238     while (SDL_PollEvent(&event))
1239     {
1240       switch (event.type)
1241       {
1242         case SDL_QUIT:
1243           zeRace_exit();
1244           break;
1245         case SDL_KEYDOWN:
1246           switch (event.key.keysym.sym)
1247           {
1248             case SDLK_ESCAPE:
1249               return;
1250             case SDLK_RETURN:
1251             case SDLK_SPACE:
1252             case SDLK_LEFT:
1253             case SDLK_RIGHT:
1254               switch (active)
1255               {
1256                 case 0: readstring(screen,400+10*strlen("Server : "),HEIGHT/(NETWORK_OPTIONS+4)*3,server,MAXLINELENGTH); break;
1257                 case 1: readstring(screen,400+10*strlen("Port : "),HEIGHT/(NETWORK_OPTIONS+4)*4,port,5); break;;
1258                 case 2:
1259                   zeRace_connect(server,atoi(port));
1260                   break;
1261                 case 3:
1262                   return;
1263               }
1264               update();
1265               break;
1266             case SDLK_UP:
1267               active--; if (active<0) active=NETWORK_OPTIONS-1;
1268               update();
1269               break;
1270             case SDLK_DOWN:
1271               active++; if (active>NETWORK_OPTIONS-1) active=0;
1272               update();
1273               break;
1274             default:
1275               break;
1276           }
1277           break;
1278       }
1279     }
1280     SDL_Delay(10);
1281   }
1285 /* internet game */
1286 void zeRace_internet()
1288   IPaddress ip;
1289   TCPsocket tcpsock;
1290   char *request=
1291     "GET /zerace/servers.php HTTP/1.0\n"
1292     "Host: royale.zerezo.com\n"
1293     "User-Agent: zeRace " VERSION "\n"
1294     "\n";
1295   char response[10240],*tmp;
1296   int len,result,i;
1297   struct _server
1298   {
1299     char name[MAXLINELENGTH];
1300     char ip[16];
1301     char port[6];
1302   } servers[10];
1303   SDL_Event event;
1304   int active=0;
1305   #define INTERNET_OPTIONS 11
1306   
1307   if (!config.internet) return;
1308   
1309   printf("dowloading list of servers... ");
1310   fflush(stdout);
1312   if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
1313   {
1314     fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
1315     return;
1316   }
1317   
1318   tcpsock=SDLNet_TCP_Open(&ip);
1319   if (!tcpsock)
1320   {
1321     fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
1322     return;
1323   }
1325   len=strlen(request);
1326   result=SDLNet_TCP_Send(tcpsock,request,len);
1327   if (result<len)
1328     fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
1329   else
1330   {
1331     len=SDLNet_TCP_Recv(tcpsock,response,10240);
1332     tmp=response;
1333     for (tmp=response;tmp<response+10240;tmp++) if (*tmp=='\n') *tmp='\0';
1334     tmp=response;
1335     while (*tmp!='\0' || *(tmp+1)!='\r') tmp++;
1336     tmp+=3;
1337     for (i=0;i<10;i++)
1338     {
1339       strcpy(servers[i].name,tmp);
1340       tmp+=strlen(tmp)+1;
1341       strcpy(servers[i].ip,tmp);
1342       tmp+=strlen(tmp)+1;
1343       strcpy(servers[i].port,tmp);
1344       tmp+=strlen(tmp)+1;
1345     }
1346     printf("done\n");
1347   }
1348   
1349   SDLNet_TCP_Close(tcpsock);
1350   
1351   void update()
1352   {
1353     int i;
1354     SDL_FillRect(screen,NULL,C_BLACK);
1355     print(screen,380,HEIGHT/(INTERNET_OPTIONS+4)*(3+active),">");
1356     print(screen,WIDTH/2-19*5,HEIGHT/(INTERNET_OPTIONS+4),"* Internet screen *");
1357     for (i=0;i<10;i++)
1358       print(screen,400,HEIGHT/(INTERNET_OPTIONS+4)*(i+3),servers[i].name);
1359     print(screen,400,HEIGHT/(INTERNET_OPTIONS+4)*(INTERNET_OPTIONS+2),"Back to main menu");
1360     SDL_Flip(screen);
1361   }
1363   update();
1364   for (;;)
1365   {
1366     while (SDL_PollEvent(&event))
1367     {
1368       switch (event.type)
1369       {
1370         case SDL_QUIT:
1371           zeRace_exit();
1372           break;
1373         case SDL_KEYDOWN:
1374           switch (event.key.keysym.sym)
1375           {
1376             case SDLK_ESCAPE:
1377               return;
1378             case SDLK_RETURN:
1379             case SDLK_SPACE:
1380             case SDLK_LEFT:
1381             case SDLK_RIGHT:
1382               if (active==INTERNET_OPTIONS-1)
1383                 return;
1384               else
1385                 zeRace_connect(servers[active].ip,atoi(servers[active].port));
1386               update();
1387               break;
1388             case SDLK_UP:
1389               active--; if (active<0) active=INTERNET_OPTIONS-1;
1390               update();
1391               break;
1392             case SDLK_DOWN:
1393               active++; if (active>INTERNET_OPTIONS-1) active=0;
1394               update();
1395               break;
1396             default:
1397               break;
1398           }
1399           break;
1400       }
1401     }
1402     SDL_Delay(10);
1403   }
1407 /* configuration screen */
1408 void zeRace_config()
1410   SDL_Event event;
1411   int active=0;
1412   #define CONFIG_OPTIONS 14
1413   
1414   void update()
1415   {
1416     SDL_Rect pos;
1417     SDL_FillRect(screen,NULL,C_BLACK);
1418     print(screen,20,HEIGHT/(CONFIG_OPTIONS+4)*(3+active),">");
1419     print(screen,WIDTH/2-24*5,HEIGHT/(CONFIG_OPTIONS+4),"* Configuration screen *");
1420     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*3,"Pseudo : ");
1421     print(screen,40+10*strlen("Pseudo : "),HEIGHT/(CONFIG_OPTIONS+4)*3,config.pseudo);
1422     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*4,"Url : ");
1423     print(screen,40+10*strlen("Url : "),HEIGHT/(CONFIG_OPTIONS+4)*4,config.url);
1424     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*5,"Fullscreen : ");
1425     print(screen,40+10*strlen("Fullscreen : "),HEIGHT/(CONFIG_OPTIONS+4)*5,config.fullscreen?"Yes":"No");
1426     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*6,"Sound : ");
1427     print(screen,40+10*strlen("Sound : "),HEIGHT/(CONFIG_OPTIONS+4)*6,config.sound?"Yes":"No");
1428     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*7,"Tire : ");
1429     print(screen,40+10*strlen("Tire : "),HEIGHT/(CONFIG_OPTIONS+4)*7,config.tire?"Yes":"No");
1430     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*8,"Accelerate key : ");
1431     print(screen,40+10*strlen("Accelerate key : "),HEIGHT/(CONFIG_OPTIONS+4)*8,config.up?SDL_GetKeyName(config.up):"<press key>");
1432     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*9,"Brake key : ");
1433     print(screen,40+10*strlen("Brake key : "),HEIGHT/(CONFIG_OPTIONS+4)*9,config.down?SDL_GetKeyName(config.down):"<press key>");
1434     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*10,"Turn left key : ");
1435     print(screen,40+10*strlen("Turn left key : "),HEIGHT/(CONFIG_OPTIONS+4)*10,config.left?SDL_GetKeyName(config.left):"<press key>");
1436     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*11,"Turn right key : ");
1437     print(screen,40+10*strlen("Turn right key : "),HEIGHT/(CONFIG_OPTIONS+4)*11,config.right?SDL_GetKeyName(config.right):"<press key>");
1438     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*12,"Color : ");
1439     pos.x=123;
1440     pos.y=HEIGHT/(CONFIG_OPTIONS+4)*12-7;
1441     SDL_BlitSurface(cars[config.color][0],NULL,screen,&pos);
1442     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*13,"Boss key : ");
1443     print(screen,40+10*strlen("Boss key : "),HEIGHT/(CONFIG_OPTIONS+4)*13,config.boss?SDL_GetKeyName(config.boss):"<press key>");
1444     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*14,"By night : ");
1445     print(screen,40+10*strlen("By night : "),HEIGHT/(CONFIG_OPTIONS+4)*14,config.bynight?"Yes":"No");
1446     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*15,"Internet : ");
1447     print(screen,40+10*strlen("Internet : "),HEIGHT/(CONFIG_OPTIONS+4)*15,config.internet?"Yes":"No");
1448     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*(CONFIG_OPTIONS+2),"Back to main menu");
1449     SDL_Flip(screen);
1450   }
1452   int read_key()
1453   {
1454     for (;;)
1455     {
1456       while (SDL_PollEvent(&event)) switch (event.type)
1457       {
1458         case SDL_KEYDOWN:
1459           return event.key.keysym.sym;
1460       }
1461       SDL_Delay(10);
1462     }
1463   }
1464   
1465   update();
1466   for (;;)
1467   {
1468     while (SDL_PollEvent(&event))
1469     {
1470       switch (event.type)
1471       {
1472         case SDL_QUIT:
1473           zeRace_exit();
1474           break;
1475         case SDL_KEYDOWN:
1476           switch (event.key.keysym.sym)
1477           {
1478             case SDLK_ESCAPE:
1479               return;
1480             case SDLK_RETURN:
1481             case SDLK_SPACE:
1482             case SDLK_LEFT:
1483             case SDLK_RIGHT:
1484               switch (active)
1485               {
1486                 case 0: readstring(screen,40+10*strlen("Pseudo : "),HEIGHT/(CONFIG_OPTIONS+4)*3,config.pseudo,MAXLINELENGTH); break;
1487                 case 1: readstring(screen,40+10*strlen("Url : "),HEIGHT/(CONFIG_OPTIONS+4)*4,config.url,MAXLINELENGTH); break;;
1488                 case 2: config.fullscreen=!config.fullscreen; break;
1489                 case 3: config.sound=!config.sound; break;
1490                 case 4: config.tire=!config.tire; break;
1491                 case 5: config.up=0; update(); config.up=read_key(); break;
1492                 case 6: config.down=0; update(); config.down=read_key(); break;
1493                 case 7: config.left=0; update(); config.left=read_key(); break;
1494                 case 8: config.right=0; update(); config.right=read_key(); break;
1495                 case 9:
1496                   if (event.key.keysym.sym==SDLK_LEFT) config.color--; else config.color++;
1497                   if (config.color<0) config.color=NB_CARS-1;
1498                   if (config.color>NB_CARS-1) config.color=0;
1499                   break;
1500                 case 10: config.boss=0; update(); config.boss=read_key(); break;
1501                 case 11: config.bynight=!config.bynight; break;
1502                 case 12: config.internet=!config.internet; break;
1503                 case 13:
1504                   return;
1505               }
1506               update();
1507               break;
1508             case SDLK_UP:
1509               active--; if (active<0) active=CONFIG_OPTIONS-1;
1510               update();
1511               break;
1512             case SDLK_DOWN:
1513               active++; if (active>CONFIG_OPTIONS-1) active=0;
1514               update();
1515               break;
1516             default:
1517               break;
1518           }
1519           break;
1520       }
1521     }
1522     SDL_Delay(10);
1523   }
1527 /* main menu */
1528 void zeRace_menu()
1530   SDL_Event event;
1531   int active=0;
1532   SDL_Surface *logo;
1533   #define MENU_OPTIONS 5
1534   
1535   void update()
1536   {
1537     SDL_Rect pos;
1538     SDL_FillRect(screen,NULL,C_BLACK);
1539     pos.x=WIDTH/2-logo->w/2;
1540     pos.y=HEIGHT/6-logo->h/2;
1541     SDL_BlitSurface(logo,NULL,screen,&pos);
1542     print(screen,650,HEIGHT/6+logo->h/3,"version " VERSION);
1543     print(screen,420,HEIGHT/(MENU_OPTIONS+4)*(3+active),">");
1544     print(screen,440,HEIGHT/(MENU_OPTIONS+4)*3,"Local game");
1545     print(screen,440,HEIGHT/(MENU_OPTIONS+4)*4,"Network game");
1546     print(screen,440,HEIGHT/(MENU_OPTIONS+4)*5,"Internet game");
1547     print(screen,440,HEIGHT/(MENU_OPTIONS+4)*6,"Configuration");
1548     print(screen,440,HEIGHT/(MENU_OPTIONS+4)*7,"Exit game");
1549     SDL_Flip(screen);
1550   }
1552   logo=IMG_Load("sprites/logo.jpg");
1553   update();
1554   for (;;)
1555   {
1556     while (SDL_PollEvent(&event))
1557     {
1558       switch (event.type)
1559       {
1560         case SDL_QUIT:
1561           zeRace_exit();
1562           break;
1563         case SDL_KEYDOWN:
1564           switch (event.key.keysym.sym)
1565           {
1566             case SDLK_ESCAPE:
1567               return;
1568             case SDLK_RETURN:
1569             case SDLK_SPACE:
1570             case SDLK_LEFT:
1571             case SDLK_RIGHT:
1572               switch (active)
1573               {
1574                 case 0: zeRace_local(); break;
1575                 case 1: zeRace_network(); break;
1576                 case 2: zeRace_internet(); break;
1577                 case 3: zeRace_config(); break;
1578                 case 4: return;
1579               }
1580               update();
1581               break;
1582             case SDLK_UP:
1583               active--; if (active<0) active=MENU_OPTIONS-1;
1584               update();
1585               break;
1586             case SDLK_DOWN:
1587               active++; if (active>MENU_OPTIONS-1) active=0;
1588               update();
1589               break;
1590             default:
1591               break;
1592           }
1593           break;
1594       }
1595     }
1596     SDL_Delay(10);
1597   }
1601 /* main program */
1602 int main(int argc,char *argv[])
1604   zeRace_init();
1605   zeRace_splash();
1606   zeRace_menu();
1607   zeRace_exit();
1608   return 0;