1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.end.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.end.c,v 1.4 1999/11/16 10:26:36 marcel Exp $ */
4 /* $DragonFly: src/games/hack/hack.end.c,v 1.3 2004/11/06 12:29:17 eirikn Exp $ */
9 #define Sprintf (void) sprintf
10 extern char plname[], pl_character[];
11 extern char *itoa(), *ordin(), *eos();
18 (void) signal(SIGINT,SIG_IGN);
19 pline("Really quit?");
20 if(readchar() != 'y') {
21 (void) signal(SIGINT,done1);
23 (void) fflush(stdout);
24 if(multi > 0) nomul(0);
37 (void) signal(SIGINT, SIG_IGN);
38 (void) signal(SIGQUIT, SIG_IGN);
44 (void) signal(SIGHUP, SIG_IGN);
48 done_in_by(mtmp) struct monst *mtmp; {
49 static char buf[BUFSZ];
51 if(mtmp->data->mlet == ' '){
52 Sprintf(buf, "the ghost of %s", (char *) mtmp->mextra);
54 } else if(mtmp->mnamelth) {
55 Sprintf(buf, "%s called %s",
56 mtmp->data->mname, NAME(mtmp));
58 } else if(mtmp->minvis) {
59 Sprintf(buf, "invisible %s", mtmp->data->mname);
61 } else killer = mtmp->data->mname;
65 /* called with arg "died", "drowned", "escaped", "quit", "choked", "panicked",
66 "burned", "starved" or "tricked" */
67 /* Be careful not to call panic from here! */
73 if(wizard && *st1 == 'd'){
75 if(u.uhpmax < 0) u.uhpmax = 100; /* arbitrary */
77 pline("For some reason you are still alive.");
79 if(multi > 0) multi = 0; else multi = -1;
84 (void) signal(SIGINT, done_intr);
85 (void) signal(SIGQUIT, done_intr);
86 (void) signal(SIGHUP, done_hangup);
87 if(*st1 == 'q' && u.uhp < 1){
89 killer = "quit while already on Charon's boat";
91 if(*st1 == 's') killer = "starvation"; else
92 if(*st1 == 'd' && st1[1] == 'r') killer = "drowning"; else
93 if(*st1 == 'p') killer = "panic"; else
94 if(*st1 == 't') killer = "trickery"; else
95 if(!index("bcd", *st1)) killer = st1;
98 if(flags.toplin == 1) more();
99 if(index("bcds", *st1)){
104 if(!flags.notombstone)
107 if(*st1 == 'c') killer = st1; /* after outrip() */
108 settty((char *) 0); /* does a clear_screen() */
110 printf("Goodbye %s %s...\n\n", pl_character, plname);
112 tmp = u.ugold - u.ugold0;
115 if(*st1 == 'd' || *st1 == 'b')
118 u.urexp += 50 * maxdlevel;
120 u.urexp += 1000*((maxdlevel > 30) ? 10 : maxdlevel - 20);
123 extern struct monst *mydogs;
127 unsigned worthlessct = 0;
128 boolean has_amulet = FALSE;
134 if(!done_stopprint) printf("You");
137 printf(" and %s", monnam(mtmp));
139 u.urexp += mtmp->mhp;
143 printf("\nescaped from the dungeon with %ld points,\n",
147 printf("You escaped from the dungeon with %ld points,\n",
149 for(otmp = invent; otmp; otmp = otmp->nobj) {
150 if(otmp->olet == GEM_SYM){
151 objects[otmp->otyp].oc_name_known = 1;
152 i = otmp->quan*objects[otmp->otyp].g_val;
154 worthlessct += otmp->quan;
159 printf("\t%s (worth %d Zorkmids),\n",
161 } else if(otmp->olet == AMULET_SYM) {
163 i = (otmp->spe < 0) ? 2 : 5000;
166 printf("\t%s (worth %d Zorkmids),\n",
170 killer = "escaped (with amulet)";
174 if(worthlessct) if(!done_stopprint)
175 printf("\t%u worthless piece%s of coloured glass,\n",
176 worthlessct, plur(worthlessct));
177 if(has_amulet) u.urexp *= 2;
180 printf("You %s on dungeon level %d with %ld points,\n",
181 st1, dlevel, u.urexp);
183 printf("and %ld piece%s of gold, after %ld move%s.\n",
184 u.ugold, plur(u.ugold), moves, plur(moves));
186 printf("You were level %u with a maximum of %d hit points when you %s.\n",
187 u.ulevel, u.uhpmax, st1);
188 if(*st1 == 'e' && !done_stopprint){
189 getret(); /* all those pieces of coloured glass ... */
196 if(done_stopprint) printf("\n\n");
200 #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry))
204 #define POINTSMIN 1 /* must be > 0 */
205 #define ENTRYMAX 100 /* must be >= 10 */
206 #define PERS_IS_UID /* delete for PERSMAX per name; now per uid */
208 struct toptenentry *tt_next;
210 int level,maxlvl,hp,maxhp;
216 char date[7]; /* yymmdd */
221 int rank, rank0 = -1, rank1 = 0;
222 int occ_cnt = PERSMAX;
223 struct toptenentry *t0, *t1, *tprev;
224 char *recfile = RECORD;
225 char *reclock = "record_lock";
229 extern char *getdate();
230 #define HUP if(!done_hup)
231 while(link(recfile, reclock) == -1) {
234 HUP puts("I give up. Sorry.");
235 HUP puts("Perhaps there is an old record_lock around?");
238 HUP printf("Waiting for access to record file. (%d)\n",
240 HUP (void) fflush(stdout);
243 if(!(rfile = fopen(recfile,"r"))){
244 HUP puts("Cannot open record file!");
247 HUP (void) putchar('\n');
249 /* create a new 'topten' entry */
252 t0->maxlvl = maxdlevel;
254 t0->maxhp = u.uhpmax;
255 t0->points = u.urexp;
256 t0->plchar = pl_character[0];
257 t0->sex = (flags.female ? 'F' : 'M');
259 (void) strncpy(t0->name, plname, NAMSZ);
260 (t0->name)[NAMSZ] = 0;
261 (void) strncpy(t0->death, killer, DTHSZ);
262 (t0->death)[DTHSZ] = 0;
263 (void) strcpy(t0->date, getdate());
265 /* assure minimum number of points */
266 if(t0->points < POINTSMIN)
269 t1 = tt_head = newttentry();
271 /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
273 if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
275 &t1->level, &t1->maxlvl,
276 &t1->hp, &t1->maxhp, &t1->points,
277 &t1->plchar, &t1->sex, t1->name, t1->death) != 11
278 || t1->points < POINTSMIN)
280 if(rank0 < 0 && t1->points < t0->points) {
288 flg++; /* ask for a rewrite */
291 if(t1->points == 0) break;
294 t1->uid == t0->uid &&
296 strncmp(t1->name, t0->name, NAMSZ) == 0 &&
297 #endif /* PERS_IS_UID */
298 t1->plchar == t0->plchar && --occ_cnt <= 0){
302 HUP printf("You didn't beat your previous score of %ld points.\n\n",
310 if(rank <= ENTRYMAX){
311 t1 = t1->tt_next = newttentry();
319 if(flg) { /* rewrite record file */
320 (void) fclose(rfile);
321 if(!(rfile = fopen(recfile,"w"))){
322 HUP puts("Cannot write record file\n");
326 if(!done_stopprint) if(rank0 > 0){
328 puts("You made the top ten list!\n");
330 printf("You reached the %d%s place on the top %d list.\n\n",
331 rank0, ordin(rank0), ENTRYMAX);
334 if(rank0 == 0) rank0 = rank1;
335 if(rank0 <= 0) rank0 = rank;
336 if(!done_stopprint) outheader();
338 for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
339 if(flg) fprintf(rfile,"%6s %d %d %d %d %d %ld %c%c %s,%s\n",
341 t1->level, t1->maxlvl,
342 t1->hp, t1->maxhp, t1->points,
343 t1->plchar, t1->sex, t1->name, t1->death);
344 if(done_stopprint) continue;
345 if(rank > flags.end_top &&
346 (rank < rank0-flags.end_around || rank > rank0+flags.end_around)
347 && (!flags.end_own ||
349 t1->uid != t0->uid ))
351 strncmp(t1->name, t0->name, NAMSZ)))
352 #endif /* PERS_IS_UID */
354 if(rank == rank0-flags.end_around &&
355 rank0 > flags.end_top+flags.end_around+1 &&
357 (void) putchar('\n');
359 (void) outentry(rank, t1, 0);
361 (void) outentry(rank, t1, 1);
363 int t0lth = outentry(0, t0, -1);
364 int t1lth = outentry(rank, t1, t0lth);
365 if(t1lth > t0lth) t0lth = t1lth;
366 (void) outentry(0, t0, t0lth);
369 if(rank0 >= rank) if(!done_stopprint)
370 (void) outentry(0, t0, 1);
371 (void) fclose(rfile);
373 (void) unlink(reclock);
379 (void) strcpy(linebuf, "Number Points Name");
381 while(bp < linebuf + COLNO - 9) *bp++ = ' ';
382 (void) strcpy(bp, "Hp [max]");
386 /* so>0: standout line; so=0: ordinary line; so<0: no output, return lth */
388 outentry(rank,t1,so) struct toptenentry *t1; {
389 boolean quit = FALSE, killed = FALSE, starv = FALSE;
392 if(rank) Sprintf(eos(linebuf), "%3d", rank);
393 else Sprintf(eos(linebuf), " ");
394 Sprintf(eos(linebuf), " %6ld %8s", t1->points, t1->name);
395 if(t1->plchar == 'X') Sprintf(eos(linebuf), " ");
396 else Sprintf(eos(linebuf), "-%c ", t1->plchar);
397 if(!strncmp("escaped", t1->death, 7)) {
398 if(!strcmp(" (with amulet)", t1->death+7))
399 Sprintf(eos(linebuf), "escaped the dungeon with amulet");
401 Sprintf(eos(linebuf), "escaped the dungeon [max level %d]",
404 if(!strncmp(t1->death,"quit",4)) {
406 if(t1->maxhp < 3*t1->hp && t1->maxlvl < 4)
407 Sprintf(eos(linebuf), "cravenly gave up");
409 Sprintf(eos(linebuf), "quit");
411 else if(!strcmp(t1->death,"choked"))
412 Sprintf(eos(linebuf), "choked on %s food",
413 (t1->sex == 'F') ? "her" : "his");
414 else if(!strncmp(t1->death,"starv",5))
415 Sprintf(eos(linebuf), "starved to death"), starv = TRUE;
416 else Sprintf(eos(linebuf), "was killed"), killed = TRUE;
417 Sprintf(eos(linebuf), " on%s level %d",
418 (killed || starv) ? "" : " dungeon", t1->level);
419 if(t1->maxlvl != t1->level)
420 Sprintf(eos(linebuf), " [max %d]", t1->maxlvl);
421 if(quit && t1->death[4]) Sprintf(eos(linebuf), t1->death + 4);
423 if(killed) Sprintf(eos(linebuf), " by %s%s",
424 (!strncmp(t1->death, "trick", 5) || !strncmp(t1->death, "the ", 4))
426 index(vowels,*t1->death) ? "an " : "a ",
428 Sprintf(eos(linebuf), ".");
430 char *bp = eos(linebuf);
433 Sprintf(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-");
434 hppos = COLNO - 7 - strlen(hpbuf);
435 if(bp <= linebuf + hppos) {
436 while(bp < linebuf + hppos) *bp++ = ' ';
437 (void) strcpy(bp, hpbuf);
438 Sprintf(eos(bp), " [%d]", t1->maxhp);
441 if(so == 0) puts(linebuf);
443 char *bp = eos(linebuf);
444 if(so >= COLNO) so = COLNO-1;
445 while(bp < linebuf + so) *bp++ = ' ';
448 fputs(linebuf,stdout);
450 (void) putchar('\n');
452 return(strlen(linebuf));
465 return((d==0 || d>3 || n/10==1) ? "th" : (d==1) ? "st" :
466 (d==2) ? "nd" : "rd");
471 (void) signal(SIGHUP,SIG_IGN);
472 for(x = maxdlevel; x >= 0; x--) {
474 (void) unlink(lock); /* not all levels need be present */
478 #ifdef NOSAVEONHANGUP
481 (void) signal(SIGINT, SIG_IGN);
485 #endif /* NOSAVEONHANGUP */
495 /* it is the callers responsibility to check that there is room for c */
496 charcat(s,c) char *s, c; {
503 * Called with args from main if argc >= 0. In this case, list scores as
504 * requested. Otherwise, find scores for the current player (and list them
507 prscore(argc,argv) int argc; char **argv; {
512 struct toptenentry *t1, *t2;
513 char *recfile = RECORD;
518 long total_score = 0L;
521 #endif /* nonsense */
522 int outflg = (argc >= -1);
527 #endif /* PERS_IS_UID */
529 if(!(rfile = fopen(recfile,"r"))){
530 puts("Cannot open record file!");
534 if(argc > 1 && !strncmp(argv[1], "-s", 2)){
538 } else if(!argv[1][3] && index("CFKSTWX", argv[1][2])) {
550 player0 = "hackplayer";
553 #endif /* PERS_IS_UID */
558 if(outflg) putchar('\n');
560 t1 = tt_head = newttentry();
561 for(rank = 1; ; rank++) {
562 if(fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]",
564 &t1->level, &t1->maxlvl,
565 &t1->hp, &t1->maxhp, &t1->points,
566 &t1->plchar, &t1->sex, t1->name, t1->death) != 11)
568 if(t1->points == 0) break;
570 if(!playerct && t1->uid == uid)
573 #endif /* PERS_IS_UID */
574 for(i = 0; i < playerct; i++){
575 if(strcmp(players[i], "all") == 0 ||
576 strncmp(t1->name, players[i], NAMSZ) == 0 ||
577 (players[i][0] == '-' &&
578 players[i][1] == t1->plchar &&
579 players[i][2] == 0) ||
580 (digit(players[i][0]) && rank <= atoi(players[i])))
583 t1 = t1->tt_next = newttentry();
585 (void) fclose(rfile);
588 printf("Cannot find any entries for ");
589 if(playerct < 1) printf("you.\n");
591 if(playerct > 1) printf("any of ");
592 for(i=0; i<playerct; i++)
593 printf("%s%s", players[i], (i<playerct-1)?", ":".\n");
594 printf("Call is: %s -s [playernames]\n", hname);
600 if(outflg) outheader();
602 for(rank = 1; t1->points != 0; rank++, t1 = t2) {
605 if(!playerct && t1->uid == uid)
608 #endif /* PERS_IS_UID */
609 for(i = 0; i < playerct; i++){
610 if(strcmp(players[i], "all") == 0 ||
611 strncmp(t1->name, players[i], NAMSZ) == 0 ||
612 (players[i][0] == '-' &&
613 players[i][1] == t1->plchar &&
614 players[i][2] == 0) ||
615 (digit(players[i][0]) && rank <= atoi(players[i]))){
618 (void) outentry(rank, t1, 0);
620 total_score += t1->points;
621 if(totcharct < sizeof(totchars)-1)
622 totchars[totcharct++] = t1->plchar;
623 #endif /* nonsense */
630 totchars[totcharct] = 0;
632 /* We would like to determine whether he is experienced. However,
633 the information collected here only tells about the scores/roles
634 that got into the topten (top 100?). We should maintain a
635 .hacklog or something in his home directory. */
636 flags.beginner = (total_score < 6000);
638 if(!index(totchars, "CFKSTWX"[i])) {
640 if(!pl_character[0]) pl_character[0] = "CFKSTWX"[i];
643 #endif /* nonsense */