/* XBlockOut a 3D Tetris Copyright (C) 1992,1993,1994,2001 Thierry EXCOFFIER 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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA. Contact: Thierry.EXCOFFIER@liris.univ-lyon1.fr */ #include #ifdef HAVE_FCNTL_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_STDLIB_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #include #include "define.h" #include #include #include #if HAVE_STRING_H #include #else #include #endif #include "bl.h" #include "score.h" #include extern int errno ; #define MAXSCORE 25 /* Number of saved score */ #define MAXNAME 30 /* Len a a user name */ #define WIDTH 80 #define MAXFILENAME 256 /* Maximum len of the score file name */ #define LINESPACE 1 #define MAXLINE "123456789#cubes9#blocs9#level99999score9Tue9Jan995914:58:3891993000000" #define USER_SCORE_DIR ".xbl-scores" struct score { char name[MAXNAME+1] ; int nbcubes,nbblocs,score,nblevel ; time_t date ; } ; struct scores { int nb ; time_t modify_time ; char last_file_name[MAXFILENAME] ; struct score score[MAXSCORE+1] ; } ; /* Next variables are initialised in scorewin */ static Display *disp ; static Window wind ; static int heig ; static GC scgc ; static XFontStruct *xfon ; /**********************************************************************/ /* Find the file name of score file */ /**********************************************************************/ /* Hack for debian: if euid is games, use global score file, else use * per-user score file. */ #include #include void scorename(int x, int y, int z, int p, char *buf) { struct group *games = getgrnam("games"); if ((games && getegid() == games->gr_gid) && ( mkdir(SCOREDIR, 0755) != 0 ? errno == EEXIST : 1 )) { sprintf(buf,"%s/%d-%d-%d-%d",SCOREDIR,x,y,z,p) ; return ; } else { if ( getenv("HOME") ) { if ( strlen(getenv("HOME")) < MAXFILENAME - 80 ) { sprintf(buf, "%s/" USER_SCORE_DIR, getenv("HOME")) ; if ( mkdir(buf, 0755) != 0 ? errno == EEXIST : 1 ) { sprintf(buf+strlen(buf),"/%d-%d-%d-%d",x,y,z,p) ; return ; } perror(buf) ; exit(1) ; } fprintf(stderr, "Buffer overflow!\n") ; exit(1) ; } fprintf(stderr, "Where is your home?\n") ; exit(1) ; } } /**********************************************************************/ /* Read the score file */ /**********************************************************************/ int readscore(int x, int y, int z, int p, struct scores *s) { FILE *f ; char buf[MAXFILENAME] ; struct score *cs ; struct stat st ; scorename(x,y,z,p,buf) ; if( stat(buf,&st) ) switch( errno ) { default : perror("readscore") ; case ENOENT : s->nb = 0 ; strcpy(s->last_file_name,buf) ; return(0) ; } if ( strcmp(buf,s->last_file_name) == 0 ) { /* Same file !!! */ if ( st.st_mtime==s->modify_time ) return(s->score[0].score) ; } else { strcpy(s->last_file_name,buf) ; s->nb = 0 ; } s->modify_time = st.st_mtime ; f = fopen( buf,"r" ) ; if ( f==0 ) { if ( errno==EAGAIN ) { /* two times because there is alarm signals */ microsleep(100000) ; microsleep(100000) ; return(readscore(x,y,z,p,s)) ; } return(0) ; } cs = s->score ; s->nb = 0 ; while( fscanf(f,"%s%d%d%d%d%ld",cs->name,&cs->nbcubes,&cs->nbblocs, &cs->nblevel,&cs->score,&cs->date)==6 ) { cs++ ; s->nb++ ; if ( s->nb==MAXSCORE ) break ; } fclose(f) ; return( s->score[0].score ) ; } /**********************************************************************/ /* Display the scores (read them) */ /**********************************************************************/ int displayscore(int x, int y, int z, int p, int draw) { static struct scores s = {-1} ; char buf[LINE_LENGTH] ; int i,yy ; int hiscore ; int ilast ; time_t last ; int ch ; int ascent,descent,dir ; XCharStruct overall_return ; if ( s.nb==-1 ) s.last_file_name[0] = '\0' ; hiscore = readscore(x,y,z,p,&s) ; if ( draw==0 ) return(hiscore) ; XClearWindow(disp,wind) ; ch = heig+LINESPACE ; yy = ch ; sprintf(buf,"Width=%d Height=%d Depth=%d Pieces=%s", x,y,z,p==FLAT?"FLAT":p==SIMPLE?"SIMPLE":"COMPLEX") ; XDrawString(disp,wind,scgc,3,yy,buf,(int)strlen(buf)) ; yy+=ch ; yy += ch ; sprintf(buf," Name #cubes #blocs #level score") ; XDrawString(disp,wind,scgc,3,yy,buf,(int)strlen(buf)) ; yy+=ch ; last = 0 ; ilast = -1 ; for(i=0;ilast ) { last = s.score[i].date ; ilast = i ; } for(i=0;i='A' && *name<='Z' ) *tmp++ = *name++ - 'A' + 'a' ; else *tmp++ = *name++ ; } while( *name!=0 || tmp-buffer == MAXNAME-1 ) ; *tmp = '\0' ; if ( strcmp(buffer,"nobody")==0 ) return(1) ; if ( strcmp(buffer,"unknown")==0 ) return(1) ; return(0) ; } /**********************************************************************/ /* Add a new score !!!! */ /**********************************************************************/ int addscore(int x, int y, int z, int p, int nbcubes, int nbblocs, int nblevel, int score) { struct scores s ; FILE *f ; int fd ; int i,j ; char name[LINE_LENGTH] ; char buf[MAXFILENAME] ; int inscore ; if ( score==0 ) return(0) ; s.last_file_name[0] = '\0' ; umask(0111) ; (void)readscore(x,y,z,p,&s) ; scorename(x,y,z,p,buf) ; if ( s.nb==0 ) #ifdef USE_SETGID { if ( strstr(s.last_file_name, USER_SCORE_DIR) ) fd = creat(buf,(mode_t)0644) ; else fd = creat(buf,(mode_t)0664) ; chown( buf,0,GROUP_GID ) ; } #else { fd = creat(buf,(mode_t)0666) ; } #endif else fd = open(buf,O_WRONLY) ; if ( fd<0 ) { fprintf(stderr,"PLEASE Install score directory\n") ; perror(buf) ; return(0) ; /* no score file */ } #ifdef F_LOCK if ( lockf( fd , F_LOCK , 0 ) != 0 ) /* Sleep if necessary */ { perror("score.c:lockf") ; } #endif f = fdopen(fd,"w") ; if ( f==0 ) { perror(buf) ; return(0) ; /* no high score, error writing */ } for(i=s.nb-1;i>=0;i--) if ( s.score[i].score>=score ) break ; inscore = 0 ; if ( i!=MAXSCORE-1 ) { /* if ( tryname( name , getlogin() ) ) if ( tryname( name , cuserid(0L) ) ) if ( tryname( name , getenv("LOGNAME") ) ) if ( tryname( name , getenv("USER") ) ) { fprintf(stderr,"I can't find your name...\n") ; fprintf(stderr,"file=%s line=%d\n",__FILE__,__LINE__) ; fprintf(stderr,"Please give me a patch\n") ; strcpy(name,"NONAME") ; } */ strncpy(name , getpwuid(geteuid())->pw_name , sizeof(name)) ; j = i ; while( i>=0 ) if ( strcmp( s.score[i].name,name )==0 ) break ; else i-- ; if ( i==-1 ) { for(i=s.nb;i>j+1;i--) s.score[i] = s.score[i-1] ; s.score[j+1].nbblocs = nbblocs ; s.score[j+1].nbcubes = nbcubes ; s.score[j+1].nblevel = nblevel ; s.score[j+1].score = score ; time( &s.score[j+1].date ) ; strncpy( s.score[j+1].name,name,MAXNAME ) ; if ( s.nb!=MAXSCORE ) s.nb++ ; inscore = 1 ; } } for(i=0;itype ) { case Expose : do { i = XCheckWindowEvent(bl->x.display,bl->x.wscore, ExposureMask,event) ; } while(i==True) ; drawscores(bl,1) ; break ; case UnmapNotify : case MapNotify : if ( (bl->menu.showscore && event->type==UnmapNotify) || (bl->menu.showscore==0 && event->type==MapNotify) ) push_button(bl->menu.viewscore, bl->menu.viewscore->x+bl->menu.viewscore->dx/2, bl->menu.viewscore->y+bl->menu.viewscore->dy/2, 1) ; setargs(bl) ; break ; case ConfigureNotify : { XSizeHints sh ; sh.flags = PPosition ; sh.x = ((XConfigureEvent*)event)->x ; sh.y = ((XConfigureEvent*)event)->y ; XSetWMNormalHints( bl->x.display,bl->x.wscore,&sh ) ; } case ReparentNotify : setargs(bl) ; break ; default : fprintf(stderr,"Unknow event type in score window\n") ; fprintf(stderr,"event.type = %d\n",event->type) ; } }