hack.invent.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. /* $NetBSD: hack.invent.c,v 1.9 2004/01/27 20:30:29 jsm Exp $ */
  2. /*
  3. * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
  4. * Amsterdam
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are
  9. * met:
  10. *
  11. * - Redistributions of source code must retain the above copyright notice,
  12. * this list of conditions and the following disclaimer.
  13. *
  14. * - Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * - Neither the name of the Stichting Centrum voor Wiskunde en
  19. * Informatica, nor the names of its contributors may be used to endorse or
  20. * promote products derived from this software without specific prior
  21. * written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  24. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
  25. * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  26. * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  27. * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  28. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  29. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  30. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  31. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  32. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34. */
  35. /*
  36. * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
  37. * All rights reserved.
  38. *
  39. * Redistribution and use in source and binary forms, with or without
  40. * modification, are permitted provided that the following conditions
  41. * are met:
  42. * 1. Redistributions of source code must retain the above copyright
  43. * notice, this list of conditions and the following disclaimer.
  44. * 2. Redistributions in binary form must reproduce the above copyright
  45. * notice, this list of conditions and the following disclaimer in the
  46. * documentation and/or other materials provided with the distribution.
  47. * 3. The name of the author may not be used to endorse or promote products
  48. * derived from this software without specific prior written permission.
  49. *
  50. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  51. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  52. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  53. * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  54. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  55. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  56. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  57. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  58. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  59. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  60. */
  61. #include <sys/cdefs.h>
  62. #ifndef lint
  63. __RCSID("$NetBSD: hack.invent.c,v 1.9 2004/01/27 20:30:29 jsm Exp $");
  64. #endif /* not lint */
  65. #include <stdlib.h>
  66. #include "hack.h"
  67. #include "extern.h"
  68. #ifndef NOWORM
  69. #include "def.wseg.h"
  70. #endif /* NOWORM */
  71. #define NOINVSYM '#'
  72. static int lastinvnr = 51; /* 0 ... 51 */
  73. static void assigninvlet(struct obj *);
  74. static char *xprname(struct obj *, char);
  75. static void
  76. assigninvlet(otmp)
  77. struct obj *otmp;
  78. {
  79. boolean inuse[52];
  80. int i;
  81. struct obj *obj;
  82. for (i = 0; i < 52; i++)
  83. inuse[i] = FALSE;
  84. for (obj = invent; obj; obj = obj->nobj)
  85. if (obj != otmp) {
  86. i = obj->invlet;
  87. if ('a' <= i && i <= 'z')
  88. inuse[i - 'a'] = TRUE;
  89. else if ('A' <= i && i <= 'Z')
  90. inuse[i - 'A' + 26] = TRUE;
  91. if (i == otmp->invlet)
  92. otmp->invlet = 0;
  93. }
  94. if ((i = otmp->invlet) &&
  95. (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
  96. return;
  97. for (i = lastinvnr + 1; i != lastinvnr; i++) {
  98. if (i == 52) {
  99. i = -1;
  100. continue;
  101. }
  102. if (!inuse[i])
  103. break;
  104. }
  105. otmp->invlet = (inuse[i] ? NOINVSYM :
  106. (i < 26) ? ('a' + i) : ('A' + i - 26));
  107. lastinvnr = i;
  108. }
  109. struct obj *
  110. addinv(obj)
  111. struct obj *obj;
  112. {
  113. struct obj *otmp;
  114. /* merge or attach to end of chain */
  115. if (!invent) {
  116. invent = obj;
  117. otmp = 0;
  118. } else
  119. for (otmp = invent; /* otmp */ ; otmp = otmp->nobj) {
  120. if (merged(otmp, obj, 0))
  121. return (otmp);
  122. if (!otmp->nobj) {
  123. otmp->nobj = obj;
  124. break;
  125. }
  126. }
  127. obj->nobj = 0;
  128. if (flags.invlet_constant) {
  129. assigninvlet(obj);
  130. /*
  131. * The ordering of the chain is nowhere significant
  132. * so in case you prefer some other order than the
  133. * historical one, change the code below.
  134. */
  135. if (otmp) { /* find proper place in chain */
  136. otmp->nobj = 0;
  137. if ((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
  138. obj->nobj = invent;
  139. invent = obj;
  140. } else
  141. for (otmp = invent;; otmp = otmp->nobj) {
  142. if (!otmp->nobj ||
  143. (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)) {
  144. obj->nobj = otmp->nobj;
  145. otmp->nobj = obj;
  146. break;
  147. }
  148. }
  149. }
  150. }
  151. return (obj);
  152. }
  153. void
  154. useup(obj)
  155. struct obj *obj;
  156. {
  157. if (obj->quan > 1) {
  158. obj->quan--;
  159. obj->owt = weight(obj);
  160. } else {
  161. setnotworn(obj);
  162. freeinv(obj);
  163. obfree(obj, (struct obj *) 0);
  164. }
  165. }
  166. void
  167. freeinv(obj)
  168. struct obj *obj;
  169. {
  170. struct obj *otmp;
  171. if (obj == invent)
  172. invent = invent->nobj;
  173. else {
  174. for (otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
  175. if (!otmp->nobj)
  176. panic("freeinv");
  177. otmp->nobj = obj->nobj;
  178. }
  179. }
  180. /* destroy object in fobj chain (if unpaid, it remains on the bill) */
  181. void
  182. delobj(obj)
  183. struct obj *obj;
  184. {
  185. freeobj(obj);
  186. unpobj(obj);
  187. obfree(obj, (struct obj *) 0);
  188. }
  189. /* unlink obj from chain starting with fobj */
  190. void
  191. freeobj(obj)
  192. struct obj *obj;
  193. {
  194. struct obj *otmp;
  195. if (obj == fobj)
  196. fobj = fobj->nobj;
  197. else {
  198. for (otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
  199. if (!otmp)
  200. panic("error in freeobj");
  201. otmp->nobj = obj->nobj;
  202. }
  203. }
  204. /* Note: freegold throws away its argument! */
  205. void
  206. freegold(gold)
  207. struct gold *gold;
  208. {
  209. struct gold *gtmp;
  210. if (gold == fgold)
  211. fgold = gold->ngold;
  212. else {
  213. for (gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
  214. if (!gtmp)
  215. panic("error in freegold");
  216. gtmp->ngold = gold->ngold;
  217. }
  218. free((char *) gold);
  219. }
  220. void
  221. deltrap(trap)
  222. struct trap *trap;
  223. {
  224. struct trap *ttmp;
  225. if (trap == ftrap)
  226. ftrap = ftrap->ntrap;
  227. else {
  228. for (ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap);
  229. ttmp->ntrap = trap->ntrap;
  230. }
  231. free((char *) trap);
  232. }
  233. struct wseg *m_atseg;
  234. struct monst *
  235. m_at(x, y)
  236. int x, y;
  237. {
  238. struct monst *mtmp;
  239. #ifndef NOWORM
  240. struct wseg *wtmp;
  241. #endif /* NOWORM */
  242. m_atseg = 0;
  243. for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  244. if (mtmp->mx == x && mtmp->my == y)
  245. return (mtmp);
  246. #ifndef NOWORM
  247. if (mtmp->wormno) {
  248. for (wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
  249. if (wtmp->wx == x && wtmp->wy == y) {
  250. m_atseg = wtmp;
  251. return (mtmp);
  252. }
  253. }
  254. #endif /* NOWORM */
  255. }
  256. return (0);
  257. }
  258. struct obj *
  259. o_at(x, y)
  260. int x, y;
  261. {
  262. struct obj *otmp;
  263. for (otmp = fobj; otmp; otmp = otmp->nobj)
  264. if (otmp->ox == x && otmp->oy == y)
  265. return (otmp);
  266. return (0);
  267. }
  268. struct obj *
  269. sobj_at(n, x, y)
  270. int n, x, y;
  271. {
  272. struct obj *otmp;
  273. for (otmp = fobj; otmp; otmp = otmp->nobj)
  274. if (otmp->ox == x && otmp->oy == y && otmp->otyp == n)
  275. return (otmp);
  276. return (0);
  277. }
  278. int
  279. carried(obj)
  280. struct obj *obj;
  281. {
  282. struct obj *otmp;
  283. for (otmp = invent; otmp; otmp = otmp->nobj)
  284. if (otmp == obj)
  285. return (1);
  286. return (0);
  287. }
  288. int
  289. carrying(type)
  290. int type;
  291. {
  292. struct obj *otmp;
  293. for (otmp = invent; otmp; otmp = otmp->nobj)
  294. if (otmp->otyp == type)
  295. return (TRUE);
  296. return (FALSE);
  297. }
  298. struct obj *
  299. o_on(id, objchn)
  300. unsigned int id;
  301. struct obj *objchn;
  302. {
  303. while (objchn) {
  304. if (objchn->o_id == id)
  305. return (objchn);
  306. objchn = objchn->nobj;
  307. }
  308. return ((struct obj *) 0);
  309. }
  310. struct trap *
  311. t_at(x, y)
  312. int x, y;
  313. {
  314. struct trap *trap = ftrap;
  315. while (trap) {
  316. if (trap->tx == x && trap->ty == y)
  317. return (trap);
  318. trap = trap->ntrap;
  319. }
  320. return (0);
  321. }
  322. struct gold *
  323. g_at(x, y)
  324. int x, y;
  325. {
  326. struct gold *gold = fgold;
  327. while (gold) {
  328. if (gold->gx == x && gold->gy == y)
  329. return (gold);
  330. gold = gold->ngold;
  331. }
  332. return (0);
  333. }
  334. /* make dummy object structure containing gold - for temporary use only */
  335. struct obj *
  336. mkgoldobj(q)
  337. long q;
  338. {
  339. struct obj *otmp;
  340. otmp = newobj(0);
  341. /* should set o_id etc. but otmp will be freed soon */
  342. otmp->olet = '$';
  343. u.ugold -= q;
  344. OGOLD(otmp) = q;
  345. flags.botl = 1;
  346. return (otmp);
  347. }
  348. /*
  349. * getobj returns:
  350. * struct obj *xxx: object to do something with.
  351. * (struct obj *) 0 error return: no object.
  352. * &zeroobj explicitly no object (as in w-).
  353. */
  354. struct obj *
  355. getobj(let, word)
  356. const char *let, *word;
  357. {
  358. struct obj *otmp;
  359. char ilet, ilet1, ilet2;
  360. char buf[BUFSZ];
  361. char lets[BUFSZ];
  362. int foo = 0, foo2;
  363. char *bp = buf;
  364. xchar allowcnt = 0; /* 0, 1 or 2 */
  365. boolean allowgold = FALSE;
  366. boolean allowall = FALSE;
  367. boolean allownone = FALSE;
  368. xchar foox = 0;
  369. long cnt;
  370. if (*let == '0')
  371. let++, allowcnt = 1;
  372. if (*let == '$')
  373. let++, allowgold = TRUE;
  374. if (*let == '#')
  375. let++, allowall = TRUE;
  376. if (*let == '-')
  377. let++, allownone = TRUE;
  378. if (allownone)
  379. *bp++ = '-';
  380. if (allowgold)
  381. *bp++ = '$';
  382. if (bp > buf && bp[-1] == '-')
  383. *bp++ = ' ';
  384. ilet = 'a';
  385. for (otmp = invent; otmp; otmp = otmp->nobj) {
  386. if (!*let || strchr(let, otmp->olet)) {
  387. bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
  388. /* ugly check: remove inappropriate things */
  389. if ((!strcmp(word, "take off") &&
  390. !(otmp->owornmask & (W_ARMOR - W_ARM2)))
  391. || (!strcmp(word, "wear") &&
  392. (otmp->owornmask & (W_ARMOR | W_RING)))
  393. || (!strcmp(word, "wield") &&
  394. (otmp->owornmask & W_WEP))) {
  395. foo--;
  396. foox++;
  397. }
  398. }
  399. if (ilet == 'z')
  400. ilet = 'A';
  401. else
  402. ilet++;
  403. }
  404. bp[foo] = 0;
  405. if (foo == 0 && bp > buf && bp[-1] == ' ')
  406. *--bp = 0;
  407. (void) strcpy(lets, bp);/* necessary since we destroy buf */
  408. if (foo > 5) { /* compactify string */
  409. foo = foo2 = 1;
  410. ilet2 = bp[0];
  411. ilet1 = bp[1];
  412. while ((ilet = bp[++foo2] = bp[++foo]) != '\0') {
  413. if (ilet == ilet1 + 1) {
  414. if (ilet1 == ilet2 + 1)
  415. bp[foo2 - 1] = ilet1 = '-';
  416. else if (ilet2 == '-') {
  417. bp[--foo2] = ++ilet1;
  418. continue;
  419. }
  420. }
  421. ilet2 = ilet1;
  422. ilet1 = ilet;
  423. }
  424. }
  425. if (!foo && !allowall && !allowgold && !allownone) {
  426. pline("You don't have anything %sto %s.",
  427. foox ? "else " : "", word);
  428. return (0);
  429. }
  430. for (;;) {
  431. if (!buf[0])
  432. pline("What do you want to %s [*]? ", word);
  433. else
  434. pline("What do you want to %s [%s or ?*]? ",
  435. word, buf);
  436. cnt = 0;
  437. ilet = readchar();
  438. while (digit(ilet) && allowcnt) {
  439. if (cnt < 100000000)
  440. cnt = 10 * cnt + (ilet - '0');
  441. else
  442. cnt = 999999999;
  443. allowcnt = 2; /* signal presence of cnt */
  444. ilet = readchar();
  445. }
  446. if (digit(ilet)) {
  447. pline("No count allowed with this command.");
  448. continue;
  449. }
  450. if (strchr(quitchars, ilet))
  451. return ((struct obj *) 0);
  452. if (ilet == '-') {
  453. return (allownone ? &zeroobj : (struct obj *) 0);
  454. }
  455. if (ilet == '$') {
  456. if (!allowgold) {
  457. pline("You cannot %s gold.", word);
  458. continue;
  459. }
  460. if (!(allowcnt == 2 && cnt < u.ugold))
  461. cnt = u.ugold;
  462. return (mkgoldobj(cnt));
  463. }
  464. if (ilet == '?') {
  465. doinv(lets);
  466. if (!(ilet = morc))
  467. continue;
  468. /* he typed a letter (not a space) to more() */
  469. } else if (ilet == '*') {
  470. doinv((char *) 0);
  471. if (!(ilet = morc))
  472. continue;
  473. /* ... */
  474. }
  475. if (flags.invlet_constant) {
  476. for (otmp = invent; otmp; otmp = otmp->nobj)
  477. if (otmp->invlet == ilet)
  478. break;
  479. } else {
  480. if (ilet >= 'A' && ilet <= 'Z')
  481. ilet += 'z' - 'A' + 1;
  482. ilet -= 'a';
  483. for (otmp = invent; otmp && ilet;
  484. ilet--, otmp = otmp->nobj);
  485. }
  486. if (!otmp) {
  487. pline("You don't have that object.");
  488. continue;
  489. }
  490. if (cnt < 0 || otmp->quan < cnt) {
  491. pline("You don't have that many! [You have %u]"
  492. ,otmp->quan);
  493. continue;
  494. }
  495. break;
  496. }
  497. if (!allowall && let && !strchr(let, otmp->olet)) {
  498. pline("That is a silly thing to %s.", word);
  499. return (0);
  500. }
  501. if (allowcnt == 2) { /* cnt given */
  502. if (cnt == 0)
  503. return (0);
  504. if (cnt != otmp->quan) {
  505. struct obj *obj;
  506. obj = splitobj(otmp, (int) cnt);
  507. if (otmp == uwep)
  508. setuwep(obj);
  509. }
  510. }
  511. return (otmp);
  512. }
  513. int
  514. ckunpaid(otmp)
  515. struct obj *otmp;
  516. {
  517. return (otmp->unpaid);
  518. }
  519. /* interactive version of getobj - used for Drop and Identify */
  520. /* return the number of times fn was called successfully */
  521. int
  522. ggetobj(word, fn, max)
  523. const char *word;
  524. int (*fn)(struct obj *);
  525. int max;
  526. {
  527. char buf[BUFSZ];
  528. char *ip;
  529. char sym;
  530. int oletct = 0, iletct = 0;
  531. boolean allflag = FALSE;
  532. char olets[20], ilets[20];
  533. int (*ckfn)(struct obj *) =
  534. (int (*)(struct obj *)) 0;
  535. xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0; /* BAH */
  536. if (!invent && !allowgold) {
  537. pline("You have nothing to %s.", word);
  538. return (0);
  539. } else {
  540. struct obj *otmp = invent;
  541. int uflg = 0;
  542. if (allowgold)
  543. ilets[iletct++] = '$';
  544. ilets[iletct] = 0;
  545. while (otmp) {
  546. if (!strchr(ilets, otmp->olet)) {
  547. ilets[iletct++] = otmp->olet;
  548. ilets[iletct] = 0;
  549. }
  550. if (otmp->unpaid)
  551. uflg = 1;
  552. otmp = otmp->nobj;
  553. }
  554. ilets[iletct++] = ' ';
  555. if (uflg)
  556. ilets[iletct++] = 'u';
  557. if (invent)
  558. ilets[iletct++] = 'a';
  559. ilets[iletct] = 0;
  560. }
  561. pline("What kinds of thing do you want to %s? [%s] ",
  562. word, ilets);
  563. getlin(buf);
  564. if (buf[0] == '\033') {
  565. clrlin();
  566. return (0);
  567. }
  568. ip = buf;
  569. olets[0] = 0;
  570. while ((sym = *ip++) != '\0') {
  571. if (sym == ' ')
  572. continue;
  573. if (sym == '$') {
  574. if (allowgold == 1)
  575. (*fn) (mkgoldobj(u.ugold));
  576. else if (!u.ugold)
  577. pline("You have no gold.");
  578. allowgold = 2;
  579. } else if (sym == 'a' || sym == 'A')
  580. allflag = TRUE;
  581. else if (sym == 'u' || sym == 'U')
  582. ckfn = ckunpaid;
  583. else if (strchr("!%?[()=*/\"0", sym)) {
  584. if (!strchr(olets, sym)) {
  585. olets[oletct++] = sym;
  586. olets[oletct] = 0;
  587. }
  588. } else
  589. pline("You don't have any %c's.", sym);
  590. }
  591. if (allowgold == 2 && !oletct)
  592. return (1); /* he dropped gold (or at least tried to) */
  593. else
  594. return (askchain(invent, olets, allflag, fn, ckfn, max));
  595. }
  596. /*
  597. * Walk through the chain starting at objchn and ask for all objects
  598. * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
  599. * whether the action in question (i.e., fn) has to be performed.
  600. * If allflag then no questions are asked. Max gives the max nr of
  601. * objects to be treated. Return the number of objects treated.
  602. */
  603. int
  604. askchain(objchn, olets, allflag, fn, ckfn, max)
  605. struct obj *objchn;
  606. char *olets;
  607. int allflag;
  608. int (*fn)(struct obj *);
  609. int (*ckfn)(struct obj *);
  610. int max;
  611. {
  612. struct obj *otmp, *otmp2;
  613. char sym, ilet;
  614. int cnt = 0;
  615. ilet = 'a' - 1;
  616. for (otmp = objchn; otmp; otmp = otmp2) {
  617. if (ilet == 'z')
  618. ilet = 'A';
  619. else
  620. ilet++;
  621. otmp2 = otmp->nobj;
  622. if (olets && *olets && !strchr(olets, otmp->olet))
  623. continue;
  624. if (ckfn && !(*ckfn) (otmp))
  625. continue;
  626. if (!allflag) {
  627. pline(xprname(otmp, ilet));
  628. addtopl(" [nyaq]? ");
  629. sym = readchar();
  630. } else
  631. sym = 'y';
  632. switch (sym) {
  633. case 'a':
  634. allflag = 1;
  635. case 'y':
  636. cnt += (*fn) (otmp);
  637. if (--max == 0)
  638. goto ret;
  639. case 'n':
  640. default:
  641. break;
  642. case 'q':
  643. goto ret;
  644. }
  645. }
  646. pline(cnt ? "That was all." : "No applicable objects.");
  647. ret:
  648. return (cnt);
  649. }
  650. char
  651. obj_to_let(obj) /* should of course only be called for things
  652. * in invent */
  653. struct obj *obj;
  654. {
  655. struct obj *otmp;
  656. char ilet;
  657. if (flags.invlet_constant)
  658. return (obj->invlet);
  659. ilet = 'a';
  660. for (otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
  661. if (++ilet > 'z')
  662. ilet = 'A';
  663. return (otmp ? ilet : NOINVSYM);
  664. }
  665. void
  666. prinv(obj)
  667. struct obj *obj;
  668. {
  669. pline(xprname(obj, obj_to_let(obj)));
  670. }
  671. static char *
  672. xprname(obj, let)
  673. struct obj *obj;
  674. char let;
  675. {
  676. static char li[BUFSZ];
  677. (void) sprintf(li, "%c - %s.",
  678. flags.invlet_constant ? obj->invlet : let,
  679. doname(obj));
  680. return (li);
  681. }
  682. int
  683. ddoinv()
  684. {
  685. doinv((char *) 0);
  686. return (0);
  687. }
  688. /* called with 0 or "": all objects in inventory */
  689. /* otherwise: all objects with (serial) letter in lets */
  690. void
  691. doinv(lets)
  692. char *lets;
  693. {
  694. struct obj *otmp;
  695. char ilet;
  696. int ct = 0;
  697. char any[BUFSZ];
  698. morc = 0; /* just to be sure */
  699. if (!invent) {
  700. pline("Not carrying anything.");
  701. return;
  702. }
  703. cornline(0, (char *) 0);
  704. ilet = 'a';
  705. for (otmp = invent; otmp; otmp = otmp->nobj) {
  706. if (flags.invlet_constant)
  707. ilet = otmp->invlet;
  708. if (!lets || !*lets || strchr(lets, ilet)) {
  709. cornline(1, xprname(otmp, ilet));
  710. any[ct++] = ilet;
  711. }
  712. if (!flags.invlet_constant)
  713. if (++ilet > 'z')
  714. ilet = 'A';
  715. }
  716. any[ct] = 0;
  717. cornline(2, any);
  718. }
  719. int
  720. dotypeinv()
  721. { /* free after Robert Viduya */
  722. /* Changed to one type only, so he doesnt have to type cr */
  723. char c, ilet;
  724. char stuff[BUFSZ];
  725. int stct;
  726. struct obj *otmp;
  727. boolean billx = inshop() && doinvbill(0);
  728. boolean unpd = FALSE;
  729. if (!invent && !u.ugold && !billx) {
  730. pline("You aren't carrying anything.");
  731. return (0);
  732. }
  733. stct = 0;
  734. if (u.ugold)
  735. stuff[stct++] = '$';
  736. stuff[stct] = 0;
  737. for (otmp = invent; otmp; otmp = otmp->nobj) {
  738. if (!strchr(stuff, otmp->olet)) {
  739. stuff[stct++] = otmp->olet;
  740. stuff[stct] = 0;
  741. }
  742. if (otmp->unpaid)
  743. unpd = TRUE;
  744. }
  745. if (unpd)
  746. stuff[stct++] = 'u';
  747. if (billx)
  748. stuff[stct++] = 'x';
  749. stuff[stct] = 0;
  750. if (stct > 1) {
  751. pline("What type of object [%s] do you want an inventory of? ",
  752. stuff);
  753. c = readchar();
  754. if (strchr(quitchars, c))
  755. return (0);
  756. } else
  757. c = stuff[0];
  758. if (c == '$')
  759. return (doprgold());
  760. if (c == 'x' || c == 'X') {
  761. if (billx)
  762. (void) doinvbill(1);
  763. else
  764. pline("No used-up objects on the shopping bill.");
  765. return (0);
  766. }
  767. if ((c == 'u' || c == 'U') && !unpd) {
  768. pline("You are not carrying any unpaid objects.");
  769. return (0);
  770. }
  771. stct = 0;
  772. ilet = 'a';
  773. for (otmp = invent; otmp; otmp = otmp->nobj) {
  774. if (flags.invlet_constant)
  775. ilet = otmp->invlet;
  776. if (c == otmp->olet || (c == 'u' && otmp->unpaid))
  777. stuff[stct++] = ilet;
  778. if (!flags.invlet_constant)
  779. if (++ilet > 'z')
  780. ilet = 'A';
  781. }
  782. stuff[stct] = '\0';
  783. if (stct == 0)
  784. pline("You have no such objects.");
  785. else
  786. doinv(stuff);
  787. return (0);
  788. }
  789. /* look at what is here */
  790. int
  791. dolook()
  792. {
  793. struct obj *otmp = NULL, *otmp0 = NULL;
  794. struct gold *gold = NULL;
  795. const char *verb = Blind ? "feel" : "see";
  796. int ct = 0;
  797. if (!u.uswallow) {
  798. if (Blind) {
  799. pline("You try to feel what is lying here on the floor.");
  800. if (Levitation) { /* ab@unido */
  801. pline("You cannot reach the floor!");
  802. return (1);
  803. }
  804. }
  805. otmp0 = o_at(u.ux, u.uy);
  806. gold = g_at(u.ux, u.uy);
  807. }
  808. if (u.uswallow || (!otmp0 && !gold)) {
  809. pline("You %s no objects here.", verb);
  810. return (!!Blind);
  811. }
  812. cornline(0, "Things that are here:");
  813. for (otmp = otmp0; otmp; otmp = otmp->nobj) {
  814. if (otmp->ox == u.ux && otmp->oy == u.uy) {
  815. ct++;
  816. cornline(1, doname(otmp));
  817. if (Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
  818. pline("Touching the dead cockatrice is a fatal mistake ...");
  819. pline("You die ...");
  820. killer = "dead cockatrice";
  821. done("died");
  822. }
  823. }
  824. }
  825. if (gold) {
  826. char gbuf[30];
  827. (void) sprintf(gbuf, "%ld gold piece%s",
  828. gold->amount, plur(gold->amount));
  829. if (!ct++)
  830. pline("You %s here %s.", verb, gbuf);
  831. else
  832. cornline(1, gbuf);
  833. }
  834. if (ct == 1 && !gold) {
  835. pline("You %s here %s.", verb, doname(otmp0));
  836. cornline(3, (char *) 0);
  837. }
  838. if (ct > 1)
  839. cornline(2, (char *) 0);
  840. return (!!Blind);
  841. }
  842. void
  843. stackobj(obj)
  844. struct obj *obj;
  845. {
  846. struct obj *otmp = fobj;
  847. for (otmp = fobj; otmp; otmp = otmp->nobj)
  848. if (otmp != obj)
  849. if (otmp->ox == obj->ox && otmp->oy == obj->oy &&
  850. merged(obj, otmp, 1))
  851. return;
  852. }
  853. /* merge obj with otmp and delete obj if types agree */
  854. int
  855. merged(otmp, obj, lose)
  856. struct obj *otmp, *obj;
  857. int lose;
  858. {
  859. if (obj->otyp == otmp->otyp &&
  860. obj->unpaid == otmp->unpaid &&
  861. obj->spe == otmp->spe &&
  862. obj->dknown == otmp->dknown &&
  863. obj->cursed == otmp->cursed &&
  864. (strchr("%*?!", obj->olet) ||
  865. (obj->known == otmp->known &&
  866. (obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
  867. otmp->quan += obj->quan;
  868. otmp->owt += obj->owt;
  869. if (lose)
  870. freeobj(obj);
  871. obfree(obj, otmp); /* free(obj), bill->otmp */
  872. return (1);
  873. } else
  874. return (0);
  875. }
  876. static long goldcounted;
  877. /*
  878. * Gold is no longer displayed; in fact, when you have a lot of money,
  879. * it may take a while before you have counted it all.
  880. * [Bug: d$ and pickup still tell you how much it was.]
  881. */
  882. int
  883. countgold()
  884. {
  885. if ((goldcounted += 100 * (u.ulevel + 1)) >= u.ugold) {
  886. long eps = 0;
  887. if (!rn2(2))
  888. eps = rnd((int) (u.ugold / 100 + 1));
  889. pline("You probably have about %ld gold pieces.",
  890. u.ugold + eps);
  891. return (0); /* done */
  892. }
  893. return (1); /* continue */
  894. }
  895. int
  896. doprgold()
  897. {
  898. if (!u.ugold)
  899. pline("You do not carry any gold.");
  900. else if (u.ugold <= 500)
  901. pline("You are carrying %ld gold pieces.", u.ugold);
  902. else {
  903. pline("You sit down in order to count your gold pieces.");
  904. goldcounted = 500;
  905. occupation = countgold;
  906. occtxt = "counting your gold";
  907. }
  908. return (1);
  909. }
  910. /* --- end of gold counting section --- */
  911. int
  912. doprwep()
  913. {
  914. if (!uwep)
  915. pline("You are empty handed.");
  916. else
  917. prinv(uwep);
  918. return (0);
  919. }
  920. int
  921. doprarm()
  922. {
  923. if (!uarm && !uarmg && !uarms && !uarmh)
  924. pline("You are not wearing any armor.");
  925. else {
  926. char lets[6];
  927. int ct = 0;
  928. if (uarm)
  929. lets[ct++] = obj_to_let(uarm);
  930. if (uarm2)
  931. lets[ct++] = obj_to_let(uarm2);
  932. if (uarmh)
  933. lets[ct++] = obj_to_let(uarmh);
  934. if (uarms)
  935. lets[ct++] = obj_to_let(uarms);
  936. if (uarmg)
  937. lets[ct++] = obj_to_let(uarmg);
  938. lets[ct] = 0;
  939. doinv(lets);
  940. }
  941. return (0);
  942. }
  943. int
  944. doprring()
  945. {
  946. if (!uleft && !uright)
  947. pline("You are not wearing any rings.");
  948. else {
  949. char lets[3];
  950. int ct = 0;
  951. if (uleft)
  952. lets[ct++] = obj_to_let(uleft);
  953. if (uright)
  954. lets[ct++] = obj_to_let(uright);
  955. lets[ct] = 0;
  956. doinv(lets);
  957. }
  958. return (0);
  959. }
  960. int
  961. digit(c)
  962. char c;
  963. {
  964. return (c >= '0' && c <= '9');
  965. }