misc.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. /* $NetBSD: misc.c,v 1.14 2005/02/15 12:58:21 jsm Exp $ */
  2. /*
  3. * misc.c Phantasia miscellaneous support routines
  4. */
  5. #include "include.h"
  6. #undef bool
  7. #include <curses.h>
  8. void
  9. movelevel()
  10. {
  11. const struct charstats *statptr; /* for pointing into Stattable */
  12. double new; /* new level */
  13. double inc; /* increment between new and old levels */
  14. Changed = TRUE;
  15. if (Player.p_type == C_EXPER)
  16. /* roll a type to use for increment */
  17. statptr = &Stattable[(int) ROLL(C_MAGIC, C_HALFLING - C_MAGIC + 1)];
  18. else
  19. statptr = Statptr;
  20. new = explevel(Player.p_experience);
  21. inc = new - Player.p_level;
  22. Player.p_level = new;
  23. /* add increments to statistics */
  24. Player.p_strength += statptr->c_strength.increase * inc;
  25. Player.p_mana += statptr->c_mana.increase * inc;
  26. Player.p_brains += statptr->c_brains.increase * inc;
  27. Player.p_magiclvl += statptr->c_magiclvl.increase * inc;
  28. Player.p_maxenergy += statptr->c_energy.increase * inc;
  29. /* rest to maximum upon reaching new level */
  30. Player.p_energy = Player.p_maxenergy + Player.p_shield;
  31. if (Player.p_crowns > 0 && Player.p_level >= 1000.0)
  32. /* no longer able to be king -- turn crowns into cash */
  33. {
  34. Player.p_gold += ((double) Player.p_crowns) * 5000.0;
  35. Player.p_crowns = 0;
  36. }
  37. if (Player.p_level >= 3000.0 && Player.p_specialtype < SC_COUNCIL)
  38. /* make a member of the council */
  39. {
  40. mvaddstr(6, 0, "You have made it to the Council of the Wise.\n");
  41. addstr("Good Luck on your search for the Holy Grail.\n");
  42. Player.p_specialtype = SC_COUNCIL;
  43. /* no rings for council and above */
  44. Player.p_ring.ring_type = R_NONE;
  45. Player.p_ring.ring_duration = 0;
  46. Player.p_lives = 3; /* three extra lives */
  47. }
  48. if (Player.p_level > 9999.0 && Player.p_specialtype != SC_VALAR)
  49. death("Old age");
  50. }
  51. const char *
  52. descrlocation(playerp, shortflag)
  53. struct player *playerp;
  54. phbool shortflag;
  55. {
  56. double circle; /* corresponding circle for coordinates */
  57. int quadrant; /* quandrant of grid */
  58. const char *label; /* pointer to place name */
  59. static const char *const nametable[4][4] = /* names of places */
  60. {
  61. {"Anorien", "Ithilien", "Rohan", "Lorien"},
  62. {"Gondor", "Mordor", "Dunland", "Rovanion"},
  63. {"South Gondor", "Khand", "Eriador", "The Iron Hills"},
  64. {"Far Harad", "Near Harad", "The Northern Waste", "Rhun"}
  65. };
  66. if (playerp->p_specialtype == SC_VALAR)
  67. return (" is in Valhala");
  68. else
  69. if ((circle = CIRCLE(playerp->p_x, playerp->p_y)) >= 1000.0) {
  70. if (MAX(fabs(playerp->p_x), fabs(playerp->p_y)) > D_BEYOND)
  71. label = "The Point of No Return";
  72. else
  73. label = "The Ashen Mountains";
  74. } else
  75. if (circle >= 55)
  76. label = "Morannon";
  77. else
  78. if (circle >= 35)
  79. label = "Kennaquahair";
  80. else
  81. if (circle >= 20)
  82. label = "The Dead Marshes";
  83. else
  84. if (circle >= 9)
  85. label = "The Outer Waste";
  86. else
  87. if (circle >= 5)
  88. label = "The Moors Adventurous";
  89. else {
  90. if (playerp->p_x == 0.0 && playerp->p_y == 0.0)
  91. label = "The Lord's Chamber";
  92. else {
  93. /* this
  94. *
  95. * expr
  96. * essi
  97. * on
  98. * is
  99. * spli
  100. * t
  101. * to
  102. * prev
  103. * ent
  104. * comp
  105. * iler
  106. *
  107. * loop
  108. *
  109. * with
  110. *
  111. * some
  112. *
  113. * comp
  114. * iler
  115. * s */
  116. quadrant = ((playerp->p_x > 0.0) ? 1 : 0);
  117. quadrant += ((playerp->p_y >= 0.0) ? 2 : 0);
  118. label = nametable[((int) circle) - 1][quadrant];
  119. }
  120. }
  121. if (shortflag)
  122. sprintf(Databuf, "%.29s", label);
  123. else
  124. sprintf(Databuf, " is in %s (%.0f,%.0f)", label, playerp->p_x, playerp->p_y);
  125. return (Databuf);
  126. }
  127. void
  128. tradingpost()
  129. {
  130. double numitems; /* number of items to purchase */
  131. double cost; /* cost of purchase */
  132. double blessingcost; /* cost of blessing */
  133. int ch; /* input */
  134. int size; /* size of the trading post */
  135. int loop; /* loop counter */
  136. int cheat = 0; /* number of times player has tried to cheat */
  137. bool dishonest = FALSE; /* set when merchant is dishonest */
  138. Player.p_status = S_TRADING;
  139. writerecord(&Player, Fileloc);
  140. clear();
  141. addstr("You are at a trading post. All purchases must be made with gold.");
  142. size = sqrt(fabs(Player.p_x / 100)) + 1;
  143. size = MIN(7, size);
  144. /* set up cost of blessing */
  145. blessingcost = 1000.0 * (Player.p_level + 5.0);
  146. /* print Menu */
  147. move(7, 0);
  148. for (loop = 0; loop < size; ++loop)
  149. /* print Menu */
  150. {
  151. if (loop == 6)
  152. cost = blessingcost;
  153. else
  154. cost = Menu[loop].cost;
  155. printw("(%d) %-12s: %6.0f\n", loop + 1, Menu[loop].item, cost);
  156. }
  157. mvprintw(5, 0, "L:Leave P:Purchase S:Sell Gems ? ");
  158. for (;;) {
  159. adjuststats(); /* truncate any bad values */
  160. /* print some important statistics */
  161. mvprintw(1, 0, "Gold: %9.0f Gems: %9.0f Level: %6.0f Charms: %6d\n",
  162. Player.p_gold, Player.p_gems, Player.p_level, Player.p_charms);
  163. printw("Shield: %9.0f Sword: %9.0f Quicksilver:%3.0f Blessed: %s\n",
  164. Player.p_shield, Player.p_sword, Player.p_quksilver,
  165. (Player.p_blessing ? " True" : "False"));
  166. printw("Brains: %9.0f Mana: %9.0f", Player.p_brains, Player.p_mana);
  167. move(5, 36);
  168. ch = getanswer("LPS", FALSE);
  169. move(15, 0);
  170. clrtobot();
  171. switch (ch) {
  172. case 'L': /* leave */
  173. case '\n':
  174. altercoordinates(0.0, 0.0, A_NEAR);
  175. return;
  176. case 'P': /* make purchase */
  177. mvaddstr(15, 0, "What what would you like to buy ? ");
  178. ch = getanswer(" 1234567", FALSE);
  179. move(15, 0);
  180. clrtoeol();
  181. if (ch - '0' > size)
  182. addstr("Sorry, this merchant doesn't have that.");
  183. else
  184. switch (ch) {
  185. case '1':
  186. printw("Mana is one per %.0f gold piece. How many do you want (%.0f max) ? ",
  187. Menu[0].cost, floor(Player.p_gold / Menu[0].cost));
  188. cost = (numitems = floor(infloat())) * Menu[0].cost;
  189. if (cost > Player.p_gold || numitems < 0)
  190. ++cheat;
  191. else {
  192. cheat = 0;
  193. Player.p_gold -= cost;
  194. if (drandom() < 0.02)
  195. dishonest = TRUE;
  196. else
  197. Player.p_mana += numitems;
  198. }
  199. break;
  200. case '2':
  201. printw("Shields are %.0f per +1. How many do you want (%.0f max) ? ",
  202. Menu[1].cost, floor(Player.p_gold / Menu[1].cost));
  203. cost = (numitems = floor(infloat())) * Menu[1].cost;
  204. if (numitems == 0.0)
  205. break;
  206. else
  207. if (cost > Player.p_gold || numitems < 0)
  208. ++cheat;
  209. else
  210. if (numitems < Player.p_shield)
  211. NOBETTER();
  212. else {
  213. cheat = 0;
  214. Player.p_gold -= cost;
  215. if (drandom() < 0.02)
  216. dishonest = TRUE;
  217. else
  218. Player.p_shield = numitems;
  219. }
  220. break;
  221. case '3':
  222. printw("A book costs %.0f gp. How many do you want (%.0f max) ? ",
  223. Menu[2].cost, floor(Player.p_gold / Menu[2].cost));
  224. cost = (numitems = floor(infloat())) * Menu[2].cost;
  225. if (cost > Player.p_gold || numitems < 0)
  226. ++cheat;
  227. else {
  228. cheat = 0;
  229. Player.p_gold -= cost;
  230. if (drandom() < 0.02)
  231. dishonest = TRUE;
  232. else
  233. if (drandom() * numitems > Player.p_level / 10.0
  234. && numitems != 1) {
  235. printw("\nYou blew your mind!\n");
  236. Player.p_brains /= 5;
  237. } else {
  238. Player.p_brains += floor(numitems) * ROLL(20, 8);
  239. }
  240. }
  241. break;
  242. case '4':
  243. printw("Swords are %.0f gp per +1. How many + do you want (%.0f max) ? ",
  244. Menu[3].cost, floor(Player.p_gold / Menu[3].cost));
  245. cost = (numitems = floor(infloat())) * Menu[3].cost;
  246. if (numitems == 0.0)
  247. break;
  248. else
  249. if (cost > Player.p_gold || numitems < 0)
  250. ++cheat;
  251. else
  252. if (numitems < Player.p_sword)
  253. NOBETTER();
  254. else {
  255. cheat = 0;
  256. Player.p_gold -= cost;
  257. if (drandom() < 0.02)
  258. dishonest = TRUE;
  259. else
  260. Player.p_sword = numitems;
  261. }
  262. break;
  263. case '5':
  264. printw("A charm costs %.0f gp. How many do you want (%.0f max) ? ",
  265. Menu[4].cost, floor(Player.p_gold / Menu[4].cost));
  266. cost = (numitems = floor(infloat())) * Menu[4].cost;
  267. if (cost > Player.p_gold || numitems < 0)
  268. ++cheat;
  269. else {
  270. cheat = 0;
  271. Player.p_gold -= cost;
  272. if (drandom() < 0.02)
  273. dishonest = TRUE;
  274. else
  275. Player.p_charms += numitems;
  276. }
  277. break;
  278. case '6':
  279. printw("Quicksilver is %.0f gp per +1. How many + do you want (%.0f max) ? ",
  280. Menu[5].cost, floor(Player.p_gold / Menu[5].cost));
  281. cost = (numitems = floor(infloat())) * Menu[5].cost;
  282. if (numitems == 0.0)
  283. break;
  284. else
  285. if (cost > Player.p_gold || numitems < 0)
  286. ++cheat;
  287. else
  288. if (numitems < Player.p_quksilver)
  289. NOBETTER();
  290. else {
  291. cheat = 0;
  292. Player.p_gold -= cost;
  293. if (drandom() < 0.02)
  294. dishonest = TRUE;
  295. else
  296. Player.p_quksilver = numitems;
  297. }
  298. break;
  299. case '7':
  300. if (Player.p_blessing) {
  301. addstr("You already have a blessing.");
  302. break;
  303. }
  304. printw("A blessing requires a %.0f gp donation. Still want one ? ", blessingcost);
  305. ch = getanswer("NY", FALSE);
  306. if (ch == 'Y') {
  307. if (Player.p_gold < blessingcost)
  308. ++cheat;
  309. else {
  310. cheat = 0;
  311. Player.p_gold -= blessingcost;
  312. if (drandom() < 0.02)
  313. dishonest = TRUE;
  314. else
  315. Player.p_blessing = TRUE;
  316. }
  317. }
  318. break;
  319. }
  320. break;
  321. case 'S': /* sell gems */
  322. mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ",
  323. (double) N_GEMVALUE, Player.p_gems);
  324. numitems = floor(infloat());
  325. if (numitems > Player.p_gems || numitems < 0)
  326. ++cheat;
  327. else {
  328. cheat = 0;
  329. Player.p_gems -= numitems;
  330. Player.p_gold += numitems * N_GEMVALUE;
  331. }
  332. }
  333. if (cheat == 1)
  334. mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n");
  335. else
  336. if (cheat == 2) {
  337. mvaddstr(17, 0, "You had your chance. This merchant happens to be\n");
  338. printw("a %.0f level magic user, and you made %s mad!\n",
  339. ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her");
  340. altercoordinates(0.0, 0.0, A_FAR);
  341. Player.p_energy /= 2.0;
  342. ++Player.p_sin;
  343. more(23);
  344. return;
  345. } else
  346. if (dishonest) {
  347. mvaddstr(17, 0, "The merchant stole your money!");
  348. refresh();
  349. altercoordinates(Player.p_x - Player.p_x / 10.0,
  350. Player.p_y - Player.p_y / 10.0, A_SPECIFIC);
  351. sleep(2);
  352. return;
  353. }
  354. }
  355. }
  356. void
  357. displaystats()
  358. {
  359. mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE));
  360. mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n",
  361. Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield,
  362. Player.p_mana, Users);
  363. mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n",
  364. Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might,
  365. Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player));
  366. }
  367. void
  368. allstatslist()
  369. {
  370. static const char *const flags[] = /* to print value of some bools */
  371. {
  372. "False",
  373. " True"
  374. };
  375. mvprintw(8, 0, "Type: %s\n", descrtype(&Player, FALSE));
  376. mvprintw(10, 0, "Experience: %9.0f", Player.p_experience);
  377. mvprintw(11, 0, "Brains : %9.0f", Player.p_brains);
  378. mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl);
  379. mvprintw(13, 0, "Sin : %9.5f", Player.p_sin);
  380. mvprintw(14, 0, "Poison : %9.5f", Player.p_poison);
  381. mvprintw(15, 0, "Gems : %9.0f", Player.p_gems);
  382. mvprintw(16, 0, "Age : %9ld", Player.p_age);
  383. mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater);
  384. mvprintw(11, 40, "Amulets : %9d", Player.p_amulets);
  385. mvprintw(12, 40, "Charms : %9d", Player.p_charms);
  386. mvprintw(13, 40, "Crowns : %9d", Player.p_crowns);
  387. mvprintw(14, 40, "Shield : %9.0f", Player.p_shield);
  388. mvprintw(15, 40, "Sword : %9.0f", Player.p_sword);
  389. mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver);
  390. mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s",
  391. flags[(int)Player.p_blessing],
  392. flags[Player.p_ring.ring_type != R_NONE],
  393. flags[(int)Player.p_virgin],
  394. flags[(int)Player.p_palantir]);
  395. }
  396. const char *
  397. descrtype(playerp, shortflag)
  398. struct player *playerp;
  399. phbool shortflag;
  400. {
  401. int type; /* for caluculating result subscript */
  402. static const char *const results[] =/* description table */
  403. {
  404. " Magic User", " MU",
  405. " Fighter", " F ",
  406. " Elf", " E ",
  407. " Dwarf", " D ",
  408. " Halfling", " H ",
  409. " Experimento", " EX",
  410. " Super", " S ",
  411. " King", " K ",
  412. " Council of Wise", " CW",
  413. " Ex-Valar", " EV",
  414. " Valar", " V ",
  415. " ? ", " ? "
  416. };
  417. type = playerp->p_type;
  418. switch (playerp->p_specialtype) {
  419. case SC_NONE:
  420. type = playerp->p_type;
  421. break;
  422. case SC_KING:
  423. type = 7;
  424. break;
  425. case SC_COUNCIL:
  426. type = 8;
  427. break;
  428. case SC_EXVALAR:
  429. type = 9;
  430. break;
  431. case SC_VALAR:
  432. type = 10;
  433. break;
  434. }
  435. type *= 2; /* calculate offset */
  436. if (type > 20)
  437. /* error */
  438. type = 22;
  439. if (shortflag)
  440. /* use short descriptions */
  441. ++type;
  442. if (playerp->p_crowns > 0) {
  443. strcpy(Databuf, results[type]);
  444. Databuf[0] = '*';
  445. return (Databuf);
  446. } else
  447. return (results[type]);
  448. }
  449. long
  450. findname(name, playerp)
  451. const char *name;
  452. struct player *playerp;
  453. {
  454. long loc = 0; /* location in the file */
  455. fseek(Playersfp, 0L, SEEK_SET);
  456. while (fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
  457. if (strcmp(playerp->p_name, name) == 0) {
  458. if (playerp->p_status != S_NOTUSED || Wizard)
  459. /* found it */
  460. return (loc);
  461. }
  462. loc += SZ_PLAYERSTRUCT;
  463. }
  464. return (-1);
  465. }
  466. long
  467. allocrecord()
  468. {
  469. long loc = 0L; /* location in file */
  470. fseek(Playersfp, 0L, SEEK_SET);
  471. while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
  472. if (Other.p_status == S_NOTUSED)
  473. /* found an empty record */
  474. return (loc);
  475. else
  476. loc += SZ_PLAYERSTRUCT;
  477. }
  478. /* make a new record */
  479. initplayer(&Other);
  480. Player.p_status = S_OFF;
  481. writerecord(&Other, loc);
  482. return (loc);
  483. }
  484. void
  485. freerecord(playerp, loc)
  486. struct player *playerp;
  487. long loc;
  488. {
  489. playerp->p_name[0] = CH_MARKDELETE;
  490. playerp->p_status = S_NOTUSED;
  491. writerecord(playerp, loc);
  492. }
  493. void
  494. leavegame()
  495. {
  496. if (Player.p_level < 1.0)
  497. /* delete character */
  498. freerecord(&Player, Fileloc);
  499. else {
  500. Player.p_status = S_OFF;
  501. writerecord(&Player, Fileloc);
  502. }
  503. cleanup(TRUE);
  504. /* NOTREACHED */
  505. }
  506. void
  507. death(how)
  508. const char *how;
  509. {
  510. FILE *fp; /* for updating various files */
  511. int ch; /* input */
  512. static const char *const deathmesg[] =
  513. /* add more messages here, if desired */
  514. {
  515. "You have been wounded beyond repair. ",
  516. "You have been disemboweled. ",
  517. "You've been mashed, mauled, and spit upon. (You're dead.)\n",
  518. "You died! ",
  519. "You're a complete failure -- you've died!!\n",
  520. "You have been dealt a fatal blow! "
  521. };
  522. clear();
  523. if (strcmp(how, "Stupidity") != 0) {
  524. if (Player.p_level > 9999.0)
  525. /* old age */
  526. addstr("Characters must be retired upon reaching level 10000. Sorry.");
  527. else
  528. if (Player.p_lives > 0)
  529. /* extra lives */
  530. {
  531. addstr("You should be more cautious. You've been killed.\n");
  532. printw("You only have %d more chance(s).\n", --Player.p_lives);
  533. more(3);
  534. Player.p_energy = Player.p_maxenergy;
  535. return;
  536. } else
  537. if (Player.p_specialtype == SC_VALAR) {
  538. addstr("You had your chances, but Valar aren't totally\n");
  539. addstr("immortal. You are now left to wither and die . . .\n");
  540. more(3);
  541. Player.p_brains = Player.p_level / 25.0;
  542. Player.p_energy = Player.p_maxenergy /= 5.0;
  543. Player.p_quksilver = Player.p_sword = 0.0;
  544. Player.p_specialtype = SC_COUNCIL;
  545. return;
  546. } else
  547. if (Player.p_ring.ring_inuse &&
  548. (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG))
  549. /* good ring in use - saved
  550. * from death */
  551. {
  552. mvaddstr(4, 0, "Your ring saved you from death!\n");
  553. refresh();
  554. Player.p_ring.ring_type = R_NONE;
  555. Player.p_energy = Player.p_maxenergy / 12.0 + 1.0;
  556. if (Player.p_crowns > 0)
  557. --Player.p_crowns;
  558. return;
  559. } else
  560. if (Player.p_ring.ring_type == R_BAD
  561. || Player.p_ring.ring_type == R_SPOILED)
  562. /* bad ring in
  563. * possession; name
  564. * idiot after player */
  565. {
  566. mvaddstr(4, 0,
  567. "Your ring has taken control of you and turned you into a monster!\n");
  568. fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
  569. fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
  570. strcpy(Curmonster.m_name, Player.p_name);
  571. fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
  572. fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
  573. fflush(Monstfp);
  574. }
  575. }
  576. enterscore(); /* update score board */
  577. /* put info in last dead file */
  578. fp = fopen(_PATH_LASTDEAD, "w");
  579. fprintf(fp, "%s (%s, run by %s, level %.0f, killed by %s)",
  580. Player.p_name, descrtype(&Player, TRUE),
  581. Player.p_login, Player.p_level, how);
  582. fclose(fp);
  583. /* let other players know */
  584. fp = fopen(_PATH_MESS, "w");
  585. fprintf(fp, "%s was killed by %s.", Player.p_name, how);
  586. fclose(fp);
  587. freerecord(&Player, Fileloc);
  588. clear();
  589. move(10, 0);
  590. addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]);
  591. addstr("Care to give it another try ? ");
  592. ch = getanswer("NY", FALSE);
  593. if (ch == 'Y') {
  594. cleanup(FALSE);
  595. execl(_PATH_GAMEPROG, "phantasia", "-s",
  596. (Wizard ? "-S" : (char *) NULL), (char *) NULL);
  597. exit(0);
  598. /* NOTREACHED */
  599. }
  600. cleanup(TRUE);
  601. /* NOTREACHED */
  602. }
  603. void
  604. writerecord(playerp, place)
  605. struct player *playerp;
  606. long place;
  607. {
  608. fseek(Playersfp, place, SEEK_SET);
  609. fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
  610. fflush(Playersfp);
  611. }
  612. double
  613. explevel(experience)
  614. double experience;
  615. {
  616. if (experience < 1.1e7)
  617. return (floor(pow((experience / 1000.0), 0.4875)));
  618. else
  619. return (floor(pow((experience / 1250.0), 0.4865)));
  620. }
  621. void
  622. truncstring(string)
  623. char *string;
  624. {
  625. int length; /* length of string */
  626. length = strlen(string);
  627. while (string[--length] == ' ')
  628. string[length] = '\0';
  629. }
  630. void
  631. altercoordinates(xnew, ynew, operation)
  632. double xnew;
  633. double ynew;
  634. int operation;
  635. {
  636. switch (operation) {
  637. case A_FORCED: /* move with no checks */
  638. break;
  639. case A_NEAR: /* pick random coordinates near */
  640. xnew = Player.p_x + ROLL(1.0, 5.0);
  641. ynew = Player.p_y - ROLL(1.0, 5.0);
  642. /* fall through for check */
  643. case A_SPECIFIC: /* just move player */
  644. if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND)
  645. /*
  646. * cannot move back from point of no return
  647. * pick the largest coordinate to remain unchanged
  648. */
  649. {
  650. if (fabs(xnew) > fabs(ynew))
  651. xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND);
  652. else
  653. ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND);
  654. }
  655. break;
  656. case A_FAR: /* pick random coordinates far */
  657. xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle);
  658. ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle);
  659. break;
  660. }
  661. /* now set location flags and adjust coordinates */
  662. Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew));
  663. /* set up flags based upon location */
  664. Throne = Marsh = Beyond = FALSE;
  665. if (Player.p_x == 0.0 && Player.p_y == 0.0)
  666. Throne = TRUE;
  667. else
  668. if (Circle < 35 && Circle >= 20)
  669. Marsh = TRUE;
  670. else
  671. if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND)
  672. Beyond = TRUE;
  673. Changed = TRUE;
  674. }
  675. void
  676. readrecord(playerp, loc)
  677. struct player *playerp;
  678. long loc;
  679. {
  680. fseek(Playersfp, loc, SEEK_SET);
  681. fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
  682. }
  683. void
  684. adjuststats()
  685. {
  686. double dtemp; /* for temporary calculations */
  687. if (explevel(Player.p_experience) > Player.p_level)
  688. /* move one or more levels */
  689. {
  690. movelevel();
  691. if (Player.p_level > 5.0)
  692. Timeout = TRUE;
  693. }
  694. if (Player.p_specialtype == SC_VALAR)
  695. /* valar */
  696. Circle = Player.p_level / 5.0;
  697. /* calculate effective quickness */
  698. dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote
  699. - Player.p_level;
  700. dtemp = MAX(0.0, dtemp);/* gold slows player down */
  701. Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp;
  702. /* calculate effective strength */
  703. if (Player.p_poison > 0.0)
  704. /* poison makes player weaker */
  705. {
  706. dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0;
  707. dtemp = MAX(0.1, dtemp);
  708. } else
  709. dtemp = 1.0;
  710. Player.p_might = dtemp * Player.p_strength + Player.p_sword;
  711. /* insure that important things are within limits */
  712. Player.p_quksilver = MIN(99.0, Player.p_quksilver);
  713. Player.p_mana = MIN(Player.p_mana,
  714. Player.p_level * Statptr->c_maxmana + 1000.0);
  715. Player.p_brains = MIN(Player.p_brains,
  716. Player.p_level * Statptr->c_maxbrains + 200.0);
  717. Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0);
  718. /*
  719. * some implementations have problems with floating point compare
  720. * we work around it with this stuff
  721. */
  722. Player.p_gold = floor(Player.p_gold) + 0.1;
  723. Player.p_gems = floor(Player.p_gems) + 0.1;
  724. Player.p_mana = floor(Player.p_mana) + 0.1;
  725. if (Player.p_ring.ring_type != R_NONE)
  726. /* do ring things */
  727. {
  728. /* rest to max */
  729. Player.p_energy = Player.p_maxenergy + Player.p_shield;
  730. if (Player.p_ring.ring_duration <= 0)
  731. /* clean up expired rings */
  732. switch (Player.p_ring.ring_type) {
  733. case R_BAD: /* ring drives player crazy */
  734. Player.p_ring.ring_type = R_SPOILED;
  735. Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0);
  736. break;
  737. case R_NAZREG: /* ring disappears */
  738. Player.p_ring.ring_type = R_NONE;
  739. break;
  740. case R_SPOILED: /* ring kills player */
  741. death("A cursed ring");
  742. break;
  743. case R_DLREG: /* this ring doesn't expire */
  744. Player.p_ring.ring_duration = 0;
  745. break;
  746. }
  747. }
  748. if (Player.p_age / N_AGE > Player.p_degenerated)
  749. /* age player slightly */
  750. {
  751. ++Player.p_degenerated;
  752. if (Player.p_quickness > 23.0)
  753. Player.p_quickness *= 0.99;
  754. Player.p_strength *= 0.97;
  755. Player.p_brains *= 0.95;
  756. Player.p_magiclvl *= 0.97;
  757. Player.p_maxenergy *= 0.95;
  758. Player.p_quksilver *= 0.95;
  759. Player.p_sword *= 0.93;
  760. Player.p_shield *= 0.93;
  761. }
  762. }
  763. void
  764. initplayer(playerp)
  765. struct player *playerp;
  766. {
  767. playerp->p_experience =
  768. playerp->p_level =
  769. playerp->p_strength =
  770. playerp->p_sword =
  771. playerp->p_might =
  772. playerp->p_energy =
  773. playerp->p_maxenergy =
  774. playerp->p_shield =
  775. playerp->p_quickness =
  776. playerp->p_quksilver =
  777. playerp->p_speed =
  778. playerp->p_magiclvl =
  779. playerp->p_mana =
  780. playerp->p_brains =
  781. playerp->p_poison =
  782. playerp->p_gems =
  783. playerp->p_sin =
  784. playerp->p_1scratch =
  785. playerp->p_2scratch = 0.0;
  786. playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */
  787. playerp->p_x = ROLL(-125.0, 251.0);
  788. playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */
  789. /* clear ring */
  790. playerp->p_ring.ring_type = R_NONE;
  791. playerp->p_ring.ring_duration = 0;
  792. playerp->p_ring.ring_inuse = FALSE;
  793. playerp->p_age = 0L;
  794. playerp->p_degenerated = 1; /* don't degenerate initially */
  795. playerp->p_type = C_FIGHTER; /* default */
  796. playerp->p_specialtype = SC_NONE;
  797. playerp->p_lives =
  798. playerp->p_crowns =
  799. playerp->p_charms =
  800. playerp->p_amulets =
  801. playerp->p_holywater =
  802. playerp->p_lastused = 0;
  803. playerp->p_status = S_NOTUSED;
  804. playerp->p_tampered = T_OFF;
  805. playerp->p_istat = I_OFF;
  806. playerp->p_palantir =
  807. playerp->p_blessing =
  808. playerp->p_virgin =
  809. playerp->p_blindness = FALSE;
  810. playerp->p_name[0] =
  811. playerp->p_password[0] =
  812. playerp->p_login[0] = '\0';
  813. }
  814. void
  815. readmessage()
  816. {
  817. move(3, 0);
  818. clrtoeol();
  819. fseek(Messagefp, 0L, SEEK_SET);
  820. if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL)
  821. addstr(Databuf);
  822. }
  823. void
  824. error(whichfile)
  825. const char *whichfile;
  826. {
  827. int (*funcp)(const char *,...);
  828. if (Windows) {
  829. funcp = printw;
  830. clear();
  831. } else
  832. funcp = printf;
  833. (*funcp) ("An unrecoverable error has occurred reading %s. (%s)\n", whichfile, strerror(errno));
  834. (*funcp) ("Please run 'setup' to determine the problem.\n");
  835. cleanup(TRUE);
  836. /* NOTREACHED */
  837. }
  838. double
  839. distance(x1, x2, y1, y2)
  840. double x1, x2, y1, y2;
  841. {
  842. double deltax, deltay;
  843. deltax = x1 - x2;
  844. deltay = y1 - y2;
  845. return (sqrt(deltax * deltax + deltay * deltay));
  846. }
  847. void
  848. ill_sig(whichsig)
  849. int whichsig;
  850. {
  851. clear();
  852. if (!(whichsig == SIGINT || whichsig == SIGQUIT))
  853. printw("Error: caught signal # %d.\n", whichsig);
  854. cleanup(TRUE);
  855. /* NOTREACHED */
  856. }
  857. const char *
  858. descrstatus(playerp)
  859. struct player *playerp;
  860. {
  861. switch (playerp->p_status) {
  862. case S_PLAYING:
  863. if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield))
  864. return ("Low Energy");
  865. else
  866. if (playerp->p_blindness)
  867. return ("Blind");
  868. else
  869. return ("In game");
  870. case S_CLOAKED:
  871. return ("Cloaked");
  872. case S_INBATTLE:
  873. return ("In Battle");
  874. case S_MONSTER:
  875. return ("Encounter");
  876. case S_TRADING:
  877. return ("Trading");
  878. case S_OFF:
  879. return ("Off");
  880. case S_HUNGUP:
  881. return ("Hung up");
  882. default:
  883. return ("");
  884. }
  885. }
  886. double
  887. drandom()
  888. {
  889. if (sizeof(int) != 2)
  890. /* use only low bits */
  891. return ((double) (random() & 0x7fff) / 32768.0);
  892. else
  893. return ((double) random() / 32768.0);
  894. }
  895. void
  896. collecttaxes(gold, gems)
  897. double gold;
  898. double gems;
  899. {
  900. FILE *fp; /* to update Goldfile */
  901. double dtemp; /* for temporary calculations */
  902. double taxes; /* tax liability */
  903. /* add to cache */
  904. Player.p_gold += gold;
  905. Player.p_gems += gems;
  906. /* calculate tax liability */
  907. taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold);
  908. if (Player.p_gold < taxes)
  909. /* not enough gold to pay taxes, must convert some gems to
  910. * gold */
  911. {
  912. dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to
  913. * convert */
  914. if (Player.p_gems >= dtemp)
  915. /* player has enough to convert */
  916. {
  917. Player.p_gems -= dtemp;
  918. Player.p_gold += dtemp * N_GEMVALUE;
  919. } else
  920. /* take everything; this should never happen */
  921. {
  922. Player.p_gold += Player.p_gems * N_GEMVALUE;
  923. Player.p_gems = 0.0;
  924. taxes = Player.p_gold;
  925. }
  926. }
  927. Player.p_gold -= taxes;
  928. if ((fp = fopen(_PATH_GOLD, "r+")) != NULL)
  929. /* update taxes */
  930. {
  931. dtemp = 0.0;
  932. fread((char *) &dtemp, sizeof(double), 1, fp);
  933. dtemp += floor(taxes);
  934. fseek(fp, 0L, SEEK_SET);
  935. fwrite((char *) &dtemp, sizeof(double), 1, fp);
  936. fclose(fp);
  937. }
  938. }