main.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. /* $NetBSD: main.c,v 1.15 2004/12/09 05:15:59 jmc Exp $ */
  2. /*
  3. * Phantasia 3.3.2 -- Interterminal fantasy game
  4. *
  5. * Edward A. Estes
  6. * AT&T, March 12, 1986
  7. */
  8. /* DISCLAIMER:
  9. *
  10. * This game is distributed for free as is. It is not guaranteed to work
  11. * in every conceivable environment. It is not even guaranteed to work
  12. * in ANY environment.
  13. *
  14. * This game is distributed without notice of copyright, therefore it
  15. * may be used in any manner the recipient sees fit. However, the
  16. * author assumes no responsibility for maintaining or revising this
  17. * game, in its original form, or any derivitives thereof.
  18. *
  19. * The author shall not be responsible for any loss, cost, or damage,
  20. * including consequential damage, caused by reliance on this material.
  21. *
  22. * The author makes no warranties, express or implied, including warranties
  23. * of merchantability or fitness for a particular purpose or use.
  24. *
  25. * AT&T is in no way connected with this game.
  26. */
  27. #include <sys/stat.h>
  28. #include <sys/types.h>
  29. #include <pwd.h>
  30. #include <termios.h>
  31. /*
  32. * The program allocates as much file space as it needs to store characters,
  33. * so the possibility exists for the character file to grow without bound.
  34. * The file is purged upon normal entry to try to avoid that problem.
  35. * A similar problem exists for energy voids. To alleviate the problem here,
  36. * the void file is cleared with every new king, and a limit is placed
  37. * on the size of the energy void file.
  38. */
  39. /*
  40. * Put one line of text into the file 'motd' for announcements, etc.
  41. */
  42. /*
  43. * The scoreboard file is updated when someone dies, and keeps track
  44. * of the highest character to date for that login.
  45. * Being purged from the character file does not cause the scoreboard
  46. * to be updated.
  47. */
  48. /*
  49. * main.c Main routines for Phantasia
  50. */
  51. #include "include.h"
  52. #undef bool
  53. #include <curses.h>
  54. int main(int, char **);
  55. int
  56. main(argc, argv)
  57. int argc;
  58. char **argv;
  59. {
  60. bool noheader = FALSE; /* set if don't want header */
  61. bool headeronly = FALSE; /* set if only want header */
  62. bool examine = FALSE; /* set if examine a character */
  63. time_t seconds; /* for time of day */
  64. double dtemp; /* for temporary calculations */
  65. initialstate(); /* init globals */
  66. /* process arguments */
  67. while (--argc && (*++argv)[0] == '-')
  68. switch ((*argv)[1]) {
  69. case 's': /* short */
  70. noheader = TRUE;
  71. break;
  72. case 'H': /* Header */
  73. headeronly = TRUE;
  74. break;
  75. case 'a': /* all users */
  76. activelist();
  77. cleanup(TRUE);
  78. /* NOTREACHED */
  79. case 'p': /* purge old players */
  80. purgeoldplayers();
  81. cleanup(TRUE);
  82. /* NOTREACHED */
  83. case 'S': /* set 'Wizard' */
  84. Wizard = !getuid();
  85. break;
  86. case 'x': /* examine */
  87. examine = TRUE;
  88. break;
  89. case 'm': /* monsters */
  90. monstlist();
  91. cleanup(TRUE);
  92. /* NOTREACHED */
  93. case 'b': /* scoreboard */
  94. scorelist();
  95. cleanup(TRUE);
  96. /* NOTREACHED */
  97. }
  98. if (!isatty(0)) /* don't let non-tty's play */
  99. cleanup(TRUE);
  100. /* NOTREACHED */
  101. playinit(); /* set up to catch signals, init curses */
  102. if (examine) {
  103. changestats(FALSE);
  104. cleanup(TRUE);
  105. /* NOTREACHED */
  106. }
  107. if (!noheader) {
  108. titlelist();
  109. purgeoldplayers(); /* clean up old characters */
  110. }
  111. if (headeronly)
  112. cleanup(TRUE);
  113. /* NOTREACHED */
  114. do
  115. /* get the player structure filled */
  116. {
  117. Fileloc = -1L;
  118. mvaddstr(22, 17, "Do you have a character to run [Q = Quit] ? ");
  119. switch (getanswer("NYQ", FALSE)) {
  120. case 'Y':
  121. Fileloc = recallplayer();
  122. break;
  123. case 'Q':
  124. cleanup(TRUE);
  125. /* NOTREACHED */
  126. default:
  127. Fileloc = rollnewplayer();
  128. break;
  129. }
  130. clear();
  131. }
  132. while (Fileloc < 0L);
  133. if (Player.p_level > 5.0)
  134. /* low level players have long timeout */
  135. Timeout = TRUE;
  136. /* update some important player statistics */
  137. strcpy(Player.p_login, Login);
  138. time(&seconds);
  139. Player.p_lastused = localtime(&seconds)->tm_yday;
  140. Player.p_status = S_PLAYING;
  141. writerecord(&Player, Fileloc);
  142. Statptr = &Stattable[Player.p_type]; /* initialize pointer */
  143. /* catch interrupts */
  144. #ifdef BSD41
  145. sigset(SIGINT, interrupt);
  146. #endif
  147. #ifdef BSD42
  148. signal(SIGINT, interrupt);
  149. #endif
  150. #ifdef SYS3
  151. signal(SIGINT, interrupt);
  152. #endif
  153. #ifdef SYS5
  154. signal(SIGINT, interrupt);
  155. #endif
  156. altercoordinates(Player.p_x, Player.p_y, A_FORCED); /* set some flags */
  157. clear();
  158. for (;;)
  159. /* loop forever, processing input */
  160. {
  161. adjuststats(); /* cleanup stats */
  162. if (Throne && Player.p_crowns == 0 && Player.p_specialtype != SC_KING)
  163. /* not allowed on throne -- move */
  164. {
  165. mvaddstr(5, 0, "You're not allowed in the Lord's Chamber without a crown.\n");
  166. altercoordinates(0.0, 0.0, A_NEAR);
  167. }
  168. checktampered();/* check for energy voids, etc. */
  169. if (Player.p_status != S_CLOAKED
  170. /* not cloaked */
  171. && (dtemp = fabs(Player.p_x)) == fabs(Player.p_y)
  172. /* |x| = |y| */
  173. && !Throne)
  174. /* not on throne */
  175. {
  176. dtemp = sqrt(dtemp / 100.0);
  177. if (floor(dtemp) == dtemp)
  178. /* |x| / 100 == n*n; at a trading post */
  179. {
  180. tradingpost();
  181. clear();
  182. }
  183. }
  184. checkbattle(); /* check for player to player battle */
  185. neatstuff(); /* gurus, medics, etc. */
  186. if (Player.p_status == S_CLOAKED) {
  187. /* costs 3 mana per turn to be cloaked */
  188. if (Player.p_mana > 3.0)
  189. Player.p_mana -= 3.0;
  190. else
  191. /* ran out of mana, uncloak */
  192. {
  193. Player.p_status = S_PLAYING;
  194. Changed = TRUE;
  195. }
  196. }
  197. if (Player.p_status != S_PLAYING && Player.p_status != S_CLOAKED)
  198. /* change status back to S_PLAYING */
  199. {
  200. Player.p_status = S_PLAYING;
  201. Changed = TRUE;
  202. }
  203. if (Changed)
  204. /* update file only if important stuff has changed */
  205. {
  206. writerecord(&Player, Fileloc);
  207. Changed = FALSE;
  208. continue;
  209. }
  210. readmessage(); /* read message, if any */
  211. displaystats(); /* print statistics */
  212. move(6, 0);
  213. if (Throne)
  214. /* maybe make king, print prompt, etc. */
  215. throneroom();
  216. /* print status line */
  217. addstr("1:Move 2:Players 3:Talk 4:Stats 5:Quit ");
  218. if (Player.p_level >= MEL_CLOAK && Player.p_magiclvl >= ML_CLOAK)
  219. addstr("6:Cloak ");
  220. if (Player.p_level >= MEL_TELEPORT && Player.p_magiclvl >= ML_TELEPORT)
  221. addstr("7:Teleport ");
  222. if (Player.p_specialtype >= SC_COUNCIL || Wizard)
  223. addstr("8:Intervene ");
  224. procmain(); /* process input */
  225. }
  226. }
  227. void
  228. initialstate()
  229. {
  230. struct stat sb;
  231. Beyond = FALSE;
  232. Marsh = FALSE;
  233. Throne = FALSE;
  234. Changed = FALSE;
  235. Wizard = FALSE;
  236. Timeout = FALSE;
  237. Users = 0;
  238. Windows = FALSE;
  239. Echo = TRUE;
  240. /* setup login name */
  241. if ((Login = getlogin()) == NULL)
  242. Login = getpwuid(getuid())->pw_name;
  243. /* open some files */
  244. if ((Playersfp = fopen(_PATH_PEOPLE, "r+")) == NULL)
  245. error(_PATH_PEOPLE);
  246. /* NOTREACHED */
  247. if (fileno(Playersfp) < 3)
  248. exit(1);
  249. if ((Monstfp = fopen(_PATH_MONST, "r+")) == NULL)
  250. error(_PATH_MONST);
  251. /* NOTREACHED */
  252. if ((Messagefp = fopen(_PATH_MESS, "r")) == NULL)
  253. error(_PATH_MESS);
  254. /* NOTREACHED */
  255. if ((Energyvoidfp = fopen(_PATH_VOID, "r+")) == NULL)
  256. error(_PATH_VOID);
  257. if (fstat(fileno(Energyvoidfp), &sb) == -1)
  258. error("stat");
  259. if (sb.st_size == 0) {
  260. /* initialize grail to new location */
  261. Enrgyvoid.ev_active = TRUE;
  262. Enrgyvoid.ev_x = ROLL(-1.0e6, 2.0e6);
  263. Enrgyvoid.ev_y = ROLL(-1.0e6, 2.0e6);
  264. writevoid(&Enrgyvoid, 0L);
  265. }
  266. /* NOTREACHED */
  267. srandom((unsigned) time(NULL)); /* prime random numbers */
  268. }
  269. long
  270. rollnewplayer()
  271. {
  272. int chartype; /* character type */
  273. int ch; /* input */
  274. initplayer(&Player); /* initialize player structure */
  275. clear();
  276. mvaddstr(4, 21, "Which type of character do you want:");
  277. mvaddstr(8, 4,
  278. "1:Magic User 2:Fighter 3:Elf 4:Dwarf 5:Halfling 6:Experimento ");
  279. if (Wizard) {
  280. addstr("7:Super ? ");
  281. chartype = getanswer("1234567", FALSE);
  282. } else {
  283. addstr("? ");
  284. chartype = getanswer("123456", FALSE);
  285. }
  286. do {
  287. genchar(chartype); /* roll up a character */
  288. /* print out results */
  289. mvprintw(12, 14,
  290. "Strength : %2.0f Quickness: %2.0f Mana : %2.0f\n",
  291. Player.p_strength, Player.p_quickness, Player.p_mana);
  292. mvprintw(13, 14,
  293. "Energy Level: %2.0f Brains : %2.0f Magic Level: %2.0f\n",
  294. Player.p_energy, Player.p_brains, Player.p_magiclvl);
  295. if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
  296. break;
  297. mvaddstr(14, 14, "Type '1' to keep >");
  298. ch = getanswer(" ", TRUE);
  299. }
  300. while (ch != '1');
  301. if (Player.p_type == C_EXPER || Player.p_type == C_SUPER)
  302. /* get coordinates for experimento */
  303. for (;;) {
  304. mvaddstr(16, 0, "Enter the X Y coordinates of your experimento ? ");
  305. getstring(Databuf, SZ_DATABUF);
  306. sscanf(Databuf, "%lf %lf", &Player.p_x, &Player.p_y);
  307. if (fabs(Player.p_x) > D_EXPER || fabs(Player.p_y) > D_EXPER)
  308. mvaddstr(17, 0, "Invalid coordinates. Try again.\n");
  309. else
  310. break;
  311. }
  312. for (;;)
  313. /* name the new character */
  314. {
  315. mvprintw(18, 0,
  316. "Give your character a name [up to %d characters] ? ", SZ_NAME - 1);
  317. getstring(Player.p_name, SZ_NAME);
  318. truncstring(Player.p_name); /* remove trailing blanks */
  319. if (Player.p_name[0] == '\0')
  320. /* no null names */
  321. mvaddstr(19, 0, "Invalid name.");
  322. else
  323. if (findname(Player.p_name, &Other) >= 0L)
  324. /* cannot have duplicate names */
  325. mvaddstr(19, 0, "Name already in use.");
  326. else
  327. /* name is acceptable */
  328. break;
  329. addstr(" Pick another.\n");
  330. }
  331. /* get a password for character */
  332. Echo = FALSE;
  333. do {
  334. mvaddstr(20, 0, "Give your character a password [up to 8 characters] ? ");
  335. getstring(Player.p_password, SZ_PASSWORD);
  336. mvaddstr(21, 0, "Enter again to verify: ");
  337. getstring(Databuf, SZ_PASSWORD);
  338. }
  339. while (strcmp(Player.p_password, Databuf) != 0);
  340. Echo = TRUE;
  341. return (allocrecord());
  342. }
  343. void
  344. procmain()
  345. {
  346. int ch; /* input */
  347. double x; /* desired new x coordinate */
  348. double y; /* desired new y coordinate */
  349. double temp; /* for temporary calculations */
  350. FILE *fp; /* for opening files */
  351. int loop; /* a loop counter */
  352. bool hasmoved = FALSE; /* set if player has moved */
  353. ch = inputoption();
  354. mvaddstr(4, 0, "\n\n"); /* clear status area */
  355. move(7, 0);
  356. clrtobot(); /* clear data on bottom area of screen */
  357. if (Player.p_specialtype == SC_VALAR && (ch == '1' || ch == '7'))
  358. /* valar cannot move */
  359. ch = ' ';
  360. switch (ch) {
  361. case 'K': /* move up/north */
  362. case 'N':
  363. x = Player.p_x;
  364. y = Player.p_y + MAXMOVE();
  365. hasmoved = TRUE;
  366. break;
  367. case 'J': /* move down/south */
  368. case 'S':
  369. x = Player.p_x;
  370. y = Player.p_y - MAXMOVE();
  371. hasmoved = TRUE;
  372. break;
  373. case 'L': /* move right/east */
  374. case 'E':
  375. x = Player.p_x + MAXMOVE();
  376. y = Player.p_y;
  377. hasmoved = TRUE;
  378. break;
  379. case 'H': /* move left/west */
  380. case 'W':
  381. x = Player.p_x - MAXMOVE();
  382. y = Player.p_y;
  383. hasmoved = TRUE;
  384. break;
  385. default: /* rest */
  386. Player.p_energy += (Player.p_maxenergy + Player.p_shield) / 15.0
  387. + Player.p_level / 3.0 + 2.0;
  388. Player.p_energy =
  389. MIN(Player.p_energy, Player.p_maxenergy + Player.p_shield);
  390. if (Player.p_status != S_CLOAKED)
  391. /* cannot find mana if cloaked */
  392. {
  393. Player.p_mana += (Circle + Player.p_level) / 4.0;
  394. if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
  395. /* wandering monster */
  396. encounter(-1);
  397. }
  398. break;
  399. case 'X': /* change/examine a character */
  400. changestats(TRUE);
  401. break;
  402. case '1': /* move */
  403. for (loop = 3; loop; --loop) {
  404. mvaddstr(4, 0, "X Y Coordinates ? ");
  405. getstring(Databuf, SZ_DATABUF);
  406. if (sscanf(Databuf, "%lf %lf", &x, &y) != 2)
  407. mvaddstr(5, 0, "Try again\n");
  408. else
  409. if (distance(Player.p_x, x, Player.p_y, y) > MAXMOVE())
  410. ILLMOVE();
  411. else {
  412. hasmoved = TRUE;
  413. break;
  414. }
  415. }
  416. break;
  417. case '2': /* players */
  418. userlist(TRUE);
  419. break;
  420. case '3': /* message */
  421. mvaddstr(4, 0, "Message ? ");
  422. getstring(Databuf, SZ_DATABUF);
  423. /* we open the file for writing to erase any data which is
  424. * already there */
  425. fp = fopen(_PATH_MESS, "w");
  426. if (Databuf[0] != '\0')
  427. fprintf(fp, "%s: %s", Player.p_name, Databuf);
  428. fclose(fp);
  429. break;
  430. case '4': /* stats */
  431. allstatslist();
  432. break;
  433. case '5': /* good-bye */
  434. leavegame();
  435. /* NOTREACHED */
  436. case '6': /* cloak */
  437. if (Player.p_level < MEL_CLOAK || Player.p_magiclvl < ML_CLOAK)
  438. ILLCMD();
  439. else
  440. if (Player.p_status == S_CLOAKED)
  441. Player.p_status = S_PLAYING;
  442. else
  443. if (Player.p_mana < MM_CLOAK)
  444. mvaddstr(5, 0, "No mana left.\n");
  445. else {
  446. Changed = TRUE;
  447. Player.p_mana -= MM_CLOAK;
  448. Player.p_status = S_CLOAKED;
  449. }
  450. break;
  451. case '7': /* teleport */
  452. /*
  453. * conditions for teleport
  454. * - 20 per (level plus magic level)
  455. * - OR council of the wise or valar or ex-valar
  456. * - OR transport from throne
  457. * transports from throne cost no mana
  458. */
  459. if (Player.p_level < MEL_TELEPORT || Player.p_magiclvl < ML_TELEPORT)
  460. ILLCMD();
  461. else
  462. for (loop = 3; loop; --loop) {
  463. mvaddstr(4, 0, "X Y Coordinates ? ");
  464. getstring(Databuf, SZ_DATABUF);
  465. if (sscanf(Databuf, "%lf %lf", &x, &y) == 2) {
  466. temp = distance(Player.p_x, x, Player.p_y, y);
  467. if (!Throne
  468. /* can transport anywhere from throne */
  469. && Player.p_specialtype <= SC_COUNCIL
  470. /* council, valar can transport
  471. * anywhere */
  472. && temp > (Player.p_level + Player.p_magiclvl) * 20.0)
  473. /* can only move 20 per exp.
  474. * level + mag. level */
  475. ILLMOVE();
  476. else {
  477. temp = (temp / 75.0 + 1.0) * 20.0; /* mana used */
  478. if (!Throne && temp > Player.p_mana)
  479. mvaddstr(5, 0, "Not enough power for that distance.\n");
  480. else {
  481. if (!Throne)
  482. Player.p_mana -= temp;
  483. hasmoved = TRUE;
  484. break;
  485. }
  486. }
  487. }
  488. }
  489. break;
  490. case 'C':
  491. case '9': /* monster */
  492. if (Throne)
  493. /* no monsters while on throne */
  494. mvaddstr(5, 0, "No monsters in the chamber!\n");
  495. else
  496. if (Player.p_specialtype != SC_VALAR)
  497. /* the valar cannot call monsters */
  498. {
  499. Player.p_sin += 1e-6;
  500. encounter(-1);
  501. }
  502. break;
  503. case '0': /* decree */
  504. if (Wizard || (Player.p_specialtype == SC_KING && Throne))
  505. /* kings must be on throne to decree */
  506. dotampered();
  507. else
  508. ILLCMD();
  509. break;
  510. case '8': /* intervention */
  511. if (Wizard || Player.p_specialtype >= SC_COUNCIL)
  512. dotampered();
  513. else
  514. ILLCMD();
  515. break;
  516. }
  517. if (hasmoved)
  518. /* player has moved -- alter coordinates, and do random
  519. * monster */
  520. {
  521. altercoordinates(x, y, A_SPECIFIC);
  522. if (drandom() < 0.2 && Player.p_status == S_PLAYING && !Throne)
  523. encounter(-1);
  524. }
  525. }
  526. void
  527. titlelist()
  528. {
  529. FILE *fp; /* used for opening various files */
  530. bool councilfound = FALSE; /* set if we find a member of the
  531. * council */
  532. bool kingfound = FALSE; /* set if we find a king */
  533. double hiexp, nxtexp; /* used for finding the two highest players */
  534. double hilvl, nxtlvl; /* used for finding the two highest players */
  535. char hiname[21], nxtname[21]; /* used for finding the two
  536. * highest players */
  537. nxtexp = 0;
  538. mvaddstr(0, 14,
  539. "W e l c o m e t o P h a n t a s i a (vers. 3.3.2)!");
  540. /* print message of the day */
  541. if ((fp = fopen(_PATH_MOTD, "r")) != NULL
  542. && fgets(Databuf, SZ_DATABUF, fp) != NULL) {
  543. mvaddstr(2, 40 - strlen(Databuf) / 2, Databuf);
  544. fclose(fp);
  545. }
  546. /* search for king */
  547. fseek(Playersfp, 0L, SEEK_SET);
  548. while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
  549. if (Other.p_specialtype == SC_KING &&
  550. Other.p_status != S_NOTUSED)
  551. /* found the king */
  552. {
  553. sprintf(Databuf, "The present ruler is %s Level:%.0f",
  554. Other.p_name, Other.p_level);
  555. mvaddstr(4, 40 - strlen(Databuf) / 2, Databuf);
  556. kingfound = TRUE;
  557. break;
  558. }
  559. if (!kingfound)
  560. mvaddstr(4, 24, "There is no ruler at this time.");
  561. /* search for valar */
  562. fseek(Playersfp, 0L, SEEK_SET);
  563. while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
  564. if (Other.p_specialtype == SC_VALAR && Other.p_status != S_NOTUSED)
  565. /* found the valar */
  566. {
  567. sprintf(Databuf, "The Valar is %s Login: %s", Other.p_name, Other.p_login);
  568. mvaddstr(6, 40 - strlen(Databuf) / 2, Databuf);
  569. break;
  570. }
  571. /* search for council of the wise */
  572. fseek(Playersfp, 0L, SEEK_SET);
  573. Lines = 10;
  574. while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
  575. if (Other.p_specialtype == SC_COUNCIL && Other.p_status != S_NOTUSED)
  576. /* found a member of the council */
  577. {
  578. if (!councilfound) {
  579. mvaddstr(8, 30, "Council of the Wise:");
  580. councilfound = TRUE;
  581. }
  582. /* This assumes a finite (<=5) number of C.O.W.: */
  583. sprintf(Databuf, "%s Login: %s", Other.p_name, Other.p_login);
  584. mvaddstr(Lines++, 40 - strlen(Databuf) / 2, Databuf);
  585. }
  586. /* search for the two highest players */
  587. nxtname[0] = hiname[0] = '\0';
  588. hiexp = 0.0;
  589. nxtlvl = hilvl = 0;
  590. fseek(Playersfp, 0L, SEEK_SET);
  591. while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
  592. if (Other.p_experience > hiexp && Other.p_specialtype <= SC_KING && Other.p_status != S_NOTUSED)
  593. /* highest found so far */
  594. {
  595. nxtexp = hiexp;
  596. hiexp = Other.p_experience;
  597. nxtlvl = hilvl;
  598. hilvl = Other.p_level;
  599. strcpy(nxtname, hiname);
  600. strcpy(hiname, Other.p_name);
  601. } else
  602. if (Other.p_experience > nxtexp
  603. && Other.p_specialtype <= SC_KING
  604. && Other.p_status != S_NOTUSED)
  605. /* next highest found so far */
  606. {
  607. nxtexp = Other.p_experience;
  608. nxtlvl = Other.p_level;
  609. strcpy(nxtname, Other.p_name);
  610. }
  611. mvaddstr(15, 28, "Highest characters are:");
  612. sprintf(Databuf, "%s Level:%.0f and %s Level:%.0f",
  613. hiname, hilvl, nxtname, nxtlvl);
  614. mvaddstr(17, 40 - strlen(Databuf) / 2, Databuf);
  615. /* print last to die */
  616. if ((fp = fopen(_PATH_LASTDEAD, "r")) != NULL
  617. && fgets(Databuf, SZ_DATABUF, fp) != NULL) {
  618. mvaddstr(19, 25, "The last character to die was:");
  619. mvaddstr(20, 40 - strlen(Databuf) / 2, Databuf);
  620. fclose(fp);
  621. }
  622. refresh();
  623. }
  624. long
  625. recallplayer()
  626. {
  627. long loc = 0L; /* location in player file */
  628. int loop; /* loop counter */
  629. int ch; /* input */
  630. clear();
  631. mvprintw(10, 0, "What was your character's name ? ");
  632. getstring(Databuf, SZ_NAME);
  633. truncstring(Databuf);
  634. if ((loc = findname(Databuf, &Player)) >= 0L)
  635. /* found character */
  636. {
  637. Echo = FALSE;
  638. for (loop = 0; loop < 2; ++loop) {
  639. /* prompt for password */
  640. mvaddstr(11, 0, "Password ? ");
  641. getstring(Databuf, SZ_PASSWORD);
  642. if (strcmp(Databuf, Player.p_password) == 0)
  643. /* password good */
  644. {
  645. Echo = TRUE;
  646. if (Player.p_status != S_OFF)
  647. /* player did not exit normally last
  648. * time */
  649. {
  650. clear();
  651. addstr("Your character did not exit normally last time.\n");
  652. addstr("If you think you have good cause to have your character saved,\n");
  653. printw("you may quit and mail your reason to 'root'.\n");
  654. addstr("Otherwise, continuing spells certain death.\n");
  655. addstr("Do you want to quit ? ");
  656. ch = getanswer("YN", FALSE);
  657. if (ch == 'Y') {
  658. Player.p_status = S_HUNGUP;
  659. writerecord(&Player, loc);
  660. cleanup(TRUE);
  661. /* NOTREACHED */
  662. }
  663. death("Stupidity");
  664. /* NOTREACHED */
  665. }
  666. return (loc);
  667. } else
  668. mvaddstr(12, 0, "No good.\n");
  669. }
  670. Echo = TRUE;
  671. } else
  672. mvaddstr(11, 0, "Not found.\n");
  673. more(13);
  674. return (-1L);
  675. }
  676. void
  677. neatstuff()
  678. {
  679. double temp; /* for temporary calculations */
  680. int ch; /* input */
  681. switch ((int) ROLL(0.0, 100.0)) {
  682. case 1:
  683. case 2:
  684. if (Player.p_poison > 0.0) {
  685. mvaddstr(4, 0, "You've found a medic! How much will you offer to be cured ? ");
  686. temp = floor(infloat());
  687. if (temp < 0.0 || temp > Player.p_gold)
  688. /* negative gold, or more than available */
  689. {
  690. mvaddstr(6, 0, "He was not amused, and made you worse.\n");
  691. Player.p_poison += 1.0;
  692. } else
  693. if (drandom() / 2.0 > (temp + 1.0) / MAX(Player.p_gold, 1))
  694. /* medic wants 1/2 of available gold */
  695. mvaddstr(5, 0, "Sorry, he wasn't interested.\n");
  696. else {
  697. mvaddstr(5, 0, "He accepted.");
  698. Player.p_poison = MAX(0.0, Player.p_poison - 1.0);
  699. Player.p_gold -= temp;
  700. }
  701. }
  702. break;
  703. case 3:
  704. mvaddstr(4, 0, "You've been caught raping and pillaging!\n");
  705. Player.p_experience += 4000.0;
  706. Player.p_sin += 0.5;
  707. break;
  708. case 4:
  709. temp = ROLL(10.0, 75.0);
  710. mvprintw(4, 0, "You've found %.0f gold pieces, want them ? ", temp);
  711. ch = getanswer("NY", FALSE);
  712. if (ch == 'Y')
  713. collecttaxes(temp, 0.0);
  714. break;
  715. case 5:
  716. if (Player.p_sin > 1.0) {
  717. mvaddstr(4, 0, "You've found a Holy Orb!\n");
  718. Player.p_sin -= 0.25;
  719. }
  720. break;
  721. case 6:
  722. if (Player.p_poison < 1.0) {
  723. mvaddstr(4, 0, "You've been hit with a plague!\n");
  724. Player.p_poison += 1.0;
  725. }
  726. break;
  727. case 7:
  728. mvaddstr(4, 0, "You've found some holy water.\n");
  729. ++Player.p_holywater;
  730. break;
  731. case 8:
  732. mvaddstr(4, 0, "You've met a Guru. . .");
  733. if (drandom() * Player.p_sin > 1.0)
  734. addstr("You disgusted him with your sins!\n");
  735. else
  736. if (Player.p_poison > 0.0) {
  737. addstr("He looked kindly upon you, and cured you.\n");
  738. Player.p_poison = 0.0;
  739. } else {
  740. addstr("He rewarded you for your virtue.\n");
  741. Player.p_mana += 50.0;
  742. Player.p_shield += 2.0;
  743. }
  744. break;
  745. case 9:
  746. mvaddstr(4, 0, "You've found an amulet.\n");
  747. ++Player.p_amulets;
  748. break;
  749. case 10:
  750. if (Player.p_blindness) {
  751. mvaddstr(4, 0, "You've regained your sight!\n");
  752. Player.p_blindness = FALSE;
  753. }
  754. break;
  755. default: /* deal with poison */
  756. if (Player.p_poison > 0.0) {
  757. temp = Player.p_poison * Statptr->c_weakness
  758. * Player.p_maxenergy / 600.0;
  759. if (Player.p_energy > Player.p_maxenergy / 10.0
  760. && temp + 5.0 < Player.p_energy)
  761. Player.p_energy -= temp;
  762. }
  763. break;
  764. }
  765. }
  766. void
  767. genchar(type)
  768. int type;
  769. {
  770. int subscript; /* used for subscripting into Stattable */
  771. const struct charstats *statptr; /* for pointing into Stattable */
  772. subscript = type - '1';
  773. if (subscript < C_MAGIC || subscript > C_EXPER)
  774. if (subscript != C_SUPER || !Wizard)
  775. /* fighter is default */
  776. subscript = C_FIGHTER;
  777. statptr = &Stattable[subscript];
  778. Player.p_quickness =
  779. ROLL(statptr->c_quickness.base, statptr->c_quickness.interval);
  780. Player.p_strength =
  781. ROLL(statptr->c_strength.base, statptr->c_strength.interval);
  782. Player.p_mana =
  783. ROLL(statptr->c_mana.base, statptr->c_mana.interval);
  784. Player.p_maxenergy =
  785. Player.p_energy =
  786. ROLL(statptr->c_energy.base, statptr->c_energy.interval);
  787. Player.p_brains =
  788. ROLL(statptr->c_brains.base, statptr->c_brains.interval);
  789. Player.p_magiclvl =
  790. ROLL(statptr->c_magiclvl.base, statptr->c_magiclvl.interval);
  791. Player.p_type = subscript;
  792. if (Player.p_type == C_HALFLING)
  793. /* give halfling some experience */
  794. Player.p_experience = ROLL(600.0, 200.0);
  795. }
  796. void
  797. playinit()
  798. {
  799. #ifdef NCURSES_VERSION
  800. struct termios tty;
  801. #endif
  802. /* catch/ingnore signals */
  803. #ifdef BSD41
  804. sigignore(SIGQUIT);
  805. sigignore(SIGALRM);
  806. sigignore(SIGTERM);
  807. sigignore(SIGTSTP);
  808. sigignore(SIGTTIN);
  809. sigignore(SIGTTOU);
  810. sighold(SIGINT);
  811. sigset(SIGHUP, ill_sig);
  812. sigset(SIGTRAP, ill_sig);
  813. sigset(SIGIOT, ill_sig);
  814. sigset(SIGEMT, ill_sig);
  815. sigset(SIGFPE, ill_sig);
  816. sigset(SIGBUS, ill_sig);
  817. sigset(SIGSEGV, ill_sig);
  818. sigset(SIGSYS, ill_sig);
  819. sigset(SIGPIPE, ill_sig);
  820. #endif
  821. #ifdef BSD42
  822. signal(SIGQUIT, ill_sig);
  823. signal(SIGALRM, SIG_IGN);
  824. signal(SIGTERM, SIG_IGN);
  825. signal(SIGTSTP, SIG_IGN);
  826. signal(SIGTTIN, SIG_IGN);
  827. signal(SIGTTOU, SIG_IGN);
  828. signal(SIGINT, ill_sig);
  829. signal(SIGHUP, SIG_DFL);
  830. signal(SIGTRAP, ill_sig);
  831. signal(SIGIOT, ill_sig);
  832. signal(SIGEMT, ill_sig);
  833. signal(SIGFPE, ill_sig);
  834. signal(SIGBUS, ill_sig);
  835. signal(SIGSEGV, ill_sig);
  836. signal(SIGSYS, ill_sig);
  837. signal(SIGPIPE, ill_sig);
  838. #endif
  839. #ifdef SYS3
  840. signal(SIGINT, SIG_IGN);
  841. signal(SIGQUIT, SIG_IGN);
  842. signal(SIGTERM, SIG_IGN);
  843. signal(SIGALRM, SIG_IGN);
  844. signal(SIGHUP, ill_sig);
  845. signal(SIGTRAP, ill_sig);
  846. signal(SIGIOT, ill_sig);
  847. signal(SIGEMT, ill_sig);
  848. signal(SIGFPE, ill_sig);
  849. signal(SIGBUS, ill_sig);
  850. signal(SIGSEGV, ill_sig);
  851. signal(SIGSYS, ill_sig);
  852. signal(SIGPIPE, ill_sig);
  853. #endif
  854. #ifdef SYS5
  855. signal(SIGINT, SIG_IGN);
  856. signal(SIGQUIT, SIG_IGN);
  857. signal(SIGTERM, SIG_IGN);
  858. signal(SIGALRM, SIG_IGN);
  859. signal(SIGHUP, ill_sig);
  860. signal(SIGTRAP, ill_sig);
  861. signal(SIGIOT, ill_sig);
  862. signal(SIGEMT, ill_sig);
  863. signal(SIGFPE, ill_sig);
  864. signal(SIGBUS, ill_sig);
  865. signal(SIGSEGV, ill_sig);
  866. signal(SIGSYS, ill_sig);
  867. signal(SIGPIPE, ill_sig);
  868. #endif
  869. initscr(); /* turn on curses */
  870. noecho(); /* do not echo input */
  871. cbreak(); /* do not process erase, kill */
  872. #ifdef NCURSES_VERSION /* Ncurses needs some terminal mode fiddling */
  873. tcgetattr(0, &tty);
  874. tty.c_iflag |= ICRNL;
  875. tcsetattr(0, TCSANOW, &tty);
  876. #endif
  877. clear();
  878. refresh();
  879. Windows = TRUE; /* mark the state */
  880. }
  881. void
  882. cleanup(doexit)
  883. int doexit;
  884. {
  885. if (Windows) {
  886. move(LINES - 2, 0);
  887. refresh();
  888. nocbreak();
  889. endwin();
  890. }
  891. if (Playersfp)
  892. fclose(Playersfp);
  893. if (Monstfp)
  894. fclose(Monstfp);
  895. if (Messagefp)
  896. fclose(Messagefp);
  897. if (Energyvoidfp)
  898. fclose(Energyvoidfp);
  899. if (doexit)
  900. exit(0);
  901. /* NOTREACHED */
  902. }