version 0.5
[zeRace] / bot.c
1 #include "bot.h"
2
3 #define DELAY 7
4 #define MAXRECORDKEYS 9999
5
6 /* tracklist */
7 struct _tracklist *tracklist;
8
9 /* user setup */
10 struct _config
11 {
12   char pseudo[MAXLINELENGTH];
13   char url[MAXLINELENGTH];
14   int fullscreen;
15   int sound;
16   int tire;
17   SDLKey up;
18   SDLKey down;
19   SDLKey left;
20   SDLKey right;
21   int color;
22 } config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6};
23
24 /* full script for a lap */
25 struct _record
26 {
27   float x,y,angle,speed;
28   char keys[MAXRECORDKEYS];
29   int time;
30 };
31
32 /* network stuff */
33 UDPsocket udpsock=NULL;
34 UDPpacket *packet;
35 int network_speed=1;
36 int aleas;
37
38
39 /* exit the game and clean */
40 void zeRace_exit()
41 {
42   printf("quit\n");
43   SDLNet_Quit();
44   SDL_Quit();
45   exit(0);
46 }
47
48
49 /* initialize the game */
50 void zeRace_init()
51 {
52   /* do a clean exit in case of emergency */
53   signal(SIGINT,zeRace_exit);
54   signal(SIGTERM,zeRace_exit);
55
56   /* get the list of local tracks */
57   if (!zeRace_get_tracks(&tracklist)) zeRace_exit();
58   
59   srand(time(NULL));
60   
61   /* robot configuration */
62   sprintf(config.pseudo,"\"%s\" bot(%d)",bot_name(),aleas);
63   config.color=rand()%16;
64   
65   if (SDL_Init(0)<0)
66   {
67     fprintf(stderr,"could not initialize SDL : %s\n",SDL_GetError());
68     zeRace_exit();
69   }
70   atexit(SDL_Quit);
71   
72   if (SDLNet_Init()==-1)
73   {
74     fprintf(stderr,"could not initialize SDLNet : %s\n",SDLNet_GetError());
75     zeRace_exit();
76   }
77
78   packet=SDLNet_AllocPacket(1024);
79   if (!packet)
80   {
81     fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError());
82     zeRace_exit();
83   }
84 }
85
86
87 /* launch a new race */
88 void zeRace_launch(int alltime,int go)
89 {
90   SDL_Surface *cir,*fun;
91   int ku=0,kd=0,kl=0,kr=0,i;
92   struct _car car;
93   int delay=DELAY;
94   int lastack=alltime;
95   struct _record net;
96
97   cir=IMG_Load(tracklist->full);
98   fun=IMG_Load(tracklist->function);
99   
100   car.speed=0;
101   car.angle=tracklist->a*2*M_PI/360;
102   car.ox=car.x=tracklist->x;
103   car.oy=car.y=tracklist->y;
104   car.lastcheck=0;
105   car.w=30;
106   car.h=30;
107   net.time=0;
108
109   /* startup countdown */
110   for (i=4;i>=-1;i--)
111   {
112     if (!go) break;
113     if (i!=-1) SDL_Delay(1000);
114   }
115   
116   /* main loop */
117   for (;;)
118   {
119     /* call the IA */
120     bot_ia(tracklist->name,&car,fun,&ku,&kd,&kl,&kr);
121     
122     /* random movement if asked */
123     if (aleas) if (rand()%aleas==0)
124     {
125       ku=rand()%2;
126       kl=rand()%2;
127       kr=rand()%2;
128       kd=rand()%2;
129     }
130     
131     if (udpsock)
132     {
133       net.keys[net.time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
134       net.keys[net.time+1]='\0';
135     }
136
137     /* move the car */
138     move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
139
140     delay=DELAY;
141     /* if we are in network mode */
142     if (udpsock!=NULL)
143     {
144       char *tmp;
145       while (SDLNet_UDP_Recv(udpsock,packet)) if (strcmp(packet->data,"positions")==0)
146       {
147         int servertime,clienttime,nb;
148         servertime=SDLNet_Read32(packet->data+strlen("positions")+1);
149         clienttime=SDLNet_Read32(packet->data+strlen("positions")+1+4);
150         nb=SDLNet_Read16(packet->data+strlen("positions")+1+4+4);
151         if (clienttime>lastack)
152         {
153           memcpy(net.keys,net.keys+clienttime-lastack,net.time+1);
154           net.time-=clienttime-lastack;
155           if (clienttime>servertime+5) delay+=DELAY;
156           if (clienttime<servertime-5) delay-=DELAY;
157           if (delay<0) delay=0;
158           lastack=clienttime;
159         }
160       }
161       else if (strcmp(packet->data,"collision")==0)
162       {
163         net.time=-1;
164         net.keys[0]='\0';
165         lastack=SDLNet_Read32(packet->data+strlen("collision")+1);
166         car.x=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4)/65536-100;
167         car.y=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4)/65536-100;
168         car.speed=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4)/65536-100;
169         car.angle=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4+4)/65536-100;
170       }
171       else /* end of this network race */
172       {
173         SDL_FreeSurface(cir);
174         SDL_FreeSurface(fun);
175         return;
176       }
177       if (strlen(net.keys)!=0)
178       {
179         tmp=packet->data;
180         strcpy(tmp,"keys");
181         tmp+=strlen(tmp)+1;
182         SDLNet_Write32(lastack,tmp);
183         tmp+=4;
184         SDLNet_Write32(car.x,tmp);
185         tmp+=4;
186         SDLNet_Write32(car.y,tmp);
187         tmp+=4;
188         strcpy(tmp,net.keys);
189         tmp+=strlen(tmp)+1;
190         packet->len=(void *)tmp-(void *)packet->data+10;
191         if (net.time%network_speed==0) if (!SDLNet_UDP_Send(udpsock,-1,packet))
192         {
193           fprintf(stderr,"SDLNet_UDP_Send: %s\n",SDLNet_GetError());
194           exit(2);
195         };
196       }
197     }
198
199     /* let the system breath */
200     SDL_Delay(delay);
201     
202     /* game time */
203     net.time++;
204     if (udpsock && net.time>MAX_LAG)
205     {
206       fprintf(stderr,"timeout !\n");
207       SDL_FreeSurface(cir);
208       SDL_FreeSurface(fun);
209       return;
210     }
211     alltime++;
212   }
213 }
214
215
216 /* connect to a server */
217 void zeRace_connect(char *host,int port)
218 {
219   char *tmp;
220   int lag=0;
221   udpsock=SDLNet_UDP_Open(0);
222   if (udpsock==NULL)
223   {
224     fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
225     zeRace_exit();
226   }
227   SDLNet_ResolveHost(&packet->address,host,port);
228   tmp=packet->data;
229   strcpy(tmp,"connect");
230   tmp+=strlen(tmp)+1;
231   strcpy(tmp,config.pseudo);
232   tmp+=strlen(tmp)+1;
233   SDLNet_Write16(config.color,tmp);
234   tmp+=2;
235   packet->len=(void *)tmp-(void *)packet->data;
236   SDLNet_UDP_Send(udpsock,-1,packet);
237   /* network loop */
238   while (SDLNet_UDP_Recv(udpsock,packet) || lag<MAX_LAG)
239   {
240     tmp=packet->data;
241     if (strcmp(tmp,"track")==0)
242     {
243       struct _tracklist *loopcheck=tracklist;
244       int time;
245       char go;
246       tmp+=strlen(tmp)+1;
247       go=*tmp++;
248       printf("server asked for track : %s\n",tmp);
249       do if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next; while (tracklist!=loopcheck);
250       if (strcmp(tracklist->name,tmp)!=0)
251       {
252         fprintf(stderr,"unknown track : %s\n",tmp);
253         zeRace_exit();
254       }
255       tmp+=strlen(tmp)+1;
256       time=SDLNet_Read32(tmp);
257       tmp+=4;
258       network_speed=SDLNet_Read32(tmp);
259       zeRace_launch(time,go);
260       if (strcmp(packet->data,"finish")==0) SDL_Delay(5000);
261       lag=0;
262     }
263     SDL_Delay(7);
264     lag++;
265   }
266   SDLNet_UDP_Close(udpsock);
267   udpsock=NULL;
268 }
269
270
271 /* main program */
272 int main(int argc,char *argv[])
273 {
274   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); }
275   aleas=atoi(argv[3]);
276   zeRace_init();
277   zeRace_connect(argv[1],atoi(argv[2]));
278   zeRace_exit();
279   return 0;
280 }