action.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. /* =============================================================================
  2. * PROGRAM: ularn
  3. * FILENAME: action.c
  4. *
  5. * DESCRIPTION:
  6. * This module contains functions to process the player's actions.
  7. *
  8. * =============================================================================
  9. * EXPORTED VARIABLES
  10. *
  11. * None
  12. *
  13. * =============================================================================
  14. * EXPORTED FUNCTIONS
  15. *
  16. * run : Move in a direction until something interesting happens
  17. * wield : Wield an item
  18. * wear : Wear armour or shield
  19. * dropobj : Drop an object
  20. * readsrc : Read a scroll ot a book for the inventory
  21. * eatcookie : Eat a cookie in inventory, and display fortune if possible.
  22. * quaff : Drink a potion in inventory
  23. * closedoor : Close an open door
  24. * quit : Asks if really want to quit.
  25. * do_create : Create an item (wizard only)
  26. *
  27. * =============================================================================
  28. */
  29. #include "dungeon.h"
  30. #include "dungeon_obj.h"
  31. #include "fortune.h"
  32. #include "header.h"
  33. #include "itm.h"
  34. #include "monster.h"
  35. #include "object.h"
  36. #include "player.h"
  37. #include "potion.h"
  38. #include "savegame.h"
  39. #include "scroll.h"
  40. #include "show.h"
  41. #include "ularn_ask.h"
  42. #include "ularn_game.h"
  43. #include "ularn_win.h"
  44. /* =============================================================================
  45. * Local variables
  46. */
  47. /*
  48. * Possible answers to various selections
  49. */
  50. static char *SelectItemAns = "abcdefghijklmnopqrstuvwxyz*\033";
  51. static char *SelectDropAns = "abcdefghijklmnopqrstuvwxyz*.\033";
  52. static char *SelectWieldAns = "abcdefghijklmnopqrstuvwxyz*-\033";
  53. /*
  54. * Types of uses of an item
  55. */
  56. typedef enum UseType {
  57. USE_WIELD,
  58. USE_QUAFF,
  59. USE_READ,
  60. USE_WEAR,
  61. USE_EAT,
  62. USE_DROP,
  63. USE_COUNT
  64. } UseType;
  65. /*
  66. * String for each use
  67. */
  68. static char *UseStrings[USE_COUNT] = {"wield", "quaff", "read",
  69. "wear", "eat", "drop"};
  70. /* =============================================================================
  71. * Local functions
  72. */
  73. /* =============================================================================
  74. * FUNCTION: ydhi
  75. *
  76. * DESCRIPTION:
  77. * Function to print the 'you don't have item' message.
  78. *
  79. * PARAMETERS:
  80. *
  81. * x : The character index (a .. z) of the inventory slot.
  82. *
  83. * RETURN VALUE:
  84. *
  85. * None.
  86. */
  87. static void ydhi(int x) { Printf("\nYou don't have item %c!", x); }
  88. /* =============================================================================
  89. * FUNCTION: ycwi
  90. *
  91. * DESCRIPTION:
  92. * Function to print the 'you can't wield item' message.
  93. *
  94. * PARAMETERS:
  95. *
  96. * x : The character index (a .. z) of the inventory slot.
  97. *
  98. * RETURN VALUE:
  99. *
  100. * None.
  101. */
  102. static void ycwi(int x) { Printf("\nYou can't wield item %c!", x); }
  103. /* =============================================================================
  104. * FUNCTION: whatitem
  105. *
  106. * DESCRIPTION:
  107. * Ask the player what item to use for a particular use and gets the
  108. * player's response.
  109. *
  110. * PARAMETERS:
  111. *
  112. * Use : The use to which the item is to be put.
  113. *
  114. * RETURN VALUE:
  115. *
  116. * The character input:
  117. * the index of the item (a .. z) or
  118. * '*' for show list or,
  119. * '-' for nothing (wield only) or,
  120. * '.' for gold (drop only) or,
  121. * ESC for abort action.
  122. */
  123. static int whatitem(UseType Use) {
  124. int j;
  125. int i = 0;
  126. UseType ItemUse;
  127. char tmp[IVENSIZE + 2]; // Each item + gold + null terminator
  128. char prompt[80];
  129. char Ans;
  130. if (Use == USE_DROP)
  131. tmp[i++] = '.';
  132. for (j = 0; j < IVENSIZE; j++) {
  133. switch (iven[j]) {
  134. case ONOTHING:
  135. ItemUse = USE_COUNT;
  136. break;
  137. case OSWORDofSLASHING:
  138. case OHAMMER:
  139. case OSWORD:
  140. case O2SWORD:
  141. case OSPEAR:
  142. case ODAGGER:
  143. case OBATTLEAXE:
  144. case OLONGSWORD:
  145. case OFLAIL:
  146. case OSLAYER:
  147. case OLANCE:
  148. case OVORPAL:
  149. ItemUse = USE_WIELD;
  150. break;
  151. case OPOTION:
  152. ItemUse = USE_QUAFF;
  153. break;
  154. case OSCROLL:
  155. case OBOOK:
  156. ItemUse = USE_READ;
  157. break;
  158. case OPLATE:
  159. case OCHAIN:
  160. case OLEATHER:
  161. case ORING:
  162. case OSTUDLEATHER:
  163. case OSPLINT:
  164. case OPLATEARMOR:
  165. case OSSPLATE:
  166. case OSHIELD:
  167. case OELVENCHAIN:
  168. ItemUse = USE_WEAR;
  169. break;
  170. case OCOOKIE:
  171. ItemUse = USE_EAT;
  172. break;
  173. default:
  174. ItemUse = USE_DROP;
  175. break;
  176. }
  177. if ((ItemUse != USE_COUNT) && ((Use == USE_DROP) || (ItemUse == Use)))
  178. tmp[i++] = (char)(j + 'a');
  179. }
  180. tmp[i] = '\0';
  181. sprintf(prompt, "\nWhat do you want to %s [%s * for all%s] ?",
  182. UseStrings[Use], tmp, (Use == USE_WIELD) ? " - for none" : "");
  183. if (Use == USE_WIELD)
  184. Ans = get_prompt_input(prompt, SelectWieldAns, 1);
  185. else if (Use == USE_DROP)
  186. Ans = get_prompt_input(prompt, SelectDropAns, 1);
  187. else
  188. Ans = get_prompt_input(prompt, SelectItemAns, 1);
  189. if (Ans == ESC)
  190. Print(" aborted.");
  191. return Ans;
  192. }
  193. /* =============================================================================
  194. * Exported functions
  195. */
  196. /* =============================================================================
  197. * FUNCTION: run
  198. */
  199. void run(int dir) {
  200. int i;
  201. i = 1;
  202. while (i) {
  203. i = moveplayer(dir);
  204. if (i > 0) {
  205. if (c[HASTEMONST])
  206. movemonst();
  207. movemonst();
  208. randmonst();
  209. regen();
  210. }
  211. if (hitflag)
  212. i = 0;
  213. if (i != 0)
  214. showcell(playerx, playery);
  215. }
  216. }
  217. /* =============================================================================
  218. * FUNCTION: wield
  219. */
  220. void wield(void) {
  221. int i;
  222. int it;
  223. while (1) {
  224. i = whatitem(USE_WIELD);
  225. if (i == ESC)
  226. return;
  227. else if (i == '*')
  228. showwield();
  229. else if (i == '-') {
  230. c[WIELD] = -1;
  231. Print("\nYou unwield your weapon.");
  232. recalc();
  233. UpdateStatus();
  234. return;
  235. } else if ((i >= 'a') && (i <= 'z')) {
  236. it = i - 'a';
  237. if (iven[it] == ONOTHING) {
  238. ydhi(i);
  239. return;
  240. } else if (iven[it] == OPOTION) {
  241. ycwi(i);
  242. return;
  243. } else if (iven[it] == OSCROLL) {
  244. ycwi(i);
  245. return;
  246. } else if ((c[SHIELD] != -1) && (iven[it] == O2SWORD)) {
  247. Print("\nBut one arm is busy with your shield!");
  248. return;
  249. } else if ((c[WEAR] == it) || (c[SHIELD] == it)) {
  250. Printf("\nYou can't wield your %s while you're wearing it!",
  251. (c[WEAR] == it) ? "armor" : "shield");
  252. return;
  253. } else {
  254. c[WIELD] = it;
  255. Printf("\nYou wield %s", objectname[(int)iven[it]]);
  256. show_plusses(ivenarg[it]);
  257. Printc('.');
  258. recalc();
  259. UpdateStatus();
  260. return;
  261. }
  262. }
  263. }
  264. }
  265. /* =============================================================================
  266. * FUNCTION: wear
  267. */
  268. void wear(void) {
  269. int i;
  270. int it;
  271. while (1) {
  272. i = whatitem(USE_WEAR);
  273. if (i == ESC)
  274. return;
  275. else if (i == '*')
  276. showwear();
  277. else if ((i >= 'a') && (i <= 'z')) {
  278. it = i - 'a';
  279. switch (iven[it]) {
  280. case ONOTHING:
  281. ydhi(i);
  282. return;
  283. case OLEATHER:
  284. case OCHAIN:
  285. case OPLATE:
  286. case OSTUDLEATHER:
  287. case ORING:
  288. case OSPLINT:
  289. case OPLATEARMOR:
  290. case OELVENCHAIN:
  291. case OSSPLATE:
  292. if (c[WEAR] != -1) {
  293. Print("\nYou are already wearing some armor.");
  294. return;
  295. }
  296. c[WEAR] = it;
  297. if (c[WIELD] == it)
  298. c[WIELD] = -1;
  299. Printf("\nYou put on your %s", objectname[(int)iven[it]]);
  300. show_plusses(ivenarg[it]);
  301. Printc('.');
  302. recalc();
  303. UpdateStatus();
  304. return;
  305. case OSHIELD:
  306. if (c[SHIELD] != -1) {
  307. Print("\nYou are already wearing a shield.");
  308. return;
  309. }
  310. if (iven[c[WIELD]] == O2SWORD) {
  311. Print("\nYour hands are busy with the two handed sword!");
  312. return;
  313. }
  314. c[SHIELD] = it;
  315. if (c[WIELD] == it)
  316. c[WIELD] = -1;
  317. Print("\nYou put on your shield");
  318. show_plusses(ivenarg[it]);
  319. Printc('.');
  320. recalc();
  321. UpdateStatus();
  322. return;
  323. default:
  324. Print("\nYou can't wear that!");
  325. }
  326. }
  327. }
  328. }
  329. /* =============================================================================
  330. * FUNCTION: dropobj
  331. */
  332. void dropobj(void) {
  333. int i, pitflag = 0;
  334. char *p;
  335. long amt;
  336. p = &item[playerx][playery];
  337. while (1) {
  338. if ((i = whatitem(USE_DROP)) == ESC)
  339. return;
  340. if (i == '*')
  341. showstr();
  342. else {
  343. /* drop some gold */
  344. if (i == '.') {
  345. if (*p == OPIT)
  346. pitflag = 1;
  347. if ((*p != ONOTHING) && !pitflag) {
  348. Print("\nThere's something here already!");
  349. return;
  350. }
  351. Print("\n\n");
  352. Print("How much gold do you drop? ");
  353. amt = get_num_input((long)c[GOLD]);
  354. if (amt <= 0)
  355. return;
  356. if (amt > c[GOLD]) {
  357. Print("\nYou don't have that much!");
  358. return;
  359. }
  360. if (amt <= 32767) {
  361. *p = OGOLDPILE;
  362. i = (int)amt;
  363. } else if (amt <= 327670L) {
  364. *p = ODGOLD;
  365. i = (int)(amt / 10);
  366. amt = 10L * i;
  367. } else if (amt <= 3276700L) {
  368. *p = OMAXGOLD;
  369. i = (int)(amt / 100);
  370. amt = 100L * i;
  371. } else if (amt <= 32767000L) {
  372. *p = OKGOLD;
  373. i = (int)(amt / 1000);
  374. amt = 1000L * i;
  375. } else {
  376. *p = OKGOLD;
  377. i = (int)(32767);
  378. amt = 32767000L;
  379. }
  380. c[GOLD] -= amt;
  381. Printf(" You drop %d gold piece%s.", (long)amt, plural(amt));
  382. if (pitflag) {
  383. *p = OPIT;
  384. Print("\nThe gold disappears down the pit.");
  385. } else
  386. iarg[playerx][playery] = (short)i;
  387. UpdateStatus();
  388. dropflag = 1;
  389. return;
  390. } else {
  391. drop_object(i - 'a');
  392. return;
  393. }
  394. }
  395. }
  396. }
  397. /* =============================================================================
  398. * FUNCTION: readscr
  399. */
  400. void readscr(void) {
  401. int i;
  402. while (1) {
  403. if ((i = whatitem(USE_READ)) == ESC)
  404. return;
  405. if (i != '.') {
  406. if (i == '*')
  407. showread();
  408. else {
  409. if (iven[i - 'a'] == OSCROLL) {
  410. read_scroll(ivenarg[i - 'a']);
  411. iven[i - 'a'] = ONOTHING;
  412. return;
  413. }
  414. if (iven[i - 'a'] == OBOOK) {
  415. readbook(ivenarg[i - 'a']);
  416. iven[i - 'a'] = ONOTHING;
  417. return;
  418. }
  419. if (iven[i - 'a'] == ONOTHING) {
  420. ydhi(i);
  421. return;
  422. }
  423. Print("\nThere's nothing on it to read.");
  424. return;
  425. }
  426. }
  427. }
  428. }
  429. /* =============================================================================
  430. * FUNCTION: eatcookie
  431. */
  432. void eatcookie(void) {
  433. int i;
  434. char *p;
  435. while (1) {
  436. if ((i = whatitem(USE_EAT)) == ESC)
  437. return;
  438. if (i != '.') {
  439. if (i == '*')
  440. showeat();
  441. else if (iven[i - 'a'] == OCOOKIE) {
  442. Print("\nThe cookie was delicious.");
  443. iven[i - 'a'] = ONOTHING;
  444. if (!c[BLINDCOUNT]) {
  445. p = fortune(fortfile);
  446. if (p != NULL) {
  447. Print(" Inside you find a scrap of paper that says:\n");
  448. Print(p);
  449. }
  450. }
  451. return;
  452. } else if (iven[i - 'a'] == ONOTHING) {
  453. ydhi(i);
  454. return;
  455. } else {
  456. Print("\nYou can't eat that!");
  457. return;
  458. }
  459. }
  460. }
  461. }
  462. /* =============================================================================
  463. * FUNCTION: quaff
  464. */
  465. void quaff(void) {
  466. int i;
  467. while (1) {
  468. if ((i = whatitem(USE_QUAFF)) == ESC)
  469. return;
  470. if (i != '.') {
  471. if (i == '*')
  472. showquaff();
  473. else if (iven[i - 'a'] == OPOTION) {
  474. quaffpotion(ivenarg[i - 'a']);
  475. iven[i - 'a'] = ONOTHING;
  476. return;
  477. } else if (iven[i - 'a'] == ONOTHING) {
  478. ydhi(i);
  479. return;
  480. } else {
  481. Print("\nYou wouldn't want to quaff that, would you? ");
  482. return;
  483. }
  484. }
  485. }
  486. }
  487. /* =============================================================================
  488. * FUNCTION: opendoor
  489. */
  490. void opendoor(void) {
  491. int dx, dy;
  492. if (!enhance_interface)
  493. return;
  494. /* can't move objects is time is stopped */
  495. if (c[TIMESTOP]) {
  496. Printf("\nNothing can be moved while time is stopped!");
  497. return;
  498. }
  499. dx = playerx;
  500. dy = playery;
  501. dirsub(&dx, &dy);
  502. /* don't ask about items at player's location after trying to open a door */
  503. dropflag = 1;
  504. if (!checkxy(dx, dy)) {
  505. if (c[BLINDCOUNT] == 0)
  506. Print("\nYou see no door there.");
  507. else
  508. Print("\nYou cannot feel any door there.");
  509. } else {
  510. if (item[dx][dy] == OOPENDOOR)
  511. Print("\nThat door is already open.");
  512. else if (item[dx][dy] != OCLOSEDDOOR) {
  513. if (c[BLINDCOUNT] == 0)
  514. Print("\nYou see no door there.");
  515. else
  516. Print("\nYou cannot feel any door there.");
  517. } else {
  518. oopendoor(dx, dy);
  519. if (item[dx][dy] == OOPENDOOR)
  520. Print("\nThe door opens.");
  521. else
  522. Print("\nThe door resists.");
  523. }
  524. }
  525. }
  526. /* =============================================================================
  527. * FUNCTION: closedoor
  528. */
  529. void closedoor(void) {
  530. int i;
  531. int dx, dy;
  532. /* can't move objects is time is stopped */
  533. if (c[TIMESTOP]) {
  534. Printf("\nNothing can be moved while time is stopped!");
  535. return;
  536. }
  537. showcell(playerx, playery);
  538. if (enhance_interface) {
  539. dx = playerx;
  540. dy = playery;
  541. dirsub(&dx, &dy);
  542. /* don't ask about items at player's location after trying to close a door
  543. */
  544. dropflag = 1;
  545. if (!checkxy(dx, dy)) {
  546. if (c[BLINDCOUNT] == 0)
  547. Print("\nYou see no door there.");
  548. else
  549. Print("\nYou cannot feel any door there.");
  550. } else {
  551. if (item[dx][dy] == OCLOSEDDOOR)
  552. Print("\nThat door is already closed.");
  553. else if (item[dx][dy] != OOPENDOOR) {
  554. if (c[BLINDCOUNT] == 0)
  555. Print("\nYou see no door there.");
  556. else
  557. Print("\nYou cannot feel any door there.");
  558. } else {
  559. item[dx][dy] = OCLOSEDDOOR;
  560. iarg[dx][dy] = 0; /* Clear traps on door */
  561. Print("\nThe door closes.");
  562. }
  563. }
  564. } else {
  565. i = item[playerx][playery];
  566. if (i != OOPENDOOR) {
  567. Print("\nThere is no open door here.");
  568. return;
  569. }
  570. Print("\nThe door closes.");
  571. forget();
  572. item[playerx][playery] = OCLOSEDDOOR;
  573. iarg[playerx][playery] = 0;
  574. dropflag = 1; /* So we won't be asked to open it */
  575. }
  576. }
  577. /* =============================================================================
  578. * FUNCTION: openchest
  579. */
  580. void openchest(void) {
  581. if (item[playerx][playery] != OCHEST)
  582. Print("\nThere isn't a chest to open here.");
  583. else {
  584. oopenchest();
  585. dropflag = 1; /* so we don't get asked to open it again */
  586. }
  587. }
  588. /* =============================================================================
  589. * FUNCTION: quit
  590. */
  591. void quit(void) {
  592. int i;
  593. strcpy(lastmonst, "");
  594. i = get_prompt_input("\n\nDo you really want to quit? (y)es, (n)o, (s)ave",
  595. "yns\033", 1);
  596. switch (i) {
  597. case 'y':
  598. died(DIED_QUICK_QUIT, 0);
  599. break;
  600. case 'n':
  601. case ESC:
  602. Print(" no.");
  603. break;
  604. case 's':
  605. Print(" save.");
  606. Print("\nSaving...");
  607. savegame(savefilename);
  608. wizard = 1;
  609. died(DIED_SUSPENDED, 0);
  610. break;
  611. default:
  612. break;
  613. }
  614. }
  615. /* =============================================================================
  616. * FUNCTION: do_create
  617. */
  618. void do_create(void) {
  619. int t, a;
  620. int Retry;
  621. do {
  622. Retry = 0;
  623. t = get_prompt_input(
  624. "\nType of item (Scroll/Potion/Monster/Other) : ", "SsPpMmOo\033", 1);
  625. switch (t) {
  626. case ESC:
  627. break;
  628. case 's':
  629. case 'S':
  630. Print(" Scroll Arg: ");
  631. a = get_num_input((long)MAXSCROLL);
  632. Printf("\ncreateitem(OSCROLL, %d)", a);
  633. createitem(playerx, playery, OSCROLL, a);
  634. dropflag = 1;
  635. break;
  636. case 'p':
  637. case 'P':
  638. Print(" Potion Arg: ");
  639. a = get_num_input((long)MAXPOTION);
  640. Printf("\ncreateitem(OPOTION, %d)", a);
  641. createitem(playerx, playery, OPOTION, a);
  642. dropflag = 1;
  643. break;
  644. case 'o':
  645. case 'O':
  646. Print("\n\n");
  647. Print("Item : ");
  648. t = get_num_input(0);
  649. Print("Arg : ");
  650. a = get_num_input(0);
  651. Printf("\ncreateitem(%d, %d)", t, a);
  652. createitem(playerx, playery, t, a);
  653. dropflag = 1;
  654. break;
  655. case 'm':
  656. case 'M':
  657. Print("\n\n");
  658. ClearToEOPage(1, 23);
  659. Print("Monst : ");
  660. t = get_num_input(0);
  661. Printf("\ncreatemonster(%d)", t);
  662. createmonster(t);
  663. dropflag = 1;
  664. break;
  665. default:
  666. Retry = 1;
  667. break;
  668. }
  669. } while (Retry);
  670. }