-#include <dirent.h>
+/*
+ * zeRace 0.7, a funny retro racing game
+ * http://royale.zerezo.com/zerace/
+ *
+ * Copyright (C) 2004 Antoine Jacquet <royale@zerezo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#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_mixer.h>
-#include <math.h>
+#include <SDL_rotozoom.h>
#include "sdl.h"
+#include "car.h"
+#include "tracklist.h"
+#include "network.h"
+#include <sys/stat.h>
-#define MAXLINELENGTH 1000
-#define VERSION "0.1"
+/* configuration constants */
+#define COEFF 1
+#define DELAY 7
#define WIDTH 1024
#define HEIGHT 768
+#define MAXRECORDKEYS 9999
+#define NB_CARS 16
+
+/* some usefull colors */
+#define C_BLACK SDL_MapRGB(screen->format,0,0,0)
+#define C_WHITE SDL_MapRGB(screen->format,255,255,255)
+#define C_RED SDL_MapRGB(screen->format,255,0,0)
+#define C_ORANGE SDL_MapRGB(screen->format,255,200,0)
+#define C_YELLOW SDL_MapRGB(screen->format,255,255,100)
+#define T_BLACK SDL_MapRGB(cir->format,0,0,0)
-/* global variables */
+/* tracklist */
+struct _tracklist *tracklist;
-struct track
+/* user setup */
+struct _config
{
- char *name;
- char *title;
- char *author;
- char *version;
- char *full;
- char *function;
- int x,y,a;
- struct track *prev;
- struct track *next;
-} *tracklist=NULL;
-
-int fullscreen=0;
-int sound=0;
-char pseudo[MAXLINELENGTH]="anonymous";
-char url[MAXLINELENGTH]="";
+ char pseudo[MAXLINELENGTH];
+ char url[MAXLINELENGTH];
+ int fullscreen;
+ int sound;
+ int tire;
+ SDLKey up;
+ SDLKey down;
+ SDLKey left;
+ SDLKey right;
+ int color;
+ SDLKey boss;
+ int bynight;
+ int internet;
+} config = {"anonymous","",0,0,1,SDLK_UP,SDLK_DOWN,SDLK_LEFT,SDLK_RIGHT,6,SDLK_b,0,1};
+
+/* 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[NB_CARS][256];
+
+/* network stuff */
+UDPsocket udpsock=NULL;
+UDPpacket *packet;
+int network_speed=1;
+
+
+/* read the user configuration file */
+void zeRace_read_config()
+{
+ FILE *fic;
+ if ((fic=fopen("zeRace.cfg","rb"))==NULL)
+ {
+ fprintf(stderr,"can't open config file \"zeRace.cfg\"\n");
+ return;
+ }
+ fread(&config,sizeof(struct _config),1,fic);
+ fclose(fic);
+}
+
+
+/* save the user configuration file */
+void zeRace_save_config()
+{
+ FILE *fic;
+ if ((fic=fopen("zeRace.cfg","wb"))==NULL)
+ {
+ fprintf(stderr,"can't create config file \"zeRace.cfg\"\n");
+ return;
+ }
+ fwrite(&config,sizeof(struct _config),1,fic);
+ fclose(fic);
+}
+
+/* exit the game and clean */
void zeRace_exit()
{
printf("quit\n");
- if (sound) Mix_CloseAudio();
+ if (config.sound) Mix_CloseAudio();
SDLNet_Quit();
SDL_Quit();
- /*
- save_config();
- zeRace_send_ghosts();
- close_sdl();
- */
+ zeRace_save_config();
exit(0);
}
-void zeRace_read_config()
+/* check for a newer version online to warn the user */
+void zeRace_check_version()
+{
+ IPaddress ip;
+ TCPsocket tcpsock;
+ char *request=
+ "GET /zerace/version.php HTTP/1.0\n"
+ "Host: royale.zerezo.com\n"
+ "User-Agent: zeRace " VERSION "\n"
+ "\n";
+ char response[1024],*tmp,*version;
+ int len,result;
+
+ if (!config.internet) return;
+
+ printf("checking version... ");
+ 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<len)
+ fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
+ else
+ printf("done\n");
+
+ len=SDLNet_TCP_Recv(tcpsock,response,1024);
+ if (len<0)
+ fprintf(stderr,"SDLNet_TCP_Recv: %s\n",SDLNet_GetError());
+ else
+ {
+ tmp=response;
+ while (*tmp++!='\0') if (strncmp(tmp,"version=",8)==0)
+ {
+ version=tmp+8;
+ while (*tmp!='\n') tmp++;
+ *tmp='\0';
+ if (strcmp(version,VERSION)>0) printf("new version available !\nhttp://royale.zerezo.com/zerace/\n");
+ }
+ }
+
+ SDLNet_TCP_Close(tcpsock);
+}
+
+
+/* get remote list of tracks */
+void zeRace_update_tracks()
{
+ IPaddress ip;
+ TCPsocket tcpsock;
+ char *request=
+ "GET /zerace/tracks.php HTTP/1.0\n"
+ "Host: royale.zerezo.com\n"
+ "User-Agent: zeRace " VERSION "\n"
+ "\n";
+ char response[10240],*tmp;
+ int len,result;
FILE *fic;
- char line[MAXLINELENGTH];
- char keyword[MAXLINELENGTH];
- char value[MAXLINELENGTH];
- int configlines=0;
- if ((fic=fopen("zeRace.cfg","rt"))==NULL)
+ if (!config.internet) return;
+
+ printf("checking version and updating tracks... ");
+ fflush(stdout);
+
+ if (SDLNet_ResolveHost(&ip,"royale.zerezo.com",80)==-1)
{
- fprintf(stderr,"can't open config file \"zeRace.cfg\"\n");
- exit(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;
}
- while (fgets(line,MAXLINELENGTH,fic))
+ len=strlen(request);
+ result=SDLNet_TCP_Send(tcpsock,request,len);
+ if (result<len)
+ fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
+ else
{
- configlines++;
- if (*line!=';' && *line!='#' && *line!='/' && *line!='-' && *line!='\n')
+ if ((fic=fopen("tracks/list.txt","wt"))==NULL)
{
- if ((sscanf(line,"%s : %s\n",(char *)&keyword,(char *)&value))!=2) { fprintf(stderr,"error in config file : each line must have the format \"keyword : value\" (line %d)\n",configlines); exit(1); }
-
- if (strcmp("pseudo",keyword)==0)
- strcpy(pseudo,value);
- else
-
- if (strcmp("url",keyword)==0)
- strcpy(url,value);
- else
-
- if (strcmp("fullscreen",keyword)==0)
- {
- if (strcmp("no",value)==0) fullscreen=0;
- else if (strcmp("yes",value)==0) fullscreen=1;
- else { fprintf(stderr,"unknown value for \"fullscreen\" option, must be \"yes\" or \"no\"\n"); exit(1); }
- }
- else
-
- if (strcmp("sound",keyword)==0)
- {
- if (strcmp("no",value)==0) sound=0;
- else if (strcmp("yes",value)==0) sound=1;
- else { fprintf(stderr,"unknown value for \"sound\" option, must be \"yes\" or \"no\"\n"); exit(1); }
- }
-
- else { fprintf(stderr,"error in config file : \"%s\" is an unknown keyword (line %d)\n",keyword,configlines); exit(1); }
+ fprintf(stderr,"can't create track list\n");
+ 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);
+ fclose(fic);
+ printf("done\n");
}
+
+ SDLNet_TCP_Close(tcpsock);
}
-void zeRace_get_tracks()
+/* download the file if it is missing */
+void zeRace_download_file(char *file)
{
- struct dirent **namelist;
- int i;
- unsigned char ext[5];
+ IPaddress ip;
+ TCPsocket tcpsock;
+ char request[1024];
+ char response[10240],*tmp;
+ int len,result;
FILE *fic;
- char *shortname=NULL;
- char line[MAXLINELENGTH];
- int configlines;
- struct track *tmp=NULL,*first=NULL;
- DIR *dirp;
- struct dirent *dp;
-
- if ((dirp=opendir("tracks"))==NULL) { fprintf(stderr,"can't open \"tracks\" directory or no tracks\n"); return; }
-
- while (dp=readdir(dirp)) if (strlen(dp->d_name)>4)
- {
- shortname=(char *)realloc(shortname,strlen(dp->d_name)-3);
- strncpy(shortname,dp->d_name,strlen(dp->d_name)-4);
- shortname[strlen(dp->d_name)-4]='\0';
- for (i=0;i<5;i++) ext[i]=tolower(dp->d_name[strlen(dp->d_name)-4+i]);
- if (strcmp(".txt",ext)==0)
- {
- tmp=(struct track *)malloc(sizeof(struct track));
- if (first==NULL) first=tmp;
- tmp->name=(char *)malloc(strlen(shortname)+1);
- strcpy(tmp->name,shortname);
- tmp->title="";
- tmp->author="";
- tmp->version="";
- tmp->x=10;
- tmp->y=10;
- tmp->a=0;
- configlines=0;
- sprintf(line,"tracks/%s.txt",shortname);
- if ((fic=fopen(line,"rt"))==NULL)
+ struct stat buf;
+
+ if (!config.internet) return;
+
+ 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,"wb"))==NULL)
{
- fprintf(stderr,"can't open track file \"%s\"\n",line);
+ fprintf(stderr,"can't create \"%s\" file\n",file);
zeRace_exit();
}
- while (fgets(line,MAXLINELENGTH,fic))
+ 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()
+{
+ int i,j;
+ SDL_Surface *car;
+ char temp[20]="sprites/carX.png";
+ for (i=0;i<NB_CARS;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++)
+ {
+ float x,y;
+ float tcos,tsin;
+ if ((cars[i][j]=SDL_CreateRGBSurface(SDL_SWSURFACE,30,30,32,RMASK,GMASK,BMASK,AMASK))==NULL)
{
- configlines++;
- if (*line!=';' && *line!='#' && *line!='/' && *line!='-' && *line!='\n')
- {
- for (i=0;i<strlen(line)-2;i++) if (line[i]==' ' && line[i+1]==':' && line[i+2]==' ') break;
- if (line[i]!=' ' || line[i+1]!=':' || line[i+2]!=' ')
- {
- fprintf(stderr,"error in track file \"%s\" : each line must have the format \"keyword : value\" (line %d)\n",shortname,configlines);
- exit(1);
- }
- line[i]='\0';
-
- if (strcmp("title",line)==0)
- {
- tmp->title=(char *)malloc(strlen(line+i+3)+1);
- strcpy(tmp->title,line+i+3);
- }
- else
-
- if (strcmp("author",line)==0)
- {
- tmp->author=(char *)malloc(strlen(line+i+3)+1);
- strcpy(tmp->author,line+i+3);
- }
- else
-
- if (strcmp("x",line)==0)
- tmp->x=atoi(line+i+3);
- else
-
- if (strcmp("y",line)==0)
- tmp->y=atoi(line+i+3);
- else
-
- if (strcmp("a",line)==0)
- tmp->a=atoi(line+i+3);
- else
-
- if (strcmp("version",line)==0)
- {
- tmp->version=(char *)malloc(strlen(line+i+3)+1);
- strcpy(tmp->version,line+i+3);
- }
-
- else { fprintf(stderr,"error in track file \"%s\" : \"%s\" is an unknown keyword (line %d)\n",shortname,line,configlines); exit(1); }
- }
+ 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;x<cars[i][j]->w;x++) for (y=0;y<cars[i][j]->h;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 && x2<car->w && y2>0 && y2<car->h)
+ putpixel(cars[i][j],x,y,getpixel(car,x2,y2));
}
- fclose(fic);
- tmp->full=(char *)malloc(strlen(line)+20);
- sprintf(tmp->full,"tracks/%s.png",shortname);
- tmp->function=(char *)malloc(strlen(line)+30);
- sprintf(tmp->function,"tracks/%s_function.png",shortname);
- tmp->prev=tracklist;
- if (tmp->prev) tmp->prev->next=tmp;
- tracklist=tmp;
- }
- }
- if (!tmp) { fprintf(stderr,"no circuits found !\n"); zeRace_exit(); }
- while (tmp->prev) tmp=tmp->prev;
- tmp->prev=tracklist;
- tracklist->next=tmp;
+ }
+ SDL_FreeSurface(car);
+ }
}
+/* initialize the game */
void zeRace_init()
{
- SDL_Surface *car;
- int i,flags;
+ int flags;
+ struct _tracklist *loopcheck;
+ /* do a clean exit in case of emergency */
signal(SIGINT,zeRace_exit);
signal(SIGTERM,zeRace_exit);
- zeRace_read_config();
- //zeRace_check_version();
- zeRace_get_tracks();
- //zeRace_get_ghosts();
-
- srand(time(NULL));
-
+
+ /* initialize SDL */
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)<0)
{
fprintf(stderr,"could not initialize SDL : %s\n",SDL_GetError());
}
atexit(SDL_Quit);
- if(SDLNet_Init()==-1)
+ /* initialize SDLNet */
+ if (SDLNet_Init()==-1)
{
fprintf(stderr,"could not initialize SDLNet : %s\n",SDLNet_GetError());
zeRace_exit();
}
+ /* read the user configuration file */
+ zeRace_read_config();
+
+ /* check for a newer available version */
+ zeRace_check_version();
+
+ /* update the list of tracks */
+ zeRace_update_tracks();
+
+ /* get the list of local tracks */
+ if (!zeRace_get_tracks(&tracklist)) zeRace_exit();
+
+ /* download missing files */
+ loopcheck=tracklist;
+ do
+ {
+ zeRace_download_file(tracklist->full);
+ zeRace_download_file(tracklist->function);
+ tracklist=tracklist->next;
+ } while (tracklist!=loopcheck);
+
+ srand(time(NULL));
+
+ 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 (fullscreen) flags|=SDL_FULLSCREEN;
+ if (config.fullscreen) flags|=SDL_FULLSCREEN;
if ((screen=SDL_SetVideoMode(WIDTH,HEIGHT,32,flags))==NULL)
{
SDL_WM_SetCaption("zeRace " VERSION,"zeRace " VERSION);
SDL_ShowCursor(SDL_DISABLE);
- if (sound) if (Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,512)<0)
+ if (config.sound) if (Mix_OpenAudio(44100,MIX_DEFAULT_FORMAT,2,512)<0)
{
fprintf(stderr,"Mix_OpenAudio error\n");
zeRace_exit();
}
- car=IMG_Load("sprites/car.png");
- for (i=0;i<256;i++)
- {
- float x,y;
- float tcos,tsin;
- cars[i]=SDL_CreateRGBSurface(SDL_SWSURFACE,car->h*2,car->h*2,32,0x000000ff,0x0000ff00,0x00ff0000,0xff000000);
- if(cars[i]==NULL)
- {
- fprintf(stderr,"CreateRGBSurface failed: %s\n",SDL_GetError());
- exit(1);
- }
- tcos=cos(2*M_PI*i/256);
- tsin=sin(2*M_PI*i/256);
- for (x=0;x<cars[i]->w;x++) for (y=0;y<cars[i]->h;y++)
- {
- int x2,y2;
- Uint32 col;
- 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 && x2<car->w && y2>0 && y2<car->h)
- putpixel(cars[i],x,y,getpixel(car,x2,y2));
- }
- }
+ /* pre-calculate car sprites */
+ zeRace_generate_cars();
}
-void zeRace_send_time(float x,float y,float speed,float angle,int btime,char *bkeys)
+/* send the best time for this race to the web server */
+void zeRace_send_time(struct _record *record)
{
IPaddress ip;
TCPsocket tcpsock;
char *temp;
char *msg1=
- "POST /zerace/time.php HTTP/1.1\n"
+ "POST /zerace/time.php HTTP/1.0\n"
"Host: royale.zerezo.com\n"
"User-Agent: zeRace " VERSION "\n"
"Content-Type: application/x-www-form-urlencoded\n"
char *msg9="&bkeys=";
int len,result;
+ if (!config.internet) return;
+
+ /* 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;
}
- temp=(char *)malloc(strlen(msg1)+strlen(pseudo)+strlen(msg2)+strlen(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,pseudo,msg2,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);
- if(result<len)
+ if (result<len)
fprintf(stderr,"SDLNet_TCP_Send: %s\n", SDLNet_GetError());
else
- printf(" done\n");
+ printf("done\n");
SDLNet_TCP_Close(tcpsock);
}
-void zeRace_launch()
+/* print a time for a lap */
+void print_time(int x,int y,int time)
+{
+ char temp[20];
+ int q,r;
+ time*=DELAY;
+ q=(time/1000);
+ r=(time%1000);
+ if (q>100) return;
+ temp[0]=q/10+'0';
+ temp[1]=q%10+'0';
+ temp[2]='"';
+ temp[3]=r/100+'0';
+ temp[4]=r%100/10+'0';
+ temp[5]=r%10+'0';
+ temp[6]='\0';
+ print(screen,x,y,temp);
+}
+
+
+/* car lights */
+void lights(int x,int y,int r,Uint32 pixel)
+{
+ putpixel(screen,x,y,pixel);
+ if (r>1)
+ {
+ putpixel(screen,x-1,y,pixel);
+ putpixel(screen,x+1,y,pixel);
+ putpixel(screen,x,y-1,pixel);
+ putpixel(screen,x,y+1,pixel);
+ }
+ if (r>2)
+ {
+ putpixel(screen,x-2,y,pixel);
+ putpixel(screen,x+2,y,pixel);
+ putpixel(screen,x,y-2,pixel);
+ putpixel(screen,x,y+2,pixel);
+ putpixel(screen,x-1,y-1,pixel);
+ putpixel(screen,x-1,y+1,pixel);
+ putpixel(screen,x+1,y-1,pixel);
+ putpixel(screen,x+1,y+1,pixel);
+ }
+}
+
+
+/* launch a new race */
+void zeRace_launch(int alltime,int go)
{
- SDL_Surface *cir,*fun;
- SDL_Rect pos,size;
+ SDL_Surface *cir,*fun,*hilight;
+ 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,v,b;
- int temp;
- char keys[10000];
- char bkeys[10000];
- char text[10];
- Mix_Music *light,*engine,*crash,*slide;
- int lastsound_time=-999,alltime=0,lastsound=0;
+ 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,lastsound=0;
+ int delay=DELAY;
+ int lastack=alltime;
+ struct _record net;
+ struct _car oldnetpos[MAX_CLIENTS],newnetpos[MAX_CLIENTS];
+ int l=80,o=15;
+
+ /* 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);
+ /* dark the track if it is night */
+ if (config.bynight)
+ {
+ for (pos.x=0;pos.x<screen->w;pos.x++)
+ for (pos.y=0;pos.y<screen->h;pos.y++)
+ {
+ Uint32 c;
+ Uint8 r,g,b;
+ c=getpixel(cir,pos.x,pos.y);
+ SDL_GetRGB(c,cir->format,&r,&g,&b);
+ r*=0.3;
+ g*=0.3;
+ b*=0.3;
+ putpixel(cir,pos.x,pos.y,SDL_MapRGB(cir->format,r,g,b));
+ }
+ }
fun=IMG_Load(tracklist->function);
+ hilight=IMG_Load("sprites/light.png");
- 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.lapflag=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 (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")))
+ 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")))
{
fprintf(stderr,"Mix_LoadMUS error\n");
zeRace_exit();
}
+ /* startup countdown */
for (i=4;i>=-1;i--)
{
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);
SDL_BlitSurface(temp,NULL,screen,&pos);
SDL_FreeSurface(temp);
}
- if (sound) if (i!=4) Mix_PlayMusic(light,1);
+ 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 (;;)
- {
- size.w=cars[0]->w;
- size.h=cars[0]->h;
- pos.x=x;
- pos.y=y;
+ {
+ /* 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:
+ if (udpsock)
+ {
+ print(screen,WIDTH/2-strlen("Disconnecting !")*5,HEIGHT/2-10,"Disconnecting !");
+ strcpy(packet->data,"disconnect");
+ packet->len=strlen(packet->data)+1;
+ 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.up) ku=1;
+ 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;
+ 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.time<MAXRECORDKEYS) current.keys[current.time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
+ current.keys[current.time+1]='\0';
+ /* and to send to server if needed */
+ if (udpsock)
+ {
+ net.keys[net.time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
+ net.keys[net.time+1]='\0';
+ }
+
+ /* move the car */
+ move_car(&car,(ku<<3 | kd<<2 | kl<<1 | kr),fun);
+
+ 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;
+ for (i=0;i<MAX_CLIENTS;i++) newnetpos[i].w=0;
+ 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*14);
+ newnetpos[i].y=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2);
+ newnetpos[i].angle=(float)SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2)/1000;
+ newnetpos[i].color=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2);
+ newnetpos[i].lights_brake=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2);
+ newnetpos[i].lights_backwards=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2+2);
+ newnetpos[i].lights_warning=SDLNet_Read16(packet->data+strlen("positions")+1+4+4+2+i*14+2+2+2+2+2+2);
+ }
+ lastack=clienttime;
+ }
+ }
+ else if (strcmp(packet->data,"collision")==0)
+ {
+ net.time=-1;
+ net.keys[0]='\0';
+ lastack=SDLNet_Read32(packet->data+strlen("collision")+1);
+ car.x=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4)/65536-100;
+ car.y=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4)/65536-100;
+ car.speed=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4)/65536-100;
+ car.angle=(float)SDLNet_Read32(packet->data+strlen("collision")+1+4+4+4+4)/65536-100;
+ }
+ 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;
+ SDLNet_Write32(lastack,tmp);
+ tmp+=4;
+ SDLNet_Write32(car.x,tmp);
+ tmp+=4;
+ SDLNet_Write32(car.y,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);
+ };
+ }
+ }
+
+ /* clear the old network position */
+ if (udpsock) for (i=0;i<MAX_CLIENTS;i++) if (oldnetpos[i].w)
+ {
+ pos.x=oldnetpos[i].x-car.w/2;
+ pos.y=oldnetpos[i].y-car.h/2;
+ pos.w=car.w;
+ pos.h=car.h;
+ SDL_BlitSurface(cir,&pos,screen,&pos);
+ }
+
+ /* clear the old position */
+ 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);
- ox=x;
- oy=y;
- speed*=0.995;
- x=x-cos(angle)*speed;
- y=y-sin(angle)*speed;
+ /* clear the lights */
+ if (config.bynight)
+ {
+ pos.x=car.ox-cos(car.angle)*l-sin(car.angle)*o;
+ pos.y=car.oy-sin(car.angle)*l+cos(car.angle)*o;
+ pos.x-=60;
+ pos.y-=60;
+ pos.w=120;
+ pos.h=120;
+ SDL_BlitSurface(cir,&pos,screen,&pos);
+ pos.x=car.ox-cos(car.angle)*l+sin(car.angle)*o;
+ pos.y=car.oy-sin(car.angle)*l-cos(car.angle)*o;
+ pos.x-=60;
+ pos.y-=60;
+ pos.w=120;
+ pos.h=120;
+ SDL_BlitSurface(cir,&pos,screen,&pos);
+ }
+
+ /* display the network car at the new position */
+ if (udpsock) for (i=0;i<MAX_CLIENTS;i++) if (newnetpos[i].w)
+ {
+ pos.x=newnetpos[i].x-car.w/2;
+ pos.y=newnetpos[i].y-car.h/2;
+ pos.w=car.w;
+ pos.h=car.h;
+ SDL_BlitSurface(cars[newnetpos[i].color][(unsigned char)(256*newnetpos[i].angle/2.0/M_PI)%256],NULL,screen,&pos);
+
+ /* if the car is braking, display red lights */
+ if (newnetpos[i].lights_brake)
+ {
+ lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*4,3,C_RED);
+ lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*4,3,C_RED);
+ }
+
+ /* if the car is going backwards, display white lights */
+ if (newnetpos[i].lights_backwards)
+ {
+ lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*4,3,C_WHITE);
+ lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*4,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*4,3,C_WHITE);
+ }
+
+ /* if the car is stopped, then warning */
+ if (newnetpos[i].lights_warning && alltime/75%2)
+ {
+ lights(newnetpos[i].x-cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*5,newnetpos[i].y-sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*5,2,C_ORANGE);
+ lights(newnetpos[i].x-cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*5,newnetpos[i].y-sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*5,2,C_ORANGE);
+ lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3-sin(newnetpos[i].angle)*5,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3+cos(newnetpos[i].angle)*5,2,C_ORANGE);
+ lights(newnetpos[i].x+cos(newnetpos[i].angle)*car.w/3+sin(newnetpos[i].angle)*5,newnetpos[i].y+sin(newnetpos[i].angle)*car.h/3-cos(newnetpos[i].angle)*5,2,C_ORANGE);
+ }
+ }
+
+ /* 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);
- if (x<0 || x>screen->w-cars[0]->w || y<0 || y>screen->h-cars[0]->h)
+ /* if the car is braking, display red lights */
+ if (car.lights_brake)
{
- x=ox;
- y=oy;
- speed=0;
+ lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*4,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,3,C_RED);
+ lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*4,car.y+sin(car.angle)*car.h/3-cos(car.angle)*4,3,C_RED);
}
- pos.x=x;
- pos.y=y;
- i=(unsigned char)(256*angle/2.0/M_PI)%256;
- SDL_BlitSurface(cars[i],NULL,screen,&pos);
- SDL_UpdateRect(screen,ox,oy,cars[i]->w,cars[i]->h);
- SDL_UpdateRect(screen,x,y,cars[i]->w,cars[i]->h);
+ /* if the car is going backwards, display white lights */
+ if (car.lights_backwards)
+ {
+ lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*4,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,3,C_WHITE);
+ lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*4,car.y+sin(car.angle)*car.h/3-cos(car.angle)*4,3,C_WHITE);
+ }
- if (kl) angle-=0.01;
- if (kr) angle+=0.01;
- if (ku) speed+=0.01*2;
- if (kd) speed-=0.01;
-
+ /* if the car is stopped, then warning */
+ if (car.lights_warning && alltime/75%2)
+ {
+ lights(car.x-cos(car.angle)*car.w/3-sin(car.angle)*5,car.y-sin(car.angle)*car.h/3+cos(car.angle)*5,2,C_ORANGE);
+ lights(car.x-cos(car.angle)*car.w/3+sin(car.angle)*5,car.y-sin(car.angle)*car.h/3-cos(car.angle)*5,2,C_ORANGE);
+ lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*5,car.y+sin(car.angle)*car.h/3+cos(car.angle)*5,2,C_ORANGE);
+ lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*5,car.y+sin(car.angle)*car.h/3-cos(car.angle)*5,2,C_ORANGE);
+ }
+
+ /* display the lights */
+ if (config.bynight)
+ {
+ lights(car.x+cos(car.angle)*car.w/3-sin(car.angle)*3,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,2,C_RED);
+ lights(car.x+cos(car.angle)*car.w/3+sin(car.angle)*3,car.y+sin(car.angle)*car.h/3-cos(car.angle)*4,2,C_RED);
+ lights(car.x-cos(car.angle)*car.w/3-sin(car.angle)*4,car.y-sin(car.angle)*car.h/3+cos(car.angle)*4,3,C_YELLOW);
+ lights(car.x-cos(car.angle)*car.w/3+sin(car.angle)*4,car.y-sin(car.angle)*car.h/3-cos(car.angle)*4,3,C_YELLOW);
+ pos.x=car.x-cos(car.angle)*l-sin(car.angle)*o;
+ pos.y=car.y-sin(car.angle)*l+cos(car.angle)*o;
+ pos.x-=50;
+ pos.y-=50;
+ pos.w=100;
+ pos.h=100;
+ SDL_BlitSurface(hilight,NULL,screen,&pos);
+ pos.x=car.x-cos(car.angle)*l+sin(car.angle)*o;
+ pos.y=car.y-sin(car.angle)*l-cos(car.angle)*o;
+ pos.x-=50;
+ pos.y-=50;
+ pos.w=100;
+ pos.h=100;
+ SDL_BlitSurface(hilight,NULL,screen,&pos);
+ }
+
+ /* update display */
+ if (udpsock)
+ {
+ for (i=0;i<MAX_CLIENTS;i++)
+ {
+ if (oldnetpos[i].w) SDL_UpdateRect(screen,oldnetpos[i].x-car.w/2,oldnetpos[i].y-car.h/2,car.w,car.h);
+ if (newnetpos[i].w) SDL_UpdateRect(screen,newnetpos[i].x-car.w/2,newnetpos[i].y-car.h/2,car.w,car.h);
+ }
+ memcpy(oldnetpos,newnetpos,MAX_CLIENTS*sizeof(struct _car));
+ }
+ SDL_UpdateRect(screen,car.ox-car.w/2,car.oy-car.h/2,car.w,car.h);
+ SDL_UpdateRect(screen,car.x-car.w/2,car.y-car.h/2,car.w,car.h);
+
+ /* update the lights by night */
+ if (config.bynight)
+ {
+ pos.x=car.x-cos(car.angle)*l-sin(car.angle)*15;
+ pos.y=car.y-sin(car.angle)*l+cos(car.angle)*15;
+ pos.x-=60;
+ pos.y-=60;
+ pos.w=120;
+ pos.h=120;
+ if (pos.x<0) pos.x=0;
+ if (pos.y<0) pos.y=0;
+ if (pos.x+pos.w>screen->w) pos.w=screen->w-pos.x;
+ if (pos.y+pos.h>screen->h) pos.h=screen->h-pos.y;
+ SDL_UpdateRect(screen,pos.x,pos.y,pos.w,pos.h);
+ pos.x=car.x-cos(car.angle)*l+sin(car.angle)*15;
+ pos.y=car.y-sin(car.angle)*l-cos(car.angle)*15;
+ pos.x-=60;
+ pos.y-=60;
+ pos.w=120;
+ pos.h=120;
+ if (pos.x<0) pos.x=0;
+ if (pos.y<0) pos.y=0;
+ if (pos.x+pos.w>screen->w) pos.w=screen->w-pos.x;
+ if (pos.y+pos.h>screen->h) pos.h=screen->h-pos.y;
+ SDL_UpdateRect(screen,pos.x,pos.y,pos.w,pos.h);
+ }
+
+ memcpy(oldnetpos,newnetpos,MAX_CLIENTS*sizeof(struct _car));
+
+ /* play engine sound if no sound is currently playing */
if (lastsound_time+100<alltime)
{
lastsound=0;
lastsound_time=alltime;
- if (sound) Mix_PlayMusic(engine,1);
+ if (config.sound) Mix_PlayMusic(engine,1);
}
- if (kd && speed>0.5 || speed>2.0 && !ku)
+ /* if the car is fast or braking, it slides */
+ 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+100<alltime || lastsound<1)
{
lastsound=1;
lastsound_time=alltime;
- if (sound) Mix_PlayMusic(slide,1)==-1;
+ if (config.sound) Mix_PlayMusic(slide,1)==-1;
}
- putpixel(cir,x+cars[i]->w/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);
- if (kd)
+ /* display tires slide */
+ if (config.tire)
{
- 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)*4,car.y+sin(car.angle)*car.h/3+cos(car.angle)*4,T_BLACK);
+ 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,T_BLACK);
+ /* if we are braking the slide is larger */
+ if (kd)
+ {
+ 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,T_BLACK);
+ 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,T_BLACK);
+ }
}
}
-
- c=getpixel(fun,x+cars[i]->w/2,y+cars[i]->h/2);
- r=c&0x000000ff;
- v=(c&0x0000ff00)>>8;
-
- if (v==0)
+
+ /* if we crashed */
+ if (car.crashflag && (lastsound_time+100<alltime || lastsound<2))
{
- x=ox;
- y=oy;
- if (lastsound_time+100<alltime || lastsound<2)
- {
- lastsound=2;
- lastsound_time=alltime;
- if (sound) Mix_PlayMusic(crash,1)==-1;
- }
+ lastsound=2;
+ lastsound_time=alltime;
+ if (config.sound) Mix_PlayMusic(crash,1)==-1;
}
- speed-=speed*(255-v)/1000;
- if (r/8==lastcheck+1) lastcheck++;
- if (r/8==0 && lastcheck==31)
+ /* game time */
+ current.time++;
+ net.time++;
+ if (udpsock && net.time>MAX_LAG)
{
- printf("time = %d\"%d\n",time*5/1000,time*5%1000);
- if (btime==-1 || time<btime)
- {
- btime=time;
- bx=sx;
- by=sy;
- bangle=sangle;
- bspeed=sspeed;
- keys[time]='\0';
- memcpy(bkeys,keys,btime);
- }
- lastcheck=0;
- time=0;
- sx=x;
- sy=y;
- sangle=angle;
- sspeed=speed;
+ print(screen,WIDTH/2-strlen("Timeout !")*5,HEIGHT/2-10,"Timeout !");
+ SDL_Flip(screen);
+ zeRace_send_time(&best);
+ free_mem();
+ return;
}
-
- while (SDL_PollEvent(&event))
+ alltime++;
+
+ switch (car.lapflag)
{
- switch (event.type)
- {
- case SDL_QUIT:
- zeRace_exit();
- break;
- case SDL_KEYDOWN:
- switch (event.key.keysym.sym)
- {
- case SDLK_ESCAPE: // escape
- Mix_FreeMusic(light);
- Mix_FreeMusic(engine);
- Mix_FreeMusic(crash);
- Mix_FreeMusic(slide);
- if (btime<10000) zeRace_send_time(bx,by,bspeed,bangle,btime,bkeys);
- return;
- case SDLK_UP: //up
- ku=1;
- break;
- case SDLK_DOWN: //down
- kd=1;
- break;
- case SDLK_LEFT: //left
- kl=1;
- break;
- case SDLK_RIGHT: //right
- kr=1;
- break;
- }
- break;
- case SDL_KEYUP:
- switch (event.key.keysym.sym)
- {
- case SDLK_UP: //up
- ku=0;
- break;
- case SDLK_DOWN: //down
- kd=0;
- break;
- case SDLK_LEFT: //left
- kl=0;
- break;
- case SDLK_RIGHT: //right
- kr=0;
- break;
- }
- break;
- }
+ /* if we completed a lap */
+ case 1:
+ printf("time = %d\"%d\n",current.time*DELAY/1000,current.time*DELAY%1000);
+ print(screen,0,0,"Last lap : ");
+ print_time(110,0,current.time);
+ SDL_UpdateRect(screen,0,0,200,19);
+ /* if it is the first turn of the best turn, save it */
+ if (best.time==-1 || current.time<best.time)
+ memcpy(&best,¤t,sizeof(struct _record));
+ /* reset turn variables */
+ current.time=0;
+ current.x=car.x;
+ current.y=car.y;
+ current.angle=car.angle;
+ current.speed=car.speed;
+ car.lapflag=0;
+ break;
+ /* if we completed an incomplete lap */
+ case 2:
+ print(screen,0,0,"Last lap : CANCELED ");
+ SDL_UpdateRect(screen,0,0,200,19);
+ /* reset turn variables */
+ current.time=0;
+ car.lapflag=0;
+ break;
+ /* if we miss a checkpoint */
+ case 3:
+ print(screen,0,0,"Checkpoint missed ! ");
+ SDL_UpdateRect(screen,0,0,200,19);
+ break;
+ /* if we validate a missed checkpoint */
+ case 4:
+ print(screen,0,0,"Checkpoint missed OK");
+ SDL_UpdateRect(screen,0,0,200,19);
+ break;
+ /* nothing */
+ default:
+ break;
}
- SDL_Delay(5);
- if (time<btime) keys[time]=(ku<<3 | kd<<2 | kl<<1 | kr)+'A';
- time++;
- alltime++;
+ /* let the system breath */
+ SDL_Delay(delay);
}
}
+/* display a random splash screen at startup */
void zeRace_splash()
{
SDL_Surface *splash;
SDL_Rect pos;
- int i;
char temp[20]="splashs/0.jpg";
- SDL_FillRect(screen,NULL,0x000000);
- temp[8]=rand()%3+'1';
+ SDL_FillRect(screen,NULL,C_BLACK);
+ temp[8]=rand()%5+'1';
splash=IMG_Load(temp);
pos.x=screen->w/2-splash->w/2-1;
pos.w=splash->w+2;
pos.y=screen->h/2-splash->h/2-1;
pos.h=splash->h+2;
- SDL_FillRect(screen,&pos,0xffffff);
+ SDL_FillRect(screen,&pos,C_WHITE);
pos.x=screen->w/2-splash->w/2;
pos.y=screen->h/2-splash->h/2;
SDL_BlitSurface(splash,NULL,screen,&pos);
}
-void zeRace_menu()
+/* menu loop to select track */
+void zeRace_local()
{
SDL_Event event;
{
SDL_Surface *full,*preview;
SDL_Rect pos;
- SDL_FillRect(screen,NULL,0x000000);
+ SDL_FillRect(screen,NULL,C_BLACK);
print(screen,WIDTH/2-28*5,HEIGHT/6,"* Please choose your race *");
print(screen,WIDTH/2-strlen(tracklist->title)*5,5*HEIGHT/6-20,tracklist->title);
print(screen,WIDTH/2-(strlen(tracklist->author)+strlen("Author : "))*5,5*HEIGHT/6+0,"Author : ");
print(screen,WIDTH/2-(strlen(tracklist->author)-strlen("Author : "))*5,5*HEIGHT/6+0,tracklist->author);
- print(screen,WIDTH/2-(strlen(tracklist->version)+strlen("Version : "))*5,5*HEIGHT/6+20,"Version : ");
- print(screen,WIDTH/2-(strlen(tracklist->version)-strlen("Version : "))*5,5*HEIGHT/6+20,tracklist->version);
+ print(screen,WIDTH/2-( strlen("Version : ")+strlen(tracklist->version))*5,5*HEIGHT/6+20,"Version : ");
+ print(screen,WIDTH/2-(-strlen("Version : ")+strlen(tracklist->version))*5,5*HEIGHT/6+20,tracklist->version);
+ print(screen,WIDTH/2-( strlen("Best time : ")+6+strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40,"Best time : ");
+ print_time (WIDTH/2-(-strlen("Best time : ")+6+strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40,tracklist->best_time);
+ print(screen,WIDTH/2-(-strlen("Best time : ")-6+strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40," by ");
+ print(screen,WIDTH/2-(-strlen("Best time : ")-6-strlen(" by ")+strlen(tracklist->best_pseudo))*5,5*HEIGHT/6+40,tracklist->best_pseudo);
full=IMG_Load(tracklist->full);
preview=(SDL_Surface *)zoomSurface(full,0.5,0.5,1);
SDL_FreeSurface(full);
pos.w=preview->w+2;
pos.y=screen->h/2-preview->h/2-1;
pos.h=preview->h+2;
- SDL_FillRect(screen,&pos,0xffffff);
+ SDL_FillRect(screen,&pos,C_WHITE);
pos.x=WIDTH/2-preview->w/2;
pos.y=screen->h/2-preview->h/2;
SDL_BlitSurface(preview,NULL,screen,&pos);
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
- case SDLK_ESCAPE: // escape
- zeRace_exit();
- break;
- case SDLK_RETURN: //enter
- case SDLK_SPACE: //space
- zeRace_launch();
+ case SDLK_ESCAPE:
+ return;
+ case SDLK_RETURN:
+ case SDLK_SPACE:
+ zeRace_launch(0,1);
update();
break;
- case SDLK_LEFT: //left
+ case SDLK_LEFT:
tracklist=tracklist->next;
update();
break;
- case SDLK_RIGHT: //right
+ case SDLK_RIGHT:
tracklist=tracklist->prev;
update();
break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ SDL_Delay(10);
+ }
+}
+
+
+/* top 10 screen */
+void zeRace_top10(char *buf)
+{
+ int i,nb,tmp;
+ SDL_Rect pos;
+ SDL_FillRect(screen,NULL,C_BLACK);
+ 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;
+ tmp=SDLNet_Read16(buf);
+ buf+=2;
+ pos.x=110;
+ pos.y=(i+3)*HEIGHT/14-8;
+ SDL_BlitSurface(cars[tmp][0],NULL,screen,&pos);
+ }
+ SDL_Flip(screen);
+ SDL_Delay(5000);
+}
+
+
+/* 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);
+ do if (strcmp(tracklist->name,tmp)==0) break; else tracklist=tracklist->next; while (tracklist!=loopcheck);
+ 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) 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,C_BLACK);
+ 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
+
+ if (!config.internet) return;
+
+ 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<len)
+ fprintf(stderr,"SDLNet_TCP_Send: %s\n",SDLNet_GetError());
+ else
+ {
+ len=SDLNet_TCP_Recv(tcpsock,response,10240);
+ tmp=response;
+ for (tmp=response;tmp<response+10240;tmp++) if (*tmp=='\n') *tmp='\0';
+ tmp=response;
+ while (*tmp!='\0' || *(tmp+1)!='\r') tmp++;
+ tmp+=3;
+ for (i=0;i<10;i++)
+ {
+ strcpy(servers[i].name,tmp);
+ tmp+=strlen(tmp)+1;
+ strcpy(servers[i].ip,tmp);
+ tmp+=strlen(tmp)+1;
+ strcpy(servers[i].port,tmp);
+ tmp+=strlen(tmp)+1;
+ }
+ printf("done\n");
+ }
+
+ SDLNet_TCP_Close(tcpsock);
+
+ void update()
+ {
+ int i;
+ SDL_FillRect(screen,NULL,C_BLACK);
+ print(screen,380,HEIGHT/(INTERNET_OPTIONS+4)*(3+active),">");
+ 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()
+{
+ SDL_Event event;
+ int active=0;
+ #define CONFIG_OPTIONS 14
+
+ void update()
+ {
+ SDL_Rect pos;
+ SDL_FillRect(screen,NULL,C_BLACK);
+ print(screen,20,HEIGHT/(CONFIG_OPTIONS+4)*(3+active),">");
+ print(screen,WIDTH/2-24*5,HEIGHT/(CONFIG_OPTIONS+4),"* Configuration screen *");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*3,"Pseudo : ");
+ print(screen,40+10*strlen("Pseudo : "),HEIGHT/(CONFIG_OPTIONS+4)*3,config.pseudo);
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*4,"Url : ");
+ print(screen,40+10*strlen("Url : "),HEIGHT/(CONFIG_OPTIONS+4)*4,config.url);
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*5,"Fullscreen : ");
+ print(screen,40+10*strlen("Fullscreen : "),HEIGHT/(CONFIG_OPTIONS+4)*5,config.fullscreen?"Yes":"No");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*6,"Sound : ");
+ print(screen,40+10*strlen("Sound : "),HEIGHT/(CONFIG_OPTIONS+4)*6,config.sound?"Yes":"No");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*7,"Tire : ");
+ print(screen,40+10*strlen("Tire : "),HEIGHT/(CONFIG_OPTIONS+4)*7,config.tire?"Yes":"No");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*8,"Accelerate key : ");
+ print(screen,40+10*strlen("Accelerate key : "),HEIGHT/(CONFIG_OPTIONS+4)*8,config.up?SDL_GetKeyName(config.up):"<press key>");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*9,"Brake key : ");
+ print(screen,40+10*strlen("Brake key : "),HEIGHT/(CONFIG_OPTIONS+4)*9,config.down?SDL_GetKeyName(config.down):"<press key>");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*10,"Turn left key : ");
+ print(screen,40+10*strlen("Turn left key : "),HEIGHT/(CONFIG_OPTIONS+4)*10,config.left?SDL_GetKeyName(config.left):"<press key>");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*11,"Turn right key : ");
+ print(screen,40+10*strlen("Turn right key : "),HEIGHT/(CONFIG_OPTIONS+4)*11,config.right?SDL_GetKeyName(config.right):"<press key>");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*12,"Color : ");
+ 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)*14,"By night : ");
+ print(screen,40+10*strlen("By night : "),HEIGHT/(CONFIG_OPTIONS+4)*14,config.bynight?"Yes":"No");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*15,"Internet : ");
+ print(screen,40+10*strlen("Internet : "),HEIGHT/(CONFIG_OPTIONS+4)*15,config.internet?"Yes":"No");
+ print(screen,40,HEIGHT/(CONFIG_OPTIONS+4)*(CONFIG_OPTIONS+2),"Back to main menu");
+ SDL_Flip(screen);
+ }
+
+ int read_key()
+ {
+ for (;;)
+ {
+ while (SDL_PollEvent(&event)) switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ return event.key.keysym.sym;
+ }
+ SDL_Delay(10);
+ }
+ }
+
+ 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,40+10*strlen("Pseudo : "),HEIGHT/(CONFIG_OPTIONS+4)*3,config.pseudo,MAXLINELENGTH); break;
+ case 1: readstring(screen,40+10*strlen("Url : "),HEIGHT/(CONFIG_OPTIONS+4)*4,config.url,MAXLINELENGTH); break;;
+ case 2: config.fullscreen=!config.fullscreen; break;
+ case 3: config.sound=!config.sound; break;
+ case 4: config.tire=!config.tire; break;
+ case 5: config.up=0; update(); config.up=read_key(); break;
+ case 6: config.down=0; update(); config.down=read_key(); break;
+ case 7: config.left=0; update(); config.left=read_key(); break;
+ case 8: config.right=0; update(); config.right=read_key(); break;
+ case 9:
+ if (event.key.keysym.sym==SDLK_LEFT) config.color--; else config.color++;
+ if (config.color<0) config.color=NB_CARS-1;
+ if (config.color>NB_CARS-1) config.color=0;
+ break;
+ case 10: config.boss=0; update(); config.boss=read_key(); break;
+ case 11: config.bynight=!config.bynight; break;
+ case 12: config.internet=!config.internet; break;
+ case 13:
+ return;
+ }
+ update();
+ break;
+ case SDLK_UP:
+ active--; if (active<0) active=CONFIG_OPTIONS-1;
+ update();
+ break;
+ case SDLK_DOWN:
+ active++; if (active>CONFIG_OPTIONS-1) active=0;
+ update();
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ }
+ SDL_Delay(10);
+ }
+}
+
+
+/* main menu */
+void zeRace_menu()
+{
+ SDL_Event event;
+ int active=0;
+ SDL_Surface *logo;
+ #define MENU_OPTIONS 5
+
+ void update()
+ {
+ SDL_Rect pos;
+ SDL_FillRect(screen,NULL,C_BLACK);
+ pos.x=WIDTH/2-logo->w/2;
+ pos.y=HEIGHT/6-logo->h/2;
+ SDL_BlitSurface(logo,NULL,screen,&pos);
+ 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)*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");
+ 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: zeRace_local(); break;
+ case 1: zeRace_network(); break;
+ case 2: zeRace_internet(); break;
+ case 3: zeRace_config(); break;
+ case 4: return;
+ }
+ update();
+ break;
+ case SDLK_UP:
+ active--; if (active<0) active=MENU_OPTIONS-1;
+ update();
+ break;
+ case SDLK_DOWN:
+ active++; if (active>MENU_OPTIONS-1) active=0;
+ update();
+ break;
+ default:
+ break;
}
break;
}
}
+/* main program */
int main(int argc,char *argv[])
{
zeRace_init();