static void topten(void) { int uid = getuid(); int rank, rank0 = -1, rank1 = 0; int occ_cnt = PERSMAX; struct toptenentry *t0, *t1, *tprev; const char *recfile = RECORD; const char *reclock = "record_lock"; int sleepct = 300; FILE *rfile; int flg = 0; #define HUP if(!done_hup) while(link(recfile, reclock) == -1) { HUP perror(reclock); if(!sleepct--) { HUP puts("I give up. Sorry."); HUP puts("Perhaps there is an old record_lock around?"); return; } HUP printf("Waiting for access to record file. (%d)\n", sleepct); HUP fflush(stdout); sleep(1); } if(!(rfile = fopen(recfile,"r"))){ HUP puts("Cannot open record file!"); goto unlock; } HUP putchar('\n'); /* 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; strncpy(t0->name, plname, NAMSZ); (t0->name)[NAMSZ] = 0; strncpy(t0->death, killer, DTHSZ); (t0->death)[DTHSZ] = 0; strcpy(t0->date, getdate()); /* 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; ; ) { if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", t1->date, &t1->uid, &t1->level, &t1->maxlvl, &t1->hp, &t1->maxhp, &t1->points, &t1->plchar, &t1->sex, t1->name, t1->death) != 11 || t1->points < POINTSMIN) t1->points = 0; 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 /* PERS_IS_UID */ 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 */ fclose(rfile); if(!(rfile = fopen(recfile,"w"))){ HUP puts("Cannot write record file\n"); goto unlock; } if(!done_stopprint) if(rank0 > 0){ if(rank0 <= 10) 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) { if(flg) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n", t1->date, t1->uid, t1->level, t1->maxlvl, t1->hp, t1->maxhp, t1->points, t1->plchar, t1->sex, t1->name, t1->death); if(done_stopprint) continue; if(rank > (int)flags.end_top && (rank < rank0-(int)flags.end_around || rank > rank0+(int)flags.end_around) && (!flags.end_own || #ifdef PERS_IS_UID t1->uid != t0->uid )) #else strncmp(t1->name, t0->name, NAMSZ))) #endif /* PERS_IS_UID */ continue; if(rank == rank0-(int)flags.end_around && rank0 > (int)flags.end_top+(int)flags.end_around+1 && !flags.end_own) putchar('\n'); if(rank != rank0) outentry(rank, t1, 0); else if(!rank1) outentry(rank, t1, 1); else { int t0lth = outentry(0, t0, -1); int t1lth = outentry(rank, t1, t0lth); if(t1lth > t0lth) t0lth = t1lth; outentry(0, t0, t0lth); } } if(rank0 >= rank) if(!done_stopprint) outentry(0, t0, 1); fclose(rfile); unlock: unlink(reclock); }
struct nh_topten_entry * nh_get_topten(int *out_len, char *statusbuf, const char * volatile player, int top, int around, boolean own) { struct toptenentry *ttlist, newtt; struct nh_topten_entry *score_list; boolean game_inited = (wiz1_level.dlevel != 0); boolean game_complete = game_inited && moves && program_state.gameover; int rank = -1; /* index of the completed game in the topten list */ int fd, i, j, sel_count; boolean *selected, off_list = FALSE; statusbuf[0] = '\0'; *out_len = 0; if (!api_entry_checkpoint()) return NULL; if (!game_inited) { /* If nh_get_topten() isn't called after a game, we never went through initialization. */ dlb_init(); init_dungeons(); } if (!player) { if (game_complete) player = plname; else player = ""; } fd = open_datafile(RECORD, O_RDONLY, SCOREPREFIX); ttlist = read_topten(fd, TTLISTLEN); close(fd); if (!ttlist) { strcpy(statusbuf, "Cannot open record file!"); api_exit(); return NULL; } /* find the rank of a completed game in the score list */ if (game_complete && !strcmp(player, plname)) { fill_topten_entry(&newtt, end_how); /* find this entry in the list */ for (i = 0; i < TTLISTLEN && validentry(ttlist[i]); i++) if (!memcmp(&ttlist[i], &newtt, sizeof (struct toptenentry))) rank = i; if (wizard || discover) sprintf(statusbuf, "Since you were in %s mode, your game was not " "added to the score list.", wizard ? "wizard" : "discover"); else if (rank >= 0 && rank < 10) sprintf(statusbuf, "You made the top ten list!"); else if (rank) sprintf(statusbuf, "You reached the %d%s place on the score list.", rank + 1, ordin(rank + 1)); } /* select scores for display */ sel_count = 0; selected = calloc(TTLISTLEN, sizeof (boolean)); for (i = 0; i < TTLISTLEN && validentry(ttlist[i]); i++) { if (top == -1 || i < top) selected[i] = TRUE; if (own && !strcmp(player, ttlist[i].name)) selected[i] = TRUE; if (rank != -1 && rank - around <= i && i <= rank + around) selected[i] = TRUE; if (selected[i]) sel_count++; } if (game_complete && sel_count == 0) { /* didn't make it onto the list and nothing else is selected */ ttlist[0] = newtt; selected[0] = TRUE; sel_count++; off_list = TRUE; } score_list = xmalloc(sel_count * sizeof (struct nh_topten_entry)); memset(score_list, 0, sel_count * sizeof (struct nh_topten_entry)); *out_len = sel_count; j = 0; for (i = 0; i < TTLISTLEN && validentry(ttlist[i]); i++) { if (selected[i]) fill_nh_score_entry(&ttlist[i], &score_list[j++], i + 1, i == rank); } if (off_list) { score_list[0].rank = -1; score_list[0].highlight = TRUE; } if (!game_inited) { free_dungeon(); dlb_cleanup(); } free(selected); free(ttlist); api_exit(); return score_list; }