PageRenderTime 44ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/branches/IsengardDev/ironhells/z_src/scores.c

#
C | 784 lines | 437 code | 177 blank | 170 comment | 83 complexity | 9c7cd9001f585bd5627a50b2707b5bd3 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, Apache-2.0
  1. /* CVS: Last edit by $Author: cipher $ on $Date: 2000-04-23 23:34:51 +0200 (Sun, 23 Apr 2000) $ */
  2. /* File: scores.c */
  3. /* Purpose: Highscores handling */
  4. /*
  5. * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
  6. *
  7. * This software may be copied and distributed for educational, research, and
  8. * not for profit purposes provided that this copyright and statement are
  9. * included in all such copies.
  10. */
  11. #include "angband.h"
  12. /*
  13. * Seek score 'i' in the highscore file
  14. */
  15. static int highscore_seek(int i)
  16. {
  17. /* Seek for the requested record */
  18. return (fd_seek(highscore_fd, (huge)(i) * sizeof(high_score)));
  19. }
  20. /*
  21. * Read one score from the highscore file
  22. */
  23. static errr highscore_read(high_score *score)
  24. {
  25. /* Read the record, note failure */
  26. return (fd_read(highscore_fd, (char*)(score), sizeof(high_score)));
  27. }
  28. /*
  29. * Write one score to the highscore file
  30. */
  31. static int highscore_write(high_score *score)
  32. {
  33. /* Write the record, note failure */
  34. return (fd_write(highscore_fd, (char*)(score), sizeof(high_score)));
  35. }
  36. /*
  37. * Just determine where a new score *would* be placed
  38. * Return the location (0 is best) or -1 on failure
  39. */
  40. static int highscore_where(high_score *score)
  41. {
  42. int i;
  43. high_score the_score;
  44. /* Paranoia -- it may not have opened */
  45. if (highscore_fd < 0) return (-1);
  46. /* Go to the start of the highscore file */
  47. if (highscore_seek(0)) return (-1);
  48. /* Read until we get to a higher score */
  49. for (i = 0; i < MAX_HISCORES; i++)
  50. {
  51. if (highscore_read(&the_score)) return (i);
  52. if (strcmp(the_score.pts, score->pts) < 0) return (i);
  53. }
  54. /* The "last" entry is always usable */
  55. return (MAX_HISCORES - 1);
  56. }
  57. /*
  58. * Actually place an entry into the high score file
  59. * Return the location (0 is best) or -1 on "failure"
  60. */
  61. static int highscore_add(high_score *score)
  62. {
  63. int i, slot;
  64. bool done = FALSE;
  65. high_score the_score, tmpscore;
  66. /* Paranoia -- it may not have opened */
  67. if (highscore_fd < 0) return (-1);
  68. /* Determine where the score should go */
  69. slot = highscore_where(score);
  70. /* Hack -- Not on the list */
  71. if (slot < 0) return (-1);
  72. /* Hack -- prepare to dump the new score */
  73. the_score = (*score);
  74. /* Slide all the scores down one */
  75. for (i = slot; !done && (i < MAX_HISCORES); i++)
  76. {
  77. /* Read the old guy, note errors */
  78. if (highscore_seek(i)) return (-1);
  79. if (highscore_read(&tmpscore)) done = TRUE;
  80. /* Back up and dump the score we were holding */
  81. if (highscore_seek(i)) return (-1);
  82. if (highscore_write(&the_score)) return (-1);
  83. /* Hack -- Save the old score, for the next pass */
  84. the_score = tmpscore;
  85. }
  86. /* Return location used */
  87. return (slot);
  88. }
  89. /*
  90. * Display the scores in a given range.
  91. * Assumes the high score list is already open.
  92. * Only five entries per line, too much info.
  93. *
  94. * Mega-Hack -- allow "fake" entry at the given position.
  95. */
  96. void display_scores_aux(int from, int to, int note, high_score *score)
  97. {
  98. int i, j, k, n, place;
  99. byte attr;
  100. high_score the_score;
  101. char out_val[256];
  102. char tmp_val[160];
  103. /* Paranoia -- it may not have opened */
  104. if (highscore_fd < 0) return;
  105. /* Assume we will show the first 10 */
  106. if (from < 0) from = 0;
  107. if (to < 0) to = 10;
  108. if (to > MAX_HISCORES) to = MAX_HISCORES;
  109. /* Seek to the beginning */
  110. if (highscore_seek(0)) return;
  111. /* Hack -- Count the high scores */
  112. for (i = 0; i < MAX_HISCORES; i++)
  113. {
  114. if (highscore_read(&the_score)) break;
  115. }
  116. /* Hack -- allow "fake" entry to be last */
  117. if ((note == i) && score) i++;
  118. /* Forget about the last entries */
  119. if (i > to) i = to;
  120. /* Show 5 per page, until "done" */
  121. for (k = from, place = k+1; k < i; k += 5)
  122. {
  123. /* Clear screen */
  124. Term_clear();
  125. /* Title */
  126. put_str(" Zangband Hall of Fame", 0, 0);
  127. /* Indicate non-top scores */
  128. if (k > 0)
  129. {
  130. sprintf(tmp_val, "(from position %d)", k + 1);
  131. put_str(tmp_val, 0, 40);
  132. }
  133. /* Dump 5 entries */
  134. for (j = k, n = 0; j < i && n < 5; place++, j++, n++)
  135. {
  136. int pr, pc, clev, mlev, cdun, mdun;
  137. cptr user, gold, when, aged;
  138. /* Hack -- indicate death in yellow */
  139. attr = (j == note) ? TERM_YELLOW : TERM_WHITE;
  140. /* Mega-Hack -- insert a "fake" record */
  141. if ((note == j) && score)
  142. {
  143. the_score = (*score);
  144. attr = TERM_L_GREEN;
  145. score = NULL;
  146. note = -1;
  147. j--;
  148. }
  149. /* Read a normal record */
  150. else
  151. {
  152. /* Read the proper record */
  153. if (highscore_seek(j)) break;
  154. if (highscore_read(&the_score)) break;
  155. }
  156. /* Extract the race/class */
  157. pr = atoi(the_score.p_r);
  158. pc = atoi(the_score.p_c);
  159. /* Extract the level info */
  160. clev = atoi(the_score.cur_lev);
  161. mlev = atoi(the_score.max_lev);
  162. cdun = atoi(the_score.cur_dun);
  163. mdun = atoi(the_score.max_dun);
  164. /* Hack -- extract the gold and such */
  165. for (user = the_score.uid; isspace(*user); user++) /* loop */;
  166. for (when = the_score.day; isspace(*when); when++) /* loop */;
  167. for (gold = the_score.gold; isspace(*gold); gold++) /* loop */;
  168. for (aged = the_score.turns; isspace(*aged); aged++) /* loop */;
  169. /* Dump some info */
  170. sprintf(out_val, "%3d.%9s %s the %s %s, Level %d",
  171. place, the_score.pts, the_score.who,
  172. race_info[pr].title, class_info[pc].title,
  173. clev);
  174. /* Append a "maximum level" */
  175. if (mlev > clev) strcat(out_val, format(" (Max %d)", mlev));
  176. /* Dump the first line */
  177. c_put_str(attr, out_val, n*4 + 2, 0);
  178. /* Another line of info */
  179. sprintf(out_val, " Killed by %s on %s %d",
  180. the_score.how, "Dungeon Level", cdun);
  181. /* Some people die outside of the dungeon */
  182. if (!cdun)
  183. {
  184. /* Died in town */
  185. if (p_ptr->town_num)
  186. sprintf(out_val, " Killed by %s in the Town",
  187. the_score.how);
  188. /* Died in the wilderness */
  189. else
  190. sprintf(out_val, " Killed by %s in the Wilderness",
  191. the_score.how);
  192. }
  193. /* Append a "maximum level" */
  194. if (mdun > cdun) strcat(out_val, format(" (Max %d)", mdun));
  195. /* Dump the info */
  196. c_put_str(attr, out_val, n*4 + 3, 0);
  197. /* And still another line of info */
  198. sprintf(out_val,
  199. " (User %s, Date %s, Gold %s, Turn %s).",
  200. user, when, gold, aged);
  201. c_put_str(attr, out_val, n*4 + 4, 0);
  202. }
  203. /* Wait for response */
  204. prt("[Press ESC to quit, any other key to continue.]", 23, 17);
  205. j = inkey();
  206. prt("", 23, 0);
  207. /* Hack -- notice Escape */
  208. if (j == ESCAPE) break;
  209. }
  210. }
  211. /*
  212. * Hack -- Display the scores in a given range and quit.
  213. *
  214. * This function is only called from "main.c" when the user asks
  215. * to see the "high scores".
  216. */
  217. void display_scores(int from, int to)
  218. {
  219. char buf[1024];
  220. /* Build the filename */
  221. path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
  222. /* Open the binary high score file, for reading */
  223. highscore_fd = fd_open(buf, O_RDONLY);
  224. /* Paranoia -- No score file */
  225. if (highscore_fd < 0) quit("Score file unavailable.");
  226. /* Clear screen */
  227. Term_clear();
  228. /* Display the scores */
  229. display_scores_aux(from, to, -1, NULL);
  230. /* Shut the high score file */
  231. (void)fd_close(highscore_fd);
  232. /* Forget the high score fd */
  233. highscore_fd = -1;
  234. /* Quit */
  235. quit(NULL);
  236. }
  237. /*
  238. * Enters a players name on a hi-score table, if "legal", and in any
  239. * case, displays some relevant portion of the high score list.
  240. *
  241. * Assumes "signals_ignore_tstp()" has been called.
  242. */
  243. errr top_twenty(void)
  244. {
  245. int j;
  246. high_score the_score;
  247. time_t ct = time((time_t*)0);
  248. /* Clear screen */
  249. Term_clear();
  250. /* No score file */
  251. if (highscore_fd < 0)
  252. {
  253. msg_print("Score file unavailable.");
  254. msg_print(NULL);
  255. return (0);
  256. }
  257. #ifndef SCORE_WIZARDS
  258. /* Wizard-mode pre-empts scoring */
  259. if (noscore & 0x000F)
  260. {
  261. msg_print("Score not registered for wizards.");
  262. msg_print(NULL);
  263. display_scores_aux(0, 10, -1, NULL);
  264. return (0);
  265. }
  266. #endif
  267. #ifndef SCORE_BORGS
  268. /* Borg-mode pre-empts scoring */
  269. if (noscore & 0x00F0)
  270. {
  271. msg_print("Score not registered for borgs.");
  272. msg_print(NULL);
  273. display_scores_aux(0, 10, -1, NULL);
  274. return (0);
  275. }
  276. #endif
  277. #ifndef SCORE_CHEATERS
  278. /* Cheaters are not scored */
  279. if (noscore & 0xFF00)
  280. {
  281. msg_print("Score not registered for cheaters.");
  282. msg_print(NULL);
  283. display_scores_aux(0, 10, -1, NULL);
  284. return (0);
  285. }
  286. #endif
  287. /* Interupted */
  288. if (!total_winner && streq(died_from, "Interrupting"))
  289. {
  290. msg_print("Score not registered due to interruption.");
  291. msg_print(NULL);
  292. display_scores_aux(0, 10, -1, NULL);
  293. return (0);
  294. }
  295. /* Quitter */
  296. if (!total_winner && streq(died_from, "Quitting"))
  297. {
  298. msg_print("Score not registered due to quitting.");
  299. msg_print(NULL);
  300. display_scores_aux(0, 10, -1, NULL);
  301. return (0);
  302. }
  303. /* Clear the record */
  304. (void) WIPE(&the_score, high_score);
  305. /* Save the version */
  306. sprintf(the_score.what, "%u.%u.%u",
  307. VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
  308. /* Calculate and save the points */
  309. sprintf(the_score.pts, "%9lu", (long)total_points());
  310. the_score.pts[9] = '\0';
  311. /* Save the current gold */
  312. sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
  313. the_score.gold[9] = '\0';
  314. /* Save the current turn */
  315. sprintf(the_score.turns, "%9lu", (long)turn);
  316. the_score.turns[9] = '\0';
  317. #ifdef HIGHSCORE_DATE_HACK
  318. /* Save the date in a hacked up form (9 chars) */
  319. (void)sprintf(the_score.day, "%-.6s %-.2s", ctime(&ct) + 4, ctime(&ct) + 22);
  320. #else
  321. /* Save the date in standard form (8 chars) */
  322. (void)strftime(the_score.day, 9, "%m/%d/%y", localtime(&ct));
  323. #endif
  324. /* Save the player name (15 chars) */
  325. sprintf(the_score.who, "%-.15s", player_name);
  326. /* Save the player info XXX XXX XXX */
  327. sprintf(the_score.uid, "%7u", player_uid);
  328. sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f'));
  329. sprintf(the_score.p_r, "%2d", p_ptr->prace);
  330. sprintf(the_score.p_c, "%2d", p_ptr->pclass);
  331. /* Save the level and such */
  332. sprintf(the_score.cur_lev, "%3d", p_ptr->lev);
  333. sprintf(the_score.cur_dun, "%3d", dun_level);
  334. sprintf(the_score.max_lev, "%3d", p_ptr->max_plv);
  335. sprintf(the_score.max_dun, "%3d", p_ptr->max_dlv);
  336. /* Save the cause of death (31 chars) */
  337. sprintf(the_score.how, "%-.31s", died_from);
  338. /* Lock (for writing) the highscore file, or fail */
  339. if (fd_lock(highscore_fd, F_WRLCK)) return (1);
  340. /* Add a new entry to the score list, see where it went */
  341. j = highscore_add(&the_score);
  342. /* Unlock the highscore file, or fail */
  343. if (fd_lock(highscore_fd, F_UNLCK)) return (1);
  344. /* Hack -- Display the top fifteen scores */
  345. if (j < 10)
  346. {
  347. display_scores_aux(0, 15, j, NULL);
  348. }
  349. /* Display the scores surrounding the player */
  350. else
  351. {
  352. display_scores_aux(0, 5, j, NULL);
  353. display_scores_aux(j - 2, j + 7, j, NULL);
  354. }
  355. /* Success */
  356. return (0);
  357. }
  358. /*
  359. * Predict the players location, and display it.
  360. */
  361. errr predict_score(void)
  362. {
  363. int j;
  364. high_score the_score;
  365. /* No score file */
  366. if (highscore_fd < 0)
  367. {
  368. msg_print("Score file unavailable.");
  369. msg_print(NULL);
  370. return (0);
  371. }
  372. /* Save the version */
  373. sprintf(the_score.what, "%u.%u.%u",
  374. VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
  375. /* Calculate and save the points */
  376. sprintf(the_score.pts, "%9lu", (long)total_points());
  377. /* Save the current gold */
  378. sprintf(the_score.gold, "%9lu", (long)p_ptr->au);
  379. /* Save the current turn */
  380. sprintf(the_score.turns, "%9lu", (long)turn);
  381. /* Hack -- no time needed */
  382. strcpy(the_score.day, "TODAY");
  383. /* Save the player name (15 chars) */
  384. sprintf(the_score.who, "%-.15s", player_name);
  385. /* Save the player info XXX XXX XXX */
  386. sprintf(the_score.uid, "%7u", player_uid);
  387. sprintf(the_score.sex, "%c", (p_ptr->psex ? 'm' : 'f'));
  388. sprintf(the_score.p_r, "%2d", p_ptr->prace);
  389. sprintf(the_score.p_c, "%2d", p_ptr->pclass);
  390. /* Save the level and such */
  391. sprintf(the_score.cur_lev, "%3d", p_ptr->lev);
  392. sprintf(the_score.cur_dun, "%3d", dun_level);
  393. sprintf(the_score.max_lev, "%3d", p_ptr->max_plv);
  394. sprintf(the_score.max_dun, "%3d", p_ptr->max_dlv);
  395. /* Hack -- no cause of death */
  396. strcpy(the_score.how, "nobody (yet!)");
  397. /* See where the entry would be placed */
  398. j = highscore_where(&the_score);
  399. /* Hack -- Display the top fifteen scores */
  400. if (j < 10)
  401. {
  402. display_scores_aux(0, 15, j, &the_score);
  403. }
  404. /* Display some "useful" scores */
  405. else
  406. {
  407. display_scores_aux(0, 5, -1, NULL);
  408. display_scores_aux(j - 2, j + 7, j, &the_score);
  409. }
  410. /* Success */
  411. return (0);
  412. }
  413. /*
  414. * show_highclass - selectively list highscores based on class
  415. * -KMW-
  416. */
  417. void show_highclass(int building)
  418. {
  419. register int i = 0, j, m = 0;
  420. int pr, pc, clev/*, al*/;
  421. high_score the_score;
  422. char buf[1024], out_val[256];
  423. #if 0
  424. switch (building)
  425. {
  426. case 1:
  427. prt(" Busts of Greatest Kings", 5, 0);
  428. break;
  429. case 2:
  430. prt(" Plaque - Greatest Arena Champions", 5, 0);
  431. break;
  432. case 10:
  433. prt(" Plaque - Greatest Fighters", 5, 0);
  434. break;
  435. case 11:
  436. prt(" Spires of the Greatest Magic-Users", 5, 0);
  437. break;
  438. case 12:
  439. prt(" Busts of Greatest Priests", 5, 0);
  440. break;
  441. case 13:
  442. prt(" Wall Inscriptions - Greatest Thieves", 5, 0);
  443. break;
  444. case 14:
  445. prt(" Plaque - Greatest Rangers", 5, 0);
  446. break;
  447. case 15:
  448. prt(" Plaque - Greatest Paladins", 5, 0);
  449. break;
  450. case 16:
  451. prt(" Spires of the Greatest Illusionists", 5, 0);
  452. break;
  453. default:
  454. bell();
  455. break;
  456. }
  457. #endif
  458. /* Build the filename */
  459. path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
  460. highscore_fd = fd_open(buf, O_RDONLY);
  461. if (highscore_fd < 0)
  462. {
  463. msg_print("Score file unavailable.");
  464. msg_print(NULL);
  465. return;
  466. }
  467. if (highscore_seek(0)) return;
  468. for (i = 0; i < MAX_HISCORES; i++)
  469. if (highscore_read(&the_score)) break;
  470. m = 0;
  471. j = 0;
  472. clev = 0;
  473. while ((m < 9) || (j < MAX_HISCORES))
  474. {
  475. if (highscore_seek(j)) break;
  476. if (highscore_read(&the_score)) break;
  477. pr = atoi(the_score.p_r);
  478. pc = atoi(the_score.p_c);
  479. clev = atoi(the_score.cur_lev);
  480. sprintf(out_val, "%3d) %s the %s (Level %2d)",
  481. (m + 1), the_score.who, race_info[pr].title, clev);
  482. prt(out_val, (m + 7), 0);
  483. m++;
  484. j++;
  485. }
  486. sprintf(out_val, "You) %s the %s (Level %2d)",
  487. player_name, race_info[p_ptr->prace].title, p_ptr->lev);
  488. prt(out_val, (m + 8), 0);
  489. (void)fd_close(highscore_fd);
  490. highscore_fd = -1;
  491. msg_print("Hit any key to continue");
  492. msg_print(NULL);
  493. for (j = 5; j < 18; j++) prt("", j, 0);
  494. }
  495. /*
  496. * Race Legends
  497. * -KMW-
  498. */
  499. void race_score(int race_num)
  500. {
  501. register int i = 0, j, m = 0;
  502. int pr, pc, clev, lastlev;
  503. high_score the_score;
  504. char buf[1024], out_val[256], tmp_str[80];
  505. lastlev = 0;
  506. /* rr9: TODO - pluralize the race */
  507. sprintf(tmp_str,"The Greatest of all the %s", race_info[race_num].title);
  508. prt(tmp_str, 5, 15);
  509. /* Build the filename */
  510. path_build(buf, 1024, ANGBAND_DIR_APEX, "scores.raw");
  511. highscore_fd = fd_open(buf, O_RDONLY);
  512. if (highscore_fd < 0)
  513. {
  514. msg_print("Score file unavailable.");
  515. msg_print(NULL);
  516. return;
  517. }
  518. if (highscore_seek(0)) return;
  519. for (i = 0; i < MAX_HISCORES; i++)
  520. {
  521. if (highscore_read(&the_score)) break;
  522. }
  523. m = 0;
  524. j = 0;
  525. while ((m < 10) || (j < MAX_HISCORES))
  526. {
  527. if (highscore_seek(j)) break;
  528. if (highscore_read(&the_score)) break;
  529. pr = atoi(the_score.p_r);
  530. pc = atoi(the_score.p_c);
  531. clev = atoi(the_score.cur_lev);
  532. if (pr == race_num)
  533. {
  534. sprintf(out_val, "%3d) %s the %s (Level %3d)",
  535. (m + 1), the_score.who,
  536. race_info[pr].title, clev);
  537. prt(out_val, (m + 7), 0);
  538. m++;
  539. lastlev = clev;
  540. }
  541. j++;
  542. }
  543. /* add player if qualified */
  544. if ((p_ptr->prace == race_num) && (p_ptr->lev >= lastlev))
  545. {
  546. sprintf(out_val, "You) %s the %s (Level %3d)",
  547. player_name, race_info[p_ptr->prace].title, p_ptr->lev);
  548. prt(out_val, (m + 8), 0);
  549. }
  550. (void)fd_close(highscore_fd);
  551. highscore_fd = -1;
  552. }
  553. /*
  554. * Race Legends
  555. * -KMW-
  556. */
  557. void race_legends(void)
  558. {
  559. int i, j;
  560. for (i = 0; i < MAX_RACES; i++)
  561. {
  562. race_score(i);
  563. msg_print("Hit any key to continue");
  564. msg_print(NULL);
  565. for (j = 5; j < 19; j++)
  566. prt("", j, 0);
  567. }
  568. }
  569. /*
  570. * Change the player into a King! -RAK-
  571. */
  572. void kingly(void)
  573. {
  574. /* Hack -- retire in town */
  575. dun_level = 0;
  576. /* Fake death */
  577. (void)strcpy(died_from, "Ripe Old Age");
  578. /* Restore the experience */
  579. p_ptr->exp = p_ptr->max_exp;
  580. /* Restore the level */
  581. p_ptr->lev = p_ptr->max_plv;
  582. /* Hack -- Instant Gold */
  583. p_ptr->au += 10000000L;
  584. /* Clear screen */
  585. Term_clear();
  586. /* Display a crown */
  587. put_str("#", 1, 34);
  588. put_str("#####", 2, 32);
  589. put_str("#", 3, 34);
  590. put_str(",,, $$$ ,,,", 4, 28);
  591. put_str(",,=$ \"$$$$$\" $=,,", 5, 24);
  592. put_str(",$$ $$$ $$,", 6, 22);
  593. put_str("*> <*> <*", 7, 22);
  594. put_str("$$ $$$ $$", 8, 22);
  595. put_str("\"$$ $$$ $$\"", 9, 22);
  596. put_str("\"$$ $$$ $$\"", 10, 23);
  597. put_str("*#########*#########*", 11, 24);
  598. put_str("*#########*#########*", 12, 24);
  599. /* Display a message */
  600. put_str("Veni, Vidi, Vici!", 15, 26);
  601. put_str("I came, I saw, I conquered!", 16, 21);
  602. put_str(format("All Hail the Mighty %s!", sp_ptr->winner), 17, 22);
  603. /* Flush input */
  604. flush();
  605. /* Wait for response */
  606. pause_line(23);
  607. }