scores.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. /* =============================================================================
  2. * PROGRAM: ularn
  3. * FILENAME: scores.c
  4. *
  5. * DESCRIPTION:
  6. * This modules contains functions to handle the scoreboard display and
  7. * update at the end of the game.
  8. *
  9. * =============================================================================
  10. * EXPORTED VARIABLES
  11. *
  12. * None.
  13. *
  14. * =============================================================================
  15. * EXPORTED FUNCTIONS
  16. *
  17. * makeboard : Create a new scoreboard (deleting the old one)
  18. * hashewon : Checks if the player has previously won.
  19. * paytaxes : Note the payment of taxes.
  20. * showscores : Display the scoreboard
  21. * showallscores : Show scores including inventories.
  22. * endgame : Game tidyup and exit function.
  23. * died : Function to handle player dying.
  24. *
  25. * =============================================================================
  26. */
  27. #include "scores.h"
  28. #include "dungeon.h"
  29. #include "header.h"
  30. #include "itm.h"
  31. #include "monster.h"
  32. #include "player.h"
  33. #include "potion.h"
  34. #include "scroll.h"
  35. #include "show.h"
  36. #include "sphere.h"
  37. #include "store.h"
  38. #include "ularn_ask.h"
  39. #include "ularn_game.h"
  40. #include "ularn_win.h"
  41. /* =============================================================================
  42. * Local variables
  43. */
  44. /*
  45. * This is a header written to the scoreboard file for version identification
  46. * If the scoreboard format doesn't match then make a new score board.
  47. * If you change the score board format then increase SCORE_VERSION by 1
  48. * to prevent ularn from attempting to use old format scoreboards.
  49. * Energetic coders may provide an automatic score board format upgrade.
  50. */
  51. #define SCORE_VERSION 2
  52. struct score_header_type {
  53. char Id[4];
  54. int Format;
  55. };
  56. static struct score_header_type CurrentHeader = {{'u', 'l', 's', 'b'},
  57. SCORE_VERSION};
  58. /* This is the structure for the scoreboard */
  59. struct score_type {
  60. long score; /* the score of the player */
  61. int suid; /* the user id number of the player*/
  62. DiedReasonType reason; /* the reason the player died */
  63. short what; /* the number of the monster that killedplayer */
  64. short level; /* the level player was on when he died */
  65. short hardlev; /* the level of difficulty player played at */
  66. short order; /* the relative ordering place of this entry */
  67. char who[LOGNAMESIZE + 1]; /* the name of the character */
  68. char char_class[20]; /* the character class */
  69. short sciv[IVENSIZE][2]; /* this is the inventory list of the character*/
  70. };
  71. /* This is the structure for the winning scoreboard */
  72. struct win_score_type {
  73. long score; /* the score of the player */
  74. short timeused; /* the time used in mobuls to win the game*/
  75. long taxes; /* taxes he owes to LRS */
  76. int suid; /* the user id number of the player*/
  77. short hardlev; /* the level of difficulty player played at*/
  78. short order; /* the relative ordering place of this entry*/
  79. char who[LOGNAMESIZE + 1]; /* the name of the character */
  80. char char_class[20]; /* the character class */
  81. };
  82. /* storage for the scoreboard */
  83. static struct score_type scoreboard[SCORESIZE];
  84. /* storage for the winners scoreboard */
  85. static struct win_score_type winboard[SCORESIZE];
  86. /* Died reason messages */
  87. static char *whydead[DIED_COUNT] = {"killed by a monster",
  88. "quit",
  89. "suspended",
  90. "self-annihilated",
  91. "shot by an arrow",
  92. "hit by a dart",
  93. "fell into a pit",
  94. "fell into a pit to HELL",
  95. "a winner",
  96. "trapped in solid rock",
  97. "killed by a missing save file",
  98. "killed by an old save file",
  99. "caught by the greedy cheater checker trap",
  100. "killed by a protected save file",
  101. "killed his family and committed suicide",
  102. "erased by a wayward finger",
  103. "fell through a trap door to HELL",
  104. "fell through a trap door",
  105. "drank some poisonous water",
  106. "fried by an electric shock",
  107. "slipped in a volcano shaft",
  108. "killed by a stupid act of frustration",
  109. "attacked by a revolting demon",
  110. "hit by his own magic",
  111. "demolished by an unseen attacker",
  112. "fell into the dreadful sleep",
  113. "killed by an exploding chest",
  114. "died of internal complications",
  115. "annihilated by a sphere",
  116. "died a post mortem death",
  117. "wasted by a malloc() failure",
  118. "wasted by an annoyed genie",
  119. "took an elevator straight to HELL"};
  120. /*
  121. * The last error reading/writing the score file
  122. */
  123. static int scorerror = 0;
  124. /*
  125. * The score to highlight when showing the score board
  126. * This is set to the player's score if it is better that the previous score
  127. */
  128. static int highlight_pos = -1;
  129. static int highlight_win = 0;
  130. /* =============================================================================
  131. * Local functions
  132. */
  133. /* =============================================================================
  134. * FUNCTION: calc_score
  135. *
  136. * DESCRIPTION:
  137. * This function calculates the score for the player.
  138. *
  139. * PARAMETERS:
  140. *
  141. * Winner : Indicates if the player is a winner (0 = non-winner, 1 = winner)
  142. *
  143. * RETURN VALUE:
  144. *
  145. * The player's score.
  146. */
  147. static long calc_score(int Winner) {
  148. int gold_value;
  149. int idx;
  150. int dlev;
  151. int deepest;
  152. int score;
  153. int stupidity_penalty;
  154. /*
  155. * Start by calculating the player's net worth, converting items to their
  156. * value in gold according to what the trading post would pay.
  157. * This is a bit mean for gems as the bank pays 5x this.
  158. */
  159. gold_value = c[GOLD] + c[BANKACCOUNT];
  160. for (idx = 0; idx < IVENSIZE; idx++)
  161. gold_value += item_value(iven[idx], ivenarg[idx]);
  162. if (!Winner) {
  163. /*
  164. * If the player isn't a winner, devalue score value of gold by 1/10.
  165. */
  166. gold_value -= gold_value / 10;
  167. } else
  168. /* bonus for winning */
  169. gold_value += 100000 * c[HARDGAME];
  170. /*
  171. * Add score for the deepest level visited
  172. */
  173. deepest = 0;
  174. stupidity_penalty = 1;
  175. for (dlev = 0; dlev < NLEVELS; dlev++) {
  176. if (beenhere[dlev]) {
  177. if ((dlev == MAXLEVEL) && (deepest == 0)) {
  178. /* The stupid player went directly into the volcano */
  179. if (Winner)
  180. /*
  181. * If the player actually managed to WIN doing this (pretty unlikely)
  182. * then give a reward
  183. */
  184. gold_value *= 2;
  185. else
  186. stupidity_penalty = 1;
  187. } else
  188. deepest = dlev;
  189. }
  190. }
  191. if (stupidity_penalty) {
  192. deepest = 0;
  193. gold_value /= 2;
  194. }
  195. /* Calculate the final score */
  196. score = gold_value + c[EXPERIENCE] + deepest * 50;
  197. /* no negative score */
  198. if (score < 0)
  199. score = 0;
  200. return score;
  201. }
  202. /* =============================================================================
  203. * FUNCTION: readboard
  204. *
  205. * DESCRIPTION:
  206. * Function to read in the scoreboard into a static buffer.
  207. *
  208. * PARAMETERS:
  209. *
  210. * None.
  211. *
  212. * RETURN VALUE:
  213. *
  214. * -1 if unable to read in the scoreboard,
  215. * 0 if all is OK
  216. */
  217. static int readboard(void) {
  218. FILE *fp;
  219. int n;
  220. struct score_header_type header;
  221. fp = fopen(scorefile, "rb");
  222. if (fp == (FILE *)NULL) {
  223. Printf("Can't open scorefile '%s' for reading\n", scorefile);
  224. return -1;
  225. }
  226. n = fread((char *)&header, sizeof(struct score_header_type), 1, fp);
  227. if (n != 1) {
  228. Print("Can't read score board header\n");
  229. fclose(fp);
  230. return -2;
  231. }
  232. if (strncmp(header.Id, CurrentHeader.Id, 4) != 0) {
  233. Print("Not a valid ularn score board\n");
  234. fclose(fp);
  235. return -3;
  236. }
  237. if (header.Format != CurrentHeader.Format) {
  238. Print("Incorrect score board version\n");
  239. fclose(fp);
  240. return -4;
  241. }
  242. n = fread((char *)scoreboard, sizeof(struct score_type) * SCORESIZE, 1, fp);
  243. if (n != 1) {
  244. Print("Can't read scoreboard\n");
  245. fclose(fp);
  246. return -5;
  247. }
  248. n = fread((char *)winboard, sizeof(struct win_score_type) * SCORESIZE, 1, fp);
  249. if (n != 1) {
  250. Print("Can't read scoreboard");
  251. fclose(fp);
  252. return -6;
  253. }
  254. fclose(fp);
  255. return 0;
  256. }
  257. /* =============================================================================
  258. * FUNCTION: writeboard
  259. *
  260. * DESCRIPTION:
  261. * Function to write the scoreboard from readboard()'s buffer.
  262. *
  263. * PARAMETERS:
  264. *
  265. * None.
  266. *
  267. * RETURN VALUE:
  268. *
  269. * -1 if unable to write the scoreboard,
  270. * 0 if all is OK
  271. */
  272. static int writeboard(void) {
  273. FILE *fp;
  274. int n;
  275. fp = fopen(scorefile, "wb");
  276. if (fp == (FILE *)NULL) {
  277. Print("Can't open scorefile for writing\n");
  278. return -1;
  279. }
  280. n = fwrite((char *)&CurrentHeader, sizeof(struct score_header_type), 1, fp);
  281. if (n != 1) {
  282. Print("Can't write scorefile\n");
  283. fclose(fp);
  284. return -1;
  285. }
  286. n = fwrite((char *)scoreboard, sizeof(struct score_type) * SCORESIZE, 1, fp);
  287. if (n != 1) {
  288. Print("Can't write scorefile\n");
  289. fclose(fp);
  290. return -1;
  291. }
  292. n = fwrite((char *)winboard, sizeof(struct win_score_type) * SCORESIZE, 1,
  293. fp);
  294. if (n != 1) {
  295. Print("Can't write scorefile\n");
  296. fclose(fp);
  297. return -1;
  298. }
  299. fclose(fp);
  300. return 0;
  301. }
  302. /* =============================================================================
  303. * FUNCTION: sortboard
  304. *
  305. * DESCRIPTION:
  306. * Function to calculate the position of each score in the scoreboard.
  307. * NOTE:
  308. * Unused score entries must be assigned positions in order for the score
  309. * update function to operate correctly.
  310. *
  311. * PARAMETERS:
  312. *
  313. * None.
  314. *
  315. * RETURN VALUE:
  316. *
  317. * 0 if no sorting done, else returns 1
  318. */
  319. static int sortboard(void) {
  320. int i, pos;
  321. long largest_score;
  322. int largest_score_idx;
  323. /* mark all scores as unsorted */
  324. for (i = 0; i < SCORESIZE; i++) {
  325. scoreboard[i].order = -1;
  326. winboard[i].order = -1;
  327. }
  328. /* work out the position of each score in the visitor's board */
  329. for (pos = 0; pos < SCORESIZE; pos++) {
  330. /* find the score in position pos */
  331. largest_score = -1;
  332. largest_score_idx = -1;
  333. for (i = 0; i < SCORESIZE; i++) {
  334. if ((scoreboard[i].order < 0) && (scoreboard[i].score >= largest_score)) {
  335. largest_score_idx = i;
  336. largest_score = scoreboard[i].score;
  337. }
  338. }
  339. if (largest_score_idx >= 0)
  340. scoreboard[largest_score_idx].order = (short)pos;
  341. }
  342. /* work out the position of each score in the winner's board */
  343. for (pos = 0; pos < SCORESIZE; pos++) {
  344. /* find the score in position pos */
  345. largest_score = -1;
  346. largest_score_idx = -1;
  347. for (i = 0; i < SCORESIZE; i++) {
  348. if ((winboard[i].order < 0) && (winboard[i].score >= largest_score)) {
  349. largest_score_idx = i;
  350. largest_score = winboard[i].score;
  351. }
  352. }
  353. if (largest_score_idx >= 0)
  354. winboard[largest_score_idx].order = (short)pos;
  355. }
  356. return 1;
  357. }
  358. /* =============================================================================
  359. * FUNCTION: newscore
  360. *
  361. * DESCRIPTION:
  362. * Function to add entry to scoreboard.
  363. *
  364. * PARAMETERS:
  365. *
  366. * score - the player's score
  367. *
  368. * winner - true if the player is a winner
  369. *
  370. * died_reason - the reason the player died
  371. *
  372. * what - the monster that killed the player (if any).
  373. *
  374. * RETURN VALUE:
  375. *
  376. * Returns the new position on the scoreboard if the player made the high
  377. * score list.
  378. */
  379. static int newscore(long score, int winner, DiedReasonType died_reason,
  380. int what) {
  381. int i;
  382. int board_idx;
  383. long gold;
  384. long taxes;
  385. gold = c[GOLD] + c[BANKACCOUNT];
  386. if (readboard() < 0)
  387. return -1;
  388. if (cheat)
  389. /* Cheaters can never get on the scoreboard */
  390. return -1;
  391. if (winner) {
  392. /* if a winner then delete all non-winning scores */
  393. for (i = 0; i < SCORESIZE; i++)
  394. if (scoreboard[i].suid == userid)
  395. scoreboard[i].score = 0;
  396. /* Calculate the amount of tax owing */
  397. taxes = (long)(outstanding_taxes + (gold * TAXRATE));
  398. outstanding_taxes = taxes;
  399. /*
  400. * Find where in the winner's score board the player's score is to
  401. * be stored
  402. */
  403. board_idx = -1;
  404. /* if he has a slot on the winning scoreboard update it if greater score*/
  405. for (i = 0; i < SCORESIZE; i++)
  406. if (winboard[i].suid == userid)
  407. board_idx = i;
  408. if (board_idx == -1) {
  409. /* he had no entry. look for last entry and see if he has a greater score
  410. */
  411. for (i = 0; i < SCORESIZE; i++) {
  412. if (winboard[i].order == SCORESIZE - 1)
  413. if (score > winboard[i].score)
  414. board_idx = i;
  415. }
  416. }
  417. if (board_idx >= 0) {
  418. /* Update the taxes owed */
  419. winboard[board_idx].taxes = taxes;
  420. if ((winboard[board_idx].score < score) ||
  421. (c[HARDGAME] > winboard[board_idx].hardlev)) {
  422. /* Store the new score in this slot */
  423. strcpy(winboard[board_idx].who, logname);
  424. strcpy(winboard[board_idx].char_class, char_class);
  425. winboard[board_idx].score = score;
  426. winboard[board_idx].hardlev = (short)c[HARDGAME];
  427. winboard[board_idx].suid = userid;
  428. winboard[board_idx].timeused = (short)(gtime / 100);
  429. }
  430. }
  431. } else {
  432. /* Not a winner, so update the visitors score board */
  433. /* Find where in the visitor's score board the player's score is to
  434. * be stores
  435. */
  436. board_idx = -1;
  437. /* Check if he already has a slot on the scoreboard */
  438. for (i = 0; i < SCORESIZE; i++)
  439. if (scoreboard[i].suid == userid)
  440. board_idx = i;
  441. /* he had no entry. look for last entry and see if he has a greater score */
  442. if (board_idx == -1) {
  443. for (i = 0; i < SCORESIZE; i++)
  444. if (scoreboard[i].order == SCORESIZE - 1)
  445. board_idx = i;
  446. }
  447. if (board_idx >= 0) {
  448. if ((scoreboard[board_idx].score < score) ||
  449. (c[HARDGAME] > scoreboard[board_idx].hardlev)) {
  450. /* This is a better score, so store the new score in this slot */
  451. strcpy(scoreboard[board_idx].who, logname);
  452. strcpy(scoreboard[board_idx].char_class, char_class);
  453. scoreboard[board_idx].score = score;
  454. scoreboard[board_idx].reason = died_reason;
  455. scoreboard[board_idx].what = (short)what;
  456. scoreboard[board_idx].hardlev = (short)c[HARDGAME];
  457. scoreboard[board_idx].suid = userid;
  458. scoreboard[board_idx].level = (char)level;
  459. for (i = 0; i < IVENSIZE; i++) {
  460. scoreboard[board_idx].sciv[i][0] = iven[i];
  461. scoreboard[board_idx].sciv[i][1] = ivenarg[i];
  462. }
  463. } else
  464. /* The new score isn't better */
  465. board_idx = -1;
  466. }
  467. }
  468. /* resort the score board */
  469. sortboard();
  470. if (writeboard() < 0)
  471. return -1;
  472. return board_idx;
  473. }
  474. /* =============================================================================
  475. * FUNCTION: print_died_reason
  476. *
  477. * DESCRIPTION:
  478. * Print the reason a player died.
  479. *
  480. * PARAMETERS:
  481. *
  482. * Reason : The reason the player died
  483. *
  484. * Monster : The monster involved in the player's death (if any)
  485. *
  486. * lev : The dungeon level
  487. *
  488. * RETURN VALUE:
  489. *
  490. * None
  491. */
  492. static void print_died_reason(DiedReasonType Reason, int Monster, int lev) {
  493. char ch;
  494. char *mod;
  495. if (Reason == DIED_MONSTER) {
  496. ch = monster[Monster].name[0];
  497. if ((ch == 'a') || (ch == 'e') || (ch == 'i') || (ch == 'o') || (ch == 'u'))
  498. mod = "an";
  499. else
  500. mod = "a";
  501. Printf(" killed by %s %s", mod, monster[Monster].name);
  502. } else {
  503. if (!sex &&
  504. ((Reason == DIED_KILLED_FAMILY) || (Reason == DIED_OWN_MAGIC))) {
  505. /* fix up died string for female characters */
  506. switch (Reason) {
  507. case DIED_KILLED_FAMILY:
  508. Printf(" killed her family and committed suicide");
  509. break;
  510. case DIED_OWN_MAGIC:
  511. Printf(" hit by her own magic");
  512. break;
  513. default:
  514. break;
  515. }
  516. } else
  517. Printf(" %s", whydead[Reason]);
  518. }
  519. if (Reason != DIED_WINNER)
  520. Printf(" on %s\n", levelname[lev]);
  521. else
  522. Printf("\n");
  523. }
  524. /* =============================================================================
  525. * FUNCTION: show_winners
  526. *
  527. * DESCRIPTION:
  528. * Subroutine to print out the winning scoreboard.
  529. *
  530. * PARAMETERS:
  531. *
  532. * None.
  533. *
  534. * RETURN VALUE:
  535. *
  536. * The number of entries onthe winner's score board.
  537. */
  538. static int show_winners(void) {
  539. struct win_score_type *p;
  540. int win_count;
  541. int i, j;
  542. /* is there anyone on the scoreboard? */
  543. win_count = 0;
  544. for (i = 0; i < SCORESIZE; i++)
  545. if (winboard[i].score != 0)
  546. win_count++;
  547. if (win_count > 0) {
  548. ClearText();
  549. clearpager();
  550. Print(" Score Diff Time Needed VLarn Winners List\n");
  551. pager();
  552. /* needed to print out the winners in order */
  553. for (i = 0; i < win_count; i++) {
  554. for (j = 0; j < SCORESIZE; j++) {
  555. /* pointer to the scoreboard entry */
  556. p = &winboard[j];
  557. if ((p->order == i) && (p->score > 0)) {
  558. Printf("%-10ld%8d%8d Mobuls (%s) %s\n", p->score, p->hardlev,
  559. p->timeused, p->char_class, p->who);
  560. pager();
  561. }
  562. }
  563. }
  564. }
  565. /* return number of people on scoreboard */
  566. return win_count;
  567. }
  568. /* =============================================================================
  569. * FUNCTION: show_visitors
  570. *
  571. * DESCRIPTION:
  572. * Subroutine to print out the non-winners scoreboard.
  573. *
  574. * PARAMETERS:
  575. *
  576. * x : 0 to list the scores, 1 to list inventories too.
  577. *
  578. * RETURN VALUE:
  579. *
  580. * Returns the number of players on scoreboard that were shown
  581. */
  582. static int show_visitors(int show_inv) {
  583. int i, j, n;
  584. int count;
  585. int oscrollknown[MAXSCROLL];
  586. int opotionknown[MAXPOTION];
  587. /*
  588. * Make all scrolls and potions known for displaying the scoreboard,
  589. * storing the old known status for restoration later.
  590. */
  591. for (i = 0; i < MAXSCROLL; i++) {
  592. oscrollknown[i] = scrollknown[i];
  593. scrollknown[i] = 1;
  594. }
  595. for (i = 0; i < MAXPOTION; i++) {
  596. opotionknown[i] = potionknown[i];
  597. potionknown[i] = 1;
  598. }
  599. c[WEAR] = -1;
  600. c[WIELD] = -1;
  601. c[SHIELD] = -1;
  602. /* is the scoreboard empty? */
  603. count = 0;
  604. for (i = 0; i < SCORESIZE; i++)
  605. if (scoreboard[i].score != 0)
  606. count++;
  607. if (count > 0) {
  608. ClearText();
  609. clearpager();
  610. Print(" Score Diff VLarn Visitor Log\n");
  611. pager();
  612. for (i = 0; i < count; i++) {
  613. for (j = 0; j < SCORESIZE; j++) {
  614. if ((scoreboard[j].order == i) && (scoreboard[j].score > 0)) {
  615. if ((j == highlight_pos) && (!highlight_win))
  616. SetFormat(FORMAT_STANDOUT);
  617. Printf("%7ld %3ld (%s) %s ", scoreboard[j].score,
  618. (long)scoreboard[j].hardlev, scoreboard[j].char_class,
  619. scoreboard[j].who);
  620. print_died_reason(scoreboard[j].reason, scoreboard[j].what,
  621. scoreboard[j].level);
  622. if ((j == highlight_pos) && (!highlight_win))
  623. SetFormat(FORMAT_NORMAL);
  624. pager();
  625. if (show_inv) {
  626. for (n = 0; n < IVENSIZE; n++) {
  627. iven[n] = scoreboard[j].sciv[n][0];
  628. ivenarg[n] = scoreboard[j].sciv[n][1];
  629. }
  630. for (n = 0; n < IVENSIZE; n++) {
  631. if (iven[n] != ONOTHING) {
  632. show3(n);
  633. pager();
  634. }
  635. }
  636. pager();
  637. }
  638. }
  639. } /* for each score in the score board */
  640. } /* for each score position */
  641. } /* if any scores in the scoreboard */
  642. /* Restore the known scrolls and potions */
  643. for (i = 0; i < MAXSCROLL; i++)
  644. scrollknown[i] = oscrollknown[i];
  645. for (i = 0; i < MAXPOTION; i++)
  646. potionknown[i] = opotionknown[i];
  647. return count; /* return the number of players just shown */
  648. }
  649. /* =============================================================================
  650. * FUNCTION: show_player_score
  651. *
  652. * DESCRIPTION:
  653. * Subroutine to print out the line showing the player when he is killed.
  654. *
  655. * PARAMETERS:
  656. *
  657. * Reason : The reason the player died
  658. *
  659. * Monster : The monster involved in the player's death.
  660. *
  661. * score : The player's score.
  662. *
  663. * RETURN VALUE:
  664. *
  665. * None.
  666. */
  667. static void show_player_score(DiedReasonType Reason, int Monster, long score) {
  668. char *cls;
  669. cls = class[c[LEVEL]];
  670. if (char_class[0] == 0)
  671. strcpy(char_class, "<unknown>");
  672. Print("----------------------------------------------------------------------"
  673. "-------\n");
  674. Print(" V L A R N S C O R E S\n");
  675. Print("----------------------------------------------------------------------"
  676. "-------\n\n");
  677. Printf(" Score: %ld Diff: %d ", score, c[HARDGAME]);
  678. Printf(" Level: %s Char: %s\n", cls, char_class);
  679. Printf("\t%s", logname);
  680. print_died_reason(Reason, Monster, level);
  681. if (wizard)
  682. Print(" (wizard)");
  683. if (cheat)
  684. Print(" (cheater)");
  685. Print("\n");
  686. Print("----------------------------------------------------------------------"
  687. "-------");
  688. }
  689. /* =============================================================================
  690. * Exported functions
  691. */
  692. /* =============================================================================
  693. * FUNCTION: makeboard
  694. */
  695. int makeboard(void) {
  696. int i;
  697. for (i = 0; i < SCORESIZE; i++) {
  698. winboard[i].taxes = 0;
  699. winboard[i].score = 0;
  700. winboard[i].hardlev = 0;
  701. winboard[i].order = (short)i;
  702. scoreboard[i].score = 0;
  703. scoreboard[i].hardlev = 0;
  704. scoreboard[i].order = (short)i;
  705. }
  706. if (writeboard())
  707. return -1;
  708. #ifdef UNIX
  709. chmod(scorefile, 0666);
  710. #endif
  711. return 0;
  712. }
  713. /* =============================================================================
  714. * FUNCTION: hashewon
  715. */
  716. int hashewon(void) {
  717. int i;
  718. int rt;
  719. c[HARDGAME] = 0;
  720. rt = readboard();
  721. if (rt < 0)
  722. return 0;
  723. /* search through winners scoreboard */
  724. for (i = 0; i < SCORESIZE; i++) {
  725. if ((winboard[i].suid == userid) && (winboard[i].score > 0)) {
  726. c[HARDGAME] = winboard[i].hardlev + 1;
  727. outstanding_taxes = winboard[i].taxes;
  728. return 1;
  729. }
  730. }
  731. return 0;
  732. }
  733. /* =============================================================================
  734. * FUNCTION: paytaxes
  735. */
  736. long paytaxes(long x) {
  737. int i;
  738. long amt;
  739. if (x <= 0)
  740. return 0L;
  741. if (readboard() < 0)
  742. return 0L;
  743. /* look for players winning entry */
  744. for (i = 0; i < SCORESIZE; i++) {
  745. if ((winboard[i].suid == userid) && (winboard[i].score > 0)) {
  746. /* calculate the amount to pay (making sure the player doesn't overpay */
  747. amt = winboard[i].taxes;
  748. if (x < amt)
  749. amt = x;
  750. winboard[i].taxes -= amt;
  751. outstanding_taxes -= amt;
  752. if (writeboard() < 0)
  753. return 0;
  754. return amt;
  755. }
  756. }
  757. return 0L; /* couldn't find user on winning scoreboard */
  758. }
  759. /* =============================================================================
  760. * FUNCTION: showscores
  761. */
  762. void showscores(void) {
  763. int i, j;
  764. if (readboard() < 0) {
  765. get_prompt_input("\nPress return to continue", "\015", 0);
  766. return;
  767. }
  768. i = show_winners();
  769. if (i > 0)
  770. get_prompt_input("\nPress return to continue", "\015", 0);
  771. j = show_visitors(0);
  772. if ((i + j) == 0)
  773. Print("\nThe scoreboard is empty.\n");
  774. else
  775. Print("\n");
  776. get_prompt_input("\nPress return to continue", "\015", 0);
  777. }
  778. /* =============================================================================
  779. * FUNCTION: showallscores
  780. */
  781. void showallscores(void) {
  782. int i, j;
  783. if (readboard() < 0)
  784. return;
  785. i = show_winners();
  786. j = show_visitors(1);
  787. if ((i + j) == 0)
  788. Print("\nThe scoreboard is empty.\n");
  789. else
  790. Print("\n");
  791. get_prompt_input("\nPress return to continue", "\015", 0);
  792. }
  793. /* =============================================================================
  794. * FUNCTION: endgame
  795. */
  796. void endgame(void) {
  797. /* deallocate any allocated memory */
  798. free_cells();
  799. free_spheres();
  800. /* close the application */
  801. close_app();
  802. /* and exit */
  803. exit(0);
  804. }
  805. /* =============================================================================
  806. * FUNCTION: died
  807. */
  808. void died(DiedReasonType Reason, int Monster) {
  809. int win;
  810. int can_revive;
  811. long score;
  812. can_revive = 1;
  813. if (c[LIFEPROT] > 0) {
  814. /* if life protection */
  815. switch (Reason) {
  816. case DIED_QUIT:
  817. case DIED_SUSPENDED:
  818. case DIED_FELL_INTO_BOTTOMLESS_PIT:
  819. case DIED_WINNER:
  820. case DIED_MISSING_SAVE_FILE:
  821. case DIED_OLD_SAVE_FILE:
  822. case DIED_GREEDY_CHEATER:
  823. case DIED_PROTECTED_SAVE_FILE:
  824. case DIED_KILLED_FAMILY:
  825. case DIED_FELL_THROUGH_BOTTOMLESS_TRAPDOOR:
  826. case DIED_INTERNAL_COMPLICATIONS:
  827. case DIED_POST_MORTEM_DEATH:
  828. case DIED_MALLOC_FAILURE:
  829. case DIED_ELEVATOR_TO_HELL:
  830. case DIED_QUICK_QUIT:
  831. can_revive = 0;
  832. break;
  833. default:
  834. break;
  835. }
  836. if (can_revive) {
  837. --c[LIFEPROT];
  838. c[HP] = c[HPMAX];
  839. --c[CONSTITUTION];
  840. Print("\nYou feel wiiieeeeerrrrrd all over! ");
  841. UlarnBeep();
  842. nap(4000);
  843. /* only case where died() returns */
  844. return;
  845. }
  846. }
  847. /* remove checkpoint file if used */
  848. if (ckpflag)
  849. unlink(ckpfile);
  850. /* if we are not to display the scores */
  851. if ((Reason == DIED_QUICK_QUIT) || (Reason == DIED_SUSPENDED)) {
  852. /* for quick exit or saved game */
  853. ClearText();
  854. Printf("Tidying up...\n");
  855. endgame();
  856. }
  857. win = (Reason == DIED_WINNER);
  858. /* Now calculate the player's final score */
  859. score = calc_score(win);
  860. set_display(DISPLAY_TEXT);
  861. ClearText();
  862. /* Show the players final score */
  863. show_player_score(Reason, Monster, score);
  864. get_prompt_input("\nPress return to continue", "\015", 0);
  865. if (!(wizard || cheat)) {
  866. /* wizards and cheaters can't get on the score boards */
  867. highlight_pos = newscore(score, win, Reason, Monster);
  868. highlight_win = win;
  869. }
  870. if (scorerror == 0)
  871. /* if we updated the scoreboard*/
  872. showscores();
  873. /* if (win && mail) mailbill(); */
  874. ClearText();
  875. Print("\n");
  876. /* exit the game */
  877. endgame();
  878. }