This is topten.c in view mode; [Download] [Up]
/* SCCS Id: @(#)topten.c 3.0 89/12/31 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Modified by cmarq@cube.net for graphical NEXTSTEP version (added notice: 8/26/94) */ #define MONATTK_H /* comment line for pre-compiled headers */ #define MONFLAG_H /* comment line for pre-compiled headers */ /* block some unused #defines to avoid overloading some cpp's */ #include "hack.h" #ifndef MACOS #include <errno.h> /* George Barbanis */ #else extern short macflags; extern WindowPtr HackWindow; #endif #ifdef NO_FILE_LINKS #include <fcntl.h> /* Ralf Brown */ #endif #include <ctype.h> #ifdef LATTICE static void FDECL(lattice_mung_line,(char*)); static void FDECL(lattice_unmung_line,(char*)); #endif #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry)) #define NAMSZ 10 #define DTHSZ 60 #define PERSMAX 3 /* entries per name/uid per char. allowed */ #define POINTSMIN 1 /* must be > 0 */ #define ENTRYMAX 100 /* must be >= 10 */ #ifndef MSDOS #define PERS_IS_UID /* delete for PERSMAX per name; now per uid */ #endif struct toptenentry { struct toptenentry *tt_next; long int points; int level,maxlvl,hp,maxhp; int uid; char plchar; char sex; char name[NAMSZ+1]; char death[DTHSZ+1]; char date[7]; /* yymmdd */ } *tt_head; static char *FDECL(itoa, (int)); static const char *FDECL(ordin, (int)); static void outheader(); static int FDECL(outentry, (int,struct toptenentry *,int)); /* must fit with end.c */ static const char *killed_by_prefix[] = { "killed by ", "choked on ", "poisoned by ", "", "drowned in ", "", "crushed to death by ", "petrified by ", "", "", "", "", "", "" }; void topten(how) int how; { int uid = getuid(); int rank, rank0 = -1, rank1 = 0; int occ_cnt = PERSMAX; register struct toptenentry *t0, *t1, *tprev; #ifdef UNIX char *reclock = "record_lock"; # ifdef NO_FILE_LINKS int lockfd ; # endif #endif /* UNIX */ #ifdef VMS char *reclock = "record_lock;1"; char recfile[] = RECORD; #else const char *recfile = RECORD; #endif #if defined(UNIX) || defined(VMS) int sleepct = 100; #endif FILE *rfile; register int flg = 0; #ifdef LOGFILE char *lgfile = LOGFILE; FILE *lfile; # ifdef UNIX char *loglock = "logfile_lock"; # endif /* UNIX */ # ifdef VMS char *loglock = "logfile_lock;1"; # endif /* VMS */ # if defined(UNIX) || defined(VMS) int sleeplgct = 30; # endif /* UNIX or VMS */ #endif /* LOGFILE */ #if defined(MSDOS) || defined(MACOS) #define HUP #else #define HUP if(!done_hup) #endif #ifdef MACOS macflags &= ~fDoUpdate; uid = TickCount(); #endif /* create a new 'topten' entry */ t0 = newttentry(); t0->level = dlevel; t0->maxlvl = maxdlevel; t0->hp = u.uhp; t0->maxhp = u.uhpmax; t0->points = u.urexp; t0->plchar = pl_character[0]; t0->sex = (flags.female ? 'F' : 'M'); t0->uid = uid; (void) strncpy(t0->name, plname, NAMSZ); (t0->name)[NAMSZ] = 0; (t0->death)[0] = 0; switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcat(t0->death, killed_by_prefix[how]), (void) strncat(t0->death, an(killer), DTHSZ); break; case KILLED_BY: Strcat(t0->death, killed_by_prefix[how]), (void) strncat(t0->death, killer, DTHSZ); break; case NO_KILLER_PREFIX: (void) strncat(t0->death, killer, DTHSZ); break; } Strcpy(t0->date, getdate()); #ifdef LOGFILE /* used for debugging (who dies of what, where) */ # if defined(UNIX) || defined(VMS) # ifdef NO_FILE_LINKS loglock = (char *)alloc(sizeof(LOCKDIR)+1+strlen(lgfile)+6); Strcpy(loglock,LOCKDIR) ; Strcat(loglock,"/") ; Strcat(loglock,lgfile) ; Strcat(loglock,"_lock") ; while ((lockfd = open(loglock,O_RDWR|O_CREAT|O_EXCL,0666)) == -1) { # else while(link(lgfile, loglock) == -1) { # endif /* NO_FILE_LINKS */ extern int errno; if (errno == ENOENT) /* If no such file, do not keep log */ goto lgend; /* George Barbanis */ HUP perror(loglock); if(!sleeplgct--) { HUP (void) puts("I give up. Sorry."); HUP (void) puts("Perhaps there is an old logfile_lock around?"); goto lgend; } HUP Printf("Waiting for access to log file. (%d)\n", sleeplgct); HUP (void) fflush(stdout); # if defined(SYSV) || defined(ULTRIX) || defined(VMS) (void) # endif sleep(1); } # endif /* UNIX or VMS */ if(!(lfile = fopen(lgfile,"a"))){ HUP (void) puts("Cannot open log file!"); goto lgend; } (void) fprintf(lfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n", t0->date, t0->uid, t0->level, t0->maxlvl, t0->hp, t0->maxhp, t0->points, t0->plchar, t0->sex, t0->name, t0->death); (void) fclose(lfile); # if defined(UNIX) || defined(VMS) (void) unlink(loglock); # endif /* UNIX or VMS */ lgend:; # ifdef NO_FILE_LINKS (void) close(lockfd) ; # endif # if defined(WIZARD) || defined(EXPLORE_MODE) if (wizard || discover) { Printf("\nSince you were in %s mode, the score list will not be checked.\n", wizard ? "wizard" : "discover"); return; } # endif #endif /* LOGFILE */ #if defined(UNIX) || defined(VMS) # ifdef NO_FILE_LINKS reclock = (char *)alloc(sizeof(LOCKDIR)+1+strlen(recfile)+7); Strcpy(reclock,LOCKDIR) ; Strcat(reclock,"/") ; Strcat(reclock,recfile) ; Strcat(reclock,"_lock") ; while ((lockfd = open(reclock,O_RDWR|O_CREAT|O_EXCL,0666)) == -1) { # else while(link(recfile, reclock) == -1) { # endif /* NO_FILE_LINKS */ HUP perror(reclock); if(!sleepct--) { HUP (void) puts("I give up. Sorry."); HUP (void) puts("Perhaps there is an old record_lock around?"); return; } HUP Printf("Waiting for access to record file. (%d)\n", sleepct); HUP (void) fflush(stdout); # if defined(SYSV) || defined(ULTRIX) || defined(VMS) (void) # endif sleep(1); } #endif /* UNIX or VMS */ #ifdef MACOS { term_info *t; t = (term_info *)GetWRefCon(HackWindow); SetVol((StringPtr)0L, t->recordVRefNum); if (!(rfile = fopen(recfile,"r"))) { short i; rfile = openFile(recfile,"r"); for (i = 0;i < t->maxRow; i++) { MoveTo(Screen_Border, t->ascent + (i * t->height) + Screen_Border); DrawText(&t->screen[i][0], 0, t->maxCol); } ValidRect(&(**(*HackWindow).visRgn).rgnBBox); } } if (!rfile) { #else if(!(rfile = fopen(recfile,"r"))){ #endif HUP (void) puts("Cannot open record file!"); goto unlock; } #ifdef NO_FILE_LINKS (void) close(lockfd) ; #endif HUP (void) putchar('\n'); /* assure minimum number of points */ if(t0->points < POINTSMIN) t0->points = 0; t1 = tt_head = newttentry(); tprev = 0; /* rank0: -1 undefined, 0 not_on_list, n n_th on list */ for(rank = 1; ; ) { #ifdef LATTICE if(fscanf(rfile,"%6s %d %d %d %d %d %ld%*c%c%c %s %s", #else if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", #endif /* LATTICE */ t1->date, &t1->uid, &t1->level, &t1->maxlvl, &t1->hp, &t1->maxhp, &t1->points, &t1->plchar, &t1->sex, #ifdef LATTICE /* return value is broken also, sigh */ t1->name, t1->death) <1 || t1->points < POINTSMIN) #else t1->name, t1->death) != 11 || t1->points < POINTSMIN) #endif t1->points = 0; #ifdef LATTICE lattice_unmung_line(t1->death); #endif if(rank0 < 0 && t1->points < t0->points) { rank0 = rank++; if(tprev == 0) tt_head = t0; else tprev->tt_next = t0; t0->tt_next = t1; occ_cnt--; flg++; /* ask for a rewrite */ } else tprev = t1; if(t1->points == 0) break; if( #ifdef PERS_IS_UID t1->uid == t0->uid && #else strncmp(t1->name, t0->name, NAMSZ) == 0 && #endif t1->plchar == t0->plchar && --occ_cnt <= 0) { if(rank0 < 0) { rank0 = 0; rank1 = rank; HUP Printf("You didn't beat your previous score of %ld points.\n\n", t1->points); } if(occ_cnt < 0) { flg++; continue; } } if(rank <= ENTRYMAX) { t1 = t1->tt_next = newttentry(); rank++; } if(rank > ENTRYMAX) { t1->points = 0; break; } } if(flg) { /* rewrite record file */ (void) fclose(rfile); #ifdef VMS { char *sem = rindex(recfile, ';'); if (sem) *sem = '\0'; } #endif if(!(rfile = fopen(recfile,"w"))){ HUP (void) puts("Cannot write record file\n"); goto unlock; } if(!done_stopprint) if(rank0 > 0){ if(rank0 <= 10) (void) puts("You made the top ten list!\n"); else Printf("You reached the %d%s place on the top %d list.\n\n", rank0, ordin(rank0), ENTRYMAX); } } if(rank0 == 0) rank0 = rank1; if(rank0 <= 0) rank0 = rank; if(!done_stopprint) outheader(); t1 = tt_head; for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { #ifdef LATTICE lattice_mung_line(t1->death); if(flg) (void) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s %s\n", #else if(flg) (void) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n", #endif t1->date, t1->uid, t1->level, t1->maxlvl, t1->hp, t1->maxhp, t1->points, t1->plchar, t1->sex, t1->name, t1->death); #ifdef LATTICE lattice_unmung_line(t1->death); #endif if(done_stopprint) continue; if(rank > flags.end_top && (rank < rank0-flags.end_around || rank > rank0+flags.end_around) && (!flags.end_own || #ifdef PERS_IS_UID t1->uid != t0->uid #else strncmp(t1->name, t0->name, NAMSZ) #endif )) continue; if(rank == rank0-flags.end_around && rank0 > flags.end_top+flags.end_around+1 && !flags.end_own) (void) putchar('\n'); if(rank != rank0) (void) outentry(rank, t1, 0); else if(!rank1) (void) outentry(rank, t1, 1); else { int t0lth = outentry(0, t0, -1); int t1lth = outentry(rank, t1, t0lth); if(t1lth > t0lth) t0lth = t1lth; (void) outentry(0, t0, t0lth); } } if(rank0 >= rank) if(!done_stopprint) (void) outentry(0, t0, 1); (void) fclose(rfile); #ifdef VMS if (flg) { delete(RECORD); rename(recfile, RECORD); } # undef unlink #endif unlock: ; #if defined(UNIX) || defined(VMS) # ifdef NO_FILE_LINKS (void) close(lockfd) ; # endif if (unlink(reclock) < 0) Printf("Can't unlink %s\n",reclock) ; #endif } static void outheader() { char linebuf[BUFSZ]; register char *bp; Strcpy(linebuf, " No Points Name"); bp = eos(linebuf); while(bp < linebuf + COLNO - 9) *bp++ = ' '; Strcpy(bp, "Hp [max]"); #ifdef NEXT (void) printf("%s", linebuf); #else (void) puts(linebuf); #endif /* NEXT */ #ifdef NEXT printf("\n"); #endif #ifdef MACOS putchar('\n'); #endif } /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */ static int outentry(rank, t1, so) register struct toptenentry *t1; register int rank, so; { register boolean second_line = TRUE; char linebuf[BUFSZ], linebuf2[BUFSZ]; linebuf[0] = linebuf2[0] = 0; if(rank) Sprintf(eos(linebuf), " %2d", rank); else Strcat(linebuf, " "); Sprintf(eos(linebuf), " %10ld %.10s", t1->points, t1->name); Sprintf(eos(linebuf), "-%c ", t1->plchar); if(!strncmp("escaped", t1->death, 7)) { second_line = FALSE; if(!strcmp(" (with the Amulet)", t1->death+7)) Strcat(linebuf, "escaped the dungeon with the Amulet"); else Sprintf(eos(linebuf), "escaped the dungeon [max level %d]", t1->maxlvl); #ifdef ENDGAME } else if(!strncmp("ascended", t1->death, 8)) { Strcat(linebuf, "ascended to demigod"); if (t1->sex == 'F') Strcat(linebuf, "dess"); Strcat(linebuf, "-hood"); second_line = FALSE; #endif } else { if(!strncmp(t1->death,"quit",4)) { Strcat(linebuf, "quit"); second_line = FALSE; } else if(!strncmp(t1->death,"starv",5)) { Strcat(linebuf, "starved to death"); second_line = FALSE; } else if(!strncmp(t1->death,"choked",6)) { Sprintf(eos(linebuf), "choked on h%s food", (t1->sex == 'F') ? "er" : "is"); } else if(!strncmp(t1->death,"poisoned",8)) { Strcat(linebuf, "was poisoned"); } else if(!strncmp(t1->death,"crushed",7)) { Strcat(linebuf, "was crushed to death"); } else if(!strncmp(t1->death, "petrified by ",13)) { Strcat(linebuf, "turned to stone"); } else Strcat(linebuf, "died"); #ifdef ENDLEVEL if (t1->level == ENDLEVEL) Strcat(linebuf, " in the endgame"); else #endif Sprintf(eos(linebuf), " on dungeon level %d", t1->level); if(t1->maxlvl != t1->level) Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); /* kuldge for "quit while already on Charon's boat" */ if(!strncmp(t1->death, "quit ", 5)) Strcat(linebuf, t1->death + 4); } Strcat(linebuf, "."); if(t1->maxhp) { register char *bp = eos(linebuf); char hpbuf[10]; int hppos; int lngr = strlen(linebuf); Strcpy(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-"); hppos = COLNO - 7 - strlen(hpbuf); if (lngr >= hppos) hppos = (2*COLNO) - 7 - strlen(hpbuf); if(bp <= linebuf + hppos) { /* pad any necessary blanks to the hit point entry */ #ifdef MACOS while(bp <= linebuf + hppos) *bp++ = ' '; #else while(bp < linebuf + hppos) *bp++ = ' '; #endif Strcpy(bp, hpbuf); if(t1->maxhp < 10) Sprintf(eos(bp), " [%d]", t1->maxhp); else if(t1->maxhp < 100) Sprintf(eos(bp), " [%d]", t1->maxhp); else Sprintf(eos(bp), " [%d]", t1->maxhp); } } /* Line 2 now contains the killer name */ /* Quit, starved, ascended, and escaped contain no second line */ if (second_line) { Strcpy(linebuf2, t1->death); *linebuf2 = toupper(*linebuf2); Strcat(linebuf2, "."); } if(so == 0) { #ifdef NEXT (void) printf("%s", linebuf); #else (void) puts(linebuf); #endif /* NEXT */ if (second_line) (void) Printf(" %s\n", linebuf2); } else if(so > 0) { register char *bp = eos(linebuf); if(so >= COLNO) so = COLNO-1; while(bp < linebuf + so) *bp++ = ' '; *bp = 0; standoutbeg(); #ifdef NEXT (void) printf("%s", linebuf); #else (void) puts(linebuf); #endif /* NEXT */ if(second_line) (void) Printf(" %s", linebuf2); standoutend(); if(second_line) #ifdef NEXT (void) printf("\n"); #else (void) putchar('\n'); #endif /* NEXT */ } return(strlen(linebuf)+strlen(linebuf2)); } static char * itoa(a) int a; { #ifdef LINT /* static char buf[12]; */ char buf[12]; #else static char buf[12]; #endif Sprintf(buf,"%d",a); return(buf); } static const char * ordin(n) int n; { register int dd = n%10; #if ENTRYMAX > 110 return((dd==0 || dd>3 || (n/10)%10==1) ? "th" : #else return((dd==0 || dd>3 || n/10==1) ? "th" : #endif (dd==1) ? "st" : (dd==2) ? "nd" : "rd"); } /* * Called with args from main if argc >= 0. In this case, list scores as * requested. Otherwise, find scores for the current player (and list them * if argc == -1). */ void prscore(argc,argv) int argc; char **argv; { const char **players; int playerct; int rank; register struct toptenentry *t1, *t2; const char *recfile = RECORD; FILE *rfile; register int flg = 0, i; #ifdef nonsense long total_score = 0L; char totchars[10]; int totcharct = 0; #endif int outflg = (argc >= -1); #ifdef PERS_IS_UID int uid = -1; #else const char *player0; #endif #ifdef MACOS if(!(rfile = fopen(recfile,"r"))) rfile = openFile(recfile,"r"); if (!rfile) { #else if(!(rfile = fopen(recfile,"r"))){ #endif (void) puts("Cannot open record file!"); return; } if(argc > 1 && !strncmp(argv[1], "-s", 2)){ if(!argv[1][2]){ argc--; argv++; } else if(!argv[1][3] && index(pl_classes, argv[1][2])) { argv[1]++; argv[1][0] = '-'; } else argv[1] += 2; } if(argc <= 1){ #ifdef PERS_IS_UID uid = getuid(); playerct = 0; #else player0 = plname; if(!*player0) player0 = "hackplayer"; playerct = 1; players = &player0; #endif } else { playerct = --argc; players = (const char **)++argv; } if(outflg) (void) putchar('\n'); t1 = tt_head = newttentry(); for(rank = 1; ; rank++) { #ifdef LATTICE if(fscanf(rfile, "%6s %d %d %d %d %d %ld%*c%c%c %s %s", #else if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", #endif /* LATTICE */ t1->date, &t1->uid, &t1->level, &t1->maxlvl, &t1->hp, &t1->maxhp, &t1->points, &t1->plchar, &t1->sex, #ifdef LATTICE t1->name, t1->death)<1) #else t1->name, t1->death) != 11) #endif t1->points = 0; if(t1->points == 0) break; #ifdef LATTICE lattice_unmung_line(t1->death); #endif #ifdef PERS_IS_UID if(!playerct && t1->uid == uid) flg++; else #endif for(i = 0; i < playerct; i++){ if(strcmp(players[i], "all") == 0 || strncmp(t1->name, players[i], NAMSZ) == 0 || (players[i][0] == '-' && players[i][1] == t1->plchar && players[i][2] == 0) || (digit(players[i][0]) && rank <= atoi(players[i]))) flg++; } t1 = t1->tt_next = newttentry(); } (void) fclose(rfile); if(!flg) { if(outflg) { Printf("Cannot find any entries for "); if(playerct < 1) Printf("you.\n"); else { if(playerct > 1) Printf("any of "); for(i=0; i<playerct; i++) Printf("%s%s", players[i], (i<playerct-1)?", ":".\n"); Printf("Call is: %s -s [-role] [maxrank] [playernames]\n", hname); } } return; } if(outflg) outheader(); t1 = tt_head; for(rank = 1; t1->points != 0; rank++, t1 = t2) { t2 = t1->tt_next; #ifdef PERS_IS_UID if(!playerct && t1->uid == uid) goto outwithit; else #endif for(i = 0; i < playerct; i++){ if(strcmp(players[i], "all") == 0 || strncmp(t1->name, players[i], NAMSZ) == 0 || (players[i][0] == '-' && players[i][1] == t1->plchar && players[i][2] == 0) || (digit(players[i][0]) && rank <= atoi(players[i]))){ #ifdef PERS_IS_UID outwithit: #endif if(outflg) (void) outentry(rank, t1, 0); #ifdef nonsense total_score += t1->points; if(totcharct < sizeof(totchars)-1) totchars[totcharct++] = t1->plchar; #endif break; } } free((genericptr_t) t1); } #ifdef nonsense totchars[totcharct] = 0; /* We would like to determine whether he is experienced. However, the information collected here only tells about the scores/roles that got into the topten (top 100?). We should maintain a .hacklog or something in his home directory. */ flags.beginner = (total_score < 6000); for(i=0; i<6; i++) if(!index(totchars, pl_classes[i])) { flags.beginner = 1; if(!pl_character[0]) pl_character[0] = pl_classes[i]; break; } #endif /* nonsense /**/ } static int classmon(plch, fem) char plch; boolean fem; { switch (plch) { case 'A': return PM_ARCHEOLOGIST; case 'B': return PM_BARBARIAN; case 'C': return (fem ? PM_CAVEWOMAN : PM_CAVEMAN); case 'E': return PM_ELF; case 'H': return PM_HEALER; case 'F': /* accept old Fighter class */ case 'K': return PM_KNIGHT; case 'P': return (fem ? PM_PRIESTESS : PM_PRIEST); case 'R': return PM_ROGUE; case 'N': /* accept old Ninja class */ case 'S': return PM_SAMURAI; case 'T': return PM_TOURIST; case 'V': return PM_VALKYRIE; case 'W': return PM_WIZARD; default: impossible("What weird class is this? (%c)", plch); return PM_HUMAN_ZOMBIE; } } /* * Get a random player name and class from the high score list, * and attach them to an object (for statues or morgue corpses). */ struct obj * tt_oname(otmp) struct obj *otmp; { int rank; register int i; register struct toptenentry *tt; const char *recfile = RECORD; FILE *rfile; if (!otmp) return((struct obj *) 0); #ifdef MACOS if(!(rfile = fopen(recfile,"r"))) rfile = openFile(recfile, "r"); if (!rfile) { #else if(!(rfile = fopen(recfile,"r"))){ #endif panic("Cannot open record file!"); } tt = newttentry(); rank = rnd(10); pickentry: for(i = rank; i; i--) { #ifdef LATTICE if(fscanf(rfile, "%6s %d %d %d %d %d %ld%*c%c%c %s %s", #else if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", #endif tt->date, &tt->uid, &tt->level, &tt->maxlvl, &tt->hp, &tt->maxhp, &tt->points, &tt->plchar, &tt->sex, #ifdef LATTICE tt->name, tt->death) <1) #else tt->name, tt->death) != 11) #endif tt->points = 0; if(tt->points == 0) break; #ifdef LATTICE lattice_unmung_line(tt->death); #endif } if(tt->points == 0) { if(rank > 1) { rank = 1; goto pickentry; } free((genericptr_t) tt); otmp = (struct obj *) 0; } else { otmp->corpsenm = classmon(tt->plchar, (tt->sex == 'F')); otmp->owt = weight(otmp); /* Note: oname() is safe since otmp is first in chains */ otmp = oname(otmp, tt->name, 0); fobj = otmp; level.objects[otmp->ox][otmp->oy] = otmp; free((genericptr_t) tt); } (void) fclose(rfile); return otmp; } #ifdef LATTICE /* Lattice scanf isn't up to reading the scorefile. What */ /* follows deals with that; I admit it's ugly. (KL) */ static void lattice_mung_line(p) char *p; { while(p=strchr(p,' '))*p='|'; } static void lattice_unmung_line(p) char *p; { while(p=strchr(p,'|'))*p=' '; } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.