Change log file for zeRace
+version 0.4 (2004-11-28)
+ * added "loop" track
+ * fixed "car" track
+ * fixed "hairpins" track
+ * added boss key (thank you Christophe Sauthier)
+ * tracks server (client can now download new tracks when they are available)
+ * improved network protocol
+ * added a framework to program bots
+ * first bot for the game : "Anticip"
+ * fixed memory management (server and client release memory when changing track)
+ * generic Makefile (easier to compile Linux/Windows binaries)
+ * network startup was fixed to avoid to much delay between clients and server
+ * fixed a bug when sending keys for record validation
+ * also send records in network mode
+ * game and network protocol are now endian safe (thank you Markus W. Weissmann)
+
version 0.3 (2004-09-27)
* added network/internet mode
* code is now split into generic modules
CC=gcc
+SDLCONFIG=sdl-config
-all:zeRace server
+all:zeRace server bot_anticip
-zeRace:zeRace.c network.h sdl.o car.o tracklist.o
- $(CC) -ansi -Wall -o zeRace zeRace.c sdl.o car.o tracklist.o `sdl-config --cflags --libs` -lSDL_net -lSDL_mixer -lSDL_image -lSDL_gfx
+zeRace:zeRace.c network.h sdl.o car.o tracklist.o $(ICON)
+ $(CC) -ansi -Wall -o zeRace$(EXT) zeRace.c sdl.o car.o tracklist.o $(ICON) `$(SDLCONFIG) --cflags --libs` -lSDL_net -lSDL_mixer -lSDL_image -lSDL_gfx -L.
server:server.c network.h sdl.o car.o tracklist.o
- $(CC) -ansi -Wall -o server server.c sdl.o car.o tracklist.o `sdl-config --cflags --libs` -lSDL_net -lSDL_image
+ $(CC) -ansi -Wall -o server$(EXT) server.c sdl.o car.o tracklist.o `$(SDLCONFIG) --cflags --libs` -lSDL_net -lSDL_image -L.
+
+bot_anticip:bot_anticip.c bot.o sdl.o car.o tracklist.o
+ $(CC) -ansi -Wall -o bot_anticip$(EXT) bot_anticip.c bot.o sdl.o car.o tracklist.o `$(SDLCONFIG) --cflags --libs` -lSDL_net -lSDL_image -L.
sdl.o:sdl.c sdl.h
- $(CC) -ansi -Wall -c sdl.c `sdl-config --cflags`
+ $(CC) -ansi -Wall -c sdl.c `$(SDLCONFIG) --cflags`
-car.o:car.c car.h
- $(CC) -ansi -Wall -c car.c `sdl-config --cflags`
+car.o:car.c car.h sdl.h
+ $(CC) -ansi -Wall -c car.c `$(SDLCONFIG) --cflags`
tracklist.o:tracklist.c tracklist.h
$(CC) -ansi -Wall -c tracklist.c
+bot.o:bot.c sdl.o car.o tracklist.o
+ $(CC) -ansi -Wall -c bot.c `$(SDLCONFIG) --cflags`
+
+icon.o:icon.rc
+ $(WINDRES) -i icon.rc -o icon.o
+
clean:
- rm -f zeRace server *.o *.cfg
+ rm -f zeRace server bot_anticip *.exe *.o *.cfg
-zeRace 0.3
+zeRace 0.4
site: http://royale.zerezo.com/zerace/
mail: royale@zerezo.com
+
+install:
+In order to compile the game, you will need SDL, SDL_net, SDL_mixer, SDL_image, SDL_gfx and the related developpement headers.
+Then, just type "make" to build the game.
+The Makefile as some parameters. For example, in order to cross-compile Windows binaries using MinGW you can type :
+make CC=i586-mingw32msvc-gcc SDLCONFIG=/path/to/sdl-config WINDRES=i586-mingw32msvc-windres ICON=icon.o EXT=.exe
+
+bots:
+To play a game against bots, you will first need to launch a local server :
+./server "My private server" 5 1 private
+Then launch as many bots as you want :
+./bot_anticip localhost 3600 0
+./bot_anticip localhost 3600 8
+./bot_anticip localhost 3600 16
+Then you can join your own server in zeRace in the "network game" section.
+If you are under Windows, replace by "server.exe" and "bot_anticip.exe" in MS-DOS commands.
--- /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;
+}
--- /dev/null
+/* generic bot framework */
+
+#include <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#include <math.h>
+#include <string.h>
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_net.h>
+#include "sdl.h"
+#include "car.h"
+#include "tracklist.h"
+#include "network.h"
+
+/* ia functions */
+char *bot_name();
+void bot_ia(char *trackname,struct _car *car,SDL_Surface *fun,int *ku,int *kd,int *kl,int *kr);
--- /dev/null
+/*
+ * zeRace "anticip" bot
+ * http://royale.zerezo.com/zerace/
+ *
+ * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com>
+ * Licensed under GPL
+ *
+ * This robot uses the idea described on this page :
+ * http://rars.sourceforge.net/selection/felix.html
+ * Thanks to Doug Eleveld
+ */
+
+#include "bot.h"
+
+char *bot_name()
+{
+ return "Anticip";
+}
+
+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;
+ float o,m,s;
+
+ /* adjust the properties depending of the track, this was "manually" optimized ;) */
+ if (strcmp(trackname,"car")==0)
+ {
+ a1=190;
+ a2=180;
+ o=0.1;
+ m=0.1;
+ s=car->speed/3.3+0.4;
+ og=130;
+ }
+ else if (strcmp(trackname,"first")==0)
+ {
+ a1=240;
+ a2=230;
+ o=0.1;
+ m=0.1;
+ s=car->speed/3.3+0.3;
+ og=120;
+ }
+ else if (strcmp(trackname,"icy")==0)
+ {
+ a1=250;
+ a2=240;
+ o=0.3;
+ m=0.1;
+ s=car->speed/3.3+0.3;
+ og=120;
+ }
+ else if (strcmp(trackname,"hairpins")==0)
+ {
+ a1=220;
+ a2=210;
+ o=0.6;
+ m=0.1;
+ s=car->speed/3.3+0.4;
+ og=120;
+ }
+ else if (strcmp(trackname,"simple")==0)
+ {
+ a1=190;
+ a2=180;
+ o=0.2;
+ m=0.1;
+ s=car->speed/3.3+0.4;
+ og=1;
+ }
+ else if (strcmp(trackname,"loop")==0)
+ {
+ a1=150;
+ a2=90;
+ o=0.8;
+ m=0.1;
+ s=car->speed/3.3+0.4;
+ og=1;
+ }
+ /* some default values that may work on some tracks */
+ else
+ {
+ a1=190;
+ a2=180;
+ o=0.2;
+ m=0.1;
+ s=car->speed/3.3+0.4;
+ og=1;
+ }
+
+ /* should we accelerate or brake ? */
+ c=getpixel(fun,car->x,car->y);
+ *ku=1,*kd=0;
+ for (l=0;l<a1;l++)
+ {
+ 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 (g<og && car->speed>m) { *ku=0,*kd=1; break; }
+ }
+
+ /* should we turn ? left or right ? */
+ *kl=0;
+ *kr=0;
+ for (l=0;l<a2;l++)
+ {
+ x2=car->x-cos(car->angle)*l*s;
+ y2=car->y-sin(car->angle)*l*s;
+ x3=car->x-cos(car->angle-o)*l*s;
+ y3=car->y-sin(car->angle-o)*l*s;
+ 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 (g>tg) { *kr=1; break; } else if (g<tg) { *kl=1; break; }
+ }
+}
void move_car(struct _car *car,int keys,SDL_Surface *fun)
{
- int c,r,g,b;
+ Uint32 c,r,g,b;
/* reset flags */
car->lapflag=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 )&0xff;
+ r=(c>>RSHIFT)&0xff;
/* green layer (road quality) */
- g=(c>>8 )&0xff;
- /* blue layer (unused) */
- b=(c>>16)&0xff;
+ g=(c>>GSHIFT)&0xff;
+ /* blue layer (grip) */
+ b=(c>>BSHIFT)&0xff;
if (keys & 8) /* up */
car->speed+=0.01*2*COEFF;
#define MAX_LAG 500
#define MAX_CLIENTS 32
#define PORT "3600"
-#define VERSION "0.3"
+#define VERSION "0.4"
#include <SDL.h>
#include <SDL_image.h>
+/* endianness setup */
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+ #define RSHIFT 24
+ #define GSHIFT 16
+ #define BSHIFT 8
+ #define ASHIFT 0
+#else
+ #define RSHIFT 0
+ #define GSHIFT 8
+ #define BSHIFT 16
+ #define ASHIFT 24
+#endif
+
void print(SDL_Surface *dst,int x,int y,unsigned char *text);
void readstring(SDL_Surface *dst,int x,int y,unsigned char *text,int limit);
Uint32 getpixel(SDL_Surface *surface, int x, int y);
printf("announcing server... ");
fflush(stdout);
- if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
{
fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
return;
}
tcpsock=SDLNet_TCP_Open(&ip);
- if(!tcpsock)
+ if (!tcpsock)
{
fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
return;
len=strlen(temp);
result=SDLNet_TCP_Send(tcpsock,temp,len);
- if(result<len)
+ if (result<len)
fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
else
printf("done\n");
-
+
+ free(temp);
SDLNet_TCP_Close(tcpsock);
}
*tmp++=1; /* startup countdown */
strcpy(tmp,tracklist->name);
tmp+=strlen(tmp)+1;
- memcpy(tmp,&time,sizeof(int));
- tmp+=sizeof(int);
- memcpy(tmp,&network_speed,sizeof(int));
- tmp+=sizeof(int);
+ SDLNet_Write32(time,tmp);
+ tmp+=4;
+ SDLNet_Write32(network_speed,tmp);
+ tmp+=4;
packet->len=(void *)tmp-(void *)packet->data;
for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
{
/* wait for everybody startup */
for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected) break;
- if (i!=MAX_CLIENTS) SDL_Delay(5000);
+ /* 5000ms for countdown, and 500ms for loading time... */
+ if (i!=MAX_CLIENTS) SDL_Delay(5500);
printf("go\n");
tmp+=strlen(tmp)+1;
strcpy(clients[i].pseudo,tmp);
tmp+=strlen(tmp)+1;
- memcpy(&clients[i].car.color,tmp,sizeof(int));
+ clients[i].car.color=SDLNet_Read16(tmp);
clients[i].car.x=tracklist->x;
clients[i].car.y=tracklist->y;
clients[i].car.w=30;
*tmp++=0; /* no startup countdown */
strcpy(tmp,tracklist->name);
tmp+=strlen(tmp)+1;
- memcpy(tmp,&time,sizeof(int));
- tmp+=sizeof(int);
- memcpy(tmp,&network_speed,sizeof(int));
- tmp+=sizeof(int);
+ SDLNet_Write32(time,tmp);
+ tmp+=4;
+ SDLNet_Write32(network_speed,tmp);
+ tmp+=4;
packet->len=(void *)tmp-(void *)packet->data;
SDLNet_UDP_Send(udpsock,-1,packet);
break;
{
int temp;
tmp+=strlen(tmp)+1;
- memcpy(&temp,tmp,sizeof(int));
- tmp+=sizeof(int);
- if (clients[id].lasttime==temp)
+ temp=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)
tmp=packet->data;
strcpy(tmp,"positions");
tmp+=strlen(tmp)+1;
- memcpy(tmp,&time,sizeof(int));
- tmp+=sizeof(int); /* for server time */
- tmp+=sizeof(int); /* for client time */
- tmp+=sizeof(int); /* for number of cars */
+ SDLNet_Write32(time,tmp);
+ tmp+=4; /* for server time */
+ tmp+=4; /* for client time */
+ tmp+=2; /* for number of cars */
nb=0;
for (j=0;j<MAX_CLIENTS;j++) if (j!=i && clients[j].connected)
{
- memcpy(tmp,&clients[j].car,sizeof(struct _car));
- tmp+=sizeof(struct _car);
+ SDLNet_Write16(clients[j].car.x,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.y,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.angle*1000,tmp);
+ tmp+=2;
+ SDLNet_Write16(clients[j].car.color,tmp);
+ tmp+=2;
nb++;
}
- memcpy(packet->data+strlen("positions")+1+sizeof(int)+sizeof(int),&nb,sizeof(int));
+ SDLNet_Write16(nb,packet->data+strlen("positions")+1+4+4);
+ SDLNet_Write32(clients[i].lasttime,packet->data+strlen("positions")+1+4);
packet->len=(void *)tmp-(void *)packet->data;
- memcpy(packet->data+strlen("positions")+1+sizeof(int),&clients[i].lasttime,sizeof(int));
packet->address=clients[i].address;
SDLNet_UDP_Send(udpsock,-1,packet);
}
tmp=packet->data;
strcpy(tmp,"finish");
tmp+=strlen(tmp)+1;
- tmp+=sizeof(int); /* space for number */
+ tmp+=2; /* space for number */
nb=0;
for (i=0;i<10;i++)
{
{
sprintf(tmp,"%s : %d",clients[best_id].pseudo,best_sc);
tmp+=strlen(tmp)+1;
- memcpy(tmp,&clients[best_id].car.color,sizeof(int));
- tmp+=sizeof(int);
+ SDLNet_Write16(clients[best_id].car.color,tmp);
+ tmp+=2;
clients[best_id].car.lap=-1;
nb++;
printf("top %d : %s - %d\n",nb,clients[best_id].pseudo,best_sc);
}
}
- memcpy(packet->data+strlen("finish")+1,&nb,sizeof(int));
+ SDLNet_Write16(nb,packet->data+strlen("finish")+1);
packet->len=(void *)tmp-(void *)packet->data;
for (i=0;i<MAX_CLIENTS;i++) if (clients[i].connected)
{
SDLNet_UDP_Send(udpsock,-1,packet);
}
SDL_Delay(5000);
-
+
+ SDL_FreeSurface(fun);
tracklist=tracklist->next;
}
435
215
180
-1175
-Royale
+1149
+mrhe
hairpins
Hairpins
505
665
0
-3158
-Voisin
+3030
+Royale
simple
Simple
585
565
0
-1784
-Voisin
+1766
+Royale
+
+loop
+Loop
+Royale
+0.1
+678
+686
+0
+1614
+Royale
/*
- * zeRace 0.3, a funny retro racing game
+ * zeRace 0.4, a funny retro racing game
* http://royale.zerezo.com/zerace/
*
* Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com>
#include "car.h"
#include "tracklist.h"
#include "network.h"
+#include <sys/stat.h>
/* configuration constants */
#define COEFF 1
SDLKey left;
SDLKey right;
int color;
-} config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6};
+ SDLKey boss;
+} config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6,SDLK_b};
/* full script for a lap */
struct _record
printf("checking version... ");
fflush(stdout);
- if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
{
fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
return;
}
tcpsock=SDLNet_TCP_Open(&ip);
- if(!tcpsock)
+ if (!tcpsock)
{
fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
return;
len=strlen(request);
result=SDLNet_TCP_Send(tcpsock,request,len);
- if(result<len)
+ if (result<len)
fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
else
printf("done\n");
printf("checking version and updating tracks... ");
fflush(stdout);
- if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
{
fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
return;
}
tcpsock=SDLNet_TCP_Open(&ip);
- if(!tcpsock)
+ if (!tcpsock)
{
fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
return;
len=strlen(request);
result=SDLNet_TCP_Send(tcpsock,request,len);
- if(result<len)
+ if (result<len)
fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
else
{
}
+/* download the file if it is missing */
+void zeRace_download_file(char *file)
+{
+ IPaddress ip;
+ TCPsocket tcpsock;
+ char request[1024];
+ char response[10240],*tmp;
+ int len,result;
+ FILE *fic;
+ struct stat buf;
+
+ if (stat(file,&buf)<0)
+ {
+ printf("downloading file \"%s\" : ",file);
+ fflush(stdout);
+
+ if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ {
+ fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
+ return;
+ }
+
+ tcpsock=SDLNet_TCP_Open(&ip);
+ if (!tcpsock)
+ {
+ fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
+ return;
+ }
+
+ sprintf(request,
+ "GET /zerace/%s HTTP/1.0\n"
+ "Host: royale.zerezo.com\n"
+ "User-Agent: zeRace " VERSION "\n"
+ "\n",file);
+ len=strlen(request);
+ result=SDLNet_TCP_Send(tcpsock,request,len);
+ if (result<len)
+ fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
+ else
+ {
+ if ((fic=fopen(file,"wt"))==NULL)
+ {
+ fprintf(stderr,"can't create \"%s\" file\n",file);
+ zeRace_exit();
+ }
+ len=SDLNet_TCP_Recv(tcpsock,response,10240);
+ tmp=response;
+ while (*tmp!='\n' || *(tmp+1)!='\r') tmp++;
+ tmp+=3;
+ fwrite(tmp,1,len+response-tmp,fic);
+ while ((len=SDLNet_TCP_Recv(tcpsock,response,10240))) fwrite(response,1,len,fic);
+ fclose(fic);
+ printf("done\n");
+ }
+
+ SDLNet_TCP_Close(tcpsock);
+ }
+}
+
+
/* load the car sprite and rotate it for every angles */
void zeRace_generate_cars()
{
{
float x,y;
float tcos,tsin;
- if ((cars[i][j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,0x000000ff,0x0000ff00,0x00ff0000,0xff000000))==NULL)
+ if ((cars[i][j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,0xff<<RSHIFT,0xff<<GSHIFT,0xff<<BSHIFT,0xff<<ASHIFT))==NULL)
{
fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
zeRace_exit();
void zeRace_init()
{
int flags;
+ struct _tracklist *loopcheck;
/* do a clean exit in case of emergency */
signal(SIGINT,zeRace_exit);
/* get the list of local tracks */
if (!zeRace_get_tracks(&tracklist)) zeRace_exit();
+ /* download missing files */
+ loopcheck=tracklist;
+ while (tracklist->next!=loopcheck)
+ {
+ zeRace_download_file(tracklist->full);
+ zeRace_download_file(tracklist->function);
+ tracklist=tracklist->next;
+ }
+
srand(time(NULL));
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0)
}
atexit(SDL_Quit);
- if(SDLNet_Init()==-1)
+ if (SDLNet_Init()==-1)
{
fprintf(stderr,"could not initialize SDLNet : %s\n",SDLNet_GetError());
zeRace_exit();
/* send the best time for this race to the web server */
-void zeRace_send_time(struct _record record/*float x,float y,float speed,float angle,int btime,char *bkeys*/)
+void zeRace_send_time(struct _record record)
{
IPaddress ip;
TCPsocket tcpsock;
char *msg9="&bkeys=";
int len,result;
+ /* if the best time is small enought to save all keys, send it */
+ if (record.time>=MAXRECORDKEYS) return;
+
printf("sending time... ");
fflush(stdout);
- if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
{
fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
return;
}
tcpsock=SDLNet_TCP_Open(&ip);
- if(!tcpsock)
+ if (!tcpsock)
{
fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
return;
len=strlen(temp);
result=SDLNet_TCP_Send(tcpsock,temp,len);
- if(result<len)
+ if (result<len)
fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
else
printf("done\n");
int lastack=alltime;
struct _record net;
struct _car oldnetpos[MAX_CLIENTS],newnetpos[MAX_CLIENTS];
+
+ /* free memory */
+ void free_mem()
+ {
+ SDL_FreeSurface(cir);
+ SDL_FreeSurface(fun);
+ if (config.sound)
+ {
+ Mix_FreeMusic(light);
+ Mix_FreeMusic(engine);
+ Mix_FreeMusic(crash);
+ Mix_FreeMusic(slide);
+ }
+ return;
+ }
cir=IMG_Load(tracklist->full);
fun=IMG_Load(tracklist->function);
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
- /* free memory */
- Mix_FreeMusic(light);
- Mix_FreeMusic(engine);
- Mix_FreeMusic(crash);
- Mix_FreeMusic(slide);
- /* if the best time is small enought to save all keys, send it */
- if (best.time<MAXRECORDKEYS) zeRace_send_time(best);
if (udpsock)
{
print(screen,WIDTH/2-strlen("Disconnecting !")*5,HEIGHT/2-10,"Disconnecting !");
SDLNet_UDP_Send(udpsock,-1,packet);
SDL_Flip(screen);
}
+ zeRace_send_time(best);
+ free_mem();
return;
default:
i=event.key.keysym.sym;
if (i==config.down) kd=1;
if (i==config.left) kl=1;
if (i==config.right) kr=1;
+ if (i==config.boss)
+ {
+ /* display the boss screen */
+ SDL_Surface *boss;
+ boss=IMG_Load("sprites/boss.png");
+ SDL_BlitSurface(boss,NULL,screen,NULL);
+ SDL_FreeSurface(boss);
+ SDL_Flip(screen);
+ /* and wait until the user press another key */
+ for (;;) if (SDL_PollEvent(&event)) { if (event.type==SDL_KEYDOWN) break; } else SDL_Delay(10);
+ SDL_BlitSurface(cir,NULL,screen,NULL);
+ SDL_Flip(screen);
+ }
break;
}
break;
char *tmp;
while (SDLNet_UDP_Recv(udpsock,packet)) if (strcmp(packet->data,"positions")==0)
{
- /*struct _car netcar;*/
int servertime,clienttime,nb;
- memcpy(&servertime,packet->data+strlen("positions")+1,sizeof(int));
- memcpy(&clienttime,packet->data+strlen("positions")+1+sizeof(int),sizeof(int));
- memcpy(&nb,packet->data+strlen("positions")+1+sizeof(int)+sizeof(int),sizeof(int));
+ 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);
if (clienttime>servertime+5) delay+=DELAY;
if (clienttime<servertime-5) delay-=DELAY;
if (delay<0) delay=0;
- /* printf("servertime = %d clienttime = %d lastack = %d nb = %d delay = %d net.time = %d\n",servertime,clienttime,lastack,nb,delay,net.time); */
for (i=0;i<MAX_CLIENTS;i++) newnetpos[i].w=0;
- memcpy(newnetpos,packet->data+strlen("positions")+1+sizeof(int)*3,sizeof(struct _car)*nb);
+ 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);
+ }
lastack=clienttime;
}
- } else return;
+ }
+ else /* end of this network race */
+ {
+ zeRace_send_time(best);
+ free_mem();
+ return;
+ }
if (strlen(net.keys)!=0)
{
tmp=packet->data;
strcpy(tmp,"keys");
tmp+=strlen(tmp)+1;
- memcpy(tmp,&lastack,sizeof(int));
- tmp+=sizeof(int);
+ SDLNet_Write32(lastack,tmp);
+ tmp+=4;
strcpy(tmp,net.keys);
tmp+=strlen(tmp)+1;
packet->len=(void *)tmp-(void *)packet->data+10;
if (config.sound) Mix_PlayMusic(crash,1)==-1;
}
+ /* game time */
+ current.time++;
+ net.time++;
+ if (udpsock && net.time>MAX_LAG)
+ {
+ print(screen,WIDTH/2-strlen("Timeout !")*5,HEIGHT/2-10,"Timeout !");
+ SDL_Flip(screen);
+ zeRace_send_time(best);
+ free_mem();
+ return;
+ }
+ alltime++;
+
/* if we completed a lap */
if (car.lapflag)
{
/* let the system breath */
SDL_Delay(delay);
- /* game time */
- current.time++;
- net.time++;
- if (udpsock && net.time>MAX_LAG)
- {
- print(screen,WIDTH/2-strlen("Timeout !")*5,HEIGHT/2-10,"Timeout !");
- SDL_Flip(screen);
- return;
- }
- alltime++;
}
}
print(screen,screen->w/2-strlen("zeRace " VERSION)*5,screen->h/2-splash->h/2-20,"zeRace " VERSION);
SDL_FreeSurface(splash);
SDL_Flip(screen);
- /*SDL_Delay(2000);*/
+ SDL_Delay(2000);
}
int i,nb,tmp;
SDL_Rect pos;
SDL_FillRect(screen,NULL,0x000000);
- memcpy(&nb,buf,sizeof(int));
- buf+=sizeof(int);
+ nb=SDLNet_Read16(buf);
+ buf+=2;
print(screen,WIDTH/2-16*5,HEIGHT/14,"* Race results *");
for (i=0;i<nb;i++)
{
print(screen,150,(i+3)*HEIGHT/14,buf);
buf+=strlen(buf)+1;
- memcpy(&tmp,buf,sizeof(int));
- buf+=sizeof(int);
+ tmp=SDLNet_Read16(buf);
+ buf+=2;
pos.x=110;
pos.y=(i+3)*HEIGHT/14-8;
SDL_BlitSurface(cars[tmp][0],NULL,screen,&pos);
tmp+=strlen(tmp)+1;
strcpy(tmp,config.pseudo);
tmp+=strlen(tmp)+1;
- memcpy(tmp,&config.color,sizeof(int));
- tmp+=sizeof(int);
+ SDLNet_Write16(config.color,tmp);
+ tmp+=2;
packet->len=(void *)tmp-(void *)packet->data;
SDLNet_UDP_Send(udpsock,-1,packet);
/* network loop */
zeRace_exit();
}
tmp+=strlen(tmp)+1;
- memcpy(&time,tmp,sizeof(int));
- tmp+=sizeof(int);
- memcpy(&network_speed,tmp,sizeof(int));
+ time=SDLNet_Read32(tmp);
+ tmp+=4;
+ network_speed=SDLNet_Read32(tmp);
zeRace_launch(time,go);
if (strcmp(packet->data,"finish")==0) zeRace_top10(packet->data+strlen(packet->data)+1);
lag=0;
printf("dowloading list of servers... ");
fflush(stdout);
- if(SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
+ if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
{
fprintf(stderr,"SDLNet_ResolveHost: %s\n",SDLNet_GetError());
return;
}
tcpsock=SDLNet_TCP_Open(&ip);
- if(!tcpsock)
+ if (!tcpsock)
{
fprintf(stderr,"SDLNet_TCP_Open: %s\n",SDLNet_GetError());
return;
len=strlen(request);
result=SDLNet_TCP_Send(tcpsock,request,len);
- if(result<len)
+ if (result<len)
fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
else
{
tmp=response;
while (*tmp!='\0' || *(tmp+1)!='\r') tmp++;
tmp+=3;
- printf("%s\n",tmp);
for (i=0;i<10;i++)
{
strcpy(servers[i].name,tmp);
{
SDL_Event event;
int active=0;
- #define CONFIG_OPTIONS 11
+ #define CONFIG_OPTIONS 12
void update()
{
pos.x=123;
pos.y=HEIGHT/(CONFIG_OPTIONS+4)*12-7;
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)*(CONFIG_OPTIONS+2),"Back to main menu");
SDL_Flip(screen);
}
if (config.color<0) config.color=11;
if (config.color>11) config.color=0;
break;
- case 10:
+ case 10: config.boss=0; update(); config.boss=read_key(); break;
+ case 11:
return;
}
update();