Git

Antoine Jacquet [Fri, 15 Apr 2005 22:00:00 +0000 (00:00 +0200)]
* added "formula" track (thank you Julien)
* added some new car sprites (thank you Julien)
* added collisions between cars in network mode
* added a synchronization check between server and clients
* added informations about missed checkpoints and wrong laps (thank you Julien)
* added car lights (red lights, backwards lights, warnings)
* added night mode with car night lights
* fixed a bug with Win32 version downloading new tracks
* fixed SDL_Init(0) in bot framework
* use SDL_GetRGB and SDL_MapRGB to handle colors

21 files changed:
CHANGELOG
README
bot.c
bot_anticip.c
car.c
car.h
network.h
sdl.h
server.c
splashs/4.jpg [new file with mode: 0644]
splashs/5.jpg [new file with mode: 0644]
sprites/carM.png [new file with mode: 0644]
sprites/carN.png [new file with mode: 0644]
sprites/carO.png [new file with mode: 0644]
sprites/carP.png [new file with mode: 0644]
sprites/light.png [new file with mode: 0644]
tracks/formula.png [new file with mode: 0644]
tracks/formula_function.png [new file with mode: 0644]
tracks/list.txt
tracks/loop_function.png
zeRace.c

index 421f75c..a8daa9a 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,17 @@
 Change log file for zeRace
 
+version 0.5    (2005-04-16)
+       * added "formula" track (thank you Julien)
+       * added some new car sprites (thank you Julien)
+       * added collisions between cars in network mode
+       * added a synchronization check between server and clients
+       * added informations about missed checkpoints and wrong laps (thank you Julien)
+       * added car lights (red lights, backwards lights, warnings)
+       * added night mode with car night lights
+       * fixed a bug with Win32 version downloading new tracks
+       * fixed SDL_Init(0) in bot framework
+       * use SDL_GetRGB and SDL_MapRGB to handle colors
+
 version 0.4    (2004-11-28)
        * added "loop" track
        * fixed "car" track
diff --git a/README b/README
index ff68211..699c954 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-zeRace 0.4
+zeRace 0.5
 site: http://royale.zerezo.com/zerace/
 mail: royale@zerezo.com
 
@@ -10,7 +10,7 @@ make CC=i586-mingw32msvc-gcc SDLCONFIG=/path/to/sdl-config WINDRES=i586-mingw32m
 
 bots:
 To play a game against bots, you will first need to launch a local server :
-./server "My private server" 5 1 private
+./server "My private server" 5 1 private col
 Then launch as many bots as you want :
 ./bot_anticip localhost 3600 0
 ./bot_anticip localhost 3600 8
diff --git a/bot.c b/bot.c
index ef93b04..b9631a9 100644 (file)
--- a/bot.c
+++ b/bot.c
@@ -60,9 +60,9 @@ void zeRace_init()
   
   /* robot configuration */
   sprintf(config.pseudo,"\"%s\" bot(%d)",bot_name(),aleas);
-  config.color=rand()%12;
+  config.color=rand()%16;
   
-  if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0)
+  if (SDL_Init(0)<0)
   {
     fprintf(stderr,"could not initialize SDL : %s\n",SDL_GetError());
     zeRace_exit();
@@ -134,6 +134,9 @@ void zeRace_launch(int alltime,int go)
       net.keys[net.time+1]='\0';
     }
 
+    /* move the car */
+    move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
+
     delay=DELAY;
     /* if we are in network mode */
     if (udpsock!=NULL)
@@ -155,6 +158,16 @@ void zeRace_launch(int alltime,int go)
           lastack=clienttime;
         }
       }
+      else if (strcmp(packet->data,"collision")==0)
+      {
+        net.time=-1;
+        net.keys[0]='\0';
+        lastack=SDLNet_Read32(packet->data+strlen("collision")+1);
+        car.x=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4)/65536-100;
+        car.y=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4)/65536-100;
+        car.speed=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4)/65536-100;
+        car.angle=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4+4)/65536-100;
+      }
       else /* end of this network race */
       {
         SDL_FreeSurface(cir);
@@ -168,6 +181,10 @@ void zeRace_launch(int alltime,int go)
         tmp+=strlen(tmp)+1;
         SDLNet_Write32(lastack,tmp);
         tmp+=4;
+        SDLNet_Write32(car.x,tmp);
+        tmp+=4;
+        SDLNet_Write32(car.y,tmp);
+        tmp+=4;
         strcpy(tmp,net.keys);
         tmp+=strlen(tmp)+1;
         packet->len=(void *)tmp-(void *)packet->data+10;
@@ -179,9 +196,6 @@ void zeRace_launch(int alltime,int go)
       }
     }
 
-    /* move the car */
-    move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
-
     /* let the system breath */
     SDL_Delay(delay);
     
@@ -232,7 +246,7 @@ void zeRace_connect(char *host,int port)
       tmp+=strlen(tmp)+1;
       go=*tmp++;
       printf("server asked for track : %s\n",tmp);
-      while (tracklist->next!=loopcheck) if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next;
+      do if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next; while (tracklist!=loopcheck);
       if (strcmp(tracklist->name,tmp)!=0)
       {
         fprintf(stderr,"unknown track : %s\n",tmp);
index 22de8dd..424e875 100644 (file)
@@ -19,8 +19,10 @@ char *bot_name()
 
 void bot_ia(char *trackname,struct _car *car,SDL_Surface *fun,int *ku,int *kd,int *kl,int *kr)
 {
-  int a1,a2,c,g,tg,og,l,x1,x2,x3,x4,y1,y2,y3,y4;
+  int a1,a2,l,x1,x2,x3,x4,y1,y2,y3,y4;
   float o,m,s;
+  Uint32 c;
+  Uint8 g,og,tg,t;
   
   /* adjust the properties depending of the track, this was "manually" optimized ;) */
   if (strcmp(trackname,"car")==0)
@@ -77,6 +79,15 @@ void bot_ia(char *trackname,struct _car *car,SDL_Surface *fun,int *ku,int *kd,in
     s=car->speed/3.3+0.4;
     og=1;
   }
+  else if (strcmp(trackname,"formula")==0)
+  {
+    a1=150;
+    a2=90;
+    o=0.8;
+    m=0.1;
+    s=car->speed/3.3+0.4;
+    og=120;
+  }
   /* some default values that may work on some tracks */
   else
   {
@@ -95,8 +106,8 @@ void bot_ia(char *trackname,struct _car *car,SDL_Surface *fun,int *ku,int *kd,in
   {
     x1=car->x-cos(car->angle)*l*s;
     y1=car->y-sin(car->angle)*l*s;
-    if (x1>0 && y1>0 && x1<fun->w && y1<fun->h) c=getpixel(fun,x1,y1); else c=0;
-    g=(c>>GSHIFT)&0xff;
+    if (x1>0 && y1>0 && x1<fun->w && y1<fun->h) c=getpixel(fun,x1,y1); else c=SDL_MapRGB(fun->format,0,0,0);
+    SDL_GetRGB(c,fun->format,&t,&g,&t);
     if (g<og && car->speed>m) { *ku=0,*kd=1; break; }
   }
   
@@ -112,10 +123,10 @@ void bot_ia(char *trackname,struct _car *car,SDL_Surface *fun,int *ku,int *kd,in
     x4=car->x-cos(car->angle+o)*l*s;
     y4=car->y-sin(car->angle+o)*l*s;
     
-    if (x3>0 && y3>0 && x3<fun->w && y3<fun->h) c=getpixel(fun,x3,y3); else c=0;
-    tg=(c>>GSHIFT)&0xff;
-    if (x4>0 && y4>0 && x4<fun->w && y4<fun->h) c=getpixel(fun,x4,y4); else c=0;
-    g=(c>>GSHIFT)&0xff;
+    if (x3>0 && y3>0 && x3<fun->w && y3<fun->h) c=getpixel(fun,x3,y3); else c=SDL_MapRGB(fun->format,0,0,0);
+    SDL_GetRGB(c,fun->format,&t,&tg,&t);
+    if (x4>0 && y4>0 && x4<fun->w && y4<fun->h) c=getpixel(fun,x4,y4); else c=SDL_MapRGB(fun->format,0,0,0);
+    SDL_GetRGB(c,fun->format,&t,&g,&t);
     if (g>tg) { *kr=1; break; } else if (g<tg) { *kl=1; break; }
   }
 }
diff --git a/car.c b/car.c
index 3c9be9b..9caf3bd 100644 (file)
--- a/car.c
+++ b/car.c
@@ -4,20 +4,18 @@
 
 void move_car(struct _car *car,int keys,SDL_Surface *fun)
 {
-  Uint32 c,r,g,b;
+  Uint32 c;
+  Uint8 r,g,b;
   
   /* reset flags */
-  car->lapflag=0;
   car->crashflag=0;
   
   /* get the pixel color under the center of car in the function map */
   c=getpixel(fun,car->x,car->y);
   /* red layer (checkpoints) */
-  r=(c>>RSHIFT)&0xff;
   /* green layer (road quality) */
-  g=(c>>GSHIFT)&0xff;
   /* blue layer (grip) */
-  b=(c>>BSHIFT)&0xff;
+  SDL_GetRGB(c,fun->format,&r,&g,&b);
 
   if (keys & 8) /* up */
     car->speed+=0.01*2*COEFF;
@@ -69,8 +67,17 @@ void move_car(struct _car *car,int keys,SDL_Surface *fun)
     car->crashflag=1;
   }
   
-  /* if we are on the next checkpoint, validate it (no missing allowed) */
-  if (r/8==car->lastcheck+1) car->lastcheck++;
+  /* if we are on the next checkpoint, validate it */
+  if (r/8==car->lastcheck+1)
+  {
+    /* If we validate a missed checkpoint */
+    if (car->lapflag==3) car->lapflag=4;
+    car->lastcheck++;
+  }
+  
+  /* if we missed a checkpoint */
+  if ((r/8>car->lastcheck+1) && (car->lastcheck!=0)) car->lapflag=3;
+
   /* if we validate all and start over, we complete a turn */
   if (r/8==0 && car->lastcheck==31)
   {
@@ -80,5 +87,24 @@ void move_car(struct _car *car,int keys,SDL_Surface *fun)
     car->lapflag=1;
   }
   
+  /* if we are at the start but not each checkpoint validate, it's an incomplete lap */
+  if (r/8==0 && r!=0 && car->lastcheck!=31 && car->lastcheck>0)
+  {
+    car->lastcheck=0;
+    car->lapflag=2;
+  }
+  
+  /* if the car is braking, display red lights */
+  if (keys & 4 && car->speed>0.1) car->lights_brake=1; else car->lights_brake=0;
+  
+  /* if the car is going backwards, display white lights */
+  if (car->speed<-0.1) car->lights_backwards=1; else car->lights_backwards=0;
+  
+  /* if the car is stopped, then warning */
+  if (car->speed>=-0.1 && car->speed<=0.1)
+    car->lights_warning=1;
+  else
+    car->lights_warning=0;
+  
   return;
 }
diff --git a/car.h b/car.h
index cb9e511..e6260d7 100644 (file)
--- a/car.h
+++ b/car.h
@@ -13,6 +13,7 @@ struct _car
   int w,h,lastcheck,lap;
   int lapflag,crashflag;
   int color;
+  int lights_brake,lights_backwards,lights_warning;
 };
 
 void move_car(struct _car *car,int keys,SDL_Surface *function);
index 206cfe6..1d3b0f7 100644 (file)
--- a/network.h
+++ b/network.h
@@ -4,4 +4,4 @@
 #define MAX_LAG 500
 #define MAX_CLIENTS 32
 #define PORT "3600"
-#define VERSION "0.4"
+#define VERSION "0.5"
diff --git a/sdl.h b/sdl.h
index 3eceb70..26245c5 100644 (file)
--- a/sdl.h
+++ b/sdl.h
@@ -6,15 +6,15 @@
 
 /* endianness setup */
 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
-  #define RSHIFT 24
-  #define GSHIFT 16
-  #define BSHIFT 8
-  #define ASHIFT 0
+  #define RMASK 0xff000000
+  #define GMASK 0x00ff0000
+  #define BMASK 0x0000ff00
+  #define AMASK 0x000000ff
 #else
-  #define RSHIFT 0
-  #define GSHIFT 8
-  #define BSHIFT 16
-  #define ASHIFT 24
+  #define RMASK 0x000000ff
+  #define GMASK 0x0000ff00
+  #define BMASK 0x00ff0000
+  #define AMASK 0xff000000
 #endif
 
 void print(SDL_Surface *dst,int x,int y,unsigned char *text);
index 047d985..a2ccbcd 100644 (file)
--- a/server.c
+++ b/server.c
@@ -13,6 +13,7 @@ struct _clients
   int lasttime;
   struct _car car;
   IPaddress address;
+  int dx,dy;
 } clients [MAX_CLIENTS];
 
 /* UDP stuff */
@@ -21,6 +22,7 @@ UDPpacket *packet;
 
 struct _tracklist *tracklist;
 SDL_Surface *fun;
+SDL_Surface *cars[256];
 
 
 /* return the id of a connected address */
@@ -82,22 +84,56 @@ void announce(char *name,int clients)
 }
 
 
+/* load the car sprite and rotate it for every angles */
+void zeRace_generate_cars()
+{
+  int j;
+  SDL_Surface *car;
+  char temp[20]="sprites/carX.png";
+  temp[11]='A';
+  /* load the car sprite */
+  car=IMG_Load(temp);
+  /* and rotate it for all available angles */
+  for (j=0;j<256;j++)
+  {
+    float x,y;
+    float tcos,tsin;
+    if ((cars[j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,RMASK,GMASK,BMASK,AMASK))==NULL)
+    {
+      fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
+    };
+    tcos=cos(2*M_PI*j/256);
+    tsin=sin(2*M_PI*j/256);
+    for (x=0;x<cars[j]->w;x++) for (y=0;y<cars[j]->h;y++)
+    {
+      int x2,y2;
+      x2=(x-cars[j]->w/2.0)*tcos+(y-cars[j]->h/2.0)*tsin+car->w/2.0;
+      y2=(x-cars[j]->w/2.0)*tsin-(y-cars[j]->h/2.0)*tcos+car->h/2.0;
+      if (x2>0 && x2<car->w && y2>0 && y2<car->h)
+        putpixel(cars[j],x,y,getpixel(car,x2,y2));
+    }
+  }
+  SDL_FreeSurface(car);
+}
+
+
 /* main program */
 int main(int argc,char *argv[])
 {
   int id,i,j,time=0,nb;
   char *tmp;
   unsigned char ip[4];
-  int nb_laps,network_speed,pub;
+  int nb_laps,network_speed,pub,col;
   
-  if (argc!=5)
+  if (argc!=6)
   {
     fprintf(stderr,
-      "usage: %s 'server_name' nb_laps network_speed (public|private)\n"
+      "usage: %s 'server_name' nb_laps network_speed (public|private) (col|nocol)\n"
       "  server_name : the name of the server\n"
       "  nb_laps : the number of laps to complete for each race\n"
       "  network_speed : frequency of network messages (1 for fast network, 10 for slow network...)\n"
       "  private : this server will not be listed in the 'internet games'\n"
+      "  col : the server will compute collisions between cars\n"
       ,argv[0]
     );
     exit(1);
@@ -106,6 +142,7 @@ int main(int argc,char *argv[])
   printf("nb_laps : %d\n",nb_laps=atoi(argv[2]));
   printf("network_speed : %d\n",network_speed=atoi(argv[3]));
   printf("public : %d\n",pub=strcmp("private",argv[4]));
+  printf("col : %d\n",col=strcmp("nocol",argv[5]));
   
   if (!zeRace_get_tracks(&tracklist)) exit(1);
 
@@ -133,7 +170,9 @@ int main(int argc,char *argv[])
     fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
     exit(2);
   }
-
+  
+  zeRace_generate_cars();
+  
   for (;;)
   {
     /* announce the server on internet if wanted */
@@ -197,7 +236,6 @@ int main(int argc,char *argv[])
         
         /* look for type of message */
         tmp=packet->data;
-        /*printf("%s\n",tmp);*/
         
         /* new connection ? */
         if (strcmp(tmp,"connect")==0)
@@ -264,22 +302,58 @@ int main(int argc,char *argv[])
           }
           else
           {
-            int temp;
+            int temp,x,y,x2,y2;
             tmp+=strlen(tmp)+1;
             temp=SDLNet_Read32(tmp);
             tmp+=4;
+            x=SDLNet_Read32(tmp);
+            tmp+=4;
+            y=SDLNet_Read32(tmp);
+            tmp+=4;
             if (clients[id].lasttime<=temp)
             {
               tmp+=temp-clients[id].lasttime;
-              /* printf("servertime = %d lasttime = %d temp = %d strlen(tmp) = %d\n",time,clients[id].lasttime,temp,strlen(tmp)); */
-              /*printf("keys = %s\n",tmp);*/
               while (*tmp)
               {
                 move_car(&clients[id].car,*tmp-'A',fun);
-                /*printf("%d = %f\n",id,clients[id].car.angle);*/
                 clients[id].lasttime++;
                 tmp++;
               }
+              /* check that the server and the client are still synchronized */
+              x2=clients[id].car.x;
+              y2=clients[id].car.y;
+              if (x!=x2 || y!=y2)
+              {
+                int round;
+                /* this should not happen with a perfect network protocol :) */
+                printf("client %d unsync at %d\n",id,time);
+                /* instead of dropping the client, we send him a "dumb" collision to resync him */
+                tmp=packet->data;
+                strcpy(tmp,"collision");
+                tmp+=strlen(tmp)+1;
+                SDLNet_Write32(time,tmp);
+                tmp+=4;
+                round=(clients[id].car.x+100)*65536;
+                clients[id].car.x=(float)round/65536-100;
+                SDLNet_Write32(round,tmp);
+                tmp+=4;
+                round=(clients[id].car.y+100)*65536;
+                clients[id].car.y=(float)round/65536-100;
+                SDLNet_Write32(round,tmp);
+                tmp+=4;
+                round=(clients[id].car.speed+100)*65536;
+                clients[id].car.speed=(float)round/65536-100;
+                SDLNet_Write32(round,tmp);
+                tmp+=4;
+                round=(clients[id].car.angle+100)*65536;
+                clients[id].car.angle=(float)round/65536-100;
+                SDLNet_Write32(round,tmp);
+                tmp+=4;
+                packet->len=(void *)tmp-(void *)packet->data;
+                packet->address=clients[id].address;
+                SDLNet_UDP_Send(udpsock,-1,packet);
+                clients[id].lasttime=time;
+              }
             }
           }
         }
@@ -295,6 +369,83 @@ int main(int argc,char *argv[])
         clients[i].connected=0;
       }
       
+      /* should we check for collisions ? */
+      if (col)
+      {
+        /* check for collisions */
+        for (i=0;i<MAX_CLIENTS;i++) clients[i].dx=clients[i].dy=0;
+        for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
+          for (j=i+1;j<MAX_CLIENTS;j++) if (clients[j].connected)
+            if (i!=j)
+              if (abs(clients[i].car.x-clients[j].car.x)<30 && abs(clients[i].car.y-clients[j].car.y)<30)
+              {
+                int x1,y1,x2,y2;
+                for (x1=0;x1<30;x1++)
+                  for (y1=0;y1<30;y1++)
+                    if (getpixel(cars[(unsigned char)(256*clients[i].car.angle/2.0/M_PI)%256],x1,y1)!=0)
+                    {
+                      x2=x1+clients[i].car.x-clients[j].car.x;
+                      y2=y1+clients[i].car.y-clients[j].car.y;
+                      if (x2>0 && x2<30 && y2>0 && y2<30)
+                      {
+                        if (getpixel(cars[(unsigned char)(256*clients[j].car.angle/2.0/M_PI)%256],x2,y2)!=0)
+                        {
+                          if (x1<30/2) { clients[i].dx++; clients[j].dx--; } else { clients[i].dx--; clients[j].dx++; }
+                          if (y1<30/2) { clients[i].dy++; clients[j].dy--; } else { clients[i].dy--; clients[j].dy++; }
+                        }
+                      }
+                    }
+              }
+        
+        /* now compute the collisions */
+        for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) if (clients[i].dx || clients[i].dy)
+        {
+          Uint32 c;
+          Uint8 g,t;
+          int dx=clients[i].dx;
+          int dy=clients[i].dy;
+          /* do not jump to much */
+          while (abs(dx)>5) dx/=2;
+          while (abs(dy)>5) dy/=2;
+          /* get the pixel color under the center of car in the function map */
+          c=getpixel(fun,clients[i].car.x+dx,clients[i].car.y+dy);
+          /* green layer (road quality) */
+          SDL_GetRGB(c,fun->format,&t,&g,&t);
+          /* if the destination is not a wall and not outside of the track */
+          if (g!=0 && clients[i].car.x>cars[0]->w && clients[i].car.x<fun->w-cars[0]->w && clients[i].car.y>cars[0]->h && clients[i].car.y<fun->h-cars[0]->h)
+          {
+            int round;
+            clients[i].car.x+=dx;
+            clients[i].car.y+=dy;
+            tmp=packet->data;
+            strcpy(tmp,"collision");
+            tmp+=strlen(tmp)+1;
+            SDLNet_Write32(time,tmp);
+            tmp+=4;
+            round=(clients[i].car.x+100)*65536;
+            clients[i].car.x=(float)round/65536-100;
+            SDLNet_Write32(round,tmp);
+            tmp+=4;
+            round=(clients[i].car.y+100)*65536;
+            clients[i].car.y=(float)round/65536-100;
+            SDLNet_Write32(round,tmp);
+            tmp+=4;
+            round=(clients[i].car.speed+100)*65536;
+            clients[i].car.speed=(float)round/65536-100;
+            SDLNet_Write32(round,tmp);
+            tmp+=4;
+            round=(clients[i].car.angle+100)*65536;
+            clients[i].car.angle=(float)round/65536-100;
+            SDLNet_Write32(round,tmp);
+            tmp+=4;
+            packet->len=(void *)tmp-(void *)packet->data;
+            packet->address=clients[i].address;
+            SDLNet_UDP_Send(udpsock,-1,packet);
+            clients[i].lasttime=time;
+          }
+        }
+      }
+      
       /* send update to clients */
       if (time%network_speed==0) for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
       {
@@ -316,6 +467,12 @@ int main(int argc,char *argv[])
           tmp+=2;
           SDLNet_Write16(clients[j].car.color,tmp);
           tmp+=2;
+          SDLNet_Write16(clients[j].car.lights_brake,tmp);
+          tmp+=2;
+          SDLNet_Write16(clients[j].car.lights_backwards,tmp);
+          tmp+=2;
+          SDLNet_Write16(clients[j].car.lights_warning,tmp);
+          tmp+=2;
           nb++;
         }
         SDLNet_Write16(nb,packet->data+strlen("positions")+1+4+4);
@@ -326,6 +483,7 @@ int main(int argc,char *argv[])
       }
       
       /* did someone finish the track ? */
+      for (i=0;i<MAX_CLIENTS;i++) { if (clients[i].car.lapflag==1) printf("client %d : %d laps\n",i,clients[i].car.lap); clients[i].car.lapflag=0; }
       for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected && clients[i].car.lap==nb_laps) finish=1;
       if (finish) break;
         
diff --git a/splashs/4.jpg b/splashs/4.jpg
new file mode 100644 (file)
index 0000000..da2bca3
Binary files /dev/null and b/splashs/4.jpg differ
diff --git a/splashs/5.jpg b/splashs/5.jpg
new file mode 100644 (file)
index 0000000..7063edb
Binary files /dev/null and b/splashs/5.jpg differ
diff --git a/sprites/carM.png b/sprites/carM.png
new file mode 100644 (file)
index 0000000..af5231e
Binary files /dev/null and b/sprites/carM.png differ
diff --git a/sprites/carN.png b/sprites/carN.png
new file mode 100644 (file)
index 0000000..07b0106
Binary files /dev/null and b/sprites/carN.png differ
diff --git a/sprites/carO.png b/sprites/carO.png
new file mode 100644 (file)
index 0000000..ec5d4a0
Binary files /dev/null and b/sprites/carO.png differ
diff --git a/sprites/carP.png b/sprites/carP.png
new file mode 100644 (file)
index 0000000..f85d450
Binary files /dev/null and b/sprites/carP.png differ
diff --git a/sprites/light.png b/sprites/light.png
new file mode 100644 (file)
index 0000000..50e7d88
Binary files /dev/null and b/sprites/light.png differ
diff --git a/tracks/formula.png b/tracks/formula.png
new file mode 100644 (file)
index 0000000..2a64cc3
Binary files /dev/null and b/tracks/formula.png differ
diff --git a/tracks/formula_function.png b/tracks/formula_function.png
new file mode 100644 (file)
index 0000000..ff75da9
Binary files /dev/null and b/tracks/formula_function.png differ
index d198f48..4baf3ea 100644 (file)
@@ -5,8 +5,8 @@ ICFP Programming Contest
 450
 655
 180
-923
-Voisin
+913
+inz
 
 first
 First circuit for this game...
@@ -15,8 +15,8 @@ Royale
 435
 215
 180
-999
-Voisin
+996
+inz
 
 icy
 Same as "First", but in winter !
@@ -25,8 +25,8 @@ Royale
 435
 215
 180
-1149
-mrhe
+1132
+Royale
 
 hairpins
 Hairpins
@@ -35,8 +35,8 @@ ICFP Programming Contest
 505
 665
 0
-3030
-Royale
+2824
+ukero
 
 simple
 Simple
@@ -45,8 +45,8 @@ ICFP Programming Contest
 585
 565
 0
-1766
-Royale
+1548
+ukero
 
 loop
 Loop
@@ -55,5 +55,15 @@ Royale
 678
 686
 0
-1614
-Royale
+1384
+ukero
+
+formula
+Formula
+Ju
+0.1
+350
+330
+220
+1294
+inz
index 3d486b9..96afcf3 100644 (file)
Binary files a/tracks/loop_function.png and b/tracks/loop_function.png differ
index 6f787e0..a4f5252 100644 (file)
--- a/zeRace.c
+++ b/zeRace.c
@@ -1,5 +1,5 @@
 /*
- * zeRace 0.4, a funny retro racing game
+ * zeRace 0.5, a funny retro racing game
  * http://royale.zerezo.com/zerace/
  * 
  * Copyright (C) 2004  Antoine Jacquet <royale@zerezo.com>
 #define WIDTH 1024
 #define HEIGHT 768
 #define MAXRECORDKEYS 9999
+#define NB_CARS 16
+
+/* some usefull colors */
+#define C_BLACK SDL_MapRGB(screen->format,0,0,0)
+#define C_WHITE SDL_MapRGB(screen->format,255,255,255)
+#define C_RED SDL_MapRGB(screen->format,255,0,0)
+#define C_ORANGE SDL_MapRGB(screen->format,255,200,0)
+#define C_YELLOW SDL_MapRGB(screen->format,255,255,100)
 
 /* tracklist */
 struct _tracklist *tracklist;
@@ -59,7 +67,8 @@ struct _config
   SDLKey right;
   int color;
   SDLKey boss;
-} config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6,SDLK_b};
+  int bynight;
+} config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6,SDLK_b,0};
 
 /* full script for a lap */
 struct _record
@@ -71,7 +80,7 @@ struct _record
 
 /* display and all directions for the car */
 SDL_Surface *screen;
-SDL_Surface *cars[12][256];
+SDL_Surface *cars[NB_CARS][256];
 
 /* network stuff */
 UDPsocket udpsock=NULL;
@@ -83,7 +92,7 @@ int network_speed=1;
 void zeRace_read_config()
 {
   FILE *fic;
-  if ((fic=fopen("zeRace.cfg","rt"))==NULL)
+  if ((fic=fopen("zeRace.cfg","rb"))==NULL)
   {
     fprintf(stderr,"can't open config file \"zeRace.cfg\"\n");
     return;
@@ -97,7 +106,7 @@ void zeRace_read_config()
 void zeRace_save_config()
 {
   FILE *fic;
-  if ((fic=fopen("zeRace.cfg","wt"))==NULL)
+  if ((fic=fopen("zeRace.cfg","wb"))==NULL)
   {
     fprintf(stderr,"can't create config file \"zeRace.cfg\"\n");
     return;
@@ -268,7 +277,7 @@ void zeRace_download_file(char *file)
       fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
     else
     {
-      if ((fic=fopen(file,"wt"))==NULL)
+      if ((fic=fopen(file,"wb"))==NULL)
       {
         fprintf(stderr,"can't create \"%s\" file\n",file);
         zeRace_exit();
@@ -294,7 +303,7 @@ void zeRace_generate_cars()
   int i,j;
   SDL_Surface *car;
   char temp[20]="sprites/carX.png";
-  for (i=0;i<12;i++)
+  for (i=0;i<NB_CARS;i++)
   {
     temp[11]='A'+i;
     /* load the car sprite */
@@ -304,7 +313,7 @@ void zeRace_generate_cars()
     {
       float x,y;
       float tcos,tsin;
-      if ((cars[i][j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,0xff<<RSHIFT,0xff<<GSHIFT,0xff<<BSHIFT,0xff<<ASHIFT))==NULL)
+      if ((cars[i][j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,RMASK,GMASK,BMASK,AMASK))==NULL)
       {
         fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
         zeRace_exit();
@@ -349,12 +358,12 @@ void zeRace_init()
   
   /* download missing files */
   loopcheck=tracklist;
-  while (tracklist->next!=loopcheck)
+  do
   {
     zeRace_download_file(tracklist->full);
     zeRace_download_file(tracklist->function);
     tracklist=tracklist->next;
-  }
+  } while (tracklist!=loopcheck);
   
   srand(time(NULL));
   
@@ -481,10 +490,35 @@ void print_time(int x,int y,int time)
 }
 
 
+/* car lights */
+void lights(int x,int y,int r,Uint32 pixel)
+{
+  putpixel(screen,x,y,pixel);
+  if (r>1)
+  {
+    putpixel(screen,x-1,y,pixel);
+    putpixel(screen,x+1,y,pixel);
+    putpixel(screen,x,y-1,pixel);
+    putpixel(screen,x,y+1,pixel);
+  }
+  if (r>2)
+  {
+    putpixel(screen,x-2,y,pixel);
+    putpixel(screen,x+2,y,pixel);
+    putpixel(screen,x,y-2,pixel);
+    putpixel(screen,x,y+2,pixel);
+    putpixel(screen,x-1,y-1,pixel);
+    putpixel(screen,x-1,y+1,pixel);
+    putpixel(screen,x+1,y-1,pixel);
+    putpixel(screen,x+1,y+1,pixel);
+  }
+}
+
+
 /* launch a new race */
 void zeRace_launch(int alltime,int go)
 {
-  SDL_Surface *cir,*fun;
+  SDL_Surface *cir,*fun,*hilight;
   SDL_Rect pos;
   SDL_Event event;
   int ku=0,kd=0,kl=0,kr=0,i;
@@ -496,7 +530,8 @@ void zeRace_launch(int alltime,int go)
   int lastack=alltime;
   struct _record net;
   struct _car oldnetpos[MAX_CLIENTS],newnetpos[MAX_CLIENTS];
-    
+  int l=80,o=15;
+  
   /* free memory */
   void free_mem()
   {
@@ -513,13 +548,31 @@ void zeRace_launch(int alltime,int go)
   }
 
   cir=IMG_Load(tracklist->full);
+  /* dark the track if it is night */
+  if (config.bynight)
+  {
+    for (pos.x=0;pos.x<screen->w;pos.x++)
+      for (pos.y=0;pos.y<screen->h;pos.y++)
+      {
+        Uint32 c;
+        Uint8 r,g,b;
+        c=getpixel(cir,pos.x,pos.y);
+        SDL_GetRGB(c,cir->format,&r,&g,&b);
+        r*=0.3;
+        g*=0.3;
+        b*=0.3;
+        putpixel(cir,pos.x,pos.y,SDL_MapRGB(cir->format,r,g,b));
+      }
+  }
   fun=IMG_Load(tracklist->function);
+  hilight=IMG_Load("sprites/light.png");
   
   current.speed=car.speed=0;
   current.angle=car.angle=tracklist->a*2*M_PI/360;
   current.x=car.ox=car.x=tracklist->x;
   current.y=car.oy=car.y=tracklist->y;
   car.lastcheck=0;
+  car.lapflag=0;
   car.w=cars[0][0]->w;
   car.h=cars[0][0]->h;
   current.time=0;
@@ -626,6 +679,9 @@ void zeRace_launch(int alltime,int go)
       net.keys[net.time+1]='\0';
     }
 
+    /* move the car */
+    move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
+
     delay=DELAY;
     /* if we are in network mode */
     if (udpsock!=NULL)
@@ -648,14 +704,27 @@ void zeRace_launch(int alltime,int go)
           for (i=0;i<nb;i++)
           {
             newnetpos[i].w=newnetpos[i].h=30;
-            newnetpos[i].x=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*8);
-            newnetpos[i].y=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*8+2);
-            newnetpos[i].angle=(float)SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*8+2+2)/1000;
-            newnetpos[i].color=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*8+2+2+2);
+            newnetpos[i].x=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14);
+            newnetpos[i].y=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2);
+            newnetpos[i].angle=(float)SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2)/1000;
+            newnetpos[i].color=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2);
+            newnetpos[i].lights_brake=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2);
+            newnetpos[i].lights_backwards=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2+2);
+            newnetpos[i].lights_warning=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2+2+2);
           }
           lastack=clienttime;
         }
       }
+      else if (strcmp(packet->data,"collision")==0)
+      {
+        net.time=-1;
+        net.keys[0]='\0';
+        lastack=SDLNet_Read32(packet->data+strlen("collision")+1);
+        car.x=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4)/65536-100;
+        car.y=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4)/65536-100;
+        car.speed=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4)/65536-100;
+        car.angle=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4+4)/65536-100;
+      }
       else /* end of this network race */
       {
         zeRace_send_time(best);
@@ -669,6 +738,10 @@ void zeRace_launch(int alltime,int go)
         tmp+=strlen(tmp)+1;
         SDLNet_Write32(lastack,tmp);
         tmp+=4;
+        SDLNet_Write32(car.x,tmp);
+        tmp+=4;
+        SDLNet_Write32(car.y,tmp);
+        tmp+=4;
         strcpy(tmp,net.keys);
         tmp+=strlen(tmp)+1;
         packet->len=(void *)tmp-(void *)packet->data+10;
@@ -697,6 +770,25 @@ void zeRace_launch(int alltime,int go)
     pos.h=car.h;
     SDL_BlitSurface(cir,&pos,screen,&pos);
     
+    /* clear the lights */
+    if (config.bynight)
+    {
+      pos.x=car.ox-cos(car.angle)*l-sin(car.angle)*o;
+      pos.y=car.oy-sin(car.angle)*l+cos(car.angle)*o;
+      pos.x-=60;
+      pos.y-=60;
+      pos.w=120;
+      pos.h=120;
+      SDL_BlitSurface(cir,&pos,screen,&pos);
+      pos.x=car.ox-cos(car.angle)*l+sin(car.angle)*o;
+      pos.y=car.oy-sin(car.angle)*l-cos(car.angle)*o;
+      pos.x-=60;
+      pos.y-=60;
+      pos.w=120;
+      pos.h=120;
+      SDL_BlitSurface(cir,&pos,screen,&pos);
+    }
+
     /* display the network car at the new position */
     if (udpsock) for (i=0;i<MAX_CLIENTS;i++) if (newnetpos[i].w)
     {
@@ -705,6 +797,29 @@ void zeRace_launch(int alltime,int go)
       pos.w=car.w;
       pos.h=car.h;
       SDL_BlitSurface(cars[newnetpos[i].color][(unsigned char)(256*newnetpos[i].angle/2.0/M_PI)%256],NULL,screen,&pos);
+      
+      /* if the car is braking, display red lights */
+      if (newnetpos[i].lights_brake)
+      {
+        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);
+        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);
+      }
+      
+      /* if the car is going backwards, display white lights */
+      if (newnetpos[i].lights_backwards)
+      {
+        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);
+        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);
+      }
+      
+      /* if the car is stopped, then warning */
+      if (newnetpos[i].lights_warning && alltime/75%2)
+      {
+        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);
+        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);
+        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);
+        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);
+      }
     }
     
     /* display the car at the new position */
@@ -714,6 +829,52 @@ void zeRace_launch(int alltime,int go)
     pos.h=car.h;
     SDL_BlitSurface(cars[config.color][(unsigned char)(256*car.angle/2.0/M_PI)%256],NULL,screen,&pos);
     
+    /* if the car is braking, display red lights */
+    if (car.lights_brake)
+    {
+      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);
+      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);
+    }
+    
+    /* if the car is going backwards, display white lights */
+    if (car.lights_backwards)
+    {
+      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);
+      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);
+    }
+    
+    /* if the car is stopped, then warning */
+    if (car.lights_warning && alltime/75%2)
+    {
+      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);
+      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);
+      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);
+      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);
+    }
+    
+    /* display the lights */
+    if (config.bynight)
+    {
+      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);
+      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);
+      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);
+      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);
+      pos.x=car.x-cos(car.angle)*l-sin(car.angle)*o;
+      pos.y=car.y-sin(car.angle)*l+cos(car.angle)*o;
+      pos.x-=50;
+      pos.y-=50;
+      pos.w=100;
+      pos.h=100;
+      SDL_BlitSurface(hilight,NULL,screen,&pos);
+      pos.x=car.x-cos(car.angle)*l+sin(car.angle)*o;
+      pos.y=car.y-sin(car.angle)*l-cos(car.angle)*o;
+      pos.x-=50;
+      pos.y-=50;
+      pos.w=100;
+      pos.h=100;
+      SDL_BlitSurface(hilight,NULL,screen,&pos);
+    }
+    
     /* update display */
     if (udpsock)
     {
@@ -726,12 +887,36 @@ void zeRace_launch(int alltime,int go)
     }
     SDL_UpdateRect(screen,car.ox-car.w/2,car.oy-car.h/2,car.w,car.h);
     SDL_UpdateRect(screen,car.x-car.w/2,car.y-car.h/2,car.w,car.h);
-
+    
+    /* update the lights by night */
+    if (config.bynight)
+    {
+      pos.x=car.x-cos(car.angle)*l-sin(car.angle)*15;
+      pos.y=car.y-sin(car.angle)*l+cos(car.angle)*15;
+      pos.x-=60;
+      pos.y-=60;
+      pos.w=120;
+      pos.h=120;
+      if (pos.x<0) pos.x=0;
+      if (pos.y<0) pos.y=0;
+      if (pos.x+pos.w>screen->w) pos.w=screen->w-pos.x;
+      if (pos.y+pos.h>screen->h) pos.h=screen->h-pos.y;
+      SDL_UpdateRect(screen,pos.x,pos.y,pos.w,pos.h);
+      pos.x=car.x-cos(car.angle)*l+sin(car.angle)*15;
+      pos.y=car.y-sin(car.angle)*l-cos(car.angle)*15;
+      pos.x-=60;
+      pos.y-=60;
+      pos.w=120;
+      pos.h=120;
+      if (pos.x<0) pos.x=0;
+      if (pos.y<0) pos.y=0;
+      if (pos.x+pos.w>screen->w) pos.w=screen->w-pos.x;
+      if (pos.y+pos.h>screen->h) pos.h=screen->h-pos.y;
+      SDL_UpdateRect(screen,pos.x,pos.y,pos.w,pos.h);
+    }
+    
     memcpy(oldnetpos,newnetpos,MAX_CLIENTS*sizeof(struct _car));
     
-    /* move the car */
-    move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
-
     /* play engine sound if no sound is currently playing */
     if (lastsound_time+100<alltime)
     {
@@ -754,13 +939,13 @@ void zeRace_launch(int alltime,int go)
       /* display tires slide */
       if (config.tire)
       {
-        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,0);
-        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,0);
+        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,C_BLACK);
+        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,C_BLACK);
         /* if we are braking the slide is larger */
         if (kd)
         {
-          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,0);
-          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,0);
+          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,C_BLACK);
+          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,C_BLACK);
         }
       }
     }
@@ -786,22 +971,46 @@ void zeRace_launch(int alltime,int go)
     }
     alltime++;
 
-    /* if we completed a lap */
-    if (car.lapflag)
+    switch (car.lapflag)
     {
-      printf("time = %d\"%d\n",current.time*DELAY/1000,current.time*DELAY%1000);
-      print(screen,0,0,"Last lap : ");
-      print_time(110,0,current.time);
-      SDL_UpdateRect(screen,0,0,170,19);
-      /* if it is the first turn of the best turn, save it */
-      if (best.time==-1 || current.time<best.time)
-        memcpy(&best,&current,sizeof(struct _record));
-      /* reset turn variables */
-      current.time=0;
-      current.x=car.x;
-      current.y=car.y;
-      current.angle=car.angle;
-      current.speed=car.speed;
+      /* if we completed a lap */
+      case 1:
+        printf("time = %d\"%d\n",current.time*DELAY/1000,current.time*DELAY%1000);
+        print(screen,0,0,"Last lap :          ");
+        print_time(110,0,current.time);
+        SDL_UpdateRect(screen,0,0,200,19);
+        /* if it is the first turn of the best turn, save it */
+        if (best.time==-1 || current.time<best.time)
+          memcpy(&best,&current,sizeof(struct _record));
+        /* reset turn variables */
+        current.time=0;
+        current.x=car.x;
+        current.y=car.y;
+        current.angle=car.angle;
+        current.speed=car.speed;
+        car.lapflag=0;
+        break;
+      /* if we completed an incomplete lap */
+      case 2:
+        print(screen,0,0,"Last lap : CANCELED ");
+        SDL_UpdateRect(screen,0,0,200,19);
+        /* reset turn variables */
+        current.time=0;
+        car.lapflag=0;
+        break;
+      /* if we miss a checkpoint */
+      case 3:
+        print(screen,0,0,"Checkpoint missed ! ");
+        SDL_UpdateRect(screen,0,0,200,19);
+        break;
+      /* if we validate a missed checkpoint */
+      case 4:
+        print(screen,0,0,"Checkpoint missed OK");
+        SDL_UpdateRect(screen,0,0,200,19);
+        break;
+      /* nothing */
+      default:
+        break;
     }
     
     /* let the system breath */
@@ -817,14 +1026,14 @@ void zeRace_splash()
   SDL_Rect pos;
   char temp[20]="splashs/0.jpg";
   
-  SDL_FillRect(screen,NULL,0x000000);
-  temp[8]=rand()%3+'1';
+  SDL_FillRect(screen,NULL,C_BLACK);
+  temp[8]=rand()%5+'1';
   splash=IMG_Load(temp);
   pos.x=screen->w/2-splash->w/2-1;
   pos.w=splash->w+2;
   pos.y=screen->h/2-splash->h/2-1;
   pos.h=splash->h+2;
-  SDL_FillRect(screen,&pos,0xffffff);
+  SDL_FillRect(screen,&pos,C_WHITE);
   pos.x=screen->w/2-splash->w/2;
   pos.y=screen->h/2-splash->h/2;
   SDL_BlitSurface(splash,NULL,screen,&pos);
@@ -844,7 +1053,7 @@ void zeRace_local()
   {
     SDL_Surface *full,*preview;
     SDL_Rect pos;
-    SDL_FillRect(screen,NULL,0x000000);
+    SDL_FillRect(screen,NULL,C_BLACK);
     print(screen,WIDTH/2-28*5,HEIGHT/6,"* Please choose your race *");
     print(screen,WIDTH/2-strlen(tracklist->title)*5,5*HEIGHT/6-20,tracklist->title);
     print(screen,WIDTH/2-(strlen(tracklist->author)+strlen("Author : "))*5,5*HEIGHT/6+0,"Author : ");
@@ -862,7 +1071,7 @@ void zeRace_local()
     pos.w=preview->w+2;
     pos.y=screen->h/2-preview->h/2-1;
     pos.h=preview->h+2;
-    SDL_FillRect(screen,&pos,0xffffff);
+    SDL_FillRect(screen,&pos,C_WHITE);
     pos.x=WIDTH/2-preview->w/2;
     pos.y=screen->h/2-preview->h/2;
     SDL_BlitSurface(preview,NULL,screen,&pos);
@@ -914,7 +1123,7 @@ void zeRace_top10(char *buf)
 {
   int i,nb,tmp;
   SDL_Rect pos;
-  SDL_FillRect(screen,NULL,0x000000);
+  SDL_FillRect(screen,NULL,C_BLACK);
   nb=SDLNet_Read16(buf);
   buf+=2;
   print(screen,WIDTH/2-16*5,HEIGHT/14,"* Race results *");
@@ -966,7 +1175,7 @@ void zeRace_connect(char *host,int port)
       tmp+=strlen(tmp)+1;
       go=*tmp++;
       printf("server asked for track : %s\n",tmp);
-      while (tracklist->next!=loopcheck) if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next;
+      do if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next; while (tracklist!=loopcheck);
       if (strcmp(tracklist->name,tmp)!=0)
       {
         fprintf(stderr,"unknown track : %s\n",tmp);
@@ -999,7 +1208,7 @@ void zeRace_network()
 
   void update()
   {
-    SDL_FillRect(screen,NULL,0x000000);
+    SDL_FillRect(screen,NULL,C_BLACK);
     print(screen,380,HEIGHT/(NETWORK_OPTIONS+4)*(3+active),">");
     print(screen,WIDTH/2-18*5,HEIGHT/(NETWORK_OPTIONS+4),"* Network screen *");
     print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*3,"Server : ");
@@ -1128,7 +1337,7 @@ void zeRace_internet()
   void update()
   {
     int i;
-    SDL_FillRect(screen,NULL,0x000000);
+    SDL_FillRect(screen,NULL,C_BLACK);
     print(screen,380,HEIGHT/(INTERNET_OPTIONS+4)*(3+active),">");
     print(screen,WIDTH/2-19*5,HEIGHT/(INTERNET_OPTIONS+4),"* Internet screen *");
     for (i=0;i<10;i++)
@@ -1186,12 +1395,12 @@ void zeRace_config()
 {
   SDL_Event event;
   int active=0;
-  #define CONFIG_OPTIONS 12
+  #define CONFIG_OPTIONS 13
   
   void update()
   {
     SDL_Rect pos;
-    SDL_FillRect(screen,NULL,0x000000);
+    SDL_FillRect(screen,NULL,C_BLACK);
     print(screen,20,HEIGHT/(CONFIG_OPTIONS+4)*(3+active),">");
     print(screen,WIDTH/2-24*5,HEIGHT/(CONFIG_OPTIONS+4),"* Configuration screen *");
     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*3,"Pseudo : ");
@@ -1218,6 +1427,8 @@ void zeRace_config()
     SDL_BlitSurface(cars[config.color][0],NULL,screen,&pos);
     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*13,"Boss key : ");
     print(screen,40+10*strlen("Boss key : "),HEIGHT/(CONFIG_OPTIONS+4)*13,config.boss?SDL_GetKeyName(config.boss):"<press key>");
+    print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*14,"By night : ");
+    print(screen,40+10*strlen("By night : "),HEIGHT/(CONFIG_OPTIONS+4)*14,config.bynight?"Yes":"No");
     print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*(CONFIG_OPTIONS+2),"Back to main menu");
     SDL_Flip(screen);
   }
@@ -1267,11 +1478,12 @@ void zeRace_config()
                 case 8: config.right=0; update(); config.right=read_key(); break;
                 case 9:
                   if (event.key.keysym.sym==SDLK_LEFT) config.color--; else config.color++;
-                  if (config.color<0) config.color=11;
-                  if (config.color>11) config.color=0;
+                  if (config.color<0) config.color=NB_CARS-1;
+                  if (config.color>NB_CARS-1) config.color=0;
                   break;
                 case 10: config.boss=0; update(); config.boss=read_key(); break;
-                case 11:
+                case 11: config.bynight=!config.bynight; break;
+                case 12:
                   return;
               }
               update();
@@ -1306,7 +1518,7 @@ void zeRace_menu()
   void update()
   {
     SDL_Rect pos;
-    SDL_FillRect(screen,NULL,0x000000);
+    SDL_FillRect(screen,NULL,C_BLACK);
     pos.x=WIDTH/2-logo->w/2;
     pos.y=HEIGHT/6-logo->h/2;
     SDL_BlitSurface(logo,NULL,screen,&pos);