version 0.4
[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()%12;
64   
65   if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<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     delay=DELAY;
138     /* if we are in network mode */
139     if (udpsock!=NULL)
140     {
141       char *tmp;
142       while (SDLNet_UDP_Recv(udpsock,packet)) if (strcmp(packet->data,"positions")==0)
143       {
144         int servertime,clienttime,nb;
145         servertime=SDLNet_Read32(packet->data+strlen("positions")+1);
146         clienttime=SDLNet_Read32(packet->data+strlen("positions")+1+4);
147         nb=SDLNet_Read16(packet->data+strlen("positions")+1+4+4);
148         if (clienttime>lastack)
149         {
150           memcpy(net.keys,net.keys+clienttime-lastack,net.time+1);
151           net.time-=clienttime-lastack;
152           if (clienttime>servertime+5) delay+=DELAY;
153           if (clienttime<servertime-5) delay-=DELAY;
154           if (delay<0) delay=0;
155           lastack=clienttime;
156         }
157       }
158       else /* end of this network race */
159       {
160         SDL_FreeSurface(cir);
161         SDL_FreeSurface(fun);
162         return;
163       }
164       if (strlen(net.keys)!=0)
165       {
166         tmp=packet->data;
167         strcpy(tmp,"keys");
168         tmp+=strlen(tmp)+1;
169         SDLNet_Write32(lastack,tmp);
170         tmp+=4;
171         strcpy(tmp,net.keys);
172         tmp+=strlen(tmp)+1;
173         packet->len=(void *)tmp-(void *)packet->data+10;
174         if (net.time%network_speed==0) if (!SDLNet_UDP_Send(udpsock,-1,packet))
175         {
176           fprintf(stderr,"SDLNet_UDP_Send: %s\n",SDLNet_GetError());
177           exit(2);
178         };
179       }
180     }
181
182     /* move the car */
183     move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
184
185     /* let the system breath */
186     SDL_Delay(delay);
187     
188     /* game time */
189     net.time++;
190     if (udpsock && net.time>MAX_LAG)
191     {
192       fprintf(stderr,"timeout !\n");
193       SDL_FreeSurface(cir);
194       SDL_FreeSurface(fun);
195       return;
196     }
197     alltime++;
198   }
199 }
200
201
202 /* connect to a server */
203 void zeRace_connect(char *host,int port)
204 {
205   char *tmp;
206   int lag=0;
207   udpsock=SDLNet_UDP_Open(0);
208   if (udpsock==NULL)
209   {
210     fprintf(stderr,"SDLNet_UDP_Open: %s\n",SDLNet_GetError());
211     zeRace_exit();
212   }
213   SDLNet_ResolveHost(&packet->address,host,port);
214   tmp=packet->data;
215   strcpy(tmp,"connect");
216   tmp+=strlen(tmp)+1;
217   strcpy(tmp,config.pseudo);
218   tmp+=strlen(tmp)+1;
219   SDLNet_Write16(config.color,tmp);
220   tmp+=2;
221   packet->len=(void *)tmp-(void *)packet->data;
222   SDLNet_UDP_Send(udpsock,-1,packet);
223   /* network loop */
224   while (SDLNet_UDP_Recv(udpsock,packet) || lag<MAX_LAG)
225   {
226     tmp=packet->data;
227     if (strcmp(tmp,"track")==0)
228     {
229       struct _tracklist *loopcheck=tracklist;
230       int time;
231       char go;
232       tmp+=strlen(tmp)+1;
233       go=*tmp++;
234       printf("server asked for track : %s\n",tmp);
235       while (tracklist->next!=loopcheck) if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next;
236       if (strcmp(tracklist->name,tmp)!=0)
237       {
238         fprintf(stderr,"unknown track : %s\n",tmp);
239         zeRace_exit();
240       }
241       tmp+=strlen(tmp)+1;
242       time=SDLNet_Read32(tmp);
243       tmp+=4;
244       network_speed=SDLNet_Read32(tmp);
245       zeRace_launch(time,go);
246       if (strcmp(packet->data,"finish")==0) SDL_Delay(5000);
247       lag=0;
248     }
249     SDL_Delay(7);
250     lag++;
251   }
252   SDLNet_UDP_Close(udpsock);
253   udpsock=NULL;
254 }
255
256
257 /* main program */
258 int main(int argc,char *argv[])
259 {
260   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); }
261   aleas=atoi(argv[3]);
262   zeRace_init();
263   zeRace_connect(argv[1],atoi(argv[2]));
264   zeRace_exit();
265   return 0;
266 }