1 1.19 fox /* $NetBSD: hack.end.c,v 1.19 2020/02/07 22:04:02 fox Exp $ */ 2 1.4 christos 3 1.2 mycroft /* 4 1.6 jsm * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 1.6 jsm * Amsterdam 6 1.6 jsm * All rights reserved. 7 1.6 jsm * 8 1.6 jsm * Redistribution and use in source and binary forms, with or without 9 1.6 jsm * modification, are permitted provided that the following conditions are 10 1.6 jsm * met: 11 1.6 jsm * 12 1.6 jsm * - Redistributions of source code must retain the above copyright notice, 13 1.6 jsm * this list of conditions and the following disclaimer. 14 1.6 jsm * 15 1.6 jsm * - Redistributions in binary form must reproduce the above copyright 16 1.6 jsm * notice, this list of conditions and the following disclaimer in the 17 1.6 jsm * documentation and/or other materials provided with the distribution. 18 1.6 jsm * 19 1.6 jsm * - Neither the name of the Stichting Centrum voor Wiskunde en 20 1.6 jsm * Informatica, nor the names of its contributors may be used to endorse or 21 1.6 jsm * promote products derived from this software without specific prior 22 1.6 jsm * written permission. 23 1.6 jsm * 24 1.6 jsm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 1.6 jsm * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 1.6 jsm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 1.6 jsm * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 1.6 jsm * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 1.6 jsm * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 1.6 jsm * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 1.6 jsm * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 1.6 jsm * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 1.6 jsm */ 36 1.6 jsm 37 1.6 jsm /* 38 1.6 jsm * Copyright (c) 1982 Jay Fenlason <hack (at) gnu.org> 39 1.6 jsm * All rights reserved. 40 1.6 jsm * 41 1.6 jsm * Redistribution and use in source and binary forms, with or without 42 1.6 jsm * modification, are permitted provided that the following conditions 43 1.6 jsm * are met: 44 1.6 jsm * 1. Redistributions of source code must retain the above copyright 45 1.6 jsm * notice, this list of conditions and the following disclaimer. 46 1.6 jsm * 2. Redistributions in binary form must reproduce the above copyright 47 1.6 jsm * notice, this list of conditions and the following disclaimer in the 48 1.6 jsm * documentation and/or other materials provided with the distribution. 49 1.6 jsm * 3. The name of the author may not be used to endorse or promote products 50 1.6 jsm * derived from this software without specific prior written permission. 51 1.6 jsm * 52 1.6 jsm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 1.6 jsm * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 1.6 jsm * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 1.6 jsm * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 1.6 jsm * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 1.6 jsm * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 1.6 jsm * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 1.6 jsm * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 1.6 jsm * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 1.6 jsm * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 1.2 mycroft */ 63 1.2 mycroft 64 1.4 christos #include <sys/cdefs.h> 65 1.2 mycroft #ifndef lint 66 1.19 fox __RCSID("$NetBSD: hack.end.c,v 1.19 2020/02/07 22:04:02 fox Exp $"); 67 1.4 christos #endif /* not lint */ 68 1.1 cgd 69 1.4 christos #include <signal.h> 70 1.4 christos #include <unistd.h> 71 1.4 christos #include <stdlib.h> 72 1.1 cgd #include "hack.h" 73 1.4 christos #include "extern.h" 74 1.12 dholland #define Snprintf (void) snprintf 75 1.1 cgd 76 1.4 christos xchar maxdlevel = 1; 77 1.4 christos 78 1.13 dholland struct toptenentry; 79 1.13 dholland 80 1.13 dholland static void topten(void); 81 1.13 dholland static void outheader(void); 82 1.13 dholland static int outentry(int, struct toptenentry *, int); 83 1.13 dholland static char *itoa(int); 84 1.13 dholland static const char *ordin(int); 85 1.13 dholland 86 1.4 christos int 87 1.11 dholland dodone(void) 88 1.4 christos { 89 1.4 christos done1(0); 90 1.4 christos return 0; 91 1.4 christos } 92 1.4 christos 93 1.1 cgd 94 1.4 christos /*ARGSUSED*/ 95 1.1 cgd void 96 1.11 dholland done1(int n __unused) 97 1.1 cgd { 98 1.4 christos (void) signal(SIGINT, SIG_IGN); 99 1.1 cgd pline("Really quit?"); 100 1.4 christos if (readchar() != 'y') { 101 1.4 christos (void) signal(SIGINT, done1); 102 1.1 cgd clrlin(); 103 1.1 cgd (void) fflush(stdout); 104 1.4 christos if (multi > 0) 105 1.4 christos nomul(0); 106 1.1 cgd return; 107 1.1 cgd } 108 1.1 cgd done("quit"); 109 1.1 cgd /* NOTREACHED */ 110 1.1 cgd } 111 1.1 cgd 112 1.13 dholland static int done_stopprint; 113 1.13 dholland static int done_hup; 114 1.1 cgd 115 1.4 christos /*ARGSUSED*/ 116 1.13 dholland static void 117 1.11 dholland done_intr(int n __unused) 118 1.4 christos { 119 1.1 cgd done_stopprint++; 120 1.1 cgd (void) signal(SIGINT, SIG_IGN); 121 1.1 cgd (void) signal(SIGQUIT, SIG_IGN); 122 1.1 cgd } 123 1.1 cgd 124 1.13 dholland static void 125 1.11 dholland done_hangup(int n) 126 1.4 christos { 127 1.1 cgd done_hup++; 128 1.1 cgd (void) signal(SIGHUP, SIG_IGN); 129 1.4 christos done_intr(n); 130 1.1 cgd } 131 1.1 cgd 132 1.4 christos void 133 1.11 dholland done_in_by(struct monst *mtmp) 134 1.4 christos { 135 1.4 christos static char buf[BUFSZ]; 136 1.1 cgd pline("You die ..."); 137 1.4 christos if (mtmp->data->mlet == ' ') { 138 1.12 dholland Snprintf(buf, sizeof(buf), 139 1.12 dholland "the ghost of %s", (char *) mtmp->mextra); 140 1.1 cgd killer = buf; 141 1.4 christos } else if (mtmp->mnamelth) { 142 1.12 dholland Snprintf(buf, sizeof(buf), "%s called %s", 143 1.1 cgd mtmp->data->mname, NAME(mtmp)); 144 1.1 cgd killer = buf; 145 1.4 christos } else if (mtmp->minvis) { 146 1.12 dholland Snprintf(buf, sizeof(buf), "invisible %s", mtmp->data->mname); 147 1.1 cgd killer = buf; 148 1.4 christos } else 149 1.4 christos killer = mtmp->data->mname; 150 1.1 cgd done("died"); 151 1.1 cgd } 152 1.1 cgd 153 1.4 christos /* 154 1.4 christos * called with arg "died", "drowned", "escaped", "quit", "choked", 155 1.4 christos * "panicked", "burned", "starved" or "tricked" 156 1.4 christos */ 157 1.1 cgd /* Be careful not to call panic from here! */ 158 1.4 christos void 159 1.11 dholland done(const char *st1) 160 1.1 cgd { 161 1.1 cgd 162 1.1 cgd #ifdef WIZARD 163 1.4 christos if (wizard && *st1 == 'd') { 164 1.1 cgd u.uswldtim = 0; 165 1.4 christos if (u.uhpmax < 0) 166 1.4 christos u.uhpmax = 100; /* arbitrary */ 167 1.1 cgd u.uhp = u.uhpmax; 168 1.1 cgd pline("For some reason you are still alive."); 169 1.1 cgd flags.move = 0; 170 1.4 christos if (multi > 0) 171 1.4 christos multi = 0; 172 1.4 christos else 173 1.4 christos multi = -1; 174 1.1 cgd flags.botl = 1; 175 1.1 cgd return; 176 1.1 cgd } 177 1.4 christos #endif /* WIZARD */ 178 1.1 cgd (void) signal(SIGINT, done_intr); 179 1.1 cgd (void) signal(SIGQUIT, done_intr); 180 1.1 cgd (void) signal(SIGHUP, done_hangup); 181 1.4 christos if (*st1 == 'q' && u.uhp < 1) { 182 1.1 cgd st1 = "died"; 183 1.1 cgd killer = "quit while already on Charon's boat"; 184 1.1 cgd } 185 1.4 christos if (*st1 == 's') 186 1.4 christos killer = "starvation"; 187 1.4 christos else if (*st1 == 'd' && st1[1] == 'r') 188 1.4 christos killer = "drowning"; 189 1.4 christos else if (*st1 == 'p') 190 1.4 christos killer = "panic"; 191 1.4 christos else if (*st1 == 't') 192 1.4 christos killer = "trickery"; 193 1.4 christos else if (!strchr("bcd", *st1)) 194 1.4 christos killer = st1; 195 1.1 cgd paybill(); 196 1.1 cgd clearlocks(); 197 1.4 christos if (flags.toplin == 1) 198 1.4 christos more(); 199 1.4 christos if (strchr("bcds", *st1)) { 200 1.1 cgd #ifdef WIZARD 201 1.4 christos if (!wizard) 202 1.4 christos #endif /* WIZARD */ 203 1.4 christos savebones(); 204 1.4 christos if (!flags.notombstone) 205 1.1 cgd outrip(); 206 1.1 cgd } 207 1.4 christos if (*st1 == 'c') 208 1.4 christos killer = st1; /* after outrip() */ 209 1.17 dholland settty(NULL); /* does a clear_screen() */ 210 1.4 christos if (!done_stopprint) 211 1.1 cgd printf("Goodbye %s %s...\n\n", pl_character, plname); 212 1.4 christos { 213 1.4 christos long int tmp; 214 1.4 christos tmp = u.ugold - u.ugold0; 215 1.4 christos if (tmp < 0) 216 1.4 christos tmp = 0; 217 1.4 christos if (*st1 == 'd' || *st1 == 'b') 218 1.4 christos tmp -= tmp / 10; 219 1.4 christos u.urexp += tmp; 220 1.4 christos u.urexp += 50 * maxdlevel; 221 1.4 christos if (maxdlevel > 20) 222 1.4 christos u.urexp += 1000 * ((maxdlevel > 30) ? 10 : maxdlevel - 20); 223 1.4 christos } 224 1.4 christos if (*st1 == 'e') { 225 1.4 christos struct monst *mtmp; 226 1.4 christos struct obj *otmp; 227 1.4 christos int i; 228 1.4 christos unsigned worthlessct = 0; 229 1.4 christos boolean has_amulet = FALSE; 230 1.1 cgd 231 1.1 cgd killer = st1; 232 1.1 cgd keepdogs(); 233 1.1 cgd mtmp = mydogs; 234 1.4 christos if (mtmp) { 235 1.4 christos if (!done_stopprint) 236 1.4 christos printf("You"); 237 1.4 christos while (mtmp) { 238 1.4 christos if (!done_stopprint) 239 1.1 cgd printf(" and %s", monnam(mtmp)); 240 1.4 christos if (mtmp->mtame) 241 1.1 cgd u.urexp += mtmp->mhp; 242 1.1 cgd mtmp = mtmp->nmon; 243 1.1 cgd } 244 1.4 christos if (!done_stopprint) 245 1.4 christos printf("\nescaped from the dungeon with %ld points,\n", 246 1.4 christos u.urexp); 247 1.4 christos } else if (!done_stopprint) 248 1.4 christos printf("You escaped from the dungeon with %ld points,\n", 249 1.4 christos u.urexp); 250 1.4 christos for (otmp = invent; otmp; otmp = otmp->nobj) { 251 1.4 christos if (otmp->olet == GEM_SYM) { 252 1.1 cgd objects[otmp->otyp].oc_name_known = 1; 253 1.4 christos i = otmp->quan * objects[otmp->otyp].g_val; 254 1.4 christos if (i == 0) { 255 1.1 cgd worthlessct += otmp->quan; 256 1.1 cgd continue; 257 1.1 cgd } 258 1.1 cgd u.urexp += i; 259 1.4 christos if (!done_stopprint) 260 1.4 christos printf("\t%s (worth %d Zorkmids),\n", 261 1.4 christos doname(otmp), i); 262 1.4 christos } else if (otmp->olet == AMULET_SYM) { 263 1.1 cgd otmp->known = 1; 264 1.1 cgd i = (otmp->spe < 0) ? 2 : 5000; 265 1.1 cgd u.urexp += i; 266 1.4 christos if (!done_stopprint) 267 1.4 christos printf("\t%s (worth %d Zorkmids),\n", 268 1.4 christos doname(otmp), i); 269 1.4 christos if (otmp->spe >= 0) { 270 1.1 cgd has_amulet = TRUE; 271 1.1 cgd killer = "escaped (with amulet)"; 272 1.1 cgd } 273 1.1 cgd } 274 1.1 cgd } 275 1.4 christos if (worthlessct) 276 1.4 christos if (!done_stopprint) 277 1.4 christos printf("\t%u worthless piece%s of coloured glass,\n", 278 1.4 christos worthlessct, plur(worthlessct)); 279 1.4 christos if (has_amulet) 280 1.4 christos u.urexp *= 2; 281 1.4 christos } else if (!done_stopprint) 282 1.4 christos printf("You %s on dungeon level %d with %ld points,\n", 283 1.4 christos st1, dlevel, u.urexp); 284 1.4 christos if (!done_stopprint) 285 1.4 christos printf("and %ld piece%s of gold, after %ld move%s.\n", 286 1.4 christos u.ugold, plur(u.ugold), moves, plur(moves)); 287 1.4 christos if (!done_stopprint) 288 1.4 christos printf("You were level %u with a maximum of %d hit points when you %s.\n", 289 1.4 christos u.ulevel, u.uhpmax, st1); 290 1.4 christos if (*st1 == 'e' && !done_stopprint) { 291 1.1 cgd getret(); /* all those pieces of coloured glass ... */ 292 1.1 cgd cls(); 293 1.1 cgd } 294 1.1 cgd #ifdef WIZARD 295 1.4 christos if (!wizard) 296 1.4 christos #endif /* WIZARD */ 297 1.1 cgd topten(); 298 1.4 christos if (done_stopprint) 299 1.4 christos printf("\n\n"); 300 1.1 cgd exit(0); 301 1.1 cgd } 302 1.1 cgd 303 1.15 dholland #define newttentry() ((struct toptenentry *) alloc(sizeof(struct toptenentry))) 304 1.1 cgd #define NAMSZ 8 305 1.1 cgd #define DTHSZ 40 306 1.1 cgd #define PERSMAX 1 307 1.1 cgd #define POINTSMIN 1 /* must be > 0 */ 308 1.1 cgd #define ENTRYMAX 100 /* must be >= 10 */ 309 1.1 cgd #define PERS_IS_UID /* delete for PERSMAX per name; now per uid */ 310 1.1 cgd struct toptenentry { 311 1.1 cgd struct toptenentry *tt_next; 312 1.4 christos long int points; 313 1.4 christos int level, maxlvl, hp, maxhp; 314 1.4 christos int uid; 315 1.4 christos char plchar; 316 1.4 christos char sex; 317 1.4 christos char name[NAMSZ + 1]; 318 1.4 christos char death[DTHSZ + 1]; 319 1.4 christos char date[7];/* yymmdd */ 320 1.13 dholland }; 321 1.13 dholland 322 1.13 dholland static struct toptenentry *tt_head; 323 1.4 christos 324 1.13 dholland static void 325 1.11 dholland topten(void) 326 1.4 christos { 327 1.4 christos int uid = getuid(); 328 1.4 christos int rank, rank0 = -1, rank1 = 0; 329 1.4 christos int occ_cnt = PERSMAX; 330 1.4 christos struct toptenentry *t0, *t1, *tprev; 331 1.5 jsm const char *recfile = RECORD; 332 1.5 jsm const char *reclock = "record_lock"; 333 1.4 christos int sleepct = 300; 334 1.4 christos FILE *rfile; 335 1.4 christos int flg = 0; 336 1.1 cgd #define HUP if(!done_hup) 337 1.4 christos while (link(recfile, reclock) == -1) { 338 1.4 christos HUP perror(reclock); 339 1.4 christos if (!sleepct--) { 340 1.4 christos HUP puts("I give up. Sorry."); 341 1.4 christos HUP puts("Perhaps there is an old record_lock around?"); 342 1.1 cgd return; 343 1.1 cgd } 344 1.4 christos HUP printf("Waiting for access to record file. (%d)\n", 345 1.4 christos sleepct); 346 1.4 christos HUP(void) fflush(stdout); 347 1.1 cgd sleep(1); 348 1.1 cgd } 349 1.4 christos if (!(rfile = fopen(recfile, "r"))) { 350 1.4 christos HUP puts("Cannot open record file!"); 351 1.1 cgd goto unlock; 352 1.1 cgd } 353 1.4 christos HUP(void) putchar('\n'); 354 1.1 cgd 355 1.1 cgd /* create a new 'topten' entry */ 356 1.1 cgd t0 = newttentry(); 357 1.1 cgd t0->level = dlevel; 358 1.1 cgd t0->maxlvl = maxdlevel; 359 1.1 cgd t0->hp = u.uhp; 360 1.1 cgd t0->maxhp = u.uhpmax; 361 1.1 cgd t0->points = u.urexp; 362 1.1 cgd t0->plchar = pl_character[0]; 363 1.1 cgd t0->sex = (flags.female ? 'F' : 'M'); 364 1.1 cgd t0->uid = uid; 365 1.19 fox (void) strncpy(t0->name, plname, NAMSZ); 366 1.1 cgd (t0->name)[NAMSZ] = 0; 367 1.1 cgd (void) strncpy(t0->death, killer, DTHSZ); 368 1.1 cgd (t0->death)[DTHSZ] = 0; 369 1.10 ginsbach (void) strcpy(t0->date, getdatestr()); 370 1.1 cgd 371 1.1 cgd /* assure minimum number of points */ 372 1.4 christos if (t0->points < POINTSMIN) 373 1.1 cgd t0->points = 0; 374 1.1 cgd 375 1.1 cgd t1 = tt_head = newttentry(); 376 1.1 cgd tprev = 0; 377 1.1 cgd /* rank0: -1 undefined, 0 not_on_list, n n_th on list */ 378 1.4 christos for (rank = 1;;) { 379 1.4 christos if (fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", 380 1.4 christos t1->date, &t1->uid, 381 1.4 christos &t1->level, &t1->maxlvl, 382 1.4 christos &t1->hp, &t1->maxhp, &t1->points, 383 1.4 christos &t1->plchar, &t1->sex, t1->name, t1->death) != 11 384 1.4 christos || t1->points < POINTSMIN) 385 1.1 cgd t1->points = 0; 386 1.4 christos if (rank0 < 0 && t1->points < t0->points) { 387 1.4 christos rank0 = rank++; 388 1.4 christos if (tprev == 0) 389 1.4 christos tt_head = t0; 390 1.4 christos else 391 1.4 christos tprev->tt_next = t0; 392 1.4 christos t0->tt_next = t1; 393 1.4 christos occ_cnt--; 394 1.4 christos flg++; /* ask for a rewrite */ 395 1.4 christos } else 396 1.4 christos tprev = t1; 397 1.4 christos if (t1->points == 0) 398 1.4 christos break; 399 1.4 christos if ( 400 1.1 cgd #ifdef PERS_IS_UID 401 1.4 christos t1->uid == t0->uid && 402 1.1 cgd #else 403 1.4 christos strncmp(t1->name, t0->name, NAMSZ) == 0 && 404 1.4 christos #endif /* PERS_IS_UID */ 405 1.4 christos t1->plchar == t0->plchar && --occ_cnt <= 0) { 406 1.4 christos if (rank0 < 0) { 407 1.4 christos rank0 = 0; 408 1.4 christos rank1 = rank; 409 1.4 christos HUP printf("You didn't beat your previous score of %ld points.\n\n", 410 1.4 christos t1->points); 411 1.4 christos } 412 1.4 christos if (occ_cnt < 0) { 413 1.4 christos flg++; 414 1.4 christos continue; 415 1.4 christos } 416 1.1 cgd } 417 1.4 christos if (rank <= ENTRYMAX) { 418 1.4 christos t1 = t1->tt_next = newttentry(); 419 1.4 christos rank++; 420 1.4 christos } 421 1.4 christos if (rank > ENTRYMAX) { 422 1.4 christos t1->points = 0; 423 1.4 christos break; 424 1.1 cgd } 425 1.1 cgd } 426 1.4 christos if (flg) { /* rewrite record file */ 427 1.1 cgd (void) fclose(rfile); 428 1.4 christos if (!(rfile = fopen(recfile, "w"))) { 429 1.4 christos HUP puts("Cannot write record file\n"); 430 1.1 cgd goto unlock; 431 1.1 cgd } 432 1.4 christos if (!done_stopprint) 433 1.4 christos if (rank0 > 0) { 434 1.4 christos if (rank0 <= 10) 435 1.4 christos puts("You made the top ten list!\n"); 436 1.4 christos else 437 1.4 christos printf("You reached the %d%s place on the top %d list.\n\n", 438 1.4 christos rank0, ordin(rank0), ENTRYMAX); 439 1.4 christos } 440 1.1 cgd } 441 1.4 christos if (rank0 == 0) 442 1.4 christos rank0 = rank1; 443 1.4 christos if (rank0 <= 0) 444 1.4 christos rank0 = rank; 445 1.4 christos if (!done_stopprint) 446 1.4 christos outheader(); 447 1.1 cgd t1 = tt_head; 448 1.4 christos for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { 449 1.4 christos if (flg) 450 1.4 christos fprintf(rfile, "%6s %d %d %d %d %d %ld %c%c %s,%s\n", 451 1.4 christos t1->date, t1->uid, 452 1.4 christos t1->level, t1->maxlvl, 453 1.4 christos t1->hp, t1->maxhp, t1->points, 454 1.4 christos t1->plchar, t1->sex, t1->name, t1->death); 455 1.4 christos if (done_stopprint) 456 1.4 christos continue; 457 1.9 dholland if (rank > (int)flags.end_top && 458 1.9 dholland (rank < rank0 - (int)flags.end_around || rank > rank0 + (int)flags.end_around) 459 1.4 christos && (!flags.end_own || 460 1.1 cgd #ifdef PERS_IS_UID 461 1.4 christos t1->uid != t0->uid)) 462 1.1 cgd #else 463 1.4 christos strncmp(t1->name, t0->name, NAMSZ))) 464 1.4 christos #endif /* PERS_IS_UID */ 465 1.4 christos continue; 466 1.9 dholland if (rank == rank0 - (int)flags.end_around && 467 1.9 dholland rank0 > (int)flags.end_top + (int)flags.end_around + 1 && 468 1.4 christos !flags.end_own) 469 1.4 christos (void) putchar('\n'); 470 1.4 christos if (rank != rank0) 471 1.4 christos (void) outentry(rank, t1, 0); 472 1.4 christos else if (!rank1) 473 1.4 christos (void) outentry(rank, t1, 1); 474 1.4 christos else { 475 1.4 christos int t0lth = outentry(0, t0, -1); 476 1.4 christos int t1lth = outentry(rank, t1, t0lth); 477 1.4 christos if (t1lth > t0lth) 478 1.4 christos t0lth = t1lth; 479 1.4 christos (void) outentry(0, t0, t0lth); 480 1.4 christos } 481 1.1 cgd } 482 1.4 christos if (rank0 >= rank) 483 1.4 christos if (!done_stopprint) 484 1.4 christos (void) outentry(0, t0, 1); 485 1.1 cgd (void) fclose(rfile); 486 1.7 christos free(t0); 487 1.1 cgd unlock: 488 1.1 cgd (void) unlink(reclock); 489 1.1 cgd } 490 1.1 cgd 491 1.13 dholland static void 492 1.11 dholland outheader(void) 493 1.4 christos { 494 1.4 christos char linebuf[BUFSZ]; 495 1.4 christos char *bp; 496 1.1 cgd (void) strcpy(linebuf, "Number Points Name"); 497 1.1 cgd bp = eos(linebuf); 498 1.4 christos while (bp < linebuf + COLNO - 9) 499 1.4 christos *bp++ = ' '; 500 1.1 cgd (void) strcpy(bp, "Hp [max]"); 501 1.1 cgd puts(linebuf); 502 1.1 cgd } 503 1.1 cgd 504 1.12 dholland /* so>0: standout line; so=0: ordinary line; so<0: no output, return length */ 505 1.13 dholland static int 506 1.5 jsm outentry(int rank, struct toptenentry *t1, int so) 507 1.4 christos { 508 1.9 dholland boolean quit = FALSE, gotkilled = FALSE, starv = FALSE; 509 1.4 christos char linebuf[BUFSZ]; 510 1.12 dholland size_t pos; 511 1.12 dholland 512 1.12 dholland linebuf[0] = '\0'; 513 1.12 dholland pos = 0; 514 1.9 dholland 515 1.4 christos if (rank) 516 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, "%3d", rank); 517 1.4 christos else 518 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, " "); 519 1.12 dholland pos = strlen(linebuf); 520 1.12 dholland 521 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, " %6ld %8s", 522 1.12 dholland t1->points, t1->name); 523 1.12 dholland pos = strlen(linebuf); 524 1.12 dholland 525 1.4 christos if (t1->plchar == 'X') 526 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, " "); 527 1.4 christos else 528 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, "-%c ", t1->plchar); 529 1.12 dholland pos = strlen(linebuf); 530 1.12 dholland 531 1.4 christos if (!strncmp("escaped", t1->death, 7)) { 532 1.4 christos if (!strcmp(" (with amulet)", t1->death + 7)) 533 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 534 1.12 dholland "escaped the dungeon with amulet"); 535 1.4 christos else 536 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 537 1.12 dholland "escaped the dungeon [max level %d]", 538 1.4 christos t1->maxlvl); 539 1.12 dholland pos = strlen(linebuf); 540 1.1 cgd } else { 541 1.4 christos if (!strncmp(t1->death, "quit", 4)) { 542 1.4 christos quit = TRUE; 543 1.4 christos if (t1->maxhp < 3 * t1->hp && t1->maxlvl < 4) 544 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 545 1.12 dholland "cravenly gave up"); 546 1.4 christos else 547 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 548 1.12 dholland "quit"); 549 1.12 dholland } else if (!strcmp(t1->death, "choked")) { 550 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 551 1.12 dholland "choked on %s food", 552 1.4 christos (t1->sex == 'F') ? "her" : "his"); 553 1.12 dholland } else if (!strncmp(t1->death, "starv", 5)) { 554 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 555 1.12 dholland "starved to death"); 556 1.12 dholland starv = TRUE; 557 1.12 dholland } else { 558 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 559 1.12 dholland "was killed"); 560 1.12 dholland gotkilled = TRUE; 561 1.12 dholland } 562 1.12 dholland pos = strlen(linebuf); 563 1.12 dholland 564 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, " on%s level %d", 565 1.9 dholland (gotkilled || starv) ? "" : " dungeon", t1->level); 566 1.12 dholland pos = strlen(linebuf); 567 1.12 dholland 568 1.4 christos if (t1->maxlvl != t1->level) 569 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 570 1.12 dholland " [max %d]", t1->maxlvl); 571 1.12 dholland pos = strlen(linebuf); 572 1.12 dholland 573 1.4 christos if (quit && t1->death[4]) 574 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 575 1.12 dholland "%s", t1->death + 4); 576 1.12 dholland pos = strlen(linebuf); 577 1.4 christos } 578 1.12 dholland if (gotkilled) { 579 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, " by %s%s", 580 1.4 christos (!strncmp(t1->death, "trick", 5) || !strncmp(t1->death, "the ", 4)) 581 1.4 christos ? "" : 582 1.4 christos strchr(vowels, *t1->death) ? "an " : "a ", 583 1.4 christos t1->death); 584 1.12 dholland pos = strlen(linebuf); 585 1.12 dholland } 586 1.12 dholland strlcat(linebuf, ".", sizeof(linebuf)); 587 1.12 dholland pos = strlen(linebuf); 588 1.4 christos if (t1->maxhp) { 589 1.4 christos char hpbuf[10]; 590 1.12 dholland unsigned hppos; 591 1.12 dholland 592 1.12 dholland strlcpy(hpbuf, (t1->hp > 0) ? itoa(t1->hp) : "-", sizeof(hpbuf)); 593 1.4 christos hppos = COLNO - 7 - strlen(hpbuf); 594 1.12 dholland if (pos <= hppos) { 595 1.12 dholland while (pos < hppos) 596 1.12 dholland linebuf[pos++] = ' '; 597 1.12 dholland (void) strlcpy(linebuf+pos, hpbuf, sizeof(linebuf)-pos); 598 1.12 dholland pos = strlen(linebuf); 599 1.12 dholland Snprintf(linebuf+pos, sizeof(linebuf)-pos, 600 1.12 dholland " [%d]", t1->maxhp); 601 1.12 dholland pos = strlen(linebuf); 602 1.4 christos } 603 1.4 christos } 604 1.4 christos if (so == 0) 605 1.4 christos puts(linebuf); 606 1.4 christos else if (so > 0) { 607 1.4 christos if (so >= COLNO) 608 1.4 christos so = COLNO - 1; 609 1.12 dholland while (pos < (unsigned)so) 610 1.12 dholland linebuf[pos++] = ' '; 611 1.12 dholland linebuf[pos] = '\0'; 612 1.4 christos standoutbeg(); 613 1.4 christos fputs(linebuf, stdout); 614 1.4 christos standoutend(); 615 1.4 christos (void) putchar('\n'); 616 1.4 christos } 617 1.12 dholland return /*(strlen(linebuf))*/ pos; 618 1.4 christos } 619 1.4 christos 620 1.13 dholland static char * 621 1.11 dholland itoa(int a) 622 1.4 christos { 623 1.4 christos static char buf[12]; 624 1.12 dholland Snprintf(buf, sizeof(buf), "%d", a); 625 1.4 christos return (buf); 626 1.4 christos } 627 1.4 christos 628 1.13 dholland static const char * 629 1.11 dholland ordin(int n) 630 1.4 christos { 631 1.9 dholland int dg = n % 10; 632 1.9 dholland 633 1.9 dholland return ((dg == 0 || dg > 3 || n / 10 == 1) ? "th" : (dg == 1) ? "st" : 634 1.9 dholland (dg == 2) ? "nd" : "rd"); 635 1.4 christos } 636 1.4 christos 637 1.4 christos void 638 1.11 dholland clearlocks(void) 639 1.4 christos { 640 1.4 christos int x; 641 1.4 christos (void) signal(SIGHUP, SIG_IGN); 642 1.4 christos for (x = maxdlevel; x >= 0; x--) { 643 1.1 cgd glo(x); 644 1.1 cgd (void) unlink(lock); /* not all levels need be present */ 645 1.1 cgd } 646 1.1 cgd } 647 1.1 cgd 648 1.1 cgd #ifdef NOSAVEONHANGUP 649 1.4 christos /*ARGSUSED*/ 650 1.4 christos void 651 1.14 roy hang_up(int n __unused) 652 1.1 cgd { 653 1.1 cgd (void) signal(SIGINT, SIG_IGN); 654 1.1 cgd clearlocks(); 655 1.1 cgd exit(1); 656 1.1 cgd } 657 1.4 christos #endif /* NOSAVEONHANGUP */ 658 1.1 cgd 659 1.4 christos char * 660 1.11 dholland eos(char *s) 661 1.1 cgd { 662 1.4 christos while (*s) 663 1.4 christos s++; 664 1.4 christos return (s); 665 1.1 cgd } 666 1.1 cgd 667 1.1 cgd /* it is the callers responsibility to check that there is room for c */ 668 1.4 christos void 669 1.11 dholland charcat(char *s, int c) 670 1.4 christos { 671 1.4 christos while (*s) 672 1.4 christos s++; 673 1.1 cgd *s++ = c; 674 1.1 cgd *s = 0; 675 1.1 cgd } 676 1.1 cgd 677 1.1 cgd /* 678 1.1 cgd * Called with args from main if argc >= 0. In this case, list scores as 679 1.1 cgd * requested. Otherwise, find scores for the current player (and list them 680 1.1 cgd * if argc == -1). 681 1.1 cgd */ 682 1.4 christos void 683 1.11 dholland prscore(int argc, char **argv) 684 1.4 christos { 685 1.4 christos char **players = NULL; 686 1.4 christos int playerct; 687 1.4 christos int rank; 688 1.4 christos struct toptenentry *t1, *t2; 689 1.5 jsm const char *recfile = RECORD; 690 1.4 christos FILE *rfile; 691 1.4 christos int flg = 0; 692 1.4 christos int i; 693 1.1 cgd #ifdef nonsense 694 1.4 christos long total_score = 0L; 695 1.4 christos char totchars[10]; 696 1.4 christos int totcharct = 0; 697 1.4 christos #endif /* nonsense */ 698 1.4 christos int outflg = (argc >= -1); 699 1.1 cgd #ifdef PERS_IS_UID 700 1.4 christos int uid = -1; 701 1.1 cgd #else 702 1.4 christos char *player0; 703 1.4 christos #endif /* PERS_IS_UID */ 704 1.1 cgd 705 1.4 christos if (!(rfile = fopen(recfile, "r"))) { 706 1.1 cgd puts("Cannot open record file!"); 707 1.1 cgd return; 708 1.1 cgd } 709 1.4 christos if (argc > 1 && !strncmp(argv[1], "-s", 2)) { 710 1.4 christos if (!argv[1][2]) { 711 1.1 cgd argc--; 712 1.1 cgd argv++; 713 1.4 christos } else if (!argv[1][3] && strchr("CFKSTWX", argv[1][2])) { 714 1.1 cgd argv[1]++; 715 1.1 cgd argv[1][0] = '-'; 716 1.4 christos } else 717 1.4 christos argv[1] += 2; 718 1.1 cgd } 719 1.4 christos if (argc <= 1) { 720 1.1 cgd #ifdef PERS_IS_UID 721 1.1 cgd uid = getuid(); 722 1.1 cgd playerct = 0; 723 1.1 cgd #else 724 1.1 cgd player0 = plname; 725 1.4 christos if (!*player0) 726 1.1 cgd player0 = "hackplayer"; 727 1.1 cgd playerct = 1; 728 1.1 cgd players = &player0; 729 1.4 christos #endif /* PERS_IS_UID */ 730 1.1 cgd } else { 731 1.1 cgd playerct = --argc; 732 1.1 cgd players = ++argv; 733 1.1 cgd } 734 1.4 christos if (outflg) 735 1.4 christos putchar('\n'); 736 1.1 cgd 737 1.1 cgd t1 = tt_head = newttentry(); 738 1.4 christos for (rank = 1;; rank++) { 739 1.4 christos if (fscanf(rfile, "%6s %d %d %d %d %d %ld %c%c %[^,],%[^\n]", 740 1.4 christos t1->date, &t1->uid, 741 1.4 christos &t1->level, &t1->maxlvl, 742 1.4 christos &t1->hp, &t1->maxhp, &t1->points, 743 1.4 christos &t1->plchar, &t1->sex, t1->name, t1->death) != 11) 744 1.1 cgd t1->points = 0; 745 1.4 christos if (t1->points == 0) 746 1.4 christos break; 747 1.1 cgd #ifdef PERS_IS_UID 748 1.4 christos if (!playerct && t1->uid == uid) 749 1.1 cgd flg++; 750 1.4 christos else 751 1.4 christos #endif /* PERS_IS_UID */ 752 1.4 christos for (i = 0; i < playerct; i++) { 753 1.4 christos if (strcmp(players[i], "all") == 0 || 754 1.4 christos strncmp(t1->name, players[i], NAMSZ) == 0 || 755 1.4 christos (players[i][0] == '-' && 756 1.4 christos players[i][1] == t1->plchar && 757 1.4 christos players[i][2] == 0) || 758 1.4 christos (digit(players[i][0]) && rank <= atoi(players[i]))) 759 1.4 christos flg++; 760 1.4 christos } 761 1.4 christos t1 = t1->tt_next = newttentry(); 762 1.1 cgd } 763 1.1 cgd (void) fclose(rfile); 764 1.4 christos if (!flg) { 765 1.4 christos if (outflg) { 766 1.4 christos printf("Cannot find any entries for "); 767 1.4 christos if (playerct < 1) 768 1.4 christos printf("you.\n"); 769 1.4 christos else { 770 1.4 christos if (playerct > 1) 771 1.4 christos printf("any of "); 772 1.4 christos for (i = 0; i < playerct; i++) 773 1.4 christos printf("%s%s", players[i], (i < playerct - 1) ? ", " : ".\n"); 774 1.4 christos printf("Call is: %s -s [playernames]\n", hname); 775 1.4 christos } 776 1.1 cgd } 777 1.4 christos return; 778 1.1 cgd } 779 1.4 christos if (outflg) 780 1.4 christos outheader(); 781 1.1 cgd t1 = tt_head; 782 1.4 christos for (rank = 1; t1->points != 0; rank++, t1 = t2) { 783 1.1 cgd t2 = t1->tt_next; 784 1.1 cgd #ifdef PERS_IS_UID 785 1.4 christos if (!playerct && t1->uid == uid) 786 1.1 cgd goto outwithit; 787 1.1 cgd else 788 1.4 christos #endif /* PERS_IS_UID */ 789 1.4 christos for (i = 0; i < playerct; i++) { 790 1.4 christos if (strcmp(players[i], "all") == 0 || 791 1.4 christos strncmp(t1->name, players[i], NAMSZ) == 0 || 792 1.4 christos (players[i][0] == '-' && 793 1.4 christos players[i][1] == t1->plchar && 794 1.4 christos players[i][2] == 0) || 795 1.4 christos (digit(players[i][0]) && rank <= atoi(players[i]))) { 796 1.1 cgd outwithit: 797 1.4 christos if (outflg) 798 1.4 christos (void) outentry(rank, t1, 0); 799 1.1 cgd #ifdef nonsense 800 1.4 christos total_score += t1->points; 801 1.4 christos if (totcharct < sizeof(totchars) - 1) 802 1.4 christos totchars[totcharct++] = t1->plchar; 803 1.4 christos #endif /* nonsense */ 804 1.4 christos break; 805 1.4 christos } 806 1.1 cgd } 807 1.16 dholland free(t1); 808 1.1 cgd } 809 1.1 cgd #ifdef nonsense 810 1.1 cgd totchars[totcharct] = 0; 811 1.1 cgd 812 1.4 christos /* 813 1.4 christos * We would like to determine whether he is experienced. However, the 814 1.4 christos * information collected here only tells about the scores/roles that 815 1.4 christos * got into the topten (top 100?). We should maintain a .hacklog or 816 1.4 christos * something in his home directory. 817 1.4 christos */ 818 1.1 cgd flags.beginner = (total_score < 6000); 819 1.4 christos for (i = 0; i < 6; i++) 820 1.4 christos if (!strchr(totchars, "CFKSTWX"[i])) { 821 1.4 christos flags.beginner = 1; 822 1.4 christos if (!pl_character[0]) 823 1.4 christos pl_character[0] = "CFKSTWX"[i]; 824 1.4 christos break; 825 1.4 christos } 826 1.4 christos #endif /* nonsense */ 827 1.1 cgd } 828