hack.end.c 20 KB

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