--- /dev/null
+#include "bot.h"
+
+#define DELAY 7
+#define MAXRECORDKEYS 9999
+
+/* tracklist */
+struct _tracklist *tracklist;
+
+/* user setup */
+struct _config
+{
+ char pseudo[MAXLINELENGTH];
+ char url[MAXLINELENGTH];
+ int fullscreen;
+ int sound;
+ int tire;
+ SDLKey up;
+ SDLKey down;
+ SDLKey left;
+ SDLKey right;
+ int color;
+} config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6};
+
+/* full script for a lap */
+struct _record
+{
+ float x,y,angle,speed;
+ char keys[MAXRECORDKEYS];
+ int time;
+};
+
+/* network stuff */
+UDPsocket udpsock=NULL;
+UDPpacket *packet;
+int network_speed=1;
+int aleas;
+
+
+/* exit the game and clean */
+void zeRace_exit()
+{
+ printf("quit\n");
+ SDLNet_Quit();
+ SDL_Quit();
+ exit(0);
+}
+
+
+/* initialize the game */
+void zeRace_init()
+{
+ /* do a clean exit in case of emergency */
+ signal(SIGINT,zeRace_exit);
+ signal(SIGTERM,zeRace_exit);
+
+ /* get the list of local tracks */
+ if (!zeRace_get_tracks(&tracklist)) zeRace_exit();
+
+ srand(time(NULL));
+
+ /* robot configuration */
+ sprintf(config.pseudo,"\"%s\" bot(%d)",bot_name(),aleas);
+ config.color=rand()%12;
+
+ if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0)
+ {
+ fprintf(stderr,"could not initialize SDL : %s\n",SDL_GetError());
+ zeRace_exit();
+ }
+ atexit(SDL_Quit);
+
+ if (SDLNet_Init()==-1)
+ {
+ fprintf(stderr,"could not initialize SDLNet : %s\n",SDLNet_GetError());
+ zeRace_exit();
+ }
+
+ packet=SDLNet_AllocPacket(1024);
+ if (!packet)
+ {
+ fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
+ zeRace_exit();
+ }
+}
+
+
+/* launch a new race */
+void zeRace_launch(int alltime,int go)
+{
+ SDL_Surface *cir,*fun;
+ int ku=0,kd=0,kl=0,kr=0,i;
+ struct _car car;
+ int delay=DELAY;
+ int lastack=alltime;
+ struct _record net;
+
+ cir=IMG_Load(tracklist->full);
+ fun=IMG_Load(tracklist->function);
+
+ car.speed=0;
+ car.angle=tracklist->a*2*M_PI/360;
+ car.ox=car.x=tracklist->x;
+ car.oy=car.y=tracklist->y;
+ car.lastcheck=0;
+ car.w=30;
+ car.h=30;
+ net.time=0;
+
+ /* startup countdown */
+ for (i=4;i>=-1;i--)
+ {
+ if (!go) break;
+ if (i!=-1) SDL_Delay(1000);
+ }
+
+ /* main loop */
+ for (;;)
+ {
+ /* call the IA */
+ bot_ia(tracklist->name,&car,fun,&ku,&kd,&kl,&kr);
+
+ /* random movement if asked */
+ if (aleas) if (rand()%aleas==0)
+ {
+ ku=rand()%2;
+ kl=rand()%2;
+ kr=rand()%2;
+ kd=rand()%2;
+ }
+
+ if (udpsock)
+ {
+ net.keys[net.time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
+ net.keys[net.time+1]='\0';
+ }
+
+ delay=DELAY;
+ /* if we are in network mode */
+ if (udpsock!=NULL)
+ {
+ char *tmp;
+ while (SDLNet_UDP_Recv(udpsock,packet)) if (strcmp(packet->data,"positions")==0)
+ {
+ int servertime,clienttime,nb;
+ servertime=SDLNet_Read32(packet->data+strlen("positions")+1);
+ clienttime=SDLNet_Read32(packet->data+strlen("positions")+1+4);
+ nb=SDLNet_Read16(packet->data+strlen("positions")+1+4+4);
+ if (clienttime>lastack)
+ {
+ memcpy(net.keys,net.keys+clienttime-lastack,net.time+1);
+ net.time-=clienttime-lastack;
+ if (clienttime>servertime+5) delay+=DELAY;
+ if (clienttime<servertime-5) delay-=DELAY;
+ if (delay<0) delay=0;
+ lastack=clienttime;
+ }
+ }
+ else /* end of this network race */
+ {
+ SDL_FreeSurface(cir);
+ SDL_FreeSurface(fun);
+ return;
+ }
+ if (strlen(net.keys)!=0)
+ {
+ tmp=packet->data;
+ strcpy(tmp,"keys");
+ tmp+=strlen(tmp)+1;
+ SDLNet_Write32(lastack,tmp);
+ tmp+=4;
+ strcpy(tmp,net.keys);
+ tmp+=strlen(tmp)+1;
+ packet->len=(void *)tmp-(void *)packet->data+10;
+ if (net.time%network_speed==0) if (!SDLNet_UDP_Send(udpsock,-1,packet))
+ {
+ fprintf(stderr,"SDLNet_UDP_Send: %s\n",SDLNet_GetError());
+ exit(2);
+ };
+ }
+ }
+
+ /* move the car */
+ move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
+
+ /* let the system breath */
+ SDL_Delay(delay);
+
+ /* game time */
+ net.time++;
+ if (udpsock && net.time>MAX_LAG)
+ {
+ fprintf(stderr,"timeout !\n");
+ SDL_FreeSurface(cir);
+ SDL_FreeSurface(fun);
+ return;
+ }
+ alltime++;
+ }
+}
+
+
+/* connect to a server */
+void zeRace_connect(char *host,int port)
+{
+ char *tmp;
+ int lag=0;
+ udpsock=SDLNet_UDP_Open(0);
+ if (udpsock==NULL)
+ {
+ fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
+ zeRace_exit();
+ }
+ SDLNet_ResolveHost(&packet->address,host,port);
+ tmp=packet->data;
+ strcpy(tmp,"connect");
+ tmp+=strlen(tmp)+1;
+ strcpy(tmp,config.pseudo);
+ tmp+=strlen(tmp)+1;
+ SDLNet_Write16(config.color,tmp);
+ tmp+=2;
+ packet->len=(void *)tmp-(void *)packet->data;
+ SDLNet_UDP_Send(udpsock,-1,packet);
+ /* network loop */
+ while (SDLNet_UDP_Recv(udpsock,packet) || lag<MAX_LAG)
+ {
+ tmp=packet->data;
+ if (strcmp(tmp,"track")==0)
+ {
+ struct _tracklist *loopcheck=tracklist;
+ int time;
+ char go;
+ 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;
+ if (strcmp(tracklist->name,tmp)!=0)
+ {
+ fprintf(stderr,"unknown track : %s\n",tmp);
+ zeRace_exit();
+ }
+ tmp+=strlen(tmp)+1;
+ time=SDLNet_Read32(tmp);
+ tmp+=4;
+ network_speed=SDLNet_Read32(tmp);
+ zeRace_launch(time,go);
+ if (strcmp(packet->data,"finish")==0) SDL_Delay(5000);
+ lag=0;
+ }
+ SDL_Delay(7);
+ lag++;
+ }
+ SDLNet_UDP_Close(udpsock);
+ udpsock=NULL;
+}
+
+
+/* main program */
+int main(int argc,char *argv[])
+{
+ if (argc!=4) { fprintf(stderr,"Usage : %s host port random\n host : host or ip of the server to connect to\n port : port number of the server to connect to\n random : frequency of random moves (0 = no random moves, 1 = only random, 1000 = 1/1000 random moves)\n",argv[0]); exit(1); }
+ aleas=atoi(argv[3]);
+ zeRace_init();
+ zeRace_connect(argv[1],atoi(argv[2]));
+ zeRace_exit();
+ return 0;
+}