From: Antoine Jacquet Date: Sun, 26 Sep 2004 22:00:00 +0000 (+0200) Subject: version 0.3 X-Git-Tag: v0.3 X-Git-Url: http://royale.zerezo.com/git/?a=commitdiff_plain;h=dde2df6289f6daf23ee1632560c4c89061ef2f4a;p=zeRace version 0.3 * added network/internet mode * code is now split into generic modules * angle limited between 0 and 2*pi to avoid bugs --- diff --git a/CHANGELOG b/CHANGELOG index ae96a29..528d161 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,10 @@ Change log file for zeRace +version 0.3 (2004-09-27) + * added network/internet mode + * code is now split into generic modules + * angle limited between 0 and 2*pi to avoid bugs + version 0.2 (2004-09-14) * code has been commented :) * game is now a bit slower (easier to play) diff --git a/Makefile b/Makefile index d999c0b..0b67908 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,21 @@ -zeRace:zeRace.c sdl.o - gcc -ansi -Wall -o zeRace zeRace.c sdl.o `sdl-config --cflags --libs` -lSDL_image -lSDL_gfx -lSDL_net -lSDL_mixer +CC=gcc + +all:zeRace server + +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 + +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 sdl.o:sdl.c sdl.h - gcc -ansi -Wall -c sdl.c `sdl-config --cflags` + $(CC) -ansi -Wall -c sdl.c `sdl-config --cflags` + +car.o:car.c car.h + $(CC) -ansi -Wall -c car.c `sdl-config --cflags` + +tracklist.o:tracklist.c tracklist.h + $(CC) -ansi -Wall -c tracklist.c clean: - rm -f zeRace *.o *.cfg + rm -f zeRace server *.o *.cfg diff --git a/README b/README index 43fdabe..1c0a1e6 100644 --- a/README +++ b/README @@ -1,3 +1,3 @@ -zeRace 0.2 +zeRace 0.3 site: http://royale.zerezo.com/zerace/ mail: royale@zerezo.com diff --git a/car.c b/car.c new file mode 100644 index 0000000..e769567 --- /dev/null +++ b/car.c @@ -0,0 +1,84 @@ +#include "car.h" + +#define COEFF 1 + +void move_car(struct _car *car,int keys,SDL_Surface *fun) +{ + int c,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 )&0xff; + /* green layer (road quality) */ + g=(c>>8 )&0xff; + /* blue layer (unused) */ + b=(c>>16)&0xff; + + if (keys & 8) /* up */ + car->speed+=0.01*2*COEFF; + if (keys & 4) /* down */ + car->speed-=0.01*COEFF; + if (keys & 2) /* left */ + { + if (car->speed<0) + car->angle+=0.01*(255-b)/255*COEFF; + else + car->angle-=0.01*(255-b)/255*COEFF; + } + if (keys & 1) /* right */ + { + if (car->speed<0) + car->angle-=0.01*(255-b)/255*COEFF; + else + car->angle+=0.01*(255-b)/255*COEFF; + } + + /* limit angle between 0 and 2*pi */ + if (car->angle<0) car->angle+=2*M_PI; + if (car->angle>2*M_PI) car->angle-=2*M_PI; + + /* update the speed depending on the road quality */ + car->speed-=car->speed*(255-g)/1000; + + /* if it is a wall we move back to the last position */ + if (g==0) + { + car->x=car->ox; + car->y=car->oy; + car->crashflag=1; + } + + /* save the old position and compute the new one */ + car->ox=car->x; + car->oy=car->y; + car->speed*=0.995; + car->x-=cos(car->angle)*car->speed; + car->y-=sin(car->angle)*car->speed; + + /* collision with the border of the screen */ + if (car->xw/2 || car->x>fun->w-car->w/2 || car->yh/2 || car->y>fun->h-car->h/2) + { + car->x=car->ox; + car->y=car->oy; + car->speed=0; + 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 validate all and start over, we complete a turn */ + if (r/8==0 && car->lastcheck==31) + { + /* reset turn variables */ + car->lastcheck=0; + car->lap++; + car->lapflag=1; + } + + return; +} diff --git a/car.h b/car.h new file mode 100644 index 0000000..cb9e511 --- /dev/null +++ b/car.h @@ -0,0 +1,18 @@ +/* manages car object and its movement */ + +#include +#include "sdl.h" + +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +struct _car +{ + float x,y,ox,oy,angle,speed; + int w,h,lastcheck,lap; + int lapflag,crashflag; + int color; +}; + +void move_car(struct _car *car,int keys,SDL_Surface *function); diff --git a/network.h b/network.h new file mode 100644 index 0000000..f7cb706 --- /dev/null +++ b/network.h @@ -0,0 +1,7 @@ +/* some network constants */ + +#define MAXLINELENGTH 80 +#define MAX_LAG 500 +#define MAX_CLIENTS 32 +#define PORT "3600" +#define VERSION "0.3" diff --git a/sdl.c b/sdl.c index 16bd1c6..99891f0 100644 --- a/sdl.c +++ b/sdl.c @@ -1,5 +1,3 @@ -/* some useful functions for zeRace game */ - #include "sdl.h" SDL_Surface *font=NULL; diff --git a/server.c b/server.c new file mode 100644 index 0000000..c6da730 --- /dev/null +++ b/server.c @@ -0,0 +1,366 @@ +/* zeRace dedicated server */ + +#include +#include "network.h" +#include "car.h" +#include "tracklist.h" + +/* each client has his data */ +struct _clients +{ + char pseudo[MAXLINELENGTH]; + int connected; + int lasttime; + struct _car car; + IPaddress address; +} clients [MAX_CLIENTS]; + +/* UDP stuff */ +UDPsocket udpsock; +UDPpacket *packet; + +struct _tracklist *tracklist; +SDL_Surface *fun; + + +/* return the id of a connected address */ +int lookup(IPaddress address) +{ + int i; + for (i=0;iname); + fun=IMG_Load(tracklist->function); + + /* reset clients variables */ + for (i=0;ix; + clients[i].car.y=tracklist->y; + clients[i].car.w=30; + clients[i].car.h=30; + clients[i].car.angle=tracklist->a*2*M_PI/360; + clients[i].car.speed=0; + clients[i].car.lap=0; + clients[i].car.lastcheck=0; + } + + /* tell the clients */ + tmp=packet->data; + strcpy(tmp,"track"); + tmp+=strlen(tmp)+1; + *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); + packet->len=(void *)tmp-(void *)packet->data; + for (i=0;iaddress=clients[i].address; + SDLNet_UDP_Send(udpsock,-1,packet); + } + + /* wait for everybody startup */ + for (i=0;iaddress); + + /* look for type of message */ + tmp=packet->data; + /*printf("%s\n",tmp);*/ + + /* new connection ? */ + if (strcmp(tmp,"connect")==0) + { + /* allready connected ? */ + if (id!=-1 && clients[id].connected) + { + /* should not happen */ + printf("client %d allready connected\n",id); + } + else + for (i=0;iaddress; + clients[i].connected=1; + clients[i].lasttime=time; + memset(&clients[i].car,0,sizeof(struct _car)); + tmp+=strlen(tmp)+1; + strcpy(clients[i].pseudo,tmp); + tmp+=strlen(tmp)+1; + memcpy(&clients[i].car.color,tmp,sizeof(int)); + clients[i].car.x=tracklist->x; + clients[i].car.y=tracklist->y; + clients[i].car.w=30; + clients[i].car.h=30; + clients[i].car.angle=tracklist->a*2*M_PI/360; + clients[i].car.speed=0; + clients[i].car.lap=0; + clients[i].car.lastcheck=0; + memcpy(ip,&packet->address.host,4); + printf("client %d connected at %d : %d.%d.%d.%d:%d (pseudo : %s, color : %d)\n",i,time,ip[0],ip[1],ip[2],ip[3],packet->address.port,clients[i].pseudo,clients[i].car.color); + tmp=packet->data; + strcpy(tmp,"track"); + tmp+=strlen(tmp)+1; + *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); + packet->len=(void *)tmp-(void *)packet->data; + SDLNet_UDP_Send(udpsock,-1,packet); + break; + } + } + else + + /* disconnection ? */ + if (strcmp(tmp,"disconnect")==0 && id!=-1) + { + clients[id].connected=0; + printf("client %d disconnected\n",id); + } + else + + /* keys message ? */ + if (strcmp(tmp,"keys")==0) + { + if (id==-1 || !clients[id].connected) + { + /* should not happen */ + printf("discarded \"keys\" message\n"); + } + else + { + int temp; + tmp+=strlen(tmp)+1; + memcpy(&temp,tmp,sizeof(int)); + tmp+=sizeof(int); + if (clients[id].lasttime==temp) + { + /* 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 for timeouts */ + for (i=0;iaddress=clients[i].address; + strcpy(packet->data,"disconnected"); + SDLNet_UDP_Send(udpsock,-1,packet); + clients[i].connected=0; + } + + /* send update to clients */ + if (time%network_speed==0) for (i=0;idata; + 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 */ + nb=0; + for (j=0;jdata+strlen("positions")+1+sizeof(int)+sizeof(int),&nb,sizeof(int)); + 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); + } + + /* did someone finish the track ? */ + for (i=0;idata; + strcpy(tmp,"finish"); + tmp+=strlen(tmp)+1; + tmp+=sizeof(int); /* space for number */ + nb=0; + for (i=0;i<10;i++) + { + int best_sc=-1,best_id; + for (j=0;jbest_sc) + { + best_sc=clients[j].car.lap*32+clients[j].car.lastcheck; + best_id=j; + } + if (best_sc!=-1) + { + 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); + 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)); + packet->len=(void *)tmp-(void *)packet->data; + for (i=0;iaddress=clients[i].address; + SDLNet_UDP_Send(udpsock,-1,packet); + } + SDL_Delay(5000); + + tracklist=tracklist->next; + } + + return 0; +} diff --git a/tracklist.c b/tracklist.c new file mode 100644 index 0000000..fdab66d --- /dev/null +++ b/tracklist.c @@ -0,0 +1,62 @@ +#include "tracklist.h" + +#define MAXTRACKLENGTH 80 + +/* get available local tracks */ +int zeRace_get_tracks(struct _tracklist **tracklist) +{ + FILE *fic; + char line[MAXTRACKLENGTH]; + struct _tracklist *tmp=NULL,*first=NULL; + + *tracklist=NULL; + if ((fic=fopen("tracks/list.txt","rt"))==NULL) + { + fprintf(stderr,"can't open track list\n"); + return 0; + } + while (!feof(fic)) + { + tmp=(struct _tracklist *)malloc(sizeof(struct _tracklist)); + if (first==NULL) first=tmp; + fgets(line,MAXTRACKLENGTH,fic); + tmp->name=(char *)malloc(strlen(line)+1); + strcpy(tmp->name,line); + tmp->name[strlen(tmp->name)-1]='\0'; + fgets(line,MAXTRACKLENGTH,fic); + tmp->title=(char *)malloc(strlen(line)+1); + strcpy(tmp->title,line); + fgets(line,MAXTRACKLENGTH,fic); + tmp->author=(char *)malloc(strlen(line)+1); + strcpy(tmp->author,line); + fgets(line,MAXTRACKLENGTH,fic); + tmp->version=(char *)malloc(strlen(line)+1); + strcpy(tmp->version,line); + fgets(line,MAXTRACKLENGTH,fic); + tmp->x=atoi(line); + fgets(line,MAXTRACKLENGTH,fic); + tmp->y=atoi(line); + fgets(line,MAXTRACKLENGTH,fic); + tmp->a=atoi(line); + fgets(line,MAXTRACKLENGTH,fic); + tmp->best_time=atoi(line); + fgets(line,MAXTRACKLENGTH,fic); + tmp->best_pseudo=(char *)malloc(strlen(line)+1); + strcpy(tmp->best_pseudo,line); + tmp->full=(char *)malloc(strlen(line)+20); + sprintf(tmp->full,"tracks/%s.png",tmp->name); + tmp->function=(char *)malloc(strlen(line)+30); + sprintf(tmp->function,"tracks/%s_function.png",tmp->name); + tmp->prev=*tracklist; + if (tmp->prev) tmp->prev->next=tmp; + *tracklist=tmp; + /* skip one line */ + fgets(line,MAXTRACKLENGTH,fic); + } + fclose(fic); + if (!tmp) { fprintf(stderr,"no circuits found !\n"); return 0; } + while (tmp->prev) tmp=tmp->prev; + tmp->prev=*tracklist; + (*tracklist)->next=tmp; + return 1; +} diff --git a/tracklist.h b/tracklist.h new file mode 100644 index 0000000..34ee2a8 --- /dev/null +++ b/tracklist.h @@ -0,0 +1,22 @@ +/* load the track list */ + +#include +#include +#include + +struct _tracklist +{ + char *name; + char *title; + char *author; + char *version; + char *full; + char *function; + int x,y,a; + int best_time; + char *best_pseudo; + struct _tracklist *prev; + struct _tracklist *next; +}; + +int zeRace_get_tracks(struct _tracklist **tracklist); diff --git a/tracks/list.txt b/tracks/list.txt index 6f6f0ac..a352376 100644 --- a/tracks/list.txt +++ b/tracks/list.txt @@ -2,48 +2,48 @@ car Car ICFP Programming Contest 0.1 -435 -640 +450 +655 180 -10000 -? +923 +Voisin first First circuit for this game... Royale 0.1 -420 -200 +435 +215 180 -10000 -? +999 +Voisin icy Same as "First", but in winter ! Royale 0.1 -420 -200 +435 +215 180 -10000 -? +1175 +Royale hairpins Hairpins ICFP Programming Contest 0.1 -490 -650 +505 +665 0 -10000 -? +3158 +Voisin simple Simple ICFP Programming Contest 0.1 -570 -550 +585 +565 0 -10000 -? +1784 +Voisin diff --git a/zeRace.c b/zeRace.c index ce90ba1..c88d6cf 100644 --- a/zeRace.c +++ b/zeRace.c @@ -1,5 +1,5 @@ /* - * zeRace 0.2, a funny retro racing game + * zeRace 0.3, a funny retro racing game * http://royale.zerezo.com/zerace/ * * Copyright (C) 2004 Antoine Jacquet @@ -30,30 +30,19 @@ #include #include #include "sdl.h" +#include "car.h" +#include "tracklist.h" +#include "network.h" /* configuration constants */ #define COEFF 1 #define DELAY 7 -#define MAXLINELENGTH 80 -#define VERSION "0.2" #define WIDTH 1024 #define HEIGHT 768 +#define MAXRECORDKEYS 9999 -/* tracklist : double chained list */ -struct _tracklist -{ - char *name; - char *title; - char *author; - char *version; - char *full; - char *function; - int x,y,a; - int best_time; - char *best_pseudo; - struct _tracklist *prev; - struct _tracklist *next; -} *tracklist=NULL; +/* tracklist */ +struct _tracklist *tracklist; /* user setup */ struct _config @@ -67,12 +56,25 @@ struct _config SDLKey down; SDLKey left; SDLKey right; - char color; + 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; +}; + /* display and all directions for the car */ SDL_Surface *screen; -SDL_Surface *cars[256]; +SDL_Surface *cars[12][256]; + +/* network stuff */ +UDPsocket udpsock=NULL; +UDPpacket *packet; +int network_speed=1; /* read the user configuration file */ @@ -115,64 +117,6 @@ void zeRace_exit() } -/* get available local tracks */ -void zeRace_get_tracks() -{ - FILE *fic; - char line[MAXLINELENGTH]; - struct _tracklist *tmp=NULL,*first=NULL; - - if ((fic=fopen("tracks/list.txt","rt"))==NULL) - { - fprintf(stderr,"can't open track list\n"); - zeRace_exit(); - } - while (!feof(fic)) - { - tmp=(struct _tracklist *)malloc(sizeof(struct _tracklist)); - if (first==NULL) first=tmp; - fgets(line,MAXLINELENGTH,fic); - tmp->name=(char *)malloc(strlen(line)+1); - strcpy(tmp->name,line); - tmp->name[strlen(tmp->name)-1]='\0'; - fgets(line,MAXLINELENGTH,fic); - tmp->title=(char *)malloc(strlen(line)+1); - strcpy(tmp->title,line); - fgets(line,MAXLINELENGTH,fic); - tmp->author=(char *)malloc(strlen(line)+1); - strcpy(tmp->author,line); - fgets(line,MAXLINELENGTH,fic); - tmp->version=(char *)malloc(strlen(line)+1); - strcpy(tmp->version,line); - fgets(line,MAXLINELENGTH,fic); - tmp->x=atoi(line); - fgets(line,MAXLINELENGTH,fic); - tmp->y=atoi(line); - fgets(line,MAXLINELENGTH,fic); - tmp->a=atoi(line); - fgets(line,MAXLINELENGTH,fic); - tmp->best_time=atoi(line); - fgets(line,MAXLINELENGTH,fic); - tmp->best_pseudo=(char *)malloc(strlen(line)+1); - strcpy(tmp->best_pseudo,line); - tmp->full=(char *)malloc(strlen(line)+20); - sprintf(tmp->full,"tracks/%s.png",tmp->name); - tmp->function=(char *)malloc(strlen(line)+30); - sprintf(tmp->function,"tracks/%s_function.png",tmp->name); - tmp->prev=tracklist; - if (tmp->prev) tmp->prev->next=tmp; - tracklist=tmp; - /* skip one line */ - fgets(line,MAXLINELENGTH,fic); - } - fclose(fic); - if (!tmp) { fprintf(stderr,"no circuits found !\n"); zeRace_exit(); } - while (tmp->prev) tmp=tmp->prev; - tmp->prev=tracklist; - tracklist->next=tmp; -} - - /* check for a newer version online to warn the user */ void zeRace_check_version() { @@ -285,36 +229,44 @@ void zeRace_update_tracks() /* load the car sprite and rotate it for every angles */ void zeRace_generate_cars() { - int i; + int i,j; SDL_Surface *car; char temp[20]="sprites/carX.png"; - temp[11]='A'+config.color; - /* load the car sprite */ - car=IMG_Load(temp); - /* and rotate it for all available angles */ - for (i=0;i<256;i++) - { - float x,y; - float tcos,tsin; - tcos=cos(2*M_PI*i/256); - tsin=sin(2*M_PI*i/256); - for (x=0;xw;x++) for (y=0;yh;y++) + for (i=0;i<12;i++) + { + temp[11]='A'+i; + /* load the car sprite */ + car=IMG_Load(temp); + /* and rotate it for all available angles */ + for (j=0;j<256;j++) { - int x2,y2; - x2=(x-cars[i]->w/2.0)*tcos+(y-cars[i]->h/2.0)*tsin+car->w/2.0; - y2=(x-cars[i]->w/2.0)*tsin-(y-cars[i]->h/2.0)*tcos+car->h/2.0; - if (x2>0 && x2w && y2>0 && y2h) - putpixel(cars[i],x,y,getpixel(car,x2,y2)); + float x,y; + float tcos,tsin; + if ((cars[i][j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,0x000000ff,0x0000ff00,0x00ff0000,0xff000000))==NULL) + { + fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError()); + zeRace_exit(); + }; + tcos=cos(2*M_PI*j/256); + tsin=sin(2*M_PI*j/256); + for (x=0;xw;x++) for (y=0;yh;y++) + { + int x2,y2; + x2=(x-cars[i][j]->w/2.0)*tcos+(y-cars[i][j]->h/2.0)*tsin+car->w/2.0; + y2=(x-cars[i][j]->w/2.0)*tsin-(y-cars[i][j]->h/2.0)*tcos+car->h/2.0; + if (x2>0 && x2w && y2>0 && y2h) + putpixel(cars[i][j],x,y,getpixel(car,x2,y2)); + } } + SDL_FreeSurface(car); } - SDL_FreeSurface(car); } /* initialize the game */ void zeRace_init() { - int flags,i; + int flags; /* do a clean exit in case of emergency */ signal(SIGINT,zeRace_exit); @@ -330,7 +282,7 @@ void zeRace_init() zeRace_update_tracks(); /* get the list of local tracks */ - zeRace_get_tracks(); + if (!zeRace_get_tracks(&tracklist)) zeRace_exit(); srand(time(NULL)); @@ -347,6 +299,15 @@ void zeRace_init() zeRace_exit(); } + packet=SDLNet_AllocPacket(1024); + if (!packet) + { + fprintf(stderr,"SDLNet_AllocPacket: %s\n",SDLNet_GetError()); + zeRace_exit(); + } + + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL); + flags=SDL_HWSURFACE|SDL_ANYFORMAT; if (config.fullscreen) flags|=SDL_FULLSCREEN; @@ -366,18 +327,13 @@ void zeRace_init() zeRace_exit(); } - /* allocate memory for car sprites */ - for (i=0;i<256;i++) if ((cars[i]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,0x000000ff,0x0000ff00,0x00ff0000,0xff000000))==NULL) - { - fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError()); - zeRace_exit(); - }; + /* pre-calculate car sprites */ zeRace_generate_cars(); } /* send the best time for this race to the web server */ -void zeRace_send_time(float x,float y,float speed,float angle,int btime,char *bkeys) +void zeRace_send_time(struct _record record/*float x,float y,float speed,float angle,int btime,char *bkeys*/) { IPaddress ip; TCPsocket tcpsock; @@ -416,8 +372,8 @@ void zeRace_send_time(float x,float y,float speed,float angle,int btime,char *bk return; } - temp=(char *)malloc(strlen(msg1)+strlen(config.pseudo)+strlen(msg2)+strlen(config.url)+strlen(msg3)+strlen(tracklist->name)+strlen(msg4)+10+strlen(msg5)+10+strlen(msg6)+10+strlen(msg7)+10+strlen(msg8)+10+strlen(msg9)+strlen(bkeys)+100); - sprintf(temp,"%s%s%s%s%s%s%s%d%s%f%s%f%s%f%s%f%s%s\n",msg1,config.pseudo,msg2,config.url,msg3,tracklist->name,msg4,btime,msg5,x,msg6,y,msg7,speed,msg8,angle,msg9,bkeys); + temp=(char *)malloc(strlen(msg1)+strlen(config.pseudo)+strlen(msg2)+strlen(config.url)+strlen(msg3)+strlen(tracklist->name)+strlen(msg4)+10+strlen(msg5)+10+strlen(msg6)+10+strlen(msg7)+10+strlen(msg8)+10+strlen(msg9)+strlen(record.keys)+100); + sprintf(temp,"%s%s%s%s%s%s%s%d%s%f%s%f%s%f%s%f%s%s\n",msg1,config.pseudo,msg2,config.url,msg3,tracklist->name,msg4,record.time,msg5,record.x,msg6,record.y,msg7,record.speed,msg8,record.angle,msg9,record.keys); len=strlen(temp); result=SDLNet_TCP_Send(tcpsock,temp,len); @@ -451,32 +407,36 @@ void print_time(int x,int y,int time) /* launch a new race */ -void zeRace_launch() +void zeRace_launch(int alltime,int go) { SDL_Surface *cir,*fun; - SDL_Rect pos,size; + SDL_Rect pos; SDL_Event event; - int ku=0,kd=0,kl=0,kr=0; - int i,time=0,lastcheck=0,btime=10000; - float ox,oy; - float x,y,angle,speed; - float sx,sy,sangle,sspeed; - float bx,by,bangle,bspeed; - int c,r,g,b; - char keys[10000]; - char bkeys[10000]; + int ku=0,kd=0,kl=0,kr=0,i; + struct _car car; + struct _record current,best; Mix_Music *light,*engine,*crash,*slide; - int lastsound_time=-999,alltime=0,lastsound=0; + int lastsound_time=-999,lastsound=0; + int delay=DELAY; + int lastack=alltime; + struct _record net; + struct _car oldnetpos[MAX_CLIENTS],newnetpos[MAX_CLIENTS]; cir=IMG_Load(tracklist->full); fun=IMG_Load(tracklist->function); - sspeed=speed=0; - sangle=angle=(tracklist->a*2*M_PI/360); - sx=x=tracklist->x; - sy=y=tracklist->y; - lastcheck=0; - time=0; + 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.w=cars[0][0]->w; + car.h=cars[0][0]->h; + current.time=0; + best.time=MAXRECORDKEYS; + net.time=0; + memset(oldnetpos,0,MAX_CLIENTS*sizeof(struct _car)); + memset(newnetpos,0,MAX_CLIENTS*sizeof(struct _car)); if (config.sound) if (!(light=Mix_LoadMUS("sounds/light.wav")) || !(engine=Mix_LoadMUS("sounds/engine.wav")) || !(crash=Mix_LoadMUS("sounds/crash.wav")) || !(slide=Mix_LoadMUS("sounds/slide.wav"))) { @@ -490,10 +450,10 @@ void zeRace_launch() char startup[15]="sprites/?.png"; SDL_Surface *temp; startup[8]='0'+i; - pos.x=x; - pos.y=y; + pos.x=car.x-car.w/2; + pos.y=car.y-car.h/2; SDL_BlitSurface(cir,NULL,screen,NULL); - SDL_BlitSurface(cars[(unsigned char)(256*angle/2.0/M_PI)%256],NULL,screen,&pos); + SDL_BlitSurface(cars[config.color][(unsigned char)(256*car.angle/2.0/M_PI)%256],NULL,screen,&pos); if (i!=4 && i!=-1) { temp=IMG_Load(startup); @@ -504,47 +464,164 @@ void zeRace_launch() } if (config.sound) if (i!=4) Mix_PlayMusic(light,1); SDL_Flip(screen); + if (!go) break; if (i!=-1) SDL_Delay(1000); } /* main loop */ for (;;) { + /* look for user interaction */ + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + zeRace_exit(); + break; + case SDL_KEYDOWN: + 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.timedata,"disconnect"); + packet->len=strlen(packet->data)+1; + SDLNet_UDP_Send(udpsock,-1,packet); + SDL_Flip(screen); + } + return; + default: + i=event.key.keysym.sym; + if (i==config.up) ku=1; + if (i==config.down) kd=1; + if (i==config.left) kl=1; + if (i==config.right) kr=1; + break; + } + break; + case SDL_KEYUP: + i=event.key.keysym.sym; + if (i==config.up) ku=0; + if (i==config.down) kd=0; + if (i==config.left) kl=0; + if (i==config.right) kr=0; + break; + } + } + + /* save pressed keys to validate best time */ + if (current.timedata,"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)); + if (clienttime>lastack) + { + memcpy(net.keys,net.keys+clienttime-lastack,net.time+1); + net.time-=clienttime-lastack; + if (clienttime>servertime+5) delay+=DELAY; + if (clienttimedata+strlen("positions")+1+sizeof(int)*3,sizeof(struct _car)*nb); + lastack=clienttime; + } + } else return; + if (strlen(net.keys)!=0) + { + tmp=packet->data; + strcpy(tmp,"keys"); + tmp+=strlen(tmp)+1; + memcpy(tmp,&lastack,sizeof(int)); + tmp+=sizeof(int); + 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); + }; + } + } + + /* clear the old network position */ + if (udpsock) for (i=0;iw; - size.h=cars[0]->h; - pos.x=x; - pos.y=y; + pos.x=car.ox-car.w/2; + pos.y=car.oy-car.h/2; + pos.w=car.w; + pos.h=car.h; SDL_BlitSurface(cir,&pos,screen,&pos); - /* save the old position and compute the new one */ - ox=x; - oy=y; - speed*=0.995; - x=x-cos(angle)*speed; - y=y-sin(angle)*speed; - - /* collision with the border of the screen */ - if (x<0 || x>screen->w-cars[0]->w || y<0 || y>screen->h-cars[0]->h) + /* display the network car at the new position */ + if (udpsock) for (i=0;iw,cars[i]->h); - SDL_UpdateRect(screen,x,y,cars[i]->w,cars[i]->h); + /* display the car at the new position */ + pos.x=car.x-car.w/2; + pos.y=car.y-car.h/2; + pos.w=car.w; + pos.h=car.h; + SDL_BlitSurface(cars[config.color][(unsigned char)(256*car.angle/2.0/M_PI)%256],NULL,screen,&pos); - /* accelerate, brake and turn depending on the pressed keys */ - if (kl) { if (speed<0) angle+=0.01*(255-b)/255*COEFF; else angle-=0.01*(255-b)/255*COEFF; } - if (kr) { if (speed<0) angle-=0.01*(255-b)/255*COEFF; else angle+=0.01*(255-b)/255*COEFF; } - if (ku) speed+=0.01*2*COEFF; - if (kd) speed-=0.01*COEFF; + /* update display */ + if (udpsock) + { + for (i=0;i0.5) || (speed>2.0 && !ku)) + if ((kd && car.speed>0.5) || (car.speed>2.0 && !ku)) { /* if the only sound is the engine, play the slide sound */ if (lastsound_time+100w/2+cos(angle)*cars[i]->w/3-sin(angle)*2,y+cars[i]->h/2+sin(angle)*cars[i]->h/3+cos(angle)*2,0); - putpixel(cir,x+cars[i]->w/2+cos(angle)*cars[i]->w/3+sin(angle)*5,y+cars[i]->h/2+sin(angle)*cars[i]->h/3-cos(angle)*5,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,0); /* if we are braking the slide is larger */ if (kd) { - putpixel(cir,x+cars[i]->w/2+cos(angle)*cars[i]->w/3-sin(angle)*3,y+cars[i]->h/2+sin(angle)*cars[i]->h/3+cos(angle)*3,0); - putpixel(cir,x+cars[i]->w/2+cos(angle)*cars[i]->w/3+sin(angle)*4,y+cars[i]->h/2+sin(angle)*cars[i]->h/3-cos(angle)*4,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,0); } } } - /* get the pixel color under the center of car in the function map */ - c=getpixel(fun,x+cars[i]->w/2,y+cars[i]->h/2); - /* red layer (checkpoints) */ - r=(c )&0xff; - /* green layer (road quality) */ - g=(c>>8 )&0xff; - /* blue layer (unused) */ - b=(c>>16)&0xff; - - /* if it is a wall we move back to the last position */ - if (g==0) + /* if we crashed */ + if (car.crashflag && (lastsound_time+100MAX_LAG) + { + print(screen,WIDTH/2-strlen("Timeout !")*5,HEIGHT/2-10,"Timeout !"); + SDL_Flip(screen); + return; + } alltime++; } } @@ -704,12 +719,12 @@ void zeRace_splash() 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);*/ } /* menu loop to select track */ -void zeRace_select_track() +void zeRace_local() { SDL_Event event; @@ -760,7 +775,7 @@ void zeRace_select_track() return; case SDLK_RETURN: case SDLK_SPACE: - zeRace_launch(); + zeRace_launch(0,1); update(); break; case SDLK_LEFT: @@ -782,6 +797,279 @@ void zeRace_select_track() } +/* top 10 screen */ +void zeRace_top10(char *buf) +{ + int i,nb,tmp; + SDL_Rect pos; + SDL_FillRect(screen,NULL,0x000000); + memcpy(&nb,buf,sizeof(int)); + buf+=sizeof(int); + print(screen,WIDTH/2-16*5,HEIGHT/14,"* Race results *"); + for (i=0;iaddress,host,port); + tmp=packet->data; + strcpy(tmp,"connect"); + tmp+=strlen(tmp)+1; + strcpy(tmp,config.pseudo); + tmp+=strlen(tmp)+1; + memcpy(tmp,&config.color,sizeof(int)); + tmp+=sizeof(int); + packet->len=(void *)tmp-(void *)packet->data; + SDLNet_UDP_Send(udpsock,-1,packet); + /* network loop */ + while (SDLNet_UDP_Recv(udpsock,packet) || lagdata; + 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; + memcpy(&time,tmp,sizeof(int)); + tmp+=sizeof(int); + memcpy(&network_speed,tmp,sizeof(int)); + zeRace_launch(time,go); + if (strcmp(packet->data,"finish")==0) zeRace_top10(packet->data+strlen(packet->data)+1); + lag=0; + } + SDL_Delay(7); + lag++; + } + SDLNet_UDP_Close(udpsock); + udpsock=NULL; +} + + +/* network game */ +void zeRace_network() +{ + SDL_Event event; + int active=0; + char server[MAXLINELENGTH]="localhost"; + char port[6]=PORT; + #define NETWORK_OPTIONS 4 + + void update() + { + SDL_FillRect(screen,NULL,0x000000); + 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 : "); + print(screen,400+10*strlen("Server : "),HEIGHT/(NETWORK_OPTIONS+4)*3,server); + print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*4,"Port : "); + print(screen,400+10*strlen("Port : "),HEIGHT/(NETWORK_OPTIONS+4)*4,port); + print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*(NETWORK_OPTIONS+1),"Connect"); + print(screen,400,HEIGHT/(NETWORK_OPTIONS+4)*(NETWORK_OPTIONS+2),"Back to main menu"); + SDL_Flip(screen); + } + + update(); + for (;;) + { + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + zeRace_exit(); + break; + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + return; + case SDLK_RETURN: + case SDLK_SPACE: + case SDLK_LEFT: + case SDLK_RIGHT: + switch (active) + { + case 0: readstring(screen,400+10*strlen("Server : "),HEIGHT/(NETWORK_OPTIONS+4)*3,server,MAXLINELENGTH); break; + case 1: readstring(screen,400+10*strlen("Port : "),HEIGHT/(NETWORK_OPTIONS+4)*4,port,5); break;; + case 2: + zeRace_connect(server,atoi(port)); + break; + case 3: + return; + } + update(); + break; + case SDLK_UP: + active--; if (active<0) active=NETWORK_OPTIONS-1; + update(); + break; + case SDLK_DOWN: + active++; if (active>NETWORK_OPTIONS-1) active=0; + update(); + break; + default: + break; + } + break; + } + } + SDL_Delay(10); + } +} + + +/* internet game */ +void zeRace_internet() +{ + IPaddress ip; + TCPsocket tcpsock; + char *request= + "GET /zerace/servers.php HTTP/1.0\n" + "Host: royale.zerezo.com\n" + "User-Agent: zeRace " VERSION "\n" + "\n"; + char response[10240],*tmp; + int len,result,i; + struct _server + { + char name[MAXLINELENGTH]; + char ip[16]; + char port[6]; + } servers[10]; + SDL_Event event; + int active=0; + #define INTERNET_OPTIONS 11 + + printf("dowloading list of servers... "); + 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; + } + + len=strlen(request); + result=SDLNet_TCP_Send(tcpsock,request,len); + if(result"); + print(screen,WIDTH/2-19*5,HEIGHT/(INTERNET_OPTIONS+4),"* Internet screen *"); + for (i=0;i<10;i++) + print(screen,400,HEIGHT/(INTERNET_OPTIONS+4)*(i+3),servers[i].name); + print(screen,400,HEIGHT/(INTERNET_OPTIONS+4)*(INTERNET_OPTIONS+2),"Back to main menu"); + SDL_Flip(screen); + } + + update(); + for (;;) + { + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_QUIT: + zeRace_exit(); + break; + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + return; + case SDLK_RETURN: + case SDLK_SPACE: + case SDLK_LEFT: + case SDLK_RIGHT: + if (active==INTERNET_OPTIONS-1) + return; + else + zeRace_connect(servers[active].ip,atoi(servers[active].port)); + update(); + break; + case SDLK_UP: + active--; if (active<0) active=INTERNET_OPTIONS-1; + update(); + break; + case SDLK_DOWN: + active++; if (active>INTERNET_OPTIONS-1) active=0; + update(); + break; + default: + break; + } + break; + } + } + SDL_Delay(10); + } +} + + /* configuration screen */ void zeRace_config() { @@ -816,7 +1104,7 @@ void zeRace_config() print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*12,"Color : "); pos.x=123; pos.y=HEIGHT/(CONFIG_OPTIONS+4)*12-7; - SDL_BlitSurface(cars[0],NULL,screen,&pos); + SDL_BlitSurface(cars[config.color][0],NULL,screen,&pos); print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*(CONFIG_OPTIONS+2),"Back to main menu"); SDL_Flip(screen); } @@ -834,7 +1122,6 @@ void zeRace_config() } } - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL); update(); for (;;) { @@ -849,7 +1136,6 @@ void zeRace_config() switch (event.key.keysym.sym) { case SDLK_ESCAPE: - SDL_EnableKeyRepeat(0,0); return; case SDLK_RETURN: case SDLK_SPACE: @@ -870,10 +1156,8 @@ void zeRace_config() 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; - zeRace_generate_cars(); break; case 10: - SDL_EnableKeyRepeat(0,0); return; } update(); @@ -903,7 +1187,7 @@ void zeRace_menu() SDL_Event event; int active=0; SDL_Surface *logo; - #define MENU_OPTIONS 3 + #define MENU_OPTIONS 5 void update() { @@ -912,17 +1196,17 @@ void zeRace_menu() pos.x=WIDTH/2-logo->w/2; pos.y=HEIGHT/6-logo->h/2; SDL_BlitSurface(logo,NULL,screen,&pos); - print(screen,650,HEIGHT/(MENU_OPTIONS+4)*2,"version " VERSION); + print(screen,650,HEIGHT/6+logo->h/3,"version " VERSION); print(screen,420,HEIGHT/(MENU_OPTIONS+4)*(3+active),">"); print(screen,440,HEIGHT/(MENU_OPTIONS+4)*3,"Local game"); - /* print(screen,440,HEIGHT/(MENU_OPTIONS+4)*4,"Network game"); */ - print(screen,440,HEIGHT/(MENU_OPTIONS+4)*4,"Configuration"); - print(screen,440,HEIGHT/(MENU_OPTIONS+4)*5,"Exit game"); + print(screen,440,HEIGHT/(MENU_OPTIONS+4)*4,"Network game"); + print(screen,440,HEIGHT/(MENU_OPTIONS+4)*5,"Internet game"); + print(screen,440,HEIGHT/(MENU_OPTIONS+4)*6,"Configuration"); + print(screen,440,HEIGHT/(MENU_OPTIONS+4)*7,"Exit game"); SDL_Flip(screen); } logo=IMG_Load("sprites/logo.jpg"); - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL); update(); for (;;) { @@ -937,7 +1221,6 @@ void zeRace_menu() switch (event.key.keysym.sym) { case SDLK_ESCAPE: - SDL_EnableKeyRepeat(0,0); return; case SDLK_RETURN: case SDLK_SPACE: @@ -945,9 +1228,11 @@ void zeRace_menu() case SDLK_RIGHT: switch (active) { - case 0: zeRace_select_track(); break; - case 1: zeRace_config(); break; - case 2: return; + case 0: zeRace_local(); break; + case 1: zeRace_network(); break; + case 2: zeRace_internet(); break; + case 3: zeRace_config(); break; + case 4: return; } update(); break;