home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume16 / nethck31 / part13 < prev    next >
Encoding:
Internet Message Format  |  1993-01-31  |  57.2 KB

  1. Path: uunet!news.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v16i013:  nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part13/108
  5. Message-ID: <4296@master.CNA.TEK.COM>
  6. Date: 28 Jan 93 19:13:10 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2148
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1569
  11.  
  12. Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
  13. Posting-number: Volume 16, Issue 13
  14. Archive-name: nethack31/Part13
  15. Supersedes: nethack3p9: Volume 10, Issue 46-102
  16. Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
  17.  
  18.  
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 13 (of 108)."
  27. # Contents:  dat/yendor.des src/invent.c
  28. # Wrapped by billr@saab on Wed Jan 27 16:08:50 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'dat/yendor.des' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'dat/yendor.des'\"
  32. else
  33. echo shar: Extracting \"'dat/yendor.des'\" \(6672 characters\)
  34. sed "s/^X//" >'dat/yendor.des' <<'END_OF_FILE'
  35. X#    SCCS Id: @(#)yendor.des    3.1    92/01/10
  36. X#    Copyright (c) 1989 by Jean-Christophe Collet
  37. X#    Copyright (c) 1992 by M. Stephenson and Izchak Miller
  38. X# NetHack may be freely redistributed.  See license for details.
  39. X#
  40. X# The top (real) wizard level.
  41. X# Keeping the Moat for old-time's sake
  42. XMAZE:"wizard1",random
  43. XFLAGS:noteleport
  44. XGEOMETRY:center,center
  45. XMAP
  46. X----------------------------.
  47. X|.......|..|.........|.....|.
  48. X|.......S..|.}}}}}}}.|.....|.
  49. X|..--S--|..|.}}---}}.|---S-|.
  50. X|..|....|..|.}--.--}.|..|..|.
  51. X|..|....|..|.}|...|}.|..|..|.
  52. X|..--------|.}--.--}.|..|..|.
  53. X|..|.......|.}}---}}.|..|..|.
  54. X|..S.......|.}}}}}}}.|..|..|.
  55. X|..|.......|.........|..|..|.
  56. X|..|.......|-----------S-S-|.
  57. X|..|.......S...............|.
  58. X----------------------------.
  59. XENDMAP
  60. XSTAIR:levregion(01,00,79,20),(0,0,28,12),up
  61. XSTAIR:levregion(01,00,79,20),(0,0,28,12),down
  62. XBRANCH:levregion(01,00,79,20),(0,0,28,12)
  63. XTELEPORT_REGION:levregion(01,00,79,20),(0,0,28,12)
  64. X# Make it a morgue for rm id in mkmaze.c
  65. X# for the purpose of random sdoor placement
  66. XREGION:(12,01,20,09),unlit,"morgue",unfilled
  67. XMAZEWALK:(28,05),east
  68. XLADDER:(06,05),down
  69. X# Non diggable walls
  70. X# Walls inside the moat stay diggable
  71. XNON_DIGGABLE:(00,00,11,12)
  72. XNON_DIGGABLE:(11,00,21,00)
  73. XNON_DIGGABLE:(11,10,27,12)
  74. XNON_DIGGABLE:(21,00,27,10)
  75. X# The wizard and his guards
  76. XMONSTER:'@',"Wizard of Yendor",(16,05),asleep
  77. XMONSTER:'d',"hell hound",(15,05)
  78. XMONSTER:'V',"vampire lord",(17,05)
  79. X# The local treasure
  80. XOBJECT:'+',"Book of the Dead",(16,05)
  81. X# Surrounding terror
  82. XMONSTER:';',"kraken",(14,02)
  83. XMONSTER:';',"giant eel",(17,02)
  84. XMONSTER:';',"kraken",(13,04)
  85. XMONSTER:';',"giant eel",(13,06)
  86. XMONSTER:';',"kraken",(19,04)
  87. XMONSTER:';',"giant eel",(19,06)
  88. XMONSTER:';',"kraken",(15,08)
  89. XMONSTER:';',"giant eel",(17,08)
  90. X# Random monsters
  91. XMONSTER:'D',random,random
  92. XMONSTER:'H',random,random
  93. XMONSTER:'&',random,random
  94. XMONSTER:'&',random,random
  95. XMONSTER:'&',random,random
  96. XMONSTER:'&',random,random
  97. X# And to make things a little harder.
  98. XTRAP:"board",(16,04)
  99. XTRAP:"board",(16,06)
  100. XTRAP:"board",(15,05)
  101. XTRAP:"board",(17,05)
  102. X# Random traps.
  103. XTRAP:"spiked pit",random
  104. XTRAP:"sleep gas",random
  105. XTRAP:"anti magic",random
  106. XTRAP:"magic",random
  107. X# Some random loot.
  108. XOBJECT:'*',"ruby",random
  109. XOBJECT:'!',random,random
  110. XOBJECT:'!',random,random
  111. XOBJECT:'?',random,random
  112. XOBJECT:'?',random,random
  113. XOBJECT:'+',random,random
  114. XOBJECT:'+',random,random
  115. XOBJECT:'+',random,random
  116. X
  117. X
  118. X# The middle wizard level.
  119. XMAZE:"wizard2",random
  120. XFLAGS:noteleport
  121. XGEOMETRY:center,center
  122. XMAP
  123. X----------------------------.
  124. X|.....|.S....|.............|.
  125. X|.....|.-------S--------S--|.
  126. X|.....|.|.........|........|.
  127. X|..-S--S|.........|........|.
  128. X|..|....|.........|------S-|.
  129. X|..|....|.........|.....|..|.
  130. X|-S-----|.........|.....|..|.
  131. X|.......|.........|S--S--..|.
  132. X|.......|.........|.|......|.
  133. X|-----S----S-------.|......|.
  134. X|............|....S.|......|.
  135. X----------------------------.
  136. XENDMAP
  137. XSTAIR:levregion(01,00,79,20),(0,0,28,12),up
  138. XSTAIR:levregion(01,00,79,20),(0,0,28,12),down
  139. XBRANCH:levregion(01,00,79,20),(0,0,28,12)
  140. XTELEPORT_REGION:levregion(01,00,79,20),(0,0,28,12)
  141. XREGION:(09,03,17,09),unlit,"zoo"
  142. XDOOR:closed,(15,02)
  143. XDOOR:closed,(11,10)
  144. XMAZEWALK:(28,05),east
  145. XLADDER:(12,01),up
  146. XLADDER:(14,11),down
  147. X# Non diggable walls everywhere
  148. XNON_DIGGABLE:(00,00,27,12)
  149. X# Random traps.
  150. XTRAP:"spiked pit",random
  151. XTRAP:"sleep gas",random
  152. XTRAP:"anti magic",random
  153. XTRAP:"magic",random
  154. X# Some random loot.
  155. XOBJECT:'!',random,random
  156. XOBJECT:'!',random,random
  157. XOBJECT:'?',random,random
  158. XOBJECT:'?',random,random
  159. XOBJECT:'+',random,random
  160. X# treasures
  161. XOBJECT:'"',random,(04,06)
  162. X
  163. X
  164. X# The bottom wizard level.
  165. X# Memorialize the fakewiz setup.
  166. XMAZE:"wizard3",random
  167. XFLAGS:noteleport
  168. XGEOMETRY:center,center
  169. XMAP
  170. X----------------------------.
  171. X|..|............S..........|.
  172. X|..|..------------------S--|.
  173. X|..|..|.........|..........|.
  174. X|..S..|.}}}}}}}.|..........|.
  175. X|..|..|.}}---}}.|-S--------|.
  176. X|..|..|.}--.--}.|..|.......|.
  177. X|..|..|.}|...|}.|..|.......|.
  178. X|..---|.}--.--}.|..|.......|.
  179. X|.....|.}}---}}.|..|.......|.
  180. X|.....S.}}}}}}}.|..|.......|.
  181. X|.....|.........|..S.......|.
  182. X----------------------------.
  183. XENDMAP
  184. XSTAIR:levregion(01,00,79,20),(0,0,28,12),up
  185. XSTAIR:levregion(01,00,79,20),(0,0,28,12),down
  186. XBRANCH:levregion(01,00,79,20),(0,0,28,12)
  187. XTELEPORT_REGION:levregion(01,00,79,20),(0,0,28,12)
  188. XPORTAL:(25,11,25,11),(0,0,0,0),"fakewiz1"
  189. XMAZEWALK:(28,09),east
  190. XREGION:(07,03,15,11),unlit,"morgue",unfilled
  191. XREGION:(17,06,18,11),unlit,"beehive"
  192. XDOOR:closed,(18,05)
  193. XDOOR:closed,(19,11)
  194. XLADDER:(11,07),up
  195. X# Non diggable walls
  196. X# Walls inside the moat stay diggable
  197. XNON_DIGGABLE:(00,00,06,12)
  198. XNON_DIGGABLE:(06,00,27,02)
  199. XNON_DIGGABLE:(16,02,27,12)
  200. XNON_DIGGABLE:(06,12,16,12)
  201. XMONSTER:'L',random,(10,07)
  202. XMONSTER:'V',"vampire lord",(12,07)
  203. X# Some surrounding horrors
  204. XMONSTER:';',"kraken",(08,05)
  205. XMONSTER:';',"giant eel",(08,08)
  206. XMONSTER:';',"kraken",(14,05)
  207. XMONSTER:';',"giant eel",(14,08)
  208. X# Other monsters
  209. XMONSTER:'L',random,random
  210. XMONSTER:'D',random,random
  211. XMONSTER:'D',random,(26,09)
  212. XMONSTER:'&',random,random
  213. XMONSTER:'&',random,random
  214. XMONSTER:'&',random,random
  215. X# And to make things a little harder.
  216. XTRAP:"board",(10,07)
  217. XTRAP:"board",(12,07)
  218. XTRAP:"board",(11,06)
  219. XTRAP:"board",(11,08)
  220. X# Some loot
  221. XOBJECT:')',random,random
  222. XOBJECT:'!',random,random
  223. XOBJECT:'?',random,random
  224. XOBJECT:'?',random,random
  225. XOBJECT:'(',random,random
  226. X# treasures
  227. XOBJECT:'"',random,(11,07)
  228. X
  229. X
  230. X# The former decoy wizard levels.
  231. X# There are two of these, and we need to
  232. X# distinguish between them for the portal.
  233. XMAZE:"fakewiz1",random
  234. XGEOMETRY:center,center
  235. XMAP
  236. X.........
  237. X.}}}}}}}.
  238. X.}}---}}.
  239. X.}--.--}.
  240. X.}|...|}.
  241. X.}--.--}.
  242. X.}}---}}.
  243. X.}}}}}}}.
  244. XENDMAP
  245. XSTAIR:levregion(01,00,79,20),(0,0,8,7),up
  246. XSTAIR:levregion(01,00,79,20),(0,0,8,7),down
  247. XBRANCH:levregion(01,00,79,20),(0,0,8,7)
  248. XTELEPORT_REGION:levregion(01,00,79,20),(0,0,8,7)
  249. XPORTAL:(4,4,4,4),(0,0,0,0),"wizard3"
  250. XMAZEWALK:(08,05),east
  251. XREGION:(04,03,06,06),unlit,"ordinary",unfilled,true
  252. XMONSTER:'L',random,(04,04)
  253. XMONSTER:'V',"vampire lord",(03,04)
  254. XMONSTER:';',"kraken",(06,06)
  255. X# And to make things a little harder.
  256. XTRAP:"board",(04,03)
  257. XTRAP:"board",(04,05)
  258. XTRAP:"board",(03,04)
  259. XTRAP:"board",(05,04)
  260. X
  261. X
  262. XMAZE:"fakewiz2",random
  263. XGEOMETRY:center,center
  264. XMAP
  265. X.........
  266. X.}}}}}}}.
  267. X.}}---}}.
  268. X.}--.--}.
  269. X.}|...|}.
  270. X.}--.--}.
  271. X.}}---}}.
  272. X.}}}}}}}.
  273. XENDMAP
  274. XSTAIR:levregion(01,00,79,20),(0,0,8,7),up
  275. XSTAIR:levregion(01,00,79,20),(0,0,8,7),down
  276. XBRANCH:levregion(01,00,79,20),(0,0,8,7)
  277. XTELEPORT_REGION:levregion(01,00,79,20),(0,0,8,7)
  278. XMAZEWALK:(08,05),east
  279. XREGION:(04,03,06,06),unlit,"ordinary",unfilled,true
  280. XMONSTER:'L',random,(04,04)
  281. XMONSTER:'V',"vampire lord",(03,04)
  282. XMONSTER:';',"kraken",(06,06)
  283. X# And to make things a little harder.
  284. XTRAP:"board",(04,03)
  285. XTRAP:"board",(04,05)
  286. XTRAP:"board",(03,04)
  287. XTRAP:"board",(05,04)
  288. X# treasures
  289. XOBJECT:'"',random,(04,04)
  290. END_OF_FILE
  291. if test 6672 -ne `wc -c <'dat/yendor.des'`; then
  292.     echo shar: \"'dat/yendor.des'\" unpacked with wrong size!
  293. fi
  294. # end of 'dat/yendor.des'
  295. fi
  296. if test -f 'src/invent.c' -a "${1}" != "-c" ; then 
  297.   echo shar: Will not clobber existing file \"'src/invent.c'\"
  298. else
  299. echo shar: Extracting \"'src/invent.c'\" \(47145 characters\)
  300. sed "s/^X//" >'src/invent.c' <<'END_OF_FILE'
  301. X/*    SCCS Id: @(#)invent.c    3.1    92/12/11    */
  302. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  303. X/* NetHack may be freely redistributed.  See license for details. */
  304. X
  305. X#include "hack.h"
  306. X#include "artifact.h"
  307. X
  308. X#define    NOINVSYM    '#'
  309. X#define    CONTAINED_SYM    '>'    /* designator for inside a container */
  310. X
  311. X#ifdef OVL1
  312. Xstatic void NDECL(reorder_invent);
  313. Xstatic boolean FDECL(mergable,(struct obj *,struct obj *));
  314. Xstatic int FDECL(merged,(struct obj *,struct obj *,int));
  315. X#endif /* OVL1 */
  316. XSTATIC_DCL void FDECL(assigninvlet,(struct obj *));
  317. XSTATIC_DCL void FDECL(unlinkinv,(struct obj*));
  318. XSTATIC_DCL void FDECL(compactify,(char *));
  319. XSTATIC_PTR int FDECL(ckunpaid,(struct obj *));
  320. X#ifdef OVLB
  321. Xstatic struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
  322. Xstatic boolean NDECL(wearing_armor);
  323. Xstatic boolean FDECL(is_worn,(struct obj *));
  324. X#endif /* OVLB */
  325. XSTATIC_DCL char FDECL(obj_to_let,(struct obj *));
  326. X
  327. X#ifdef OVLB
  328. X
  329. Xstatic int lastinvnr = 51;    /* 0 ... 51 (never saved&restored) */
  330. X
  331. Xchar inv_order[] = {    /* manipulated in options.c, used below */
  332. X    AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, SCROLL_CLASS,
  333. X    SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS, TOOL_CLASS, 
  334. X    GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0 };
  335. X
  336. X#ifdef WIZARD
  337. X/* wizards can wish for venom, which will become an invisible inventory
  338. X * item without this.  putting it in inv_order would mean venom would
  339. X * suddenly become a choice for all the inventory-class commands, which
  340. X * would probably cause mass confusion.  the test for inventory venom
  341. X * is only WIZARD and not wizard because the wizard can leave venom lying
  342. X * around on a bones level for normal players to find.
  343. X */
  344. Xstatic char venom_inv[] = { VENOM_CLASS, 0 };    /* (constant) */
  345. X#endif
  346. X
  347. XSTATIC_OVL void
  348. Xassigninvlet(otmp)
  349. Xregister struct obj *otmp;
  350. X{
  351. X    boolean inuse[52];
  352. X    register int i;
  353. X    register struct obj *obj;
  354. X
  355. X    for(i = 0; i < 52; i++) inuse[i] = FALSE;
  356. X    for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
  357. X        i = obj->invlet;
  358. X        if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
  359. X        if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
  360. X        if(i == otmp->invlet) otmp->invlet = 0;
  361. X    }
  362. X    if((i = otmp->invlet) &&
  363. X        (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
  364. X        return;
  365. X    for(i = lastinvnr+1; i != lastinvnr; i++) {
  366. X        if(i == 52) { i = -1; continue; }
  367. X        if(!inuse[i]) break;
  368. X    }
  369. X    otmp->invlet = (inuse[i] ? NOINVSYM :
  370. X            (i < 26) ? ('a'+i) : ('A'+i-26));
  371. X    lastinvnr = i;
  372. X}
  373. X
  374. X#endif /* OVLB */
  375. X#ifdef OVL1
  376. X
  377. X/* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
  378. X#define inv_rank(o) ((o)->invlet ^ 040)
  379. X
  380. X/* sort the inventory; used by addinv() and doorganize() */
  381. Xstatic void
  382. Xreorder_invent()
  383. X{
  384. X    struct obj *otmp, *prev, *next;
  385. X    boolean need_more_sorting;
  386. X
  387. X    do {
  388. X        /*
  389. X         * We expect at most one item to be out of order, so this
  390. X         * isn't nearly as inefficient as it may first appear.
  391. X         */
  392. X        need_more_sorting = FALSE;
  393. X        for (otmp = invent, prev = 0; otmp; ) {
  394. X        next = otmp->nobj;
  395. X        if (next && inv_rank(next) < inv_rank(otmp)) {
  396. X            need_more_sorting = TRUE;
  397. X            if (prev) prev->nobj = next;
  398. X            else      invent = next;
  399. X            otmp->nobj = next->nobj;
  400. X            next->nobj = otmp;
  401. X            prev = next;
  402. X        } else {
  403. X            prev = otmp;
  404. X            otmp = next;
  405. X        }
  406. X        }
  407. X    } while (need_more_sorting);
  408. X}
  409. X
  410. X#undef inv_rank
  411. X
  412. X/* merge obj with otmp and delete obj if types agree */
  413. XSTATIC_OVL int
  414. Xmerged(otmp, obj, lose)
  415. Xregister struct obj *otmp, *obj;
  416. Xregister int lose;
  417. X{
  418. X    if(mergable(otmp, obj)) {
  419. X        /* Approximate age: we do it this way because if we were to
  420. X         * do it "accurately" (merge only when ages are identical)
  421. X         * we'd wind up never merging any corpses.
  422. X         * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
  423. X         */
  424. X        otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
  425. X            / (otmp->quan + obj->quan);
  426. X        otmp->quan += obj->quan;
  427. X        otmp->owt += obj->owt;
  428. X        if(!otmp->onamelth && obj->onamelth)
  429. X            otmp = oname(otmp, ONAME(obj), 1);
  430. X        if(lose) freeobj(obj);
  431. X        obfree(obj,otmp);    /* free(obj), bill->otmp */
  432. X        return(1);
  433. X    } else    return(0);
  434. X}
  435. X
  436. Xstruct obj *
  437. Xaddinv(obj)
  438. Xregister struct obj *obj;
  439. X{
  440. X    register struct obj *otmp, *prev;
  441. X
  442. X    if (obj->otyp == GOLD_PIECE) {
  443. X        u.ugold += obj->quan;
  444. X        flags.botl = 1;
  445. X        return obj;
  446. X    } else if (obj->otyp == AMULET_OF_YENDOR) {
  447. X        if (u.uhave.amulet) impossible ("already have amulet?");
  448. X        u.uhave.amulet = 1;
  449. X    } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
  450. X        if (u.uhave.menorah) impossible ("already have candelabrum?");
  451. X        u.uhave.menorah = 1;
  452. X    } else if (obj->otyp == BELL_OF_OPENING) {
  453. X        if (u.uhave.bell) impossible ("already have silver bell?");
  454. X        u.uhave.bell = 1;
  455. X    } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  456. X        if (u.uhave.book) impossible ("already have the book?");
  457. X        u.uhave.book = 1;
  458. X#ifdef MULDGN
  459. X    } else if (is_quest_artifact(obj)) {
  460. X        if (u.uhave.questart) impossible ("already have the artifact?");
  461. X        u.uhave.questart = 1;
  462. X        artitouch();
  463. X        set_artifact_intrinsic(obj, 1, W_ART);
  464. X#endif
  465. X    } else if(obj->oartifact) {
  466. X        set_artifact_intrinsic(obj, 1, W_ART);
  467. X    }
  468. X    /* merge if possible; find end of chain in the process */
  469. X    for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
  470. X        if (merged(otmp, obj, 0)) {
  471. X        obj = otmp;
  472. X        goto added;
  473. X        }
  474. X    /* didn't merge, so insert into chain */
  475. X    if (flags.invlet_constant || !prev) {
  476. X        if (flags.invlet_constant) assigninvlet(obj);
  477. X        obj->nobj = invent;        /* insert at beginning */
  478. X        invent = obj;
  479. X        if (flags.invlet_constant) reorder_invent();
  480. X    } else {
  481. X        prev->nobj = obj;        /* insert at end */
  482. X        obj->nobj = 0;
  483. X    }
  484. X
  485. Xadded:
  486. X    if (obj->otyp == LUCKSTONE
  487. X        || (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
  488. X        /* new luckstone must be in inventory by this point
  489. X         * for correct calculation */
  490. X        if (stone_luck(TRUE) >= 0) u.moreluck = LUCKADD;
  491. X        else u.moreluck = -LUCKADD;
  492. X    } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP)
  493. X        check_lamps();
  494. X    update_inventory();
  495. X    return(obj);
  496. X}
  497. X
  498. X#endif /* OVL1 */
  499. X#ifdef OVLB
  500. X
  501. X/* Add an item to the inventory unless we're fumbling, and give a message.
  502. X * If there aren't any free inventory slots, we'll drop it instead.
  503. X * If both success and failure messages are NULL, then we're just doing the
  504. X * fumbling/slot-limit checking for a silent grab.
  505. X * Note: will drop the whole bunch if the object merges first.
  506. X */
  507. Xstruct obj *
  508. Xhold_another_object(obj, drop_fmt, drop_arg, hold_msg)
  509. Xstruct obj *obj;
  510. Xconst char *drop_fmt, *drop_arg, *hold_msg;
  511. X{
  512. X    long oquan = obj->quan;
  513. X    if (!Blind) obj->dknown = 1;    /* maximize mergibility */
  514. X    if (Fumbling) {
  515. X        if (drop_fmt) pline(drop_fmt, drop_arg);
  516. X        dropy(obj);
  517. X    } else {
  518. X        obj = addinv(obj);
  519. X        if (inv_cnt() > 52
  520. X            || ((obj->otyp != LOADSTONE || !obj->cursed)
  521. X            && near_capacity() >= OVERLOADED)) {
  522. X            if (drop_fmt) pline(drop_fmt, drop_arg);
  523. X            dropx(obj);
  524. X        } else {
  525. X            if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
  526. X        }
  527. X    }
  528. X    return obj;
  529. X}
  530. X
  531. Xvoid
  532. Xuseup(obj)
  533. Xregister struct obj *obj;
  534. X{
  535. X    /*  Note:  This works correctly for containers because they */
  536. X    /*       (containers) don't merge.                */
  537. X    if(obj->quan > 1L){
  538. X#ifndef NO_SIGNAL
  539. X        obj->in_use = FALSE;    /* no longer in use */
  540. X#endif
  541. X        obj->quan--;
  542. X        obj->owt = weight(obj);
  543. X    } else {
  544. X        setnotworn(obj);
  545. X        freeinv(obj);
  546. X        obfree(obj, (struct obj *) 0);    /* deletes contents also */
  547. X    }
  548. X}
  549. X
  550. X#endif /* OVLB */
  551. X#ifdef OVL3
  552. X
  553. X/* used by freeinv and doorganize to do list manipulation */
  554. XSTATIC_OVL
  555. Xvoid
  556. Xunlinkinv(obj)
  557. Xregister struct obj *obj;
  558. X{
  559. X    register struct obj *otmp;
  560. X
  561. X    if(obj == invent)
  562. X        invent = invent->nobj;
  563. X    else {
  564. X        for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
  565. X            if(!otmp->nobj) panic("unlinkinv");
  566. X        otmp->nobj = obj->nobj;
  567. X    }
  568. X    obj->nobj = 0;
  569. X}
  570. X
  571. Xvoid
  572. Xfreeinv(obj)
  573. Xregister struct obj *obj;
  574. X{
  575. X    unlinkinv(obj);
  576. X
  577. X    if (obj->otyp == GOLD_PIECE) {
  578. X        u.ugold -= obj->quan;
  579. X        flags.botl = 1;
  580. X        return;
  581. X    } else if (obj->otyp == AMULET_OF_YENDOR) {
  582. X        if (!u.uhave.amulet) impossible ("don't have amulet?");
  583. X        u.uhave.amulet = 0;
  584. X    } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
  585. X        if (!u.uhave.menorah) impossible ("don't have candelabrum?");
  586. X        u.uhave.menorah = 0;
  587. X    } else if (obj->otyp == BELL_OF_OPENING) {
  588. X        if (!u.uhave.bell) impossible ("don't have silver bell?");
  589. X        u.uhave.bell = 0;
  590. X    } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  591. X        if (!u.uhave.book) impossible ("don't have the book?");
  592. X        u.uhave.book = 0;
  593. X#ifdef MULDGN
  594. X    } else if (is_quest_artifact(obj)) {
  595. X        if(!u.uhave.questart) impossible ("don't have the artifact?");
  596. X        u.uhave.questart = 0;
  597. X        set_artifact_intrinsic(obj, 0, W_ART);
  598. X#endif
  599. X    } else if (obj->oartifact) {
  600. X        set_artifact_intrinsic(obj, 0, W_ART);
  601. X    } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
  602. X           || obj->otyp == BRASS_LANTERN) {
  603. X        if (obj->lamplit) {
  604. X            obj->lamplit = 0;
  605. X            if (!Blind) pline("%s goes out!", The(xname(obj)));
  606. X        }
  607. X        check_lamps();
  608. X    } else if (obj->otyp == LOADSTONE) {
  609. X        curse(obj);
  610. X    } else if (obj->otyp == LUCKSTONE
  611. X           || (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
  612. X        int luckbon = stone_luck(TRUE);
  613. X        if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
  614. X        else if (luckbon >= 0) u.moreluck = LUCKADD;
  615. X        else u.moreluck = -LUCKADD;
  616. X        flags.botl = 1;
  617. X    }
  618. X    update_inventory();
  619. X}
  620. X
  621. Xvoid
  622. Xdelallobj(x, y)
  623. Xint x, y;
  624. X{
  625. X    struct obj *otmp, *otmp2;
  626. X
  627. X    for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
  628. X        otmp2 = otmp->nexthere;
  629. X        if (otmp == uball)
  630. X            unpunish();
  631. X        if (otmp == uchain)
  632. X            continue;
  633. X        delobj(otmp);
  634. X    }
  635. X}
  636. X
  637. X#endif /* OVL3 */
  638. X#ifdef OVL2
  639. X
  640. X/* destroy object in fobj chain (if unpaid, it remains on the bill) */
  641. Xvoid
  642. Xdelobj(obj)
  643. Xregister struct obj *obj;
  644. X{
  645. X#ifdef WALKIES
  646. X    if(obj->otyp == LEASH && obj->leashmon != 0) o_unleash(obj);
  647. X#endif
  648. X    freeobj(obj);
  649. X    newsym(obj->ox,obj->oy);
  650. X    obfree(obj, (struct obj *) 0);    /* frees contents also */
  651. X}
  652. X
  653. X/* unlink obj from chain starting with fobj */
  654. Xvoid
  655. Xfreeobj(obj)
  656. Xregister struct obj *obj;
  657. X{
  658. X    register struct obj *otmp;
  659. X
  660. X    if (obj == fobj)
  661. X        fobj = fobj->nobj;
  662. X    else {
  663. X        for(otmp = fobj; otmp; otmp = otmp->nobj)
  664. X        if (otmp->nobj == obj) {
  665. X            otmp->nobj = obj->nobj;
  666. X            break;
  667. X        }
  668. X        if (!otmp) panic("error in freeobj");
  669. X    }
  670. X    remove_object(obj);
  671. X}
  672. X
  673. X#endif /* OVL2 */
  674. X#ifdef OVL0
  675. X
  676. Xstruct obj *
  677. Xsobj_at(n,x,y)
  678. Xregister int n, x, y;
  679. X{
  680. X    register struct obj *otmp;
  681. X
  682. X    for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  683. X        if(otmp->otyp == n)
  684. X            return(otmp);
  685. X    return((struct obj *)0);
  686. X}
  687. X
  688. X#endif /* OVL0 */
  689. X#ifdef OVLB
  690. X
  691. Xint
  692. Xcarried(obj)
  693. Xregister struct obj *obj;
  694. X{
  695. X    register struct obj *otmp;
  696. X
  697. X    for(otmp = invent; otmp; otmp = otmp->nobj)
  698. X        if(otmp == obj) return(1);
  699. X    return(0);
  700. X}
  701. X
  702. Xstruct obj *
  703. Xcarrying(type)
  704. Xregister int type;
  705. X{
  706. X    register struct obj *otmp;
  707. X
  708. X    for(otmp = invent; otmp; otmp = otmp->nobj)
  709. X        if(otmp->otyp == type)
  710. X            return(otmp);
  711. X    return((struct obj *) 0);
  712. X}
  713. X
  714. Xboolean
  715. Xhave_lizard()
  716. X{
  717. X    register struct obj *otmp;
  718. X
  719. X    for(otmp = invent; otmp; otmp = otmp->nobj)
  720. X        if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
  721. X            return(TRUE);
  722. X    return(FALSE);
  723. X}
  724. X
  725. Xstruct obj *
  726. Xo_on(id, objchn)
  727. Xunsigned int id;
  728. Xregister struct obj *objchn;
  729. X{
  730. X    struct obj *temp;
  731. X
  732. X    while(objchn) {
  733. X        if(objchn->o_id == id) return(objchn);
  734. X        if (Is_container(objchn) && (temp = o_on(id,objchn->cobj)))
  735. X            return temp;
  736. X        objchn = objchn->nobj;
  737. X    }
  738. X    return((struct obj *) 0);
  739. X}
  740. X
  741. Xboolean
  742. Xobj_here(obj, x, y)
  743. Xregister struct obj *obj;
  744. Xint x, y;
  745. X{
  746. X    register struct obj *otmp;
  747. X
  748. X    for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
  749. X        if(obj == otmp) return(TRUE);
  750. X    return(FALSE);
  751. X}
  752. X
  753. X#endif /* OVLB */
  754. X#ifdef OVL2
  755. X
  756. Xstruct obj *
  757. Xg_at(x,y)
  758. Xregister int x, y;
  759. X{
  760. X    register struct obj *obj = level.objects[x][y];
  761. X    while(obj) {
  762. X        if (obj->otyp == GOLD_PIECE) return obj;
  763. X        obj = obj->nexthere;
  764. X    }
  765. X    return((struct obj *)0);
  766. X}
  767. X
  768. X#endif /* OVL2 */
  769. X#ifdef OVLB
  770. X
  771. X/* Make a gold object from the hero's gold. */
  772. Xstruct obj *
  773. Xmkgoldobj(q)
  774. Xregister long q;
  775. X{
  776. X    register struct obj *otmp;
  777. X
  778. X    otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
  779. X    u.ugold -= q;
  780. X    otmp->quan = q;
  781. X    otmp->owt = weight(otmp);
  782. X    flags.botl = 1;
  783. X    return(otmp);
  784. X}
  785. X
  786. X#endif /* OVLB */
  787. X#ifdef OVL1
  788. X
  789. XSTATIC_OVL void
  790. Xcompactify(buf)
  791. Xregister char *buf;
  792. X/* compact a string of inventory letters by dashing runs of letters */
  793. X{
  794. X    register int i1 = 1, i2 = 1;
  795. X    register char ilet, ilet1, ilet2;
  796. X
  797. X    ilet2 = buf[0];
  798. X    ilet1 = buf[1];
  799. X    buf[++i2] = buf[++i1];
  800. X    ilet = buf[i1];
  801. X    while(ilet) {
  802. X        if(ilet == ilet1+1) {
  803. X            if(ilet1 == ilet2+1)
  804. X                buf[i2 - 1] = ilet1 = '-';
  805. X            else if(ilet2 == '-') {
  806. X                buf[i2 - 1] = ++ilet1;
  807. X                buf[i2] = buf[++i1];
  808. X                ilet = buf[i1];
  809. X                continue;
  810. X            }
  811. X        }
  812. X        ilet2 = ilet1;
  813. X        ilet1 = ilet;
  814. X        buf[++i2] = buf[++i1];
  815. X        ilet = buf[i1];
  816. X    }
  817. X}
  818. X
  819. X/*
  820. X * getobj returns:
  821. X *    struct obj *xxx:    object to do something with.
  822. X *    (struct obj *) 0    error return: no object.
  823. X *    &zeroobj        explicitly no object (as in w-).
  824. X */
  825. Xstruct obj *
  826. Xgetobj(let,word)
  827. Xregister const char *let,*word;
  828. X{
  829. X    register struct obj *otmp;
  830. X    register char ilet;
  831. X    char buf[BUFSZ], qbuf[QBUFSZ];
  832. X    char lets[BUFSZ];
  833. X    register int foo = 0;
  834. X    register char *bp = buf;
  835. X    xchar allowcnt = 0;    /* 0, 1 or 2 */
  836. X    boolean allowgold = FALSE, usegold = FALSE;
  837. X        /* Two possibilities: they can't use gold because it's illegal,
  838. X         * or they can't use gold because they don't have any.
  839. X         */
  840. X    boolean allowall = FALSE;
  841. X    boolean allownone = FALSE;
  842. X    xchar foox = 0;
  843. X    long cnt;
  844. X    boolean prezero = FALSE;
  845. X
  846. X    if(*let == ALLOW_COUNT) let++, allowcnt = 1;
  847. X    if(*let == GOLD_CLASS) let++,
  848. X        usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);
  849. X#ifdef POLYSELF
  850. X    /* Equivalent of an "ugly check" for gold */
  851. X    if (usegold && !strcmp(word, "eat") && !metallivorous(uasmon))
  852. X        usegold = allowgold = FALSE;
  853. X#endif
  854. X    if(*let == ALL_CLASSES) let++, allowall = TRUE;
  855. X    if(*let == ALLOW_NONE) let++, allownone = TRUE;
  856. X    /* "ugly check" for reading fortune cookies, part 1 */
  857. X    if(allowall && !strcmp(word, "read")) allowall = FALSE;
  858. X
  859. X    if(allownone) *bp++ = '-';
  860. X    if(allowgold) *bp++ = def_oc_syms[GOLD_CLASS];
  861. X    if(bp > buf && bp[-1] == '-') *bp++ = ' ';
  862. X
  863. X    ilet = 'a';
  864. X    for(otmp = invent; otmp; otmp = otmp->nobj){
  865. X        if(!*let || index(let, otmp->oclass)) {
  866. X        bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
  867. X
  868. X        /* ugly check: remove inappropriate things */
  869. X        if((!strcmp(word, "take off") &&
  870. X            (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
  871. X             || (otmp==uarm && uarmc)
  872. X#ifdef TOURIST
  873. X             || (otmp==uarmu && (uarm || uarmc))
  874. X#endif
  875. X            ))
  876. X        || (!strcmp(word, "wear") &&
  877. X             (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
  878. X                            /* already worn */
  879. X        || (!strcmp(word, "wield") &&
  880. X            (otmp->owornmask & W_WEP))
  881. X            ) {
  882. X            foo--;
  883. X            foox++;
  884. X        }
  885. X
  886. X        /* Second ugly check; unlike the first it won't trigger an
  887. X         * "else" in "you don't have anything else to ___".
  888. X         */
  889. X        else if ((!strcmp(word, "wear") &&
  890. X            (otmp->oclass == TOOL_CLASS &&
  891. X             otmp->otyp != BLINDFOLD && otmp->otyp != TOWEL))
  892. X#ifdef POLYSELF
  893. X        || (!strcmp(word, "eat") && !is_edible(otmp))
  894. X#endif
  895. X        || (!strcmp(word, "can") &&
  896. X            (otmp->otyp != CORPSE))
  897. X        || (!strcmp(word, "write with") &&
  898. X            (otmp->oclass == TOOL_CLASS &&
  899. X             otmp->otyp != MAGIC_MARKER && otmp->otyp != TOWEL))
  900. X        || (!strcmp(word, "rub") &&
  901. X            (otmp->oclass == TOOL_CLASS &&
  902. X             otmp->otyp != OIL_LAMP && otmp->otyp != MAGIC_LAMP &&
  903. X             otmp->otyp != BRASS_LANTERN))
  904. X        || (!strcmp(word, "wield") &&
  905. X            (otmp->oclass == TOOL_CLASS &&
  906. X             otmp->otyp != PICK_AXE && otmp->otyp != UNICORN_HORN))
  907. X            )
  908. X            foo--;
  909. X        } else {
  910. X
  911. X        /* "ugly check" for reading fortune cookies, part 2 */
  912. X        if ((!strcmp(word, "read") && otmp->otyp == FORTUNE_COOKIE))
  913. X            allowall = TRUE;
  914. X        }
  915. X
  916. X        if(ilet == 'z') ilet = 'A'; else ilet++;
  917. X    }
  918. X    bp[foo] = 0;
  919. X    if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
  920. X    Strcpy(lets, bp);    /* necessary since we destroy buf */
  921. X    if(foo > 5)            /* compactify string */
  922. X        compactify(bp);
  923. X
  924. X    if(!foo && !allowall && !allowgold && !allownone) {
  925. X        You("don't have anything %sto %s.",
  926. X            foox ? "else " : "", word);
  927. X        return((struct obj *)0);
  928. X    }
  929. X    for(;;) {
  930. X        cnt = 0;
  931. X        if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
  932. X        if(!buf[0]) {
  933. X            Sprintf(qbuf, "What do you want to %s? [*]", word);
  934. X        } else {
  935. X            Sprintf(qbuf, "What do you want to %s? [%s or ?*]",
  936. X                word, buf);
  937. X        }
  938. X#ifdef REDO
  939. X        if(!in_doagain)
  940. X            ilet = yn_function(qbuf, NULL, '\0');
  941. X        else
  942. X#endif
  943. X            ilet = readchar();
  944. X        if(ilet == '0') prezero = TRUE;
  945. X        while(digit(ilet) && allowcnt) {
  946. X#ifdef REDO
  947. X            if (ilet != '?' && ilet != '*')    savech(ilet);
  948. X#endif
  949. X            cnt = 10*cnt + (ilet - '0');
  950. X            allowcnt = 2;    /* signal presence of cnt */
  951. X            ilet = readchar();
  952. X        }
  953. X        if(digit(ilet)) {
  954. X            pline("No count allowed with this command.");
  955. X            continue;
  956. X        }
  957. X        if(index(quitchars,ilet)) {
  958. X            if(flags.verbose)
  959. X            pline("Never mind.");
  960. X            return((struct obj *)0);
  961. X        }
  962. X        if(ilet == '-') {
  963. X            return(allownone ? &zeroobj : (struct obj *) 0);
  964. X        }
  965. X        if(ilet == def_oc_syms[GOLD_CLASS]) {
  966. X            if(!usegold){
  967. X                You("cannot %s gold.", word);
  968. X                return(struct obj *)0;
  969. X            } else if (!allowgold) {
  970. X                You("are not carrying any gold.");
  971. X                return(struct obj *)0;
  972. X            }
  973. X            if(cnt == 0 && prezero) return((struct obj *)0);
  974. X            /* Historic note: early Nethack had a bug which was
  975. X             * first reported for Larn, where trying to drop 2^32-n
  976. X             * gold pieces was allowed, and did interesting things
  977. X             * to your money supply.  The LRS is the tax bureau
  978. X             * from Larn.
  979. X             */
  980. X            if(cnt < 0) {
  981. X    pline("The LRS would be very interested to know you have that much.");
  982. X                return(struct obj *)0;
  983. X            }
  984. X
  985. X            if(!(allowcnt == 2 && cnt < u.ugold))
  986. X                cnt = u.ugold;
  987. X            return(mkgoldobj(cnt));
  988. X        }
  989. X        if(allowcnt == 2 && !strcmp(word,"throw")) {
  990. X            /* permit counts for throwing gold, but don't accept
  991. X             * counts for other things since the throw code will
  992. X             * split off a single item anyway */
  993. X            allowcnt = 1;
  994. X            if(cnt == 0 && prezero) return((struct obj *)0);
  995. X            if(cnt > 1) {
  996. X                You("can only throw one item at a time.");
  997. X                continue;
  998. X            }
  999. X        }
  1000. X        if(ilet == '?' || ilet == '*') {
  1001. X            ilet = display_inventory(ilet == '?' ? lets : NULL, FALSE);
  1002. X            if(!ilet) continue;
  1003. X            if(ilet == '\033') {
  1004. X            if(flags.verbose)
  1005. X                pline("Never mind.");
  1006. X            return((struct obj *)0);
  1007. X            }
  1008. X            /* they typed a letter (not a space) at the prompt */
  1009. X        }
  1010. X#ifdef REDO
  1011. X        savech(ilet);
  1012. X#endif
  1013. X        if(flags.invlet_constant) {
  1014. X            for(otmp = invent; otmp; otmp = otmp->nobj)
  1015. X                if(otmp->invlet == ilet) break;
  1016. X        } else {
  1017. X            if(ilet >= 'A' && ilet <= 'Z') ilet += 'z' - 'A' + 1;
  1018. X            ilet -= 'a';
  1019. X            for(otmp = invent; otmp && ilet;
  1020. X                    ilet--, otmp = otmp->nobj) ;
  1021. X        }
  1022. X        if(!otmp) {
  1023. X            You("don't have that object.");
  1024. X            continue;
  1025. X        } else if (cnt < 0 || otmp->quan < cnt) {
  1026. X            You("don't have that many!  You have only %ld.",
  1027. X                otmp->quan);
  1028. X            continue;
  1029. X        }
  1030. X        break;
  1031. X    }
  1032. X    if(!allowall && let && !index(let,otmp->oclass)) {
  1033. X        pline(silly_thing_to, word);
  1034. X        return((struct obj *)0);
  1035. X    }
  1036. X    if(allowcnt == 2) {    /* cnt given */
  1037. X        if(cnt == 0) return (struct obj *)0;
  1038. X        if(cnt != otmp->quan) {
  1039. X            register struct obj *obj = splitobj(otmp, cnt);
  1040. X        /* Very ugly kludge necessary to prevent someone from trying
  1041. X         * to drop one of several loadstones and having the loadstone
  1042. X         * now be separate.
  1043. X         */
  1044. X            if (!strcmp(word, "drop") &&
  1045. X                obj->otyp == LOADSTONE && obj->cursed)
  1046. X                otmp->corpsenm = obj->invlet;
  1047. X            if(otmp == uwep) setuwep(obj);
  1048. X        }
  1049. X    }
  1050. X    return(otmp);
  1051. X}
  1052. X
  1053. X#endif /* OVL1 */
  1054. X#ifdef OVLB
  1055. X
  1056. XSTATIC_PTR int
  1057. Xckunpaid(otmp)
  1058. Xregister struct obj *otmp;
  1059. X{
  1060. X    return((int)(otmp->unpaid));
  1061. X}
  1062. X
  1063. Xstatic boolean
  1064. Xwearing_armor() {
  1065. X    return(uarm || uarmc || uarmf || uarmg || uarmh || uarms
  1066. X#ifdef TOURIST
  1067. X        || uarmu
  1068. X#endif
  1069. X        );
  1070. X}
  1071. X
  1072. Xstatic boolean
  1073. Xis_worn(otmp)
  1074. Xregister struct obj *otmp;
  1075. X{
  1076. X    return(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP)));
  1077. X}
  1078. X
  1079. Xstatic const char NEARDATA removeables[] =
  1080. X    { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };
  1081. X
  1082. X/* interactive version of getobj - used for Drop, Identify and */
  1083. X/* Takeoff (A). Return the number of times fn was called successfully */
  1084. Xint
  1085. Xggetobj(word, fn, mx)
  1086. Xregister const char *word;
  1087. Xregister int FDECL((*fn),(OBJ_P)), mx;
  1088. X{
  1089. X    char buf[BUFSZ], qbuf[QBUFSZ];
  1090. X    register char *ip;
  1091. X    register char sym;
  1092. X    register int oletct = 0, iletct = 0;
  1093. X    register boolean allflag = FALSE;
  1094. X    char olets[20], ilets[20];
  1095. X    int FDECL((*ckfn),(OBJ_P)) = (int (*)()) 0;
  1096. X    xchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0; /* BAH */
  1097. X    register boolean takeoff = !strcmp(word, "take off");
  1098. X    struct obj *obj;
  1099. X    int unpaid, oc_of_sym;
  1100. X
  1101. X    if(takeoff && !wearing_armor() && !uwep && !uamul &&
  1102. X            !uleft && !uright && !ublindf) {
  1103. X        You("are not wearing anything.");
  1104. X        return(0);
  1105. X    }
  1106. X    if(!invent && !allowgold){
  1107. X        You("have nothing to %s.", word);
  1108. X        return(0);
  1109. X    }
  1110. X
  1111. X    if (allowgold) ilets[iletct++] = def_oc_syms[GOLD_CLASS];
  1112. X    ilets[iletct] = '\0';    /* terminate for index() */
  1113. X    unpaid = 0;
  1114. X    for (obj = invent; obj; obj = obj->nobj) {
  1115. X        sym = (char) def_oc_syms[(int) obj->oclass];
  1116. X        if (!index(ilets, sym) && (!takeoff || is_worn(obj))) {
  1117. X            ilets[iletct++] = sym;
  1118. X            /* necessary because of index() being used above */
  1119. X            ilets[iletct] = '\0';
  1120. X        }
  1121. X
  1122. X        if (obj->unpaid) unpaid = 1;
  1123. X    }
  1124. X
  1125. X    if (!takeoff && (unpaid || invent)) {
  1126. X        ilets[iletct++] = ' ';
  1127. X        if (unpaid) ilets[iletct++] = 'u';
  1128. X        if (invent) ilets[iletct++] = 'a';
  1129. X    }
  1130. X    ilets[iletct] = '\0';    /* outside the if to catch iletct==0 case */
  1131. X
  1132. X    Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
  1133. X        word, ilets);
  1134. X    getlin(qbuf, buf);
  1135. X    if(buf[0] == '\033') {
  1136. X        clear_nhwindow(WIN_MESSAGE);
  1137. X        return(0);
  1138. X    }
  1139. X    ip = buf;
  1140. X    olets[0] = 0;
  1141. X    while ((sym = *ip++) != 0) {
  1142. X        if(sym == ' ') continue;
  1143. X        oc_of_sym = def_char_to_objclass(sym);
  1144. X        if(takeoff && !(uwep && oc_of_sym == uwep->oclass)
  1145. X           && (oc_of_sym != MAXOCLASSES)) {
  1146. X            if(!index(removeables,oc_of_sym)) {
  1147. X            pline("Not applicable.");
  1148. X            return(0);
  1149. X            } else if(oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
  1150. X            You("are not wearing any armor.");
  1151. X            return(0);
  1152. X            } else if(oc_of_sym == WEAPON_CLASS && !uwep) {
  1153. X            You("are not wielding anything.");
  1154. X            return(0);
  1155. X            } else if(oc_of_sym == RING_CLASS && !uright && !uleft) {
  1156. X            You("are not wearing rings.");
  1157. X            return(0);
  1158. X            } else if(oc_of_sym == AMULET_CLASS && !uamul) {
  1159. X            You("are not wearing an amulet.");
  1160. X            return(0);
  1161. X            } else if(oc_of_sym == TOOL_CLASS && !ublindf) {
  1162. X            You("are not wearing a blindfold.");
  1163. X            return(0);
  1164. X            }
  1165. X        }
  1166. X        if(oc_of_sym == GOLD_CLASS) {
  1167. X            if(allowgold == 1)
  1168. X                (*fn)(mkgoldobj(u.ugold));
  1169. X            else if(!u.ugold)
  1170. X                You("have no gold.");
  1171. X            allowgold = 2;
  1172. X        } else if(sym == 'a' || sym == 'A')
  1173. X            allflag = TRUE;
  1174. X        else if(sym == 'u' || sym == 'U')
  1175. X            ckfn = ckunpaid;
  1176. X        else if (oc_of_sym == MAXOCLASSES)
  1177. X            You("don't have any %c's.", sym);
  1178. X        else if (oc_of_sym != VENOM_CLASS) {/* venom doesn't show up */
  1179. X            if (!index(olets, oc_of_sym)) {
  1180. X                olets[oletct++] = oc_of_sym;
  1181. X                olets[oletct] = 0;
  1182. X            }
  1183. X        }
  1184. X    }
  1185. X    if(allowgold == 2 && !oletct)
  1186. X        return 1;    /* you dropped gold (or at least tried to) */
  1187. X    else
  1188. X        return askchain((struct obj **)&invent, olets, allflag,
  1189. X                fn, ckfn, mx, word);
  1190. X}
  1191. X
  1192. X/*
  1193. X * Walk through the chain starting at objchn and ask for all objects
  1194. X * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
  1195. X * whether the action in question (i.e., fn) has to be performed.
  1196. X * If allflag then no questions are asked. Max gives the max nr of
  1197. X * objects to be treated. Return the number of objects treated.
  1198. X */
  1199. Xint
  1200. Xaskchain(objchn, olets, allflag, fn, ckfn, mx, word)
  1201. Xstruct obj **objchn;
  1202. Xregister int allflag, mx;
  1203. Xregister const char *olets, *word;    /* olets is an Obj Class char array */
  1204. Xregister int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
  1205. X{
  1206. X    register struct obj *otmp, *otmp2;
  1207. X    register char sym, ilet;
  1208. X    register int cnt = 0, dud = 0, tmp;
  1209. X    boolean takeoff, nodot, ident, ininv;
  1210. X    char qbuf[QBUFSZ];
  1211. X
  1212. X    takeoff = !strcmp(word, "take off");
  1213. X    ident = !strcmp(word, "identify");
  1214. X    nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
  1215. X         ident || takeoff);
  1216. X    ininv = (*objchn == invent);
  1217. X    /* Changed so the askchain is interrogated in the order specified.
  1218. X     * For example, if a person specifies =/ then first all rings will be
  1219. X     * asked about followed by all wands -dgk
  1220. X     */
  1221. Xnextclass:
  1222. X    ilet = 'a'-1;
  1223. X    if ((*objchn)->otyp == GOLD_PIECE) ilet--;    /* extra iteration */
  1224. X    for (otmp = *objchn; otmp; otmp = otmp2) {
  1225. X        if(ilet == 'z') ilet = 'A'; else ilet++;
  1226. X        otmp2 = otmp->nobj;
  1227. X        if (olets && *olets && otmp->oclass != *olets) continue;
  1228. X        if(takeoff && !is_worn(otmp)) continue;
  1229. X        if(ckfn && !(*ckfn)(otmp)) continue;
  1230. X        if(!allflag) {
  1231. X            Strcpy(qbuf, ininv ?
  1232. X                xprname(otmp, ilet, !nodot, 0L) : doname(otmp));
  1233. X            Strcat(qbuf, "?");
  1234. X            sym = (takeoff || ident || otmp->quan < 2L) ?
  1235. X                nyaq(qbuf) : nyNaq(qbuf);
  1236. X        }
  1237. X        else    sym = 'y';
  1238. X
  1239. X        if (sym == '#') {
  1240. X         /* Number was entered; split the object unless it corresponds
  1241. X            to 'none' or 'all'.  2 special cases: cursed loadstones and
  1242. X            welded weapons (eg, multiple daggers) will remain as merged
  1243. X            unit; done to avoid splitting an object that won't be
  1244. X            droppable (even if we're picking up rather than dropping).
  1245. X          */
  1246. X            if (!yn_number)
  1247. X            sym = 'n';
  1248. X            else {
  1249. X            sym = 'y';
  1250. X            if (yn_number < otmp->quan && !welded(otmp) &&
  1251. X                (!otmp->cursed || otmp->otyp != LOADSTONE)) {
  1252. X                struct obj *otmpx = splitobj(otmp, yn_number);
  1253. X                if (!otmpx || otmpx->nobj != otmp2)
  1254. X                impossible("bad object split in askchain");
  1255. X            }
  1256. X            }
  1257. X        }
  1258. X        switch(sym){
  1259. X        case 'a':
  1260. X            allflag = 1;
  1261. X        case 'y':
  1262. X            tmp = (*fn)(otmp);
  1263. X            if(tmp < 0) goto ret;
  1264. X            cnt += tmp;
  1265. X            if(--mx == 0) goto ret;
  1266. X        case 'n':
  1267. X            if(nodot) dud++;
  1268. X        default:
  1269. X            break;
  1270. X        case 'q':
  1271. X            goto ret;
  1272. X        }
  1273. X    }
  1274. X    if (olets && *olets && *++olets)
  1275. X        goto nextclass;
  1276. X    if(!takeoff && (dud || cnt)) pline("That was all.");
  1277. X    else if(!dud && !cnt) pline("No applicable objects.");
  1278. Xret:
  1279. X    return(cnt);
  1280. X}
  1281. X
  1282. X#endif /* OVLB */
  1283. X#ifdef OVL2
  1284. X
  1285. XSTATIC_OVL char
  1286. Xobj_to_let(obj)    /* should of course only be called for things in invent */
  1287. Xregister struct obj *obj;
  1288. X{
  1289. X    register struct obj *otmp;
  1290. X    register char ilet;
  1291. X
  1292. X    if (obj->otyp == GOLD_PIECE)
  1293. X        return GOLD_SYM;
  1294. X    else if (flags.invlet_constant)
  1295. X        return obj->invlet;
  1296. X    ilet = 'a';
  1297. X    for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
  1298. X        if(++ilet > 'z') ilet = 'A';
  1299. X    return(otmp ? ilet : NOINVSYM);
  1300. X}
  1301. X
  1302. X/*
  1303. X * Print the indicated quantity of the given object.  If quan == 0L then use
  1304. X * the current quantity.
  1305. X */
  1306. Xvoid
  1307. Xprinv(prefix, obj, quan)
  1308. Xconst char *prefix;
  1309. Xregister struct obj *obj;
  1310. Xlong quan;
  1311. X{
  1312. X#ifdef GCC_WARN
  1313. X    long savequan = 0;
  1314. X#else
  1315. X    long savequan;
  1316. X#endif
  1317. X    if ( !prefix ) prefix = "";
  1318. X    if (quan) {
  1319. X        savequan = obj->quan;
  1320. X        obj->quan = quan;
  1321. X    }
  1322. X    pline("%s%s%s",
  1323. X          prefix, *prefix ? " " : "",
  1324. X          xprname(obj, obj_to_let(obj), TRUE, 0L));
  1325. X    if (quan) obj->quan = savequan;
  1326. X}
  1327. X
  1328. X#endif /* OVL2 */
  1329. X#ifdef OVL1
  1330. X
  1331. Xchar *
  1332. Xxprname(obj,let,dot,cost)
  1333. Xregister struct obj *obj;
  1334. Xregister char let;
  1335. Xregister boolean dot;   /* append period; (dot && cost => Iu) */
  1336. Xregister long cost;     /* cost (for inventory of unpaid or expended items) */
  1337. X{
  1338. X#ifdef LINT    /* handle static char li[BUFSZ]; */
  1339. X    char li[BUFSZ];
  1340. X#else
  1341. X    static char li[BUFSZ];
  1342. X#endif
  1343. X    boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
  1344. X    /*
  1345. X     * If let is:
  1346. X     *    *  Then obj == NULL and we are printing a total amount.
  1347. X     *    >  Then the object is contained and doesn't have an inventory letter.
  1348. X     */
  1349. X    if (cost != 0 || let == '*') {
  1350. X    /* if dot is true, we're doing Iu, otherwise Ix */
  1351. X    Sprintf(li, "%c - %-45s %6ld zorkmid%s",
  1352. X        (dot && use_invlet ? obj->invlet : let),
  1353. X        (let != '*' ? doname(obj) : "Total:"), cost, plur(cost));
  1354. X    } else if (obj->otyp == GOLD_PIECE) {
  1355. X    Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
  1356. X        (dot ? "." : ""));
  1357. X    } else {
  1358. X    /* ordinary inventory display or pickup message */
  1359. X    Sprintf(li, "%c - %s",
  1360. X        (use_invlet ? obj->invlet : let),
  1361. X        doname(obj));
  1362. X    if(dot) Strcat(li,".");
  1363. X    }
  1364. X    return li;
  1365. X}
  1366. X
  1367. X#endif /* OVL1 */
  1368. X#ifdef OVLB
  1369. X
  1370. Xint
  1371. Xddoinv()
  1372. X{
  1373. X    (void) display_inventory(NULL, FALSE);
  1374. X    return 0;
  1375. X}
  1376. X
  1377. X/*
  1378. X *  find_unpaid()
  1379. X *
  1380. X *  Scan the given list of objects.  If last_found is NULL, return the first
  1381. X *  unpaid object found.  If last_found is not NULL, then skip over unpaid
  1382. X *  objects until last_found is reached, then set last_found to NULL so the
  1383. X *  next unpaid object is returned.  This routine recursively follows
  1384. X *  containers.
  1385. X */
  1386. Xstatic struct obj *
  1387. Xfind_unpaid(list, last_found)
  1388. X    struct obj *list, **last_found;
  1389. X{
  1390. X    struct obj *obj;
  1391. X
  1392. X    while (list) {
  1393. X    if (list->unpaid) {
  1394. X        if (*last_found) {
  1395. X        /* still looking for previous unpaid object */
  1396. X        if (list == *last_found)
  1397. X            *last_found = (struct obj *) 0;
  1398. X        } else
  1399. X        return (*last_found = list);
  1400. X    }
  1401. X    if (Is_container(list) && list->cobj) {
  1402. X        if ((obj = find_unpaid(list->cobj, last_found)) != 0)
  1403. X        return obj;
  1404. X    }
  1405. X    list = list->nobj;
  1406. X    }
  1407. X    return (struct obj *) 0;
  1408. X}
  1409. X
  1410. X/*
  1411. X *  If lets == NULL or "", list all objects in the inventory.  Otherwise,
  1412. X *  list all objects with object classes that match the order in lets.
  1413. X *  The last letter could possibly be a '>' which means list unpaid contained
  1414. X *  objects.
  1415. X *  Returns the letter identifier of a selected item, or 0 (nothing was
  1416. X *  selected), or '\033' (the menu was cancelled).
  1417. X */
  1418. Xchar
  1419. Xdisplay_inventory(lets,show_cost)
  1420. Xregister const char *lets;
  1421. Xboolean show_cost;
  1422. X{
  1423. X    register struct obj *otmp;
  1424. X    struct obj *z_obj;
  1425. X    register char ilet;
  1426. X    char *invlet = inv_order;
  1427. X    int classcount;
  1428. X#if defined(LINT) || defined(GCC_WARN)
  1429. X    int save_unpaid = 0;
  1430. X#else
  1431. X    int save_unpaid;
  1432. X#endif
  1433. X    long cost, totcost;
  1434. X    boolean do_containers = FALSE;
  1435. X
  1436. X    if(!invent){
  1437. X        pline("Not carrying anything.");
  1438. X        return 0;
  1439. X    }
  1440. X    if (lets != NULL) {
  1441. X        int ct = strlen(lets); /* count number of inventory slots to show */
  1442. X        /* If we've got unpaid items in containers, count all unpaid
  1443. X           objects.  At least one won't be in any inventory slot. */
  1444. X        do_containers = (ct && lets[ct-1] == CONTAINED_SYM);
  1445. X        if (do_containers && ct == 1) ct = count_unpaid(invent);
  1446. X        /* if only one item of interest, use pline instead of menus */
  1447. X        if (ct == 1) {
  1448. X        if (do_containers) {    /* single non-inventory object */
  1449. X            z_obj = (struct obj *) 0;
  1450. X            if ((otmp = find_unpaid(invent, &z_obj)) != 0)
  1451. X            pline(xprname(otmp, CONTAINED_SYM, TRUE,
  1452. X                     (show_cost ? unpaid_cost(otmp) : 0L)));
  1453. X            else
  1454. X            impossible(
  1455. X            "display_inventory: no singular unpaid contained objects");
  1456. X        } else {
  1457. X            for(otmp = invent; otmp; otmp = otmp->nobj) {
  1458. X            if (otmp->invlet == lets[0]) {
  1459. X                pline(xprname(otmp, lets[0], TRUE,
  1460. X                     (show_cost ? unpaid_cost(otmp) : 0L)));
  1461. X                break;
  1462. X            }
  1463. X            }
  1464. X        }
  1465. X        return 0;
  1466. X        }
  1467. X    }
  1468. X
  1469. X    start_menu(WIN_INVEN);
  1470. X    cost = totcost = 0;
  1471. Xnextclass:
  1472. X    classcount = 0;
  1473. X    ilet = 'a';
  1474. X    for(otmp = invent; otmp; otmp = otmp->nobj) {
  1475. X        if(flags.invlet_constant) ilet = otmp->invlet;
  1476. X        if(!lets || !*lets || index(lets, ilet)) {
  1477. X            if (!flags.sortpack || otmp->oclass == *invlet) {
  1478. X                if (flags.sortpack && !classcount) {
  1479. X                add_menu(WIN_INVEN, 0, ATR_INVERSE,
  1480. X                     let_to_name(*invlet, show_cost));
  1481. X                classcount++;
  1482. X                }
  1483. X                if (show_cost) {
  1484. X                totcost += cost = unpaid_cost(otmp);
  1485. X                /* suppress "(unpaid)" suffix */
  1486. X                save_unpaid = otmp->unpaid;
  1487. X                otmp->unpaid = 0;
  1488. X                }
  1489. X                add_menu(WIN_INVEN, ilet, 0,
  1490. X                     xprname(otmp, ilet, TRUE, cost));
  1491. X                if (show_cost)  otmp->unpaid = save_unpaid;
  1492. X            }
  1493. X        }
  1494. X        if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
  1495. X    }
  1496. X    if (flags.sortpack) {
  1497. X        if (*++invlet) goto nextclass;
  1498. X#ifdef WIZARD
  1499. X        if (--invlet != venom_inv) {
  1500. X            invlet = venom_inv;
  1501. X            goto nextclass;
  1502. X        }
  1503. X#endif
  1504. X    }
  1505. X
  1506. X    /* right now, we only do this for unpaid items, so always do cost */
  1507. X    if (do_containers) {
  1508. X        if (flags.sortpack) add_menu(WIN_INVEN, 0, ATR_INVERSE,
  1509. X                     let_to_name(CONTAINED_SYM, 1));
  1510. X        /*
  1511. X         *  Search through the container objects in the inventory for
  1512. X         *  unpaid items.  Note that we check each container, not
  1513. X         *  the invent list.  This is because the invent list could
  1514. X         *  have unpaid items that have been already listed.
  1515. X         */
  1516. X        for (otmp = invent; otmp; otmp = otmp->nobj) {
  1517. X        if (Is_container(otmp) && otmp->cobj) {
  1518. X            z_obj = (struct obj *) 0;    /* haven't found any */
  1519. X            while (find_unpaid(otmp->cobj, (struct obj **)&z_obj)) {
  1520. X            totcost += cost = unpaid_cost(z_obj);
  1521. X            save_unpaid = z_obj->unpaid;
  1522. X            z_obj->unpaid = 0;    /* suppress "(unpaid)" suffix */
  1523. X            add_menu(WIN_INVEN, 0, 0,
  1524. X                 xprname(z_obj, CONTAINED_SYM, TRUE, cost));
  1525. X            z_obj->unpaid = save_unpaid;
  1526. X            }
  1527. X        }
  1528. X        }
  1529. X    }
  1530. X
  1531. X    if (show_cost) {
  1532. X        /* give 'Totals' line */
  1533. X        add_menu(WIN_INVEN, 0, 0, "");
  1534. X        add_menu(WIN_INVEN, 0, 0,
  1535. X             xprname((struct obj *)0, '*', FALSE, totcost));
  1536. X    }
  1537. X    end_menu(WIN_INVEN, '\033', "\033 ", NULL);
  1538. X    return select_menu(WIN_INVEN);
  1539. X}
  1540. X
  1541. X/*
  1542. X *  Returns the number of unpaid items within the given list.  This includes
  1543. X *  contained objects.
  1544. X */
  1545. Xint
  1546. Xcount_unpaid(list)
  1547. X    struct obj *list;
  1548. X{
  1549. X    int count = 0;
  1550. X
  1551. X    while (list) {
  1552. X    if (list->unpaid) count++;
  1553. X    if (Is_container(list) && list->cobj)
  1554. X        count += count_unpaid(list->cobj);
  1555. X    list = list->nobj;
  1556. X    }
  1557. X    return count;
  1558. X}
  1559. X
  1560. Xint
  1561. Xdotypeinv()                /* free after Robert Viduya */
  1562. X/* Changed to one type only, so you don't have to type return */
  1563. X{
  1564. X    char c, ilet;
  1565. X    char stuff[BUFSZ];
  1566. X    register int stct;
  1567. X    register struct obj *otmp;
  1568. X    boolean billx = *u.ushops && doinvbill(0);
  1569. X    boolean do_unpd = FALSE;
  1570. X    int unpd, class;
  1571. X
  1572. X    if (!invent && !u.ugold && !billx) {
  1573. X        You("aren't carrying anything.");
  1574. X        return 0;
  1575. X    }
  1576. X
  1577. X    Strcpy(stuff, "What type of object do you want an inventory of? [");
  1578. X    /* collect a list of classes of objects carried, for use as a prompt */
  1579. X    stct = collect_obj_classes(eos(stuff), invent, FALSE, (u.ugold != 0));
  1580. X    unpd = count_unpaid(invent);
  1581. X    if(unpd) Strcat(stuff, "u");
  1582. X    if(billx) Strcat(stuff, "x");
  1583. X    Strcat(stuff, "]");
  1584. X
  1585. X    if(stct > 1) {
  1586. X      c = yn_function(stuff, NULL, '\0');
  1587. X#ifdef REDO
  1588. X        savech(c);
  1589. X#endif
  1590. X        if(c == '\0') {
  1591. X        clear_nhwindow(WIN_MESSAGE);
  1592. X        return 0;
  1593. X        }
  1594. X    } else
  1595. X        c = stuff[0];
  1596. X
  1597. X    if(c == 'x' || c == 'X') {
  1598. X        if(billx)
  1599. X        (void) doinvbill(1);
  1600. X        else
  1601. X        pline("No used-up objects on the shopping bill.");
  1602. X        return(0);
  1603. X    }
  1604. X
  1605. X    if (c == 'u' || c == 'U') {
  1606. X        if (!unpd) {
  1607. X        You("are not carrying any unpaid objects.");
  1608. X        return(0);
  1609. X        }
  1610. X        do_unpd = TRUE;
  1611. X    }
  1612. X
  1613. X    class = def_char_to_objclass(c);    /* change to object class */
  1614. X
  1615. X    if(class == GOLD_CLASS)
  1616. X        return(doprgold());
  1617. X
  1618. X    /* collect all items which match the selected objclass */
  1619. X    stct = 0;
  1620. X    ilet = 'a';
  1621. X    for (otmp = invent; otmp; otmp = otmp->nobj) {
  1622. X        if(flags.invlet_constant) ilet = otmp->invlet;
  1623. X        if (class == otmp->oclass || (do_unpd && otmp->unpaid)) {
  1624. X        stuff[stct++] = ilet;
  1625. X        --unpd;    /* decrement unpaid count */
  1626. X        }
  1627. X        if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
  1628. X    }
  1629. X    /* unpd is now the number of unpaid contained objects */
  1630. X    if (do_unpd && unpd)
  1631. X        stuff[stct++] = CONTAINED_SYM;    /* list contained unpaid items */
  1632. X
  1633. X    stuff[stct] = '\0';
  1634. X    if(stct == 0)
  1635. X        You("have no such objects.");
  1636. X    else
  1637. X        (void) display_inventory(stuff, do_unpd);
  1638. X
  1639. X    return(0);
  1640. X}
  1641. X
  1642. X/* look at what is here */
  1643. Xint
  1644. Xdolook()
  1645. X{
  1646. X    register struct obj *otmp, *otmp0;
  1647. X    struct trap *trap;
  1648. X    const char *verb = Blind ? "feel" : "see";
  1649. X    const char *dfeature = (char*) 0;
  1650. X    char fbuf[BUFSZ], fbuf2[BUFSZ];
  1651. X    int ct;
  1652. X    boolean no_article = FALSE;
  1653. X    winid tmpwin;
  1654. X
  1655. X    if(u.uswallow) {
  1656. X        You("%s no objects here.", verb);
  1657. X        return(!!Blind);
  1658. X    }
  1659. X    read_engr_at(u.ux, u.uy); /* Eric Backus */
  1660. X    if ((trap = t_at(u.ux,u.uy)) && trap->tseen)
  1661. X        pline("There is a%s here.", traps[trap->ttyp]);
  1662. X
  1663. X    otmp0 = level.objects[u.ux][u.uy];
  1664. X
  1665. X    if(IS_DOOR(levl[u.ux][u.uy].typ))  {
  1666. X        switch(levl[u.ux][u.uy].doormask) {
  1667. X            case D_NODOOR:
  1668. X            dfeature = "doorway"; break;
  1669. X            case D_ISOPEN:
  1670. X            dfeature = "open door"; break;
  1671. X            case D_BROKEN:
  1672. X            dfeature = "broken door"; break;
  1673. X            default:
  1674. X            dfeature = "closed door";
  1675. X        }
  1676. X    } else if(IS_FOUNTAIN(levl[u.ux][u.uy].typ))
  1677. X        /* added by GAN 10/30/86 */
  1678. X        dfeature = "fountain";
  1679. X    else if(IS_THRONE(levl[u.ux][u.uy].typ))
  1680. X        dfeature = "opulent throne";
  1681. X    else if(is_lava(u.ux,u.uy))
  1682. X        dfeature = "molten lava",  no_article = TRUE;
  1683. X    else if(is_ice(u.ux,u.uy))
  1684. X        dfeature = "ice",  no_article = TRUE;
  1685. X    else if(is_pool(u.ux,u.uy) && !Underwater)
  1686. X        dfeature = "pool of water";
  1687. X#ifdef SINKS
  1688. X    else if(IS_SINK(levl[u.ux][u.uy].typ))
  1689. X        dfeature = "kitchen sink";
  1690. X#endif
  1691. X    else if(IS_ALTAR(levl[u.ux][u.uy].typ))  {
  1692. X        Sprintf(fbuf2, "altar to %s (%s)",
  1693. X            a_gname(),
  1694. X            align_str(Amask2align(levl[u.ux][u.uy].altarmask
  1695. X                                & ~AM_SHRINE)));
  1696. X        dfeature = fbuf2;
  1697. X    } else if(u.ux == xupstair && u.uy == yupstair)
  1698. X        dfeature = "stairway up";
  1699. X    else if(u.ux == xdnstair && u.uy == ydnstair)
  1700. X        dfeature = "stairway down";
  1701. X    else if(u.ux == sstairs.sx && u.uy == sstairs.sy) {
  1702. X        if (sstairs.up)
  1703. X            dfeature = "stairway up";
  1704. X        else
  1705. X            dfeature = "stairway down";
  1706. X    } else if(u.ux == xupladder && u.uy == yupladder)
  1707. X        dfeature = "ladder up";
  1708. X    else if(u.ux == xdnladder && u.uy == ydnladder)
  1709. X        dfeature = "ladder down";
  1710. X    else if (levl[u.ux][u.uy].typ == DRAWBRIDGE_DOWN)
  1711. X        dfeature = "lowered drawbridge";
  1712. X
  1713. X    if (Blind) {
  1714. X        You("try to feel what is %s.",
  1715. X            Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
  1716. X            "floating here" :
  1717. X            "lying here on the floor");
  1718. X         if (Levitation &&
  1719. X            !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
  1720. X            pline("But you can't reach it!");
  1721. X            return(0);
  1722. X         }
  1723. X    }
  1724. X
  1725. X    if (dfeature)
  1726. X        Sprintf(fbuf, "There is %s%s here.",
  1727. X            no_article ? "" :
  1728. X                index(vowels,dfeature[0]) ? "an " : "a ",
  1729. X            dfeature);
  1730. X
  1731. X    if(!otmp0 || (is_pool(u.ux,u.uy) && !Underwater)) {
  1732. X            if(dfeature) pline(fbuf);
  1733. X        if(Blind || !dfeature)
  1734. X            You("%s no objects here.", verb);
  1735. X        return(!!Blind);
  1736. X    }
  1737. X    /* we know there is something here */
  1738. X
  1739. X    /* find out if there is more than one object there */
  1740. X    for (ct = 0, otmp = otmp0; otmp; otmp = otmp->nexthere)
  1741. X        if (++ct > 1) break;
  1742. X
  1743. X    if (ct == 1) {
  1744. X        if (dfeature) pline(fbuf);
  1745. X        You("%s here %s.", verb, doname(otmp0));
  1746. X    } else {
  1747. X        display_nhwindow(NHW_MESSAGE, FALSE);
  1748. X        tmpwin = create_nhwindow(NHW_MENU);
  1749. X        if(dfeature) {
  1750. X        putstr(tmpwin, 0, fbuf);
  1751. X        putstr(tmpwin, 0, "");
  1752. X        }
  1753. X        putstr(tmpwin, 0, "Things that are here:");
  1754. X        for(otmp = otmp0; otmp; otmp = otmp->nexthere) {
  1755. X        putstr(tmpwin, 0, doname(otmp));
  1756. X
  1757. X        if(Blind  && !uarmg &&
  1758. X#ifdef POLYSELF
  1759. X                !resists_ston(uasmon) &&
  1760. X#endif
  1761. X                (otmp->otyp == CORPSE &&
  1762. X                    otmp->corpsenm == PM_COCKATRICE)) {
  1763. X#if defined(POLYSELF)
  1764. X            if(poly_when_stoned(uasmon)) {
  1765. X            You("touched the cockatrice corpse with your bare hands.");
  1766. X            (void) polymon(PM_STONE_GOLEM);
  1767. X            } else
  1768. X#endif
  1769. X            {
  1770. X            pline("Touching the cockatrice corpse is a fatal mistake...");
  1771. X            You("turn to stone...");
  1772. X            killer_format = KILLED_BY_AN;
  1773. X            killer = "cockatrice corpse";
  1774. X            done(STONING);
  1775. X            }
  1776. X        }
  1777. X        }
  1778. X        display_nhwindow(tmpwin, TRUE);
  1779. X        destroy_nhwindow(tmpwin);
  1780. X    }
  1781. X    return(!!Blind);
  1782. X}
  1783. X
  1784. X#endif /* OVLB */
  1785. X#ifdef OVL1
  1786. X
  1787. Xvoid
  1788. Xstackobj(obj)
  1789. Xregister struct obj *obj;
  1790. X{
  1791. X    register struct obj *otmp;
  1792. X
  1793. X    for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
  1794. X        if(otmp != obj && merged(obj,otmp,1))
  1795. X            break;
  1796. X    return;
  1797. X}
  1798. X
  1799. Xstatic boolean
  1800. Xmergable(otmp, obj)    /* returns TRUE if obj  & otmp can be merged */
  1801. X    register struct obj *otmp, *obj;
  1802. X{
  1803. X    if(obj->otyp != otmp->otyp || obj->unpaid != otmp->unpaid ||
  1804. X       obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
  1805. X       (obj->bknown != otmp->bknown && pl_character[0] != 'P') ||
  1806. X       obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
  1807. X       obj->no_charge != otmp->no_charge ||
  1808. X       obj->obroken != otmp->obroken ||
  1809. X       obj->otrapped != otmp->otrapped ||
  1810. X       obj->oeroded != otmp->oeroded)
  1811. X        return(FALSE);
  1812. X
  1813. X    if((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
  1814. X       (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
  1815. X        return FALSE;
  1816. X
  1817. X    if(obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
  1818. X        obj->orotten != otmp->orotten))
  1819. X        return(FALSE);
  1820. X
  1821. X    if(obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
  1822. X        if((obj->corpsenm != otmp->corpsenm) ||
  1823. X            (ONAME(obj) && strcmp(ONAME(obj), ONAME(otmp))))
  1824. X                return FALSE;
  1825. X    }
  1826. X
  1827. X/* if they have names, make sure they're the same */
  1828. X    if ( (obj->onamelth != otmp->onamelth &&
  1829. X        ((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
  1830. X         ) ||
  1831. X        (obj->onamelth &&
  1832. X            strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
  1833. X        return FALSE;
  1834. X
  1835. X    if(obj->oartifact != otmp->oartifact) return FALSE;
  1836. X
  1837. X    if(obj->known == otmp->known ||
  1838. X        !objects[otmp->otyp].oc_uses_known) {
  1839. X        return(objects[obj->otyp].oc_merge);
  1840. X    } else return(FALSE);
  1841. X}
  1842. X
  1843. X#endif /* OVL1 */
  1844. X#ifdef OVLB
  1845. X
  1846. Xint
  1847. Xdoprgold(){
  1848. X    if(!u.ugold)
  1849. X        You("do not carry any gold.");
  1850. X    else
  1851. X        You("are carrying %ld gold piece%s.", u.ugold, plur(u.ugold));
  1852. X    return 0;
  1853. X}
  1854. X
  1855. Xint
  1856. Xdoprwep()
  1857. X{
  1858. X    if(!uwep) You("are empty %s.", body_part(HANDED));
  1859. X    else prinv(NULL, uwep, 0L);
  1860. X    return 0;
  1861. X}
  1862. X
  1863. Xint
  1864. Xdoprarm(){
  1865. X    if(!wearing_armor())
  1866. X        You("are not wearing any armor.");
  1867. X    else {
  1868. X#ifdef TOURIST
  1869. X        char lets[8];
  1870. X#else
  1871. X        char lets[7];
  1872. X#endif
  1873. X        register int ct = 0;
  1874. X
  1875. X#ifdef TOURIST
  1876. X        if(uarmu) lets[ct++] = obj_to_let(uarmu);
  1877. X#endif
  1878. X        if(uarm) lets[ct++] = obj_to_let(uarm);
  1879. X        if(uarmc) lets[ct++] = obj_to_let(uarmc);
  1880. X        if(uarmh) lets[ct++] = obj_to_let(uarmh);
  1881. X        if(uarms) lets[ct++] = obj_to_let(uarms);
  1882. X        if(uarmg) lets[ct++] = obj_to_let(uarmg);
  1883. X        if(uarmf) lets[ct++] = obj_to_let(uarmf);
  1884. X        lets[ct] = 0;
  1885. X        (void) display_inventory(lets, FALSE);
  1886. X    }
  1887. X    return 0;
  1888. X}
  1889. X
  1890. Xint
  1891. Xdoprring(){
  1892. X    if(!uleft && !uright)
  1893. X        You("are not wearing any rings.");
  1894. X    else {
  1895. X        char lets[3];
  1896. X        register int ct = 0;
  1897. X
  1898. X        if(uleft) lets[ct++] = obj_to_let(uleft);
  1899. X        if(uright) lets[ct++] = obj_to_let(uright);
  1900. X        lets[ct] = 0;
  1901. X        (void) display_inventory(lets, FALSE);
  1902. X    }
  1903. X    return 0;
  1904. X}
  1905. X
  1906. Xint
  1907. Xdopramulet(){
  1908. X    if (!uamul)
  1909. X        You("are not wearing an amulet.");
  1910. X    else
  1911. X        prinv(NULL, uamul, 0L);
  1912. X    return 0;
  1913. X}
  1914. X
  1915. Xint
  1916. Xdoprtool(){
  1917. X    register struct obj *otmp;
  1918. X    register int ct=0;
  1919. X    char lets[3]; /* Maximum: pick-axe, blindfold */
  1920. X
  1921. X    for(otmp = invent; otmp; otmp = otmp->nobj) {
  1922. X        if (((otmp->owornmask & W_TOOL) && otmp->oclass==TOOL_CLASS)
  1923. X           || (otmp==uwep &&
  1924. X           (otmp->otyp==PICK_AXE || otmp->otyp==TIN_OPENER)))
  1925. X            lets[ct++] = obj_to_let(otmp);
  1926. X    }
  1927. X    lets[ct] = 0;
  1928. X    if (!ct) You("are not using any tools.");
  1929. X    else (void) display_inventory(lets, FALSE);
  1930. X    return 0;
  1931. X}
  1932. X
  1933. X/*
  1934. X * uses up an object that's on the floor, charging for it as necessary
  1935. X */
  1936. Xvoid
  1937. Xuseupf(obj)
  1938. Xregister struct obj *obj;
  1939. X{
  1940. X    register struct obj *otmp;
  1941. X
  1942. X    /* burn_floor_paper() keeps an object pointer that it tries to
  1943. X     * useupf() multiple times, so obj must survive if plural */
  1944. X    if(obj->quan > 1L)
  1945. X        otmp = splitobj(obj, obj->quan - 1L);
  1946. X    else
  1947. X        otmp = obj;
  1948. X    if(costly_spot(otmp->ox, otmp->oy)) {
  1949. X        if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
  1950. X            addtobill(otmp, FALSE, FALSE, FALSE);
  1951. X        else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
  1952. X    }
  1953. X    delobj(otmp);
  1954. X}
  1955. X
  1956. X#endif /* OVLB */
  1957. X#ifdef OVL1
  1958. X
  1959. Xextern const char obj_symbols[];    /* o_init.c */
  1960. X/*
  1961. X * Conversion from a symbol to a string for printing object classes.
  1962. X * This must match the array obj_symbols[].
  1963. X */
  1964. Xstatic const char NEARDATA *names[] = {
  1965. X    "Illegal objects", "Amulets", "Coins", "Comestibles", "Weapons",
  1966. X    "Tools", "Iron balls", "Chains", "Boulders/Statues", "Armor",
  1967. X    "Potions", "Scrolls", "Wands", "Spellbooks", "Rings", "Gems"
  1968. X};
  1969. X
  1970. Xstatic const char NEARDATA oth_symbols[] = {
  1971. X#ifdef WIZARD
  1972. X    VENOM_CLASS,
  1973. X#endif
  1974. X    CONTAINED_SYM,
  1975. X    '\0'
  1976. X};
  1977. X
  1978. Xstatic const char NEARDATA *oth_names[] = {
  1979. X#ifdef WIZARD
  1980. X    "Venoms",
  1981. X#endif
  1982. X    "Bagged/Boxed items"
  1983. X};
  1984. X
  1985. Xchar *
  1986. Xlet_to_name(let,unpaid)
  1987. Xchar let;
  1988. Xboolean unpaid;
  1989. X{
  1990. X    const char *class_name;
  1991. X    const char *pos = index(obj_symbols, let);
  1992. X    int len;
  1993. X    static char NEARDATA *buf = NULL;
  1994. X    static unsigned NEARDATA bufsiz = 0;
  1995. X
  1996. X    if (pos)
  1997. X        class_name = names[pos - obj_symbols];
  1998. X    else if ((pos = index(oth_symbols, let)) != 0)
  1999. X        class_name = oth_names[pos - oth_symbols];
  2000. X    else
  2001. X        class_name = names[0];
  2002. X
  2003. X    len = strlen(class_name)
  2004. X         + (unpaid ? sizeof("unpaid_") : 1);    /* count terminating NUL */
  2005. X    if (len > bufsiz) {
  2006. X        if (buf)  free((genericptr_t)buf),  buf = NULL;
  2007. X        bufsiz = len + 10; /* add slop to avoid incremental reallocations */
  2008. X        buf = (char *) alloc(bufsiz);
  2009. X    }
  2010. X    if (unpaid)
  2011. X        Strcat(strcpy(buf, "Unpaid "), class_name);
  2012. X    else
  2013. X        Strcpy(buf, class_name);
  2014. X    return (buf);
  2015. X}
  2016. X
  2017. X#endif /* OVL1 */
  2018. X#ifdef OVLB 
  2019. X
  2020. Xvoid
  2021. Xreassign()
  2022. X{
  2023. X    register int i;
  2024. X    register struct obj *obj;
  2025. X
  2026. X    for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
  2027. X        obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
  2028. X    lastinvnr = i;
  2029. X}
  2030. X
  2031. X#endif /* OVLB */
  2032. X#ifdef OVL1
  2033. Xint
  2034. Xdoorganize()    /* inventory organizer by Del Lamb */
  2035. X{
  2036. X    register struct obj *obj, *otmp;
  2037. X    register int ix, cur;
  2038. X    register char let;
  2039. X    char alphabet[52+1], buf[52+1];
  2040. X    char qbuf[QBUFSZ];
  2041. X    char allow_all[2];
  2042. X    const char *adj_type;
  2043. X
  2044. X    /* check to see if the inventory is of the fixed kind */
  2045. X    if (!flags.invlet_constant ) {
  2046. X        pline("Sorry, only fixed inventories can be adjusted.");
  2047. X        return(0);
  2048. X    }
  2049. X#if 0
  2050. X    /* check to see if the inventory has any gaps left in it */
  2051. X    if (inv_cnt() >= 52) {
  2052. X        pline("Sorry, no available letters for adjustment.");
  2053. X        return(0);
  2054. X    }
  2055. X#endif
  2056. X    /* get a pointer to the object the user wants to organize */
  2057. X    allow_all[0] = ALL_CLASSES; allow_all[1] = '\0';
  2058. X    if (!(obj = getobj(allow_all,"adjust"))) return(0);
  2059. X
  2060. X    /* initialize the list with all upper and lower case letters */
  2061. X    for (let = 'a', ix = 0;  let <= 'z';) alphabet[ix++] = let++;
  2062. X    for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
  2063. X    alphabet[52] = 0;
  2064. X
  2065. X    /* blank out all the letters currently in use in the inventory */
  2066. X    /* except those that will be merged with the selected object   */
  2067. X    for (otmp = invent; otmp; otmp = otmp->nobj)
  2068. X        if (otmp != obj && !mergable(otmp,obj))
  2069. X            if (otmp->invlet <= 'Z')
  2070. X                alphabet[(otmp->invlet) - 'A' + 26] = ' ';
  2071. X            else    alphabet[(otmp->invlet) - 'a']        = ' ';
  2072. X
  2073. X    /* compact the list by removing all the blanks */
  2074. X    for (ix = cur = 0; ix <= 52; ix++)
  2075. X        if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];
  2076. X
  2077. X    /* and by dashing runs of letters */
  2078. X    if(cur > 5) compactify(buf);
  2079. X
  2080. X    /* get new letter to use as inventory letter */
  2081. X    for (;;) {
  2082. X        Sprintf(qbuf, "Adjust letter to what [%s]?",buf);
  2083. X        let = yn_function(qbuf, NULL, '\0');
  2084. X        if(index(quitchars,let)) {
  2085. X            pline("Never mind.");
  2086. X            return(0);
  2087. X        }
  2088. X        if (let == '@' || !letter(let))
  2089. X            pline("Select an inventory slot letter.");
  2090. X        else
  2091. X            break;
  2092. X    }
  2093. X
  2094. X    /* change the inventory and print the resulting item */
  2095. X    adj_type = "Moving:";
  2096. X
  2097. X    /*
  2098. X     * don't use freeinv/addinv to avoid double-touching artifacts,
  2099. X     * dousing lamps, losing luck, cursing loadstone, etc.
  2100. X     */
  2101. X    unlinkinv(obj);
  2102. X
  2103. X    for (otmp = invent; otmp;)
  2104. X        if (merged(otmp,obj,0)) {
  2105. X            adj_type = "Merging:";
  2106. X            obj = otmp;
  2107. X            otmp = otmp->nobj;
  2108. X            unlinkinv(obj);
  2109. X        } else {
  2110. X            if (otmp->invlet == let) {
  2111. X                adj_type = "Swapping:";
  2112. X                otmp->invlet = obj->invlet;
  2113. X            }
  2114. X            otmp = otmp->nobj;
  2115. X        }
  2116. X
  2117. X    /* inline addinv (assuming flags.invlet_constant and !merged) */
  2118. X    obj->invlet = let;
  2119. X    obj->nobj = invent; /* insert at beginning */
  2120. X    invent = obj;
  2121. X    reorder_invent();
  2122. X
  2123. X    prinv(adj_type, obj, 0L);
  2124. X    update_inventory();
  2125. X    return(0);
  2126. X}
  2127. X
  2128. X#endif /* OVL1 */
  2129. X
  2130. X/*invent.c*/
  2131. END_OF_FILE
  2132. if test 47145 -ne `wc -c <'src/invent.c'`; then
  2133.     echo shar: \"'src/invent.c'\" unpacked with wrong size!
  2134. fi
  2135. # end of 'src/invent.c'
  2136. fi
  2137. echo shar: End of archive 13 \(of 108\).
  2138. cp /dev/null ark13isdone
  2139. MISSING=""
  2140. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
  2141. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
  2142. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
  2143. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
  2144. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
  2145. 101 102 103 104 105 106 107 108 ; do
  2146.     if test ! -f ark${I}isdone ; then
  2147.     MISSING="${MISSING} ${I}"
  2148.     fi
  2149. done
  2150. if test "${MISSING}" = "" ; then
  2151.     echo You have unpacked all 108 archives.
  2152.     echo "Now execute 'rebuild.sh'"
  2153.     rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
  2154. else
  2155.     echo You still need to unpack the following archives:
  2156.     echo "        " ${MISSING}
  2157. fi
  2158. ##  End of shell archive.
  2159. exit 0
  2160.