home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume16 / nethck31 / part80 < prev    next >
Encoding:
Internet Message Format  |  1993-02-05  |  56.7 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: v16i088:  nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part80/108
  5. Message-ID: <4451@master.CNA.TEK.COM>
  6. Date: 5 Feb 93 19:21:16 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2102
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1639
  11.  
  12. Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
  13. Posting-number: Volume 16, Issue 88
  14. Archive-name: nethack31/Part80
  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 80 (of 108)."
  27. # Contents:  src/options.c src/pickup.c
  28. # Wrapped by billr@saab on Wed Jan 27 16:09:18 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'src/options.c' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'src/options.c'\"
  32. else
  33. echo shar: Extracting \"'src/options.c'\" \(26644 characters\)
  34. sed "s/^X//" >'src/options.c' <<'END_OF_FILE'
  35. X/*    SCCS Id: @(#)options.c    3.1    92/11/14    */
  36. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  37. X/* NetHack may be freely redistributed.  See license for details. */
  38. X
  39. X#include "hack.h"
  40. X#include "termcap.h"
  41. X#include <ctype.h>
  42. X
  43. X/*
  44. X *  NOTE:  If you add (or delete) an option, please update the short
  45. X *  options help (option_help()), the long options help (dat/opthelp),
  46. X *  and the current options setting display function (doset()).
  47. X */
  48. X
  49. X#if defined(TOS) && defined(TEXTCOLOR)
  50. Xextern boolean colors_changed;    /* in tos.c */
  51. X#endif
  52. X
  53. Xextern const char *roles[];    /* from u_init.c */
  54. Xextern char inv_order[];    /* from invent.c */
  55. X
  56. Xstatic boolean initial, from_file;
  57. Xstatic boolean NEARDATA set_order;
  58. X
  59. Xstatic void FDECL(nmcpy, (char *, const char *, int));
  60. Xstatic void FDECL(escapes, (const char *, char *));
  61. Xstatic void FDECL(rejectoption, (const char *));
  62. Xstatic void FDECL(badoption, (const char *));
  63. Xstatic char *FDECL(string_for_env_opt, (const char *, char *));
  64. Xstatic int FDECL(change_inv_order, (char *, int));
  65. Xstatic void FDECL(oc_to_str, (char *, char *));
  66. X
  67. Xstatic struct Bool_Opt
  68. X{
  69. X    const char *name;
  70. X    boolean    *addr, initvalue;
  71. X} boolopt[] = {
  72. X#if defined(MICRO) && !defined(AMIGA)
  73. X    {"BIOS", &flags.BIOS, FALSE},
  74. X#endif
  75. X#ifdef INSURANCE
  76. X    {"checkpoint", &flags.ins_chkpt, TRUE},
  77. X#endif
  78. X#ifdef TEXTCOLOR
  79. X# ifdef MICRO
  80. X    {"color", &flags.use_color, TRUE},
  81. X# else    /* systems that support multiple terminals, many monochrome */
  82. X    {"color", &flags.use_color, FALSE},
  83. X# endif
  84. X#endif
  85. X    {"confirm",&flags.confirm, TRUE},
  86. X#ifdef TERMLIB
  87. X    {"DECgraphics", &flags.DECgraphics, FALSE},
  88. X#endif
  89. X    {"disclose", &flags.end_disclose, TRUE},
  90. X    {"female", &flags.female, FALSE},
  91. X    {"fixinv", &flags.invlet_constant, TRUE},
  92. X#ifdef AMIFLUSH
  93. X    {"flush", &flags.amiflush, FALSE},
  94. X#endif
  95. X    {"help", &flags.help, TRUE},
  96. X#ifdef TEXTCOLOR
  97. X    {"hilite_pet", &flags.hilite_pet, FALSE},
  98. X#endif
  99. X#ifdef ASCIIGRAPH
  100. X    {"IBMgraphics", &flags.IBMgraphics, FALSE},
  101. X#endif
  102. X    {"ignintr", &flags.ignintr, FALSE},
  103. X#ifdef MAC_GRAPHICS_ENV
  104. X    {"large_font", &flags.large_font, FALSE},
  105. X#endif
  106. X    {"legacy",&flags.legacy, TRUE},
  107. X    {"lit_corridor", &flags.lit_corridor, FALSE},
  108. X#ifdef MAC_GRAPHICS_ENV
  109. X    {"MACgraphics", &flags.MACgraphics, TRUE},
  110. X#endif
  111. X#ifdef NEWS
  112. X    {"news", &flags.news, TRUE},
  113. X#endif
  114. X    {"null", &flags.null, TRUE},
  115. X    {"number_pad", &flags.num_pad, FALSE},
  116. X    {"pickup", &flags.pickup, TRUE},
  117. X#ifdef MAC
  118. X    {"popup_dialog", &flags.popup_dialog, FALSE},
  119. X#endif
  120. X#if defined(MICRO) && !defined(AMIGA)
  121. X    {"rawio", &flags.rawio, FALSE},
  122. X#endif
  123. X    {"rest_on_space", &flags.rest_on_space, FALSE},
  124. X    {"safepet", &flags.safe_dog, TRUE},
  125. X#ifdef EXP_ON_BOTL
  126. X    {"showexp", &flags.showexp, FALSE},
  127. X#endif
  128. X#ifdef SCORE_ON_BOTL
  129. X    {"showscore", &flags.showscore, FALSE},
  130. X#endif
  131. X    {"silent", &flags.silent, TRUE},
  132. X    {"sortpack", &flags.sortpack, TRUE},
  133. X    {"sound", &flags.soundok, TRUE},
  134. X    {"standout", &flags.standout, FALSE},
  135. X    {"time", &flags.time, FALSE},
  136. X    {"tombstone",&flags.tombstone, TRUE},
  137. X    {"verbose", &flags.verbose, TRUE},
  138. X    {NULL, (boolean *)0, FALSE}
  139. X};
  140. X
  141. Xstatic boolean need_redraw; /* for doset() */
  142. X
  143. Xvoid
  144. Xinitoptions()
  145. X{
  146. X    register char *opts;
  147. X    int i;
  148. X
  149. X    for (i = 0; boolopt[i].name; i++) {
  150. X        if (boolopt[i].addr)
  151. X            *(boolopt[i].addr) = boolopt[i].initvalue;
  152. X    }
  153. X    flags.end_own = FALSE;
  154. X    flags.end_top = 3;
  155. X    flags.end_around = 2;
  156. X    flags.msg_history = 20;
  157. X
  158. X    /* Set the default monster and object class symbols.  Don't use */
  159. X    /* memcpy() --- sizeof char != sizeof uchar on some machines.    */
  160. X    for (i = 0; i < MAXOCLASSES; i++)
  161. X            oc_syms[i] = (uchar) def_oc_syms[i];
  162. X    for (i = 0; i < MAXMCLASSES; i++)
  163. X            monsyms[i] = (uchar) def_monsyms[i];
  164. X
  165. X    switch_graphics(ASCII_GRAPHICS);    /* set default characters */
  166. X#ifdef UNIX
  167. X    /*
  168. X     * Set defaults for some options depending on what we can
  169. X     * detect about the environment's capabilities.
  170. X     * This has to be done after the global initialization above
  171. X     * and before reading user-specific initialization via
  172. X     * config file/environment variable below.
  173. X     */
  174. X    /* this detects the IBM-compatible console on most 386 boxes */
  175. X    if (!strncmp(getenv("TERM"), "AT", 2)) {
  176. X        switch_graphics(IBM_GRAPHICS);
  177. X# ifdef TEXTCOLOR
  178. X        flags.use_color = TRUE;
  179. X# endif
  180. X    }
  181. X#endif /* UNIX */
  182. X#if defined(UNIX) || defined(VMS)
  183. X    /* detect whether a "vt" terminal can handle alternate charsets */
  184. X    if (!strncmpi(getenv("TERM"), "vt", 2) && (AS && AE) &&
  185. X        !strcmp(AS, "\016") && !strcmp(AE, "\017")) {
  186. X        switch_graphics(DEC_GRAPHICS);
  187. X    }
  188. X#endif /* UNIX || VMS */
  189. X
  190. X#ifdef MAC_GRAPHICS_ENV
  191. X    switch_graphics(MAC_GRAPHICS);
  192. X#endif /* MAC_GRAPHICS_ENV */
  193. X
  194. X#ifdef TUTTI_FRUTTI
  195. X    /* since this is done before init_objects(), do partial init here */
  196. X    objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD;
  197. X    nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
  198. X#endif
  199. X    opts = getenv("NETHACKOPTIONS");
  200. X    if (!opts) opts = getenv("HACKOPTIONS");
  201. X    if (opts)
  202. X        if (*opts == '/' || *opts == '\\' || *opts == '@') {
  203. X            if (*opts == '@') opts++;    /* @filename */
  204. X            /* looks like a filename */
  205. X            read_config_file(opts);
  206. X        } else {
  207. X            read_config_file(NULL);
  208. X            parseoptions(opts, TRUE, FALSE);
  209. X        }
  210. X    else
  211. X        read_config_file(NULL);
  212. X#ifdef AMIGA
  213. X    ami_wbench_init();    /* must be here or can't set fruit */
  214. X#endif
  215. X#ifdef TUTTI_FRUTTI
  216. X    (void)fruitadd(pl_fruit);
  217. X    /* Remove "slime mold" from list of object names; this will    */
  218. X    /* prevent it from being wished unless it's actually present    */
  219. X    /* as a named (or default) fruit.  Wishing for "fruit" will    */
  220. X    /* result in the player's preferred fruit [better than "\033"].    */
  221. X    obj_descr[SLIME_MOLD].oc_name = "fruit";
  222. X#endif
  223. X    if(flags.female)  {    /* should have been set in NETHACKOPTIONS */
  224. X        roles[2] = "Cavewoman";
  225. X        roles[6] = "Priestess";
  226. X    }
  227. X}
  228. X
  229. Xstatic void
  230. Xnmcpy(dest, src, maxlen)
  231. X    char    *dest;
  232. X    const char *src;
  233. X    int    maxlen;
  234. X{
  235. X    int    count;
  236. X
  237. X    for(count = 1; count < maxlen; count++) {
  238. X        if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/
  239. X        *dest++ = *src++;
  240. X    }
  241. X    *dest = 0;
  242. X}
  243. X
  244. X/*
  245. X * escapes: escape expansion for showsyms. C-style escapes understood include
  246. X * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix
  247. X * for control characters is also understood, and \[mM] followed by any of the
  248. X * previous forms or by a character has the effect of 'meta'-ing the value (so
  249. X * that the alternate character set will be enabled).
  250. X */
  251. Xstatic void
  252. Xescapes(cp, tp)
  253. Xconst char    *cp;
  254. Xchar *tp;
  255. X{
  256. X    while (*cp)
  257. X    {
  258. X    int    cval = 0, meta = 0;
  259. X
  260. X    if (*cp == '\\' && index("mM", cp[1])) {
  261. X        meta = 1;
  262. X        cp += 2;
  263. X    }
  264. X    if (*cp == '\\' && index("0123456789xXoO", cp[1]))
  265. X    {
  266. X        const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
  267. X        int dcount = 0;
  268. X
  269. X        cp++;
  270. X        if (*cp == 'x' || *cp == 'X')
  271. X        for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
  272. X            cval = (cval * 16) + (dp - hex) / 2;
  273. X        else if (*cp == 'o' || *cp == 'O')
  274. X        for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
  275. X            cval = (cval * 8) + (*cp - '0');
  276. X        else
  277. X        for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++)
  278. X            cval = (cval * 10) + (*cp - '0');
  279. X    }
  280. X    else if (*cp == '\\')        /* C-style character escapes */
  281. X    {
  282. X        switch (*++cp)
  283. X        {
  284. X        case '\\': cval = '\\'; break;
  285. X        case 'n': cval = '\n'; break;
  286. X        case 't': cval = '\t'; break;
  287. X        case 'b': cval = '\b'; break;
  288. X        case 'r': cval = '\r'; break;
  289. X        default: cval = *cp;
  290. X        }
  291. X        cp++;
  292. X    }
  293. X    else if (*cp == '^')        /* expand control-character syntax */
  294. X    {
  295. X        cval = (*++cp & 0x1f);
  296. X        cp++;
  297. X    }
  298. X    else
  299. X        cval = *cp++;
  300. X    if (meta)
  301. X        cval |= 0x80;
  302. X    *tp++ = cval;
  303. X    }
  304. X    *tp = '\0';
  305. X}
  306. X
  307. Xstatic void
  308. Xrejectoption(optname)
  309. Xconst char *optname;
  310. X{
  311. X#ifdef MICRO
  312. X# ifdef AMIGA
  313. X    if(FromWBench){
  314. X        pline("\"%s\" settable only from %s or in icon.",
  315. X            optname, configfile);
  316. X    } else
  317. X# endif
  318. X        pline("\"%s\" settable only from %s.", optname, configfile);
  319. X#else
  320. X    pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
  321. X            configfile);
  322. X#endif
  323. X}
  324. X
  325. Xstatic void
  326. Xbadoption(opts)
  327. Xconst char *opts;
  328. X{
  329. X    if(!initial) {
  330. X        if(!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
  331. X        option_help();
  332. X        else
  333. X        pline("Unknown option: %s.  Enter \"?g\" for help.", opts);
  334. X        return;
  335. X    }
  336. X# ifdef AMIGA
  337. X    if(ami_wbench_badopt(opts)) {
  338. X# endif
  339. X    if(from_file)
  340. X        raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts);
  341. X    else
  342. X        raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts);
  343. X# ifdef AMIGA
  344. X    }
  345. X# endif
  346. X    wait_synch();
  347. X}
  348. X
  349. Xstatic char *
  350. Xstring_for_env_opt(optname, opts)
  351. Xconst char *optname;
  352. Xchar *opts;
  353. X{
  354. X    register char *colon;
  355. X
  356. X    if(!initial) {
  357. X        rejectoption(optname);
  358. X        return NULL;
  359. X    }
  360. X    colon = index(opts,':');
  361. X    if(!colon) {
  362. X        badoption(opts);
  363. X        return NULL;
  364. X    }
  365. X    return ++colon;
  366. X}
  367. X
  368. X/*
  369. X * Change the inventory order, using the given string as the new order.
  370. X * Missing characters in the new order are filled in at the end from
  371. X * the current inv_order.
  372. X *
  373. X * This routine always returns 1 unless the parameter 'fail' is true
  374. X * and there is a duplicate or bad char in the string.
  375. X */
  376. Xstatic int
  377. Xchange_inv_order(op, fail)
  378. X    char *op;
  379. X    int  fail;    /* If TRUE, return 0 if any duplicates or bad chars. */
  380. X{
  381. X    int oc_sym, num;
  382. X    char *sp, *tmp, buf[BUFSZ];
  383. X
  384. X    for (sp = op; *sp; sp++) {
  385. X    oc_sym = def_char_to_objclass(*sp);
  386. X
  387. X    /* Remove bad or duplicate entries. */
  388. X    if (oc_sym == MAXOCLASSES ||
  389. X        (!index(inv_order, oc_sym)) || (index(sp+1, *sp))) {
  390. X
  391. X        if (fail) return 0;
  392. X        for(tmp = sp; *tmp; tmp++)
  393. X        tmp[0] = tmp[1];
  394. X        sp--;
  395. X    } else
  396. X        *sp = (char) oc_sym;
  397. X    } 
  398. X    Strcpy(buf, op);
  399. X    for (sp = inv_order, num = strlen(buf); *sp; sp++)
  400. X    if (!index(buf, *sp))
  401. X        buf[num++] = *sp;
  402. X
  403. X    buf[num] = 0;
  404. X    Strcpy(inv_order, buf);
  405. X    return 1;
  406. X}
  407. X
  408. Xvoid
  409. Xparseoptions(opts, tinitial, tfrom_file)
  410. Xregister char *opts;
  411. Xboolean tinitial, tfrom_file;
  412. X{
  413. X    register char *op;
  414. X    unsigned num;
  415. X    boolean negated;
  416. X    int i;
  417. X
  418. X    initial = tinitial;
  419. X    from_file = tfrom_file;
  420. X    if ((op = index(opts, ',')) != 0) {
  421. X        *op++ = 0;
  422. X        parseoptions(op, initial, from_file);
  423. X    }
  424. X
  425. X    /* strip leading and trailing white space */
  426. X    while (isspace(*opts)) opts++;
  427. X    op = eos(opts);
  428. X    while (--op >= opts && isspace(*op)) *op = '\0';
  429. X
  430. X    if(!*opts) return;
  431. X    negated = FALSE;
  432. X    while((*opts == '!') || !strncmpi(opts, "no", 2)) {
  433. X        if(*opts == '!') opts++; else opts += 2;
  434. X        negated = !negated;
  435. X    }
  436. X    
  437. X#if defined(MICRO) && !defined(AMIGA)
  438. X    /* included for compatibility with old NetHack.cnf files */
  439. X    if (!strncmp(opts, "IBM_", 4)) {
  440. X        flags.BIOS = !negated;
  441. X        return;
  442. X    }
  443. X
  444. X    /* put here cause it has to come from the config file */
  445. X    if (!strncmpi(opts, "raw", 3)) {
  446. X        if (initial)
  447. X            flags.rawio = !negated;
  448. X        else
  449. X            rejectoption("rawio");
  450. X        return;
  451. X    }
  452. X#endif /* MICRO */
  453. X
  454. X#if defined(TOS) && defined(TEXTCOLOR)
  455. X    if (!strncmpi(opts, "col", 3)) {
  456. X        flags.use_color = !negated;
  457. X        if (flags.BIOS && !initial) {
  458. X            if (colors_changed)
  459. X                restore_colors();
  460. X            else
  461. X                set_colors();
  462. X        }
  463. X    }
  464. X#endif
  465. X    /* other special-case boolean options */
  466. X#ifdef TERMLIB
  467. X    if (!strncmpi(opts, "DEC", 3)) {
  468. X#ifdef REINCARNATION
  469. X        if (!initial && Is_rogue_level(&u.uz))
  470. X            assign_rogue_graphics(FALSE);
  471. X#endif
  472. X        flags.DECgraphics = !negated;
  473. X        need_redraw = TRUE;
  474. X        switch_graphics(flags.DECgraphics ?
  475. X                DEC_GRAPHICS : ASCII_GRAPHICS);
  476. X#ifdef REINCARNATION
  477. X        if (!initial && Is_rogue_level(&u.uz))
  478. X            assign_rogue_graphics(TRUE);
  479. X#endif
  480. X        return;
  481. X    }
  482. X#endif /* TERMLIB */
  483. X#ifdef ASCIIGRAPH
  484. X    if (!strncmpi(opts, "IBMg", 4)) {
  485. X#ifdef REINCARNATION
  486. X        if (!initial && Is_rogue_level(&u.uz))
  487. X            assign_rogue_graphics(FALSE);
  488. X#endif
  489. X        flags.IBMgraphics = !negated;
  490. X        need_redraw = TRUE;
  491. X        switch_graphics(flags.IBMgraphics ?
  492. X                IBM_GRAPHICS : ASCII_GRAPHICS);
  493. X#ifdef REINCARNATION
  494. X        if (!initial && Is_rogue_level(&u.uz))
  495. X            assign_rogue_graphics(TRUE);
  496. X#endif
  497. X        return;
  498. X    }
  499. X#endif /* ASCIIGRAPH */
  500. X#ifdef MAC_GRAPHICS_ENV
  501. X    if (!strncmpi(opts, "MACg", 4)) {
  502. X#ifdef REINCARNATION
  503. X        if (!initial && Is_rogue_level(&u.uz))
  504. X            assign_rogue_graphics(FALSE);
  505. X#endif
  506. X        flags.MACgraphics = !negated;
  507. X        need_redraw = TRUE;
  508. X        switch_graphics(flags.MACgraphics ?
  509. X                MAC_GRAPHICS : ASCII_GRAPHICS);
  510. X#ifdef REINCARNATION
  511. X        if (!initial && Is_rogue_level(&u.uz))
  512. X            assign_rogue_graphics(TRUE);
  513. X#endif
  514. X        return;
  515. X    }
  516. X#endif /* MAC_GRAPHICS_ENV */
  517. X
  518. X    /* common boolean options */
  519. X
  520. X    if (!strncmpi(opts, "fem", 3)) {
  521. X        if(!initial && flags.female == negated)
  522. X            pline("That is not anatomically possible.");
  523. X        else
  524. X            flags.female = !negated;
  525. X        return;
  526. X    }
  527. X
  528. X    if (!strncmpi(opts, "fix", 3)) {
  529. X        flags.invlet_constant = !negated;
  530. X        if (!initial && flags.invlet_constant) reassign();
  531. X        return;
  532. X    }
  533. X
  534. X    if (!strncmpi(opts, "male", 4)) {
  535. X        if(!initial && flags.female != negated)
  536. X            pline("That is not anatomically possible.");
  537. X        else
  538. X            flags.female = negated;
  539. X        return;
  540. X    }
  541. X
  542. X    if (!strncmpi(opts, "num", 3)) {
  543. X        flags.num_pad = !negated;
  544. X        if (!initial) number_pad(flags.num_pad ? 1 : 0);
  545. X        return;
  546. X    }
  547. X#ifdef EXP_ON_BOTL
  548. X    if (!strncmpi(opts, "showexp", 7)) {
  549. X        flags.showexp = !negated;
  550. X        flags.botl = 1;
  551. X        return;
  552. X    }
  553. X#endif
  554. X#ifdef SCORE_ON_BOTL
  555. X    if (!strncmpi(opts, "showscore", 9)) {
  556. X        flags.showscore = !negated;
  557. X        flags.botl = 1;
  558. X        return;
  559. X    }
  560. X#endif
  561. X    if (!strncmpi(opts, "time", 4)) {
  562. X        flags.time = !negated;
  563. X        flags.botl = 1;
  564. X        return;
  565. X    }
  566. X
  567. X    if (!strncmpi(opts, "legacy", 6)) {
  568. X            if(!initial) rejectoption("legacy");
  569. X        else flags.legacy = !negated;
  570. X        return;
  571. X    }
  572. X
  573. X    /* compound options */
  574. X
  575. X    if (!strncmpi(opts, "pet", 3)) {
  576. X        if ((op = string_for_env_opt("pettype", opts)) != 0)
  577. X            switch (*op) {
  578. X            case 'd':    /* dog */
  579. X            case 'D':
  580. X                preferred_pet = 'd';
  581. X                break;
  582. X            case 'c':    /* cat */
  583. X            case 'C':
  584. X            case 'f':    /* feline */
  585. X            case 'F':
  586. X                preferred_pet = 'c';
  587. X                break;
  588. X            default:
  589. X                pline("Unrecognized pettype '%s'", op);
  590. X                break;
  591. X            }
  592. X        return;
  593. X    }
  594. X
  595. X    if (!strncmpi(opts, "cat", 3)) {
  596. X        if ((op = string_for_env_opt("catname", opts)) != 0)
  597. X            nmcpy(catname, op, 62);
  598. X        return;
  599. X    }
  600. X
  601. X    if (!strncmpi(opts, "dog", 3)) {
  602. X        if ((op = string_for_env_opt("dogname", opts)) != 0)
  603. X            nmcpy(dogname, op, 62);
  604. X        return;
  605. X    }
  606. X
  607. X    if (!strncmpi(opts, "msg", 3)) {
  608. X        if ((op = string_for_env_opt("msghistory", opts)) != 0) {
  609. X            flags.msg_history = atoi(op);
  610. X        }
  611. X        return;
  612. X    }
  613. X#ifdef TUTTI_FRUTTI
  614. X    if (!strncmpi(opts, "fr", 2)) {
  615. X        op = index(opts, ':');
  616. X        if (!op) {
  617. X            badoption(opts);
  618. X            return;
  619. X        }
  620. X        op++;
  621. X        if (!initial) {
  622. X            struct fruit *f;
  623. X            int numfruits = 0;
  624. X
  625. X            for(f=ffruit; f; f=f->nextf) {
  626. X            if (!strcmp(op, f->fname)) goto goodfruit;
  627. X            numfruits++;
  628. X            }
  629. X            if (numfruits >= 100) {
  630. X            pline("Doing that so many times isn't very fruitful.");
  631. X            return;
  632. X            }
  633. X        }
  634. Xgoodfruit:
  635. X        nmcpy(pl_fruit, op, PL_FSIZ);
  636. X        if (!*pl_fruit)
  637. X            nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ);
  638. X        if (!initial)
  639. X            (void)fruitadd(pl_fruit);
  640. X        /* If initial, then initoptions is allowed to do it instead
  641. X         * of here (initoptions always has to do it even if there's
  642. X         * no fruit option at all.  Also, we don't want people
  643. X         * setting multiple fruits in their options.)
  644. X         */
  645. X        return;
  646. X    }
  647. X#endif
  648. X    /* graphics:string */
  649. X    if (!strncmpi(opts, "gr", 2)) {
  650. X        uchar translate[MAXPCHARS+1];
  651. X        int lth;
  652. X
  653. X        if (!(opts = string_for_env_opt("graphics", opts)))
  654. X            return;
  655. X        escapes(opts, opts);
  656. X
  657. X        lth = strlen(opts);
  658. X        if (lth > MAXPCHARS) lth = MAXPCHARS;
  659. X        /* match the form obtained from PC configuration files */
  660. X        for (i = 0; i < lth; i++)
  661. X            translate[i] = (uchar) opts[i];
  662. X        assign_graphics(translate, lth);
  663. X        return;
  664. X    }
  665. X
  666. X    /* objects:string */
  667. X    if (!strncmpi(opts, "objects", 7)) {
  668. X        int k, length;
  669. X
  670. X        if (!(opts = string_for_env_opt("objects", opts)))
  671. X            return;
  672. X        escapes(opts, opts);
  673. X
  674. X        /*
  675. X         * Override the default object class symbols.  The first
  676. X         * object in the object class is the "random object".  I
  677. X         * don't want to use 0 as an object class, so the "random
  678. X         * object" is basically a place holder.
  679. X         *
  680. X         * The object class symbols have already been initialized in
  681. X         * initoptions().
  682. X         */
  683. X        length = strlen(opts);
  684. X        if (length >= MAXOCLASSES)
  685. X            length = MAXOCLASSES-1;    /* don't count RANDOM_OBJECT */
  686. X
  687. X        for (k = 0; k < length; k++)
  688. X            oc_syms[k+1] = (uchar) opts[k];
  689. X        return;
  690. X    }
  691. X
  692. X    /* monsters:string */
  693. X    if (!strncmpi(opts, "monsters", 8)) {
  694. X        int k, length;
  695. X
  696. X        if (!(opts = string_for_env_opt("monsters", opts)))
  697. X            return;
  698. X        escapes(opts, opts);
  699. X
  700. X        /* Override default mon class symbols set in initoptions(). */
  701. X        length = strlen(opts);
  702. X        if (length >= MAXMCLASSES)
  703. X            length = MAXMCLASSES-1;    /* mon class 0 unused */
  704. X
  705. X        for (k = 0; k < length; k++)
  706. X            monsyms[k+1] = (uchar) opts[k];
  707. X        return;
  708. X    }
  709. X
  710. X    /* name:string */
  711. X    if (!strncmpi(opts, "name", 4)) {
  712. X        if ((op = string_for_env_opt("name", opts)) != 0)
  713. X            nmcpy(plname, op, (int)sizeof(plname)-1);
  714. X        return;
  715. X    }
  716. X
  717. X    /* the order to list the pack */
  718. X    if (!strncmpi(opts, "pack", 4)) {
  719. X        op = index(opts,':');
  720. X        if(!op) {
  721. X            badoption(opts);
  722. X            return;
  723. X        }
  724. X        op++;            /* skip : */
  725. X
  726. X        if (!change_inv_order(op, 1))
  727. X                set_order = TRUE;
  728. X        else
  729. X                badoption(opts);
  730. X        return;
  731. X    }
  732. X
  733. X    /* scores:5t[op] 5a[round] o[wn] */
  734. X    if (!strncmpi(opts, "scores", 6)) {
  735. X        op = index(opts,':');
  736. X        if(!op) {
  737. X            badoption(opts);
  738. X            return;
  739. X        }
  740. X        op++;
  741. X        while(*op) {
  742. X            num = 1;
  743. X            if(digit(*op)) {
  744. X                num = atoi(op);
  745. X                while(digit(*op)) op++;
  746. X            } else if(*op == '!') {
  747. X                negated = !negated;
  748. X                op++;
  749. X            }
  750. X            while(*op == ' ') op++;
  751. X
  752. X            switch(*op) {
  753. X                case 't':
  754. X                case 'T':
  755. X                    flags.end_top = num;
  756. X                    break;
  757. X                case 'a':
  758. X                case 'A':
  759. X                    flags.end_around = num;
  760. X                    break;
  761. X                case 'o':
  762. X                case 'O':
  763. X                    flags.end_own = !negated;
  764. X                    break;
  765. X                default:
  766. X                    badoption(opts);
  767. X                    return;
  768. X            }
  769. X            while(letter(*++op) || *op == ' ') ;
  770. X            if(*op == '/') op++;
  771. X        }
  772. X        return;
  773. X    }
  774. X    if (!strncmpi(opts, "win", 3)) {
  775. X        if ((op = string_for_env_opt("windowtype", opts)) != 0) {
  776. X        char buf[16];
  777. X        nmcpy(buf, op, 15);
  778. X        choose_windows(buf);
  779. X        }
  780. X        return;
  781. X    }
  782. X
  783. X    /* OK, if we still haven't recognized the option, check the boolean
  784. X     * options list
  785. X     */
  786. X    for (i = 0; boolopt[i].name; i++) {
  787. X        if (boolopt[i].addr && !strncmpi(boolopt[i].name, opts, 3)) {
  788. X            *(boolopt[i].addr) = !negated;
  789. X#ifdef TEXTCOLOR
  790. X            if((boolopt[i].addr) == &flags.use_color)
  791. X                need_redraw = TRUE;
  792. X
  793. X            if((boolopt[i].addr) == &flags.hilite_pet)
  794. X                need_redraw = TRUE;
  795. X#endif
  796. X            if (!initial && boolopt[i].addr==&flags.lit_corridor) {
  797. X                /*
  798. X                 * All corridor squares seen via night vision or
  799. X                 * candles & lamps change.  Update them by calling
  800. X                 * newsym() on them.  Don't do this if we are
  801. X                 * initializing the options --- the vision system
  802. X                 * isn't set up yet.
  803. X                 */
  804. X                vision_recalc(2);        /* shut down vision */
  805. X                vision_full_recalc = 1;    /* delayed recalc */
  806. X            }
  807. X            return;
  808. X        }
  809. X    }
  810. X
  811. X    /* out of valid options */
  812. X    badoption(opts);
  813. X}
  814. X
  815. X/*
  816. X * Convert the given string of object classes to a string of default object
  817. X * symbols.
  818. X */
  819. Xstatic void
  820. Xoc_to_str(src,dest)
  821. X    char *src, *dest;
  822. X{
  823. X    int i;
  824. X
  825. X    while ((i = (int) *src++) != 0) {
  826. X    if (i < 0 || i >= MAXOCLASSES)
  827. X        impossible("oc_to_str:  illegal object class %d", i);
  828. X    else
  829. X        *dest++ = def_oc_syms[i];
  830. X    }
  831. X    *dest = '\0';
  832. X}
  833. X
  834. X#ifdef MICRO
  835. X# define OPTIONS_HEADING "OPTIONS"
  836. X#else
  837. X# define OPTIONS_HEADING "NETHACKOPTIONS"
  838. X#endif
  839. X
  840. Xint
  841. Xdoset()
  842. X{
  843. X    char buf[BUFSZ], pack_order[MAXOCLASSES+1], on_off;
  844. X    const char *opt_name;
  845. X    int i;
  846. X    winid tmpwin;
  847. X
  848. X    switch (yn_function("Show the current settings [c], or set options [s]?",
  849. X                "csq", 'q')) {
  850. X    default:
  851. X    case 'q':
  852. X        clear_nhwindow(WIN_MESSAGE);
  853. X        return 0;
  854. X    case 'c':
  855. X        tmpwin = create_nhwindow(NHW_MENU);
  856. X        putstr(tmpwin, 0, OPTIONS_HEADING);
  857. X        putstr(tmpwin, 0, "");
  858. X        /* print the booleans */
  859. X        for (i = 0; boolopt[i].name; i++) {
  860. X        if (!boolopt[i].addr) continue;
  861. X        opt_name = boolopt[i].name;
  862. X        if (*(boolopt[i].addr)) {
  863. X            on_off = ' ';               /* on */
  864. X        } else {
  865. X            if (!strcmp(opt_name, "female"))
  866. X            opt_name = "male",  on_off = ' ';
  867. X            else
  868. X            on_off = '!';           /* off */
  869. X        }
  870. X        Sprintf(buf, "%c%s", on_off, opt_name);
  871. X        putstr(tmpwin, 0, buf);
  872. X        }
  873. X        /* print the compounds */
  874. X        Sprintf(buf, " catname: %s",
  875. X            (catname[0] != 0) ? catname : "(null)");
  876. X        putstr(tmpwin, 0, buf);
  877. X        Sprintf(buf, " dogname: %s",
  878. X            (dogname[0] != 0) ? dogname : "(null)");
  879. X        putstr(tmpwin, 0, buf);
  880. X#ifdef TUTTI_FRUTTI
  881. X        Sprintf(buf, " fruit: %s", pl_fruit);
  882. X        putstr(tmpwin, 0, buf);
  883. X#endif
  884. X        Sprintf(buf, " msghistory: %u", flags.msg_history);
  885. X        putstr(tmpwin, 0, buf);
  886. X        Sprintf(buf, " name: %s", plname);
  887. X        putstr(tmpwin, 0, buf);
  888. X        oc_to_str(inv_order, pack_order);
  889. X        Sprintf(buf, " packorder: %s", pack_order);
  890. X        putstr(tmpwin, 0, buf);
  891. X        Sprintf(buf, " pettype: %s", preferred_pet == 'c' ? "cat" :
  892. X                    preferred_pet == 'd' ? "dog" : "random");
  893. X        putstr(tmpwin, 0, buf);
  894. X        Sprintf(buf, " scores: %utop/%uaround%s",
  895. X                flags.end_top, flags.end_around,
  896. X                (flags.end_own ? "/own" : ""));
  897. X        putstr(tmpwin, 0, buf);
  898. X        Sprintf(buf, " windowtype: %s", windowprocs.name);
  899. X        putstr(tmpwin, 0, buf);
  900. X        display_nhwindow(tmpwin, TRUE);
  901. X        destroy_nhwindow(tmpwin);
  902. X        break;
  903. X    case 's':
  904. X        clear_nhwindow(WIN_MESSAGE);
  905. X        getlin("What options do you want to set?", buf);
  906. X        clear_nhwindow(WIN_MESSAGE);
  907. X        if(buf[0] == '\033') return 0;
  908. X        need_redraw = FALSE;
  909. X        parseoptions(buf, FALSE, FALSE);
  910. X        if(need_redraw)
  911. X        (void) doredraw();
  912. X        break;
  913. X    }
  914. X
  915. X    return 0;
  916. X}
  917. X
  918. Xint
  919. Xdotogglepickup() {
  920. X    flags.pickup = !flags.pickup;
  921. X    pline("Pickup: %s.", flags.pickup ? "ON" : "OFF");
  922. X    return 0;
  923. X}
  924. X
  925. X/* data for option_help() */
  926. Xstatic const char *opt_intro[] = {
  927. X    "",
  928. X    "                 NetHack Options Help:",
  929. X    "",
  930. X#define CONFIG_SLOT 3    /* fill in next value at run-time */
  931. X    NULL,
  932. X#ifndef MICRO
  933. X    "or use `NETHACKOPTIONS=\"<options>\"' in your environment;",
  934. X# ifdef VMS
  935. X    "-- for example, $ DEFINE NETHACKOPTIONS \"nopickup,fruit:kumquat\"",
  936. X# endif
  937. X#endif
  938. X    "or press \"O\" while playing, and type your <options> at the prompt.",
  939. X    "In either case, <options> is a list of options separated by commas.",
  940. X    "",
  941. X "Boolean options (which can be negated by prefixing them with '!' or \"no\"):",
  942. X    NULL
  943. X};
  944. Xstatic const char *opt_compound[] = {
  945. X    "Compound options:",
  946. X    "`catname'   - the name of your (first) cat (e.g., catname:Tabby),",
  947. X    "`dogname'   - the name of your (first) dog (e.g., dogname:Fang),",
  948. X#ifdef TUTTI_FRUTTI
  949. X    "`fruit'     - the name of a fruit you enjoy eating,",
  950. X# define FRUIT_OFFSET 1
  951. X#else
  952. X# define FRUIT_OFFSET 0
  953. X#endif
  954. X    "`graphics'  - defines the symbols to use in drawing the dungeon map,",
  955. X    "`monsters'  - defines the symbols to use for monsters,",
  956. X    "`msghistory'- number of top line messages to save,",
  957. X    "`name'      - your character's name (e.g., name:Merlin-W),",
  958. X    "`objects'   - defines the symbols to use for objects,",
  959. X    "`packorder' - the inventory order of the items in your pack",
  960. X#define PCKORD_SLOT 9+FRUIT_OFFSET
  961. X    NULL,
  962. X    "`pettype'   - your preferred initial pet type,",
  963. X    "`scores'    - the parts of the score list you wish to see,",
  964. X    "`windowtype'- windowing system to use.",
  965. X    "",
  966. X "Some of the options can be set only before the game is started.  You will",
  967. X    "be so informed, if you attempt to set them while in the game.",
  968. X    NULL
  969. X};
  970. X
  971. Xvoid
  972. Xoption_help()
  973. X{
  974. X    char    buf[BUFSZ], pack_order[MAXOCLASSES+1];
  975. X    register int    i;
  976. X    winid datawin;
  977. X
  978. X    datawin = create_nhwindow(NHW_TEXT);
  979. X#ifdef AMIGA
  980. X    if(FromWBench){
  981. X    Sprintf(buf,"Set options as OPTIONS= in %s or in icon;",configfile);
  982. X    } else
  983. X#endif
  984. X    Sprintf(buf, "Set options as OPTIONS=<options> in %s;", configfile);
  985. X    opt_intro[CONFIG_SLOT] = (const char *) buf;
  986. X    for (i = 0; opt_intro[i]; i++)
  987. X    putstr(datawin, 0, opt_intro[i]);
  988. X
  989. X    /* Boolean options */
  990. X    for (i = 0; boolopt[i].name; i++) {
  991. X    if (boolopt[i].addr)
  992. X        next_opt(datawin, boolopt[i].name);
  993. X    }
  994. X    next_opt(datawin, "");
  995. X
  996. X    /* Compound options */
  997. X    oc_to_str(inv_order, pack_order);
  998. X    Sprintf(buf, "              (currently, packorder:%s ),", pack_order);
  999. X#if 0
  1000. X    assert( opt_compound[PCKORD_SLOT] == NULL );
  1001. X#endif
  1002. X    opt_compound[PCKORD_SLOT] = (const char *) buf;
  1003. X    for (i = 0; opt_compound[i]; i++)
  1004. X    putstr(datawin, 0, opt_compound[i]);
  1005. X
  1006. X    display_nhwindow(datawin, FALSE);
  1007. X    destroy_nhwindow(datawin);
  1008. X    return;
  1009. X}
  1010. X
  1011. X/*
  1012. X * prints the next boolean option, on the same line if possible, on a new
  1013. X * line if not. End with next_opt("").
  1014. X */
  1015. Xvoid
  1016. Xnext_opt(datawin, str)
  1017. Xwinid datawin;
  1018. Xconst char *str;
  1019. X{
  1020. X    static char buf[121];
  1021. X    int i;
  1022. X    char *s;
  1023. X
  1024. X    if (!*str) {
  1025. X        for (s = buf; *s; s++);    /* find end of string */
  1026. X        if (s > &buf[1] && s[-2] == ',')
  1027. X            s[-2] = 0;    /* strip last ", " */
  1028. X        i = 121;
  1029. X    }
  1030. X    else    
  1031. X        i = strlen(buf) + strlen(str) + 2;
  1032. X
  1033. X    if (i > COLNO - 2) { /* rule of thumb */
  1034. X        putstr(datawin, 0, buf);
  1035. X        buf[0] = 0;
  1036. X    }
  1037. X    if (*str) {
  1038. X        Strcat(buf, str);
  1039. X        Strcat(buf, ", ");
  1040. X    }
  1041. X    else
  1042. X        putstr(datawin, 0, str);
  1043. X    return;
  1044. X}
  1045. X
  1046. X#ifdef TUTTI_FRUTTI
  1047. X/* Returns the fid of the fruit type; if that type already exists, it
  1048. X * returns the fid of that one; if it does not exist, it adds a new fruit
  1049. X * type to the chain and returns the new one.
  1050. X */
  1051. Xint
  1052. Xfruitadd(str)
  1053. Xchar *str;
  1054. X{
  1055. X    register int i,j;
  1056. X    register struct fruit *f;
  1057. X#ifdef GCC_WARN
  1058. X    struct fruit *lastf = (struct fruit *)0;
  1059. X#else
  1060. X    struct fruit *lastf;
  1061. X#endif
  1062. X    int highest_fruit_id = 0;
  1063. X    char buf[PL_FSIZ];
  1064. X    boolean user_specified = (str == pl_fruit);
  1065. X    /* if not user-specified, then it's a fruit name for a fruit on
  1066. X     * a bones level...
  1067. X     */
  1068. X
  1069. X    /* Note: every fruit has an id (spe for fruit objects) of at least
  1070. X     * 1; 0 is an error.
  1071. X     */
  1072. X    if (user_specified) {
  1073. X        /* disallow naming after other foods (since it'd be impossible
  1074. X         * to tell the difference)
  1075. X         */
  1076. X
  1077. X        boolean found = FALSE;
  1078. X
  1079. X        for(i = bases[j=letindex(FOOD_CLASS)]; i < bases[j+1]; i++) {
  1080. X            if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) {
  1081. X                found = TRUE;
  1082. X                break;
  1083. X            }
  1084. X        }
  1085. X        if (found ||
  1086. X            (!strncmp(str, "tin of ", 7) && name_to_mon(str+7) > -1) ||
  1087. X            !strcmp(str, "empty tin") ||
  1088. X            !strcmp(str, "tin of spinach") ||
  1089. X            ((!strncmp(eos(str)-6," corpse",7) ||
  1090. X                        !strncmp(eos(str)-3, " egg",4))
  1091. X            && name_to_mon(str) > -1))
  1092. X            {
  1093. X                Strcpy(buf, pl_fruit);
  1094. X                Strcpy(pl_fruit, "candied ");
  1095. X                nmcpy(pl_fruit+8, buf, PL_FSIZ-8);
  1096. X        }
  1097. X    }
  1098. X    for(f=ffruit; f; f = f->nextf) {
  1099. X        lastf = f;
  1100. X        if(f->fid > highest_fruit_id) highest_fruit_id = f->fid;
  1101. X        if(!strncmp(str, f->fname, PL_FSIZ))
  1102. X            goto nonew;
  1103. X    }
  1104. X    /* if adding another fruit would overflow spe, use a random
  1105. X       fruit instead... we've got a lot to choose from. */
  1106. X    if (highest_fruit_id >= 127) return rnd(127);
  1107. X    highest_fruit_id++;
  1108. X    f = newfruit();
  1109. X    if (ffruit) lastf->nextf = f;
  1110. X    else ffruit = f;
  1111. X    Strcpy(f->fname, str);
  1112. X    f->fid = highest_fruit_id;
  1113. X    f->nextf = 0;
  1114. Xnonew:
  1115. X    if (user_specified) current_fruit = highest_fruit_id;
  1116. X    return f->fid;
  1117. X}
  1118. X#endif
  1119. X
  1120. X/*options.c*/
  1121. END_OF_FILE
  1122. if test 26644 -ne `wc -c <'src/options.c'`; then
  1123.     echo shar: \"'src/options.c'\" unpacked with wrong size!
  1124. fi
  1125. # end of 'src/options.c'
  1126. fi
  1127. if test -f 'src/pickup.c' -a "${1}" != "-c" ; then 
  1128.   echo shar: Will not clobber existing file \"'src/pickup.c'\"
  1129. else
  1130. echo shar: Extracting \"'src/pickup.c'\" \(26706 characters\)
  1131. sed "s/^X//" >'src/pickup.c' <<'END_OF_FILE'
  1132. X/*    SCCS Id: @(#)pickup.c    3.1    93/01/04    */
  1133. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  1134. X/* NetHack may be freely redistributed.  See license for details. */
  1135. X
  1136. X/*
  1137. X *    Contains code for picking objects up, and container use.
  1138. X */
  1139. X
  1140. X#include    "hack.h"
  1141. X
  1142. Xstatic void FDECL(unsplitobj, (struct obj *,struct obj *,long));
  1143. Xstatic void FDECL(simple_look, (struct obj *,BOOLEAN_P));
  1144. Xstatic boolean FDECL(query_classes, (char *,boolean *,boolean *,
  1145. X                 const char *,struct obj *,BOOLEAN_P,BOOLEAN_P));
  1146. Xstatic boolean FDECL(pickup_object, (struct obj *,struct obj *));
  1147. Xstatic boolean FDECL(mbag_explodes, (struct obj *,int));
  1148. XSTATIC_PTR int FDECL(in_container,(struct obj *));
  1149. XSTATIC_PTR int FDECL(ck_bag,(struct obj *));
  1150. XSTATIC_PTR int FDECL(out_container,(struct obj *));
  1151. X
  1152. X/*
  1153. X *  How much the weight of the given container will change when the given
  1154. X *  object is removed from it.  This calculation must match the one used
  1155. X *  by weight() in mkobj.c.
  1156. X */
  1157. X#define DELTA_CWT(cont,obj)        \
  1158. X    ((cont)->cursed ? (obj)->owt * 2 :    \
  1159. X              1 + ((obj)->owt / ((cont)->blessed ? 4 : 2)))
  1160. X
  1161. Xstatic const char moderateloadmsg[] = "You have a little trouble lifting";
  1162. Xstatic const char nearloadmsg[] = "You have much trouble lifting";
  1163. X
  1164. Xstatic void
  1165. Xunsplitobj(obj_block, obj_chip, resplit)
  1166. Xregister struct obj *obj_block, *obj_chip;
  1167. Xlong resplit;    /* non-zero => shift the quantities */
  1168. X{
  1169. X    if (obj_block->nobj != obj_chip) {
  1170. X        impossible("can't unsplit objects");
  1171. X    } else if (resplit) { /* 1st object should be reduced to 'resplit' */
  1172. X        obj_chip->quan += (obj_block->quan - resplit);
  1173. X        obj_block->quan = resplit;
  1174. X        obj_block->owt = weight(obj_block);
  1175. X        obj_chip->owt = weight(obj_chip);
  1176. X    } else {  /* 2nd obj should be merged back into 1st, then destroyed */
  1177. X        obj_block->nobj = obj_chip->nobj;
  1178. X        obj_block->nexthere = obj_chip->nexthere;
  1179. X        obj_block->quan += obj_chip->quan;
  1180. X        obj_block->owt = weight(obj_block);
  1181. X        /* no need to worry about 'unsplitbill'; unsplit only occurs
  1182. X           when unable to pick something up, hence we're not dealing
  1183. X           with billable objects here (I hope!)
  1184. X         */
  1185. X        dealloc_obj(obj_chip);
  1186. X    }
  1187. X}
  1188. X
  1189. X/* much simpler version of the look-here code; used by query_classes() */
  1190. Xstatic void
  1191. Xsimple_look(otmp, here)
  1192. Xstruct obj *otmp;    /* list of objects */
  1193. Xboolean here;        /* flag for type of obj list linkage */
  1194. X{
  1195. X    /* Neither of the first two cases is expected to happen, since
  1196. X     * we're only called after multiple classes of objects have been
  1197. X     * detected, hence multiple objects must be present.
  1198. X     */
  1199. X    if (!otmp) {
  1200. X        impossible("simple_look(NULL)");
  1201. X    } else if (!(here ? otmp->nexthere : otmp->nobj)) {
  1202. X        pline("%s", doname(otmp));
  1203. X    } else {
  1204. X        winid tmpwin = create_nhwindow(NHW_MENU);
  1205. X        putstr(tmpwin, 0, "");
  1206. X        do {
  1207. X        putstr(tmpwin, 0, doname(otmp));
  1208. X        otmp = here ? otmp->nexthere : otmp->nobj;
  1209. X        } while (otmp);
  1210. X        display_nhwindow(tmpwin, TRUE);
  1211. X        destroy_nhwindow(tmpwin);
  1212. X    }
  1213. X}
  1214. X
  1215. Xint
  1216. Xcollect_obj_classes(ilets, otmp, here, incl_gold)
  1217. Xchar ilets[];
  1218. Xregister struct obj *otmp;
  1219. Xboolean here, incl_gold;
  1220. X{
  1221. X    register int iletct = 0;
  1222. X    register char c, last_c = '\0';
  1223. X
  1224. X    if (incl_gold)
  1225. X        ilets[iletct++] = def_oc_syms[GOLD_CLASS];
  1226. X    ilets[iletct] = '\0'; /* terminate ilets so that index() will work */
  1227. X    while (otmp) {
  1228. X        c = def_oc_syms[(int)otmp->oclass];
  1229. X        if (c != last_c && !index(ilets, (last_c = c)))
  1230. X            ilets[iletct++] = c,  ilets[iletct] = '\0';
  1231. X        otmp = here ? otmp->nexthere : otmp->nobj;
  1232. X    }
  1233. X
  1234. X    return iletct;
  1235. X}
  1236. X
  1237. Xstatic boolean
  1238. Xquery_classes(olets, one_at_a_time, everything, action, objs, here, incl_gold)
  1239. Xchar olets[];
  1240. Xboolean *one_at_a_time, *everything;
  1241. Xconst char *action;
  1242. Xstruct obj *objs;
  1243. Xboolean here, incl_gold;
  1244. X{
  1245. X    char ilets[20], inbuf[BUFSZ];
  1246. X    int iletct, oletct;
  1247. X    char qbuf[QBUFSZ];
  1248. X
  1249. X    olets[oletct = 0] = '\0';
  1250. X    *one_at_a_time = *everything = FALSE;
  1251. X    iletct = collect_obj_classes(ilets, objs, here, incl_gold);
  1252. X    if (iletct == 0) {
  1253. X        return FALSE;
  1254. X    } else if (iletct == 1) {
  1255. X        olets[0] = def_char_to_objclass(ilets[0]);
  1256. X        olets[1] = '\0';
  1257. X    } else  {    /* more than one choice available */
  1258. X        const char *where = 0;
  1259. X        register char sym, oc_of_sym, *p;
  1260. X        /* additional choices */
  1261. X        ilets[iletct++] = ' ';
  1262. X        ilets[iletct++] = 'a';
  1263. X        ilets[iletct++] = 'A';
  1264. X        ilets[iletct++] = (objs == invent ? 'i' : ':');
  1265. X        ilets[iletct] = '\0';
  1266. Xask_again:
  1267. X        olets[oletct = 0] = '\0';
  1268. X        *one_at_a_time = *everything = FALSE;
  1269. X        Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",
  1270. X            action, ilets);
  1271. X        getlin(qbuf,inbuf);
  1272. X        if (*inbuf == '\033') {
  1273. X            clear_nhwindow(WIN_MESSAGE);
  1274. X            return FALSE;
  1275. X        }
  1276. X        for (p = inbuf; (sym = *p++); ) {
  1277. X            /* new A function (selective all) added by GAN 01/09/87 */
  1278. X            if (sym == ' ') continue;
  1279. X            else if (sym == 'A') *one_at_a_time = TRUE;
  1280. X            else if (sym == 'a') *everything = TRUE;
  1281. X            else if (sym == ':') {
  1282. X            simple_look(objs, here);  /* dumb if objs==invent */
  1283. X            goto ask_again;
  1284. X            } else if (sym == 'i') {
  1285. X            (void) display_inventory(NULL, FALSE);
  1286. X            goto ask_again;
  1287. X            } else {
  1288. X            oc_of_sym = def_char_to_objclass(sym);
  1289. X            if (index(ilets,sym)) {
  1290. X                olets[oletct++] = oc_of_sym;
  1291. X                olets[oletct] = '\0';
  1292. X            } else {
  1293. X                if (!where)
  1294. X                where = !strcmp(action,"pick up")  ? "here" :
  1295. X                    !strcmp(action,"take out") ?
  1296. X                                "inside" : "";
  1297. X                if (*where)
  1298. X                pline("There are no %c's %s.", sym, where);
  1299. X                else
  1300. X                You("have no %c's.", sym);
  1301. X            }
  1302. X            }
  1303. X        }
  1304. X        if (!oletct && !*everything) *one_at_a_time = TRUE;
  1305. X    }
  1306. X    return TRUE;
  1307. X}
  1308. X
  1309. Xvoid
  1310. Xpickup(all)
  1311. Xint all;    /* all >= 0 => yes/no; < 0 => -count */
  1312. X{
  1313. X    register struct obj *obj;
  1314. X    struct obj *obj2, *objx;
  1315. X    boolean all_of_a_type = FALSE, selective = FALSE;
  1316. X    char olets[20];
  1317. X    long count;
  1318. X
  1319. X    count = (all < 0) ? (-1L * all) : 0L;
  1320. X    if (count) all = 0;
  1321. X
  1322. X    if(Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
  1323. X        if ((multi && !flags.run) || (all && !flags.pickup))
  1324. X            read_engr_at(u.ux,u.uy);
  1325. X        return;
  1326. X    }
  1327. X
  1328. X    /* multi && !flags.run means they are in the middle of some other
  1329. X     * action, or possibly paralyzed, sleeping, etc.... and they just
  1330. X     * teleported onto the object.  They shouldn't pick it up.
  1331. X     */
  1332. X    if ((multi && !flags.run) || (all && !flags.pickup)) {
  1333. X        int ct = 0;
  1334. X
  1335. X        for (obj = level.objects[u.ux][u.uy]; obj;
  1336. X                         obj = obj->nexthere)
  1337. X            if(obj != uchain)
  1338. X                ct++;
  1339. X
  1340. X        /* If there are objects here, take a look.
  1341. X         */
  1342. X        if (ct) {
  1343. X            if (flags.run)
  1344. X                nomul(0);
  1345. X            flush_screen(1);
  1346. X            if (ct < 5)
  1347. X                (void) dolook();
  1348. X            else {
  1349. X                read_engr_at(u.ux,u.uy);
  1350. X                pline("There are several objects here.");
  1351. X            }
  1352. X        } else read_engr_at(u.ux,u.uy);
  1353. X        return;
  1354. X    }
  1355. X
  1356. X    /* check for more than one object */
  1357. X    if(!all) {
  1358. X        register int ct = 0;
  1359. X
  1360. X        for(obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
  1361. X            ct++;
  1362. X        if(ct < 2)
  1363. X            all++;
  1364. X        else {
  1365. X            pline("There are several objects here.");
  1366. X            count = 0;
  1367. X        }
  1368. X    }
  1369. X
  1370. X#ifdef POLYSELF
  1371. X    if (nolimbs(uasmon)) {
  1372. X        You("cannot pick things up without limbs.");
  1373. X        return;
  1374. X    }
  1375. X#endif
  1376. X
  1377. X    /* added by GAN 10/24/86 to allow selective picking up */
  1378. X    if (!all) {
  1379. X        if (!query_classes(olets, &selective, &all_of_a_type,
  1380. X              "pick up", level.objects[u.ux][u.uy], TRUE, FALSE))
  1381. X            return;
  1382. X    }
  1383. X    if(all_of_a_type && !olets[0]) all = TRUE;
  1384. X
  1385. X    for(obj = level.objects[u.ux][u.uy]; obj; obj = obj2) {
  1386. X        obj2 = obj->nexthere;    /* perhaps obj will be picked up */
  1387. X        objx = 0;
  1388. X        if(flags.run) nomul(0);
  1389. X
  1390. X        if(!all)  {
  1391. X            if(!selective && !index(olets,obj->oclass)) continue;
  1392. X
  1393. X            if (!all_of_a_type) {
  1394. X            char qbuf[QBUFSZ];
  1395. X            Sprintf(qbuf,"Pick up %s?", doname(obj));
  1396. X            switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) {
  1397. X            case 'q': return;
  1398. X            case 'n': continue;
  1399. X            case 'a':
  1400. X                all_of_a_type = TRUE;
  1401. X                if (selective) {
  1402. X                selective = FALSE;
  1403. X                olets[0] = obj->oclass;
  1404. X                olets[1] = '\0';
  1405. X                }
  1406. X                break;
  1407. X            case '#':    /* count was entered */
  1408. X                if (!yn_number) continue; /* 0 count => No */
  1409. X                else count = yn_number;
  1410. X                /* fall thru :-} */
  1411. X            default:    /* 'y' */
  1412. X                break;
  1413. X            }
  1414. X            }
  1415. X        }
  1416. X
  1417. X        if (count) {
  1418. X            /* Pickup a specific number of items; split the object
  1419. X               unless count corresponds to full quantity.  1 special
  1420. X               case:  cursed loadstones will remain as merged unit.
  1421. X             */
  1422. X            if (count < obj->quan &&
  1423. X                (!obj->cursed || obj->otyp != LOADSTONE)) {
  1424. X            objx = splitobj(obj, count);
  1425. X            if (!objx || objx->nexthere != obj2)
  1426. X                impossible("bad object split in pickup");
  1427. X            }
  1428. X            count = 0;    /* reset */
  1429. X        }
  1430. X        if (pickup_object(obj, objx)) break;
  1431. X    }
  1432. X
  1433. X    /*
  1434. X     *  Re-map what is at the hero's location after the pickup so the
  1435. X     *  map is correct.
  1436. X     */
  1437. X    newsym(u.ux,u.uy);
  1438. X}
  1439. X
  1440. X/*
  1441. X * Pick up an object from the ground or out of a container and add it to
  1442. X * the inventory.  Returns true if pickup() should break out of its loop.
  1443. X */
  1444. Xstatic boolean
  1445. Xpickup_object(obj, objx)
  1446. Xstruct obj *obj, *objx;
  1447. X{
  1448. X    int wt, nearload;
  1449. X    long pickquan;
  1450. X
  1451. X    if (obj == uchain) {    /* do not pick up attached chain */
  1452. X        return FALSE;
  1453. X    } else if (obj->oartifact && !touch_artifact(obj,&youmonst)) {
  1454. X        return FALSE;
  1455. X    } else if (obj->otyp == GOLD_PIECE) {
  1456. X        /*
  1457. X         *  Special consideration for gold pieces...
  1458. X         */
  1459. X        long iw = (long)max_capacity() - ((u.ugold + 50L) / 100L);
  1460. X        long gold_capacity = ((-iw) * 100L) - 50L + 99L - u.ugold;
  1461. X
  1462. X        if (gold_capacity <= 0L) {
  1463. X        if (objx) unsplitobj(obj, objx, 0L);
  1464. X       pline("There %s %ld gold piece%s here, but you cannot carry any more.",
  1465. X            (obj->quan == 1L) ? "is" : "are",
  1466. X            obj->quan, plur(obj->quan));
  1467. X        return FALSE;
  1468. X        } else if (gold_capacity < obj->quan) {
  1469. X        if (objx) unsplitobj(obj, objx, 0L);
  1470. X        You("can only carry %s of the %ld gold pieces lying here.",
  1471. X            gold_capacity == 1L ? "one" : "some", obj->quan);
  1472. X        pline("%s %ld gold piece%s.",
  1473. X            nearloadmsg, gold_capacity, plur(gold_capacity));
  1474. X        u.ugold += gold_capacity;
  1475. X        obj->quan -= gold_capacity;
  1476. X        costly_gold(obj->ox, obj->oy, gold_capacity);
  1477. X        } else {
  1478. X        u.ugold += obj->quan;
  1479. X        if ((nearload = near_capacity()) != 0)
  1480. X            pline("%s %ld gold piece%s.",
  1481. X              nearload < MOD_ENCUMBER ?
  1482. X              moderateloadmsg : nearloadmsg,
  1483. X              obj->quan, plur(obj->quan));
  1484. X        else
  1485. X            prinv(NULL, obj, 0L);
  1486. X        costly_gold(obj->ox, obj->oy, obj->quan);
  1487. X        delobj(obj);
  1488. X        }
  1489. X        flags.botl = 1;
  1490. X        if (flags.run) nomul(0);
  1491. X        return FALSE;
  1492. X    } else if (obj->otyp == CORPSE) {
  1493. X
  1494. X        if (obj->corpsenm == PM_COCKATRICE && !uarmg
  1495. X#ifdef POLYSELF
  1496. X        && !resists_ston(uasmon)
  1497. X#endif
  1498. X        ) {
  1499. X#ifdef POLYSELF
  1500. X        if (poly_when_stoned(uasmon) && polymon(PM_STONE_GOLEM))
  1501. X            display_nhwindow(WIN_MESSAGE, FALSE);
  1502. X        else
  1503. X#endif
  1504. X        {
  1505. X          pline("Touching the cockatrice corpse is a fatal mistake.");
  1506. X            You("turn to stone.");
  1507. X            You("die...");
  1508. X            killer_format = KILLED_BY_AN;
  1509. X            killer = "cockatrice corpse";
  1510. X            done(STONING);
  1511. X        }
  1512. X        } else if (is_rider(&mons[obj->corpsenm])) {
  1513. X        pline("At your touch, the corpse suddenly moves...");
  1514. X        revive_corpse(obj, 1, FALSE);
  1515. X        exercise(A_WIS, FALSE);
  1516. X        return FALSE;
  1517. X        }
  1518. X
  1519. X    } else  if (obj->otyp == SCR_SCARE_MONSTER) {
  1520. X        if (obj->blessed) obj->blessed = 0;
  1521. X        else if (!obj->spe && !obj->cursed) obj->spe = 1;
  1522. X        else {
  1523. X        pline("The scroll%s turn%s to dust as you pick %s up.",
  1524. X            plur(obj->quan), (obj->quan == 1L) ? "s" : "",
  1525. X            (obj->quan == 1L) ? "it" : "them");
  1526. X        if (!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
  1527. X                    !(objects[SCR_SCARE_MONSTER].oc_uname))
  1528. X            docall(obj);
  1529. X        useupf(obj);
  1530. X        return FALSE;
  1531. X        }
  1532. X    }
  1533. X
  1534. X    wt = max_capacity() + (int)obj->owt;
  1535. X    if (obj->otyp == LOADSTONE)
  1536. X        goto lift_some;     /* pick it up even if too heavy */
  1537. X#ifdef POLYSELF
  1538. X    if (obj->otyp == BOULDER && throws_rocks(uasmon)) {
  1539. X        goto lift_some;
  1540. X    }
  1541. X#endif
  1542. X    if (wt > 0) {
  1543. X        if (obj->quan > 1L) {
  1544. X        /* see how many we can lift */
  1545. X        long qq, savequan = obj->quan;
  1546. X        int iw = max_capacity();
  1547. X        /*  This is correct only because containers */
  1548. X        /*  don't merge.    -dean            */
  1549. X        for (qq = 1; qq < savequan; qq++) {
  1550. X            obj->quan = qq;
  1551. X            if (iw + weight(obj) > 0)
  1552. X                break;
  1553. X        }
  1554. X        obj->quan = savequan;
  1555. X        qq--;
  1556. X        /* we can carry qq of them */
  1557. X        if (qq) {
  1558. X            if (objx) {        /* temporarily unsplit */
  1559. X            savequan = obj->quan;
  1560. X            obj->quan += objx->quan;
  1561. X            }
  1562. X            You("can only carry %s of the %s lying here.",
  1563. X            (qq == 1L) ? "one" : "some", doname(obj));
  1564. X            if (objx) {        /* re-do the prior split */
  1565. X            obj->quan = savequan;
  1566. X            unsplitobj(obj, objx, qq);
  1567. X            } else {        /* split into two groups */
  1568. X            objx = splitobj(obj, qq);
  1569. X            if (objx->otyp == SCR_SCARE_MONSTER) objx->spe = 0;
  1570. X            }
  1571. X            goto lift_some;
  1572. X        }
  1573. X        }
  1574. X        if (objx) unsplitobj(obj, objx, 0L);
  1575. X        pline("There %s %s here, but %s.",
  1576. X            (obj->quan == 1L) ? "is" : "are", doname(obj),
  1577. X            !invent ? (obj->quan == 1L ?
  1578. X                "it is too heavy for you to lift" :
  1579. X                "they are too heavy for you to lift") :
  1580. X            "you cannot carry any more");
  1581. X        if (obj->otyp == SCR_SCARE_MONSTER) obj->spe = 0;
  1582. X        return TRUE;
  1583. X    }
  1584. X
  1585. Xlift_some:
  1586. X    if (inv_cnt() >= 52) {
  1587. X        if (objx) unsplitobj(obj, objx, 0L);
  1588. X        Your("knapsack cannot accommodate any more items.");
  1589. X        if (obj->otyp == SCR_SCARE_MONSTER) obj->spe = 0;
  1590. X        return TRUE;
  1591. X    }
  1592. X
  1593. X    pickquan = obj->quan;    /* save number picked up */
  1594. X    obj = pick_obj(obj);
  1595. X
  1596. X    if (!Blind) obj->dknown = 1;
  1597. X    if (uwep && uwep == obj) mrg_to_wielded = TRUE;
  1598. X    nearload = near_capacity();
  1599. X    prinv(nearload > SLT_ENCUMBER ? nearloadmsg :
  1600. X          nearload > UNENCUMBERED ? moderateloadmsg : NULL,
  1601. X          obj, pickquan);
  1602. X    mrg_to_wielded = FALSE;
  1603. X    return FALSE;
  1604. X}
  1605. X
  1606. X/* Gold never reaches this routine. */
  1607. Xstruct obj *
  1608. Xpick_obj(otmp)
  1609. Xregister struct obj *otmp;
  1610. X{
  1611. X    freeobj(otmp);
  1612. X    if (*u.ushops && costly_spot(u.ux, u.uy) &&
  1613. X        otmp != uball)     /* don't charge for this - kd, 1/17/90 */
  1614. X       /* sets obj->unpaid if necessary */
  1615. X        addtobill(otmp, TRUE, FALSE, FALSE);
  1616. X    if(Invisible) newsym(u.ux,u.uy);
  1617. X    return(addinv(otmp));    /* might merge it with other objects */
  1618. X}
  1619. X
  1620. X/*
  1621. X * prints a message if encumbrance changed since the last check and
  1622. X * returns the new encumbrance value (from near_capacity()).
  1623. X */
  1624. Xint
  1625. Xencumber_msg()
  1626. X{
  1627. X    static int oldcap = UNENCUMBERED;
  1628. X    int newcap = near_capacity();
  1629. X
  1630. X    if(oldcap < newcap) {
  1631. X    switch(newcap) {
  1632. X    case 1: Your("movements are slowed slightly because of your load.");
  1633. X        break;
  1634. X    case 2: You("rebalance your load.  Movement is difficult.");
  1635. X        break;
  1636. X    case 3: You("stagger under your heavy load.  Movement is very hard.");
  1637. X        break;
  1638. X    default: You("can barely move a handspan with this load!");
  1639. X        break;
  1640. X    }
  1641. X    flags.botl = 1;
  1642. X    } else if(oldcap > newcap) {
  1643. X    switch(newcap) {
  1644. X    case 0: Your("movements are now unencumbered.");
  1645. X        break;
  1646. X    case 1: Your("movements are only slowed slightly by your load.");
  1647. X        break;
  1648. X    case 2: You("rebalance your load.  Movement is still difficult.");
  1649. X        break;
  1650. X    case 3: You("stagger under your load.  Movement is still very hard.");
  1651. X        break;
  1652. X    }
  1653. X    flags.botl = 1;
  1654. X    }
  1655. X
  1656. X    oldcap = newcap;
  1657. X    return (newcap);
  1658. X}
  1659. X
  1660. Xint
  1661. Xdoloot()    /* loot a container on the floor. */
  1662. X{
  1663. X    register struct obj *cobj, *nobj;
  1664. X    register int c;
  1665. X    int timepassed = 0;
  1666. X
  1667. X    if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) {
  1668. X        You("cannot reach the floor.");
  1669. X        return(0);
  1670. X    }
  1671. X    if(is_pool(u.ux, u.uy)) {
  1672. X        You("cannot loot things that are deep in the water.");
  1673. X        return(0);
  1674. X    }
  1675. X
  1676. X#ifdef POLYSELF
  1677. X    if(nolimbs(uasmon)) {
  1678. X        You("cannot loot things without limbs.");
  1679. X        return(0);
  1680. X    }
  1681. X#endif
  1682. X
  1683. X    for(cobj = level.objects[u.ux][u.uy]; cobj; cobj = nobj) {
  1684. X        nobj = cobj->nexthere;
  1685. X
  1686. X        if(Is_container(cobj)) {
  1687. X            char qbuf[QBUFSZ];
  1688. X
  1689. X            Sprintf(qbuf, "There is %s here, loot it?", doname(cobj));
  1690. X            c = ynq(qbuf);
  1691. X            if(c == 'q') return (timepassed);
  1692. X            if(c == 'n') continue;
  1693. X
  1694. X            if(cobj->olocked) {
  1695. X            pline("Hmmm, it seems to be locked.");
  1696. X            continue;
  1697. X            }
  1698. X            if(cobj->otyp == BAG_OF_TRICKS) {
  1699. X            You("carefully open the bag...");
  1700. X            pline("It develops a huge set of teeth and bites you!");
  1701. X            c = rnd(10);
  1702. X            if(Half_physical_damage) c = (c+1) / 2;
  1703. X            losehp(c, "carnivorous bag", KILLED_BY_AN);
  1704. X            makeknown(BAG_OF_TRICKS);
  1705. X            timepassed = 1;
  1706. X            continue;
  1707. X            }
  1708. X
  1709. X            You("carefully open %s...", the(xname(cobj)));
  1710. X            if (cobj->otrapped && chest_trap(cobj, FINGER, FALSE)) {
  1711. X            timepassed = 1;
  1712. X            continue;    /* explosion destroyed cobj */
  1713. X            }
  1714. X            if(multi < 0) return (1); /* a paralysis trap */
  1715. X
  1716. X            timepassed |= use_container(cobj, 0);
  1717. X        }
  1718. X    }
  1719. X    return (timepassed);
  1720. X}
  1721. X
  1722. X/*
  1723. X * Decide whether an object being placed into a magic bag will cause
  1724. X * it to explode.  If the object is a bag itself, check recursively.
  1725. X */
  1726. Xstatic boolean
  1727. Xmbag_explodes(obj, depthin)
  1728. X    struct obj *obj;
  1729. X    int depthin;
  1730. X{
  1731. X    /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */
  1732. X    if ((Is_mbag(obj) || (obj->otyp == WAN_CANCELLATION && obj->spe > 0)) &&
  1733. X    (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin))
  1734. X    return TRUE;
  1735. X    else if (Is_container(obj)) {
  1736. X    struct obj *otmp;
  1737. X
  1738. X    for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
  1739. X        if (mbag_explodes(otmp, depthin+1)) return TRUE;
  1740. X    }
  1741. X    return FALSE;
  1742. X}
  1743. X
  1744. X/* A variable set in use_container(), to be used by the callback routines */
  1745. X/* chk_bg(), in_container(), and out_container() from askchain().      */
  1746. Xstatic struct obj NEARDATA *current_container;
  1747. X#define Icebox (current_container->otyp == ICE_BOX)
  1748. X
  1749. XSTATIC_PTR int
  1750. Xin_container(obj)
  1751. Xregister struct obj *obj;
  1752. X{
  1753. X    register struct obj *gold;
  1754. X    boolean is_gold = (obj->otyp == GOLD_PIECE);
  1755. X    boolean floor_container = !carried(current_container);
  1756. X    char buf[BUFSZ];
  1757. X
  1758. X    if (!current_container) {
  1759. X        impossible("<in> no current_container?");
  1760. X        return 0;
  1761. X    } else if (obj == uball || obj == uchain) {
  1762. X        You("must be kidding.");
  1763. X        return 0;
  1764. X    } else if (obj == current_container) {
  1765. X        pline("That would be an interesting topological exercise.");
  1766. X        return 0;
  1767. X    } else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
  1768. X        Norep("You cannot %s something you are wearing.",
  1769. X            Icebox ? "refrigerate" : "stash");
  1770. X        return 0;
  1771. X    } else if ((obj->otyp == LOADSTONE) && obj->cursed) {
  1772. X        obj->bknown = 1;
  1773. X          pline("The stone%s won't leave your person.", plur(obj->quan));
  1774. X        return 0;
  1775. X    } else if (obj->otyp == AMULET_OF_YENDOR ||
  1776. X           obj->otyp == CANDELABRUM_OF_INVOCATION ||
  1777. X           obj->otyp == BELL_OF_OPENING ||
  1778. X           obj->otyp == SPE_BOOK_OF_THE_DEAD) {
  1779. X    /* Prohibit Amulets in containers; if you allow it, monsters can't
  1780. X     * steal them.  It also becomes a pain to check to see if someone
  1781. X     * has the Amulet.  Ditto for the Candelabrum, the Bell and the Book.
  1782. X     */
  1783. X        pline("%s cannot be confined in such trappings.", The(xname(obj)));
  1784. X        return 0;
  1785. X    }
  1786. X#ifdef WALKIES
  1787. X    else if (obj->otyp == LEASH && obj->leashmon != 0) {
  1788. X        pline("%s is attached to your pet.", The(xname(obj)));
  1789. X        return 0;
  1790. X    }
  1791. X#endif
  1792. X    else if (obj == uwep) {
  1793. X        if (welded(obj)) {
  1794. X            weldmsg(obj, FALSE);
  1795. X            return 0;
  1796. X        }
  1797. X        setuwep((struct obj *) 0);
  1798. X        if (uwep) return 0;    /* unwielded, died, rewielded */
  1799. X    }
  1800. X
  1801. X    /* boxes can't fit into any container */
  1802. X    if (obj->otyp == ICE_BOX || Is_box(obj)) {
  1803. X        /*
  1804. X         *  xname() uses a static result array.  Save obj's name
  1805. X         *  before current_container's name is computed.  Don't
  1806. X         *  use the result of strcpy() within You() --- the order
  1807. X         *  of evaluation of the parameters is undefined.
  1808. X         */
  1809. X        Strcpy(buf, the(xname(obj)));
  1810. X        You("cannot fit %s into %s.", buf,
  1811. X            the(xname(current_container)));
  1812. X        return 0;
  1813. X    }
  1814. X
  1815. X    freeinv(obj);
  1816. X
  1817. X    if (is_gold) {    /* look for other gold within the container */
  1818. X        for (gold = current_container->cobj; gold; gold = gold->nobj)
  1819. X            if (gold->otyp == GOLD_PIECE) break;
  1820. X    } else
  1821. X        gold = 0;
  1822. X
  1823. X    if (gold) {
  1824. X        gold->quan += obj->quan;
  1825. X    } else {
  1826. X        obj->nobj = current_container->cobj;
  1827. X        current_container->cobj = obj;
  1828. X    }
  1829. X
  1830. X    current_container->owt = weight(current_container);
  1831. X
  1832. X    Strcpy(buf, the(xname(current_container)));
  1833. X    You("put %s into %s.", doname(obj), buf);
  1834. X
  1835. X    if (floor_container && costly_spot(u.ux, u.uy)) {
  1836. X        sellobj_state(TRUE);
  1837. X        sellobj(obj, u.ux, u.uy);
  1838. X        sellobj_state(FALSE);
  1839. X    }
  1840. X    (void) snuff_candle(obj); /* must follow the "put" msg */
  1841. X    if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN
  1842. X            && !Is_candle(obj))
  1843. X        obj->age = monstermoves - obj->age; /* actual age */
  1844. X
  1845. X    else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) {
  1846. X        You("are blasted by a magical explosion!");
  1847. X
  1848. X        /* the !floor_container case is taken care of */
  1849. X        if(*u.ushops && costly_spot(u.ux, u.uy) && floor_container) {
  1850. X            register struct monst *shkp;
  1851. X
  1852. X            if ((shkp = shop_keeper(*u.ushops)) != 0)
  1853. X            (void)stolen_value(current_container, u.ux, u.uy,
  1854. X                       (boolean)shkp->mpeaceful, FALSE);
  1855. X        }
  1856. X        delete_contents(current_container);
  1857. X        if (!floor_container)
  1858. X            useup(current_container);
  1859. X        else if (obj_here(current_container, u.ux, u.uy))
  1860. X            useupf(current_container);
  1861. X        else
  1862. X            panic("in_container:  bag not found.");
  1863. X
  1864. X        losehp(d(6,6),"magical explosion", KILLED_BY_AN);
  1865. X        current_container = 0;    /* baggone = TRUE; */
  1866. X    }
  1867. X
  1868. X    if (is_gold) {
  1869. X        if (gold) dealloc_obj(obj);
  1870. X        bot();    /* update character's gold piece count immediately */
  1871. X    }
  1872. X
  1873. X    return(current_container ? 1 : -1);
  1874. X}
  1875. X
  1876. XSTATIC_PTR int
  1877. Xck_bag(obj)
  1878. Xstruct obj *obj;
  1879. X{
  1880. X    return current_container && obj != current_container;
  1881. X}
  1882. X
  1883. XSTATIC_PTR int
  1884. Xout_container(obj)
  1885. Xregister struct obj *obj;
  1886. X{
  1887. X    register struct obj *otmp, *ootmp;
  1888. X    boolean is_gold = (obj->otyp == GOLD_PIECE);
  1889. X    int loadlev;
  1890. X    long quan;
  1891. X
  1892. X    if (!current_container) {
  1893. X        impossible("<out> no current_container?");
  1894. X        return -1;
  1895. X    } else if (is_gold) {
  1896. X        obj->owt = weight(obj);
  1897. X    } else if (inv_cnt() >= 52) {
  1898. X        You("have no room to hold anything else.");
  1899. X        return -1;    /* skips gold too; oh well */
  1900. X    }
  1901. X
  1902. X    if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0;
  1903. X
  1904. X    if(obj->otyp != LOADSTONE && max_capacity() + (int)obj->owt -
  1905. X       (carried(current_container) ?
  1906. X        (current_container->otyp == BAG_OF_HOLDING ?
  1907. X         (int)DELTA_CWT(current_container,obj) : (int)obj->owt) : 0) > 0) {
  1908. X        char buf[BUFSZ];
  1909. X
  1910. X        Strcpy(buf, doname(obj));
  1911. X        pline("There %s %s in %s, but %s.",
  1912. X            obj->quan==1 ? "is" : "are",
  1913. X            buf, the(xname(current_container)),
  1914. X            invent ? "you cannot carry any more"
  1915. X            : "it is too heavy for you to carry");
  1916. X        /* "too heavy for you to lift" is not right if you're carrying
  1917. X           the container... */
  1918. X        return(0);
  1919. X    }
  1920. X    /* Remove the object from the list. */
  1921. X    if (obj == current_container->cobj)
  1922. X        current_container->cobj = obj->nobj;
  1923. X    else {
  1924. X        for(otmp = current_container->cobj; otmp->nobj != obj;
  1925. X                                otmp = otmp->nobj)
  1926. X            if(!otmp->nobj) panic("out_container");
  1927. X        otmp->nobj = obj->nobj;
  1928. X    }
  1929. X
  1930. X    current_container->owt = weight(current_container);
  1931. X
  1932. X    if (Icebox && obj->otyp != OIL_LAMP && obj->otyp != BRASS_LANTERN
  1933. X            && !Is_candle(obj))
  1934. X        obj->age = monstermoves - obj->age;
  1935. X    /* simulated point of time */
  1936. X
  1937. X    if(!obj->unpaid && !carried(current_container) &&
  1938. X         costly_spot(current_container->ox, current_container->oy)) {
  1939. X
  1940. X        addtobill(obj, FALSE, FALSE, FALSE);
  1941. X    }
  1942. X
  1943. X    quan = obj->quan;
  1944. X    ootmp = addinv(obj);
  1945. X    loadlev = near_capacity();
  1946. X    prinv(loadlev ?
  1947. X          (loadlev < MOD_ENCUMBER ?
  1948. X           "You have a little trouble removing" :
  1949. X           "You have much trouble removing") : NULL,
  1950. X          ootmp, quan);
  1951. X
  1952. X    if (is_gold) {
  1953. X        dealloc_obj(obj);
  1954. X        bot();    /* update character's gold piece count immediately */
  1955. X    }
  1956. X    return 1;
  1957. X}
  1958. X
  1959. X/* for getobj: allow counts, allow all types, expect food */
  1960. Xstatic const char NEARDATA frozen_food[] =
  1961. X    { ALLOW_COUNT, ALL_CLASSES, FOOD_CLASS, 0 };
  1962. X
  1963. Xint
  1964. Xuse_container(obj, held)
  1965. Xregister struct obj *obj;
  1966. Xregister int held;
  1967. X{
  1968. X    register int cnt = 0;
  1969. X    register struct obj *curr, *prev, *otmp;
  1970. X    boolean one_by_one, allflag;
  1971. X    char select[MAXOCLASSES+1];
  1972. X    char qbuf[QBUFSZ];
  1973. X    int used = 0, lcnt = 0;
  1974. X    long loss = 0L;
  1975. X    register struct monst *shkp;
  1976. X
  1977. X    current_container = obj;    /* for use by in/out_container */
  1978. X    if (current_container->olocked) {
  1979. X        pline("%s seems to be locked.", The(xname(current_container)));
  1980. X        if (held) You("must put it down to unlock.");
  1981. X        return 0;
  1982. X    }
  1983. X    /* Count the number of contained objects. Sometimes toss objects if */
  1984. X    /* a cursed magic bag.                            */
  1985. X    for(curr = obj->cobj, prev = (struct obj *) 0; curr;
  1986. X                        prev = curr, curr = otmp) {
  1987. X        otmp = curr->nobj;
  1988. X        if (Is_mbag(obj) && obj->cursed && !rn2(13)) {
  1989. X        if (curr->known)
  1990. X            pline("%s to have vanished!", The(aobjnam(curr,"seem")));
  1991. X        else
  1992. X            You("%s %s disappear.", Blind ? "notice" : "see",
  1993. X                            doname(curr));
  1994. X        if (prev)
  1995. X            prev->nobj = otmp;
  1996. X        else
  1997. X            obj->cobj = otmp;
  1998. X
  1999. X        if(*u.ushops && (shkp = shop_keeper(*u.ushops))) {
  2000. X            if(held) {
  2001. X            if(curr->unpaid)
  2002. X                loss += stolen_value(curr, u.ux, u.uy,
  2003. X                         (boolean)shkp->mpeaceful, TRUE);
  2004. X            lcnt++;
  2005. X            } else if(costly_spot(u.ux, u.uy)) {
  2006. X            loss += stolen_value(curr, u.ux, u.uy,
  2007. X                         (boolean)shkp->mpeaceful, TRUE);
  2008. X            lcnt++;
  2009. X            }
  2010. X        }
  2011. X        /* obfree() will free all contained objects */
  2012. X        obfree(curr, (struct obj *) 0);
  2013. X        } else
  2014. X        cnt++;
  2015. X    }
  2016. X
  2017. X    if (cnt && loss)
  2018. X        You("owe %ld zorkmids for lost item%s.",
  2019. X        loss, lcnt > 1 ? "s" : "");
  2020. X
  2021. X    current_container->owt = weight(current_container);
  2022. X
  2023. X    if(!cnt)
  2024. X        pline("%s %s is empty.", (held) ? "Your" : "The", xname(obj));
  2025. X    else {
  2026. X        Sprintf(qbuf, "Do you want to take something out of %s?",
  2027. X            the(xname(obj)));
  2028. Xask_again:
  2029. X        switch (yn_function(qbuf, ":ynq", 'n')) {
  2030. X        case ':':
  2031. X        container_contents(current_container, FALSE, FALSE);
  2032. X        goto ask_again;
  2033. X        case 'y':
  2034. X        if (query_classes(select, &one_by_one, &allflag, "take out",
  2035. X                   current_container->cobj, FALSE, FALSE)) {
  2036. X            if (askchain((struct obj **)¤t_container->cobj,
  2037. X                 (one_by_one ? (char *)0 : select), allflag,
  2038. X                 out_container, (int (*)())0, 0, "nodot"))
  2039. X            used = 1;
  2040. X        }
  2041. X        /*FALLTHRU*/
  2042. X        case 'n':
  2043. X        break;
  2044. X        case 'q':
  2045. X        default:
  2046. X        return 0;
  2047. X        }
  2048. X    }
  2049. X
  2050. X    if (!invent && (u.ugold == 0 || Icebox)) return used;
  2051. X    if (yn_function("Do you wish to put something in?", ynqchars, 'n')
  2052. X        != 'y') return used;
  2053. X    if (Icebox && current_container->dknown) {
  2054. X        otmp = getobj(frozen_food, "put in");
  2055. X        if(!otmp || !in_container(otmp))
  2056. X            flags.move = multi = 0;
  2057. X    } else {
  2058. X        if (query_classes(select, &one_by_one, &allflag, "put in",
  2059. X                       invent, FALSE, (u.ugold != 0L))) {
  2060. X            struct obj *u_gold = (struct obj *)0;
  2061. X            if (u.ugold && (one_by_one || (allflag && !*select)
  2062. X                    || index(select, GOLD_CLASS))) {
  2063. X            /* make gold object & insert at head of inventory */
  2064. X            u_gold = mkgoldobj(u.ugold);    /*(removes gold too)*/
  2065. X            u.ugold = u_gold->quan;        /* put the gold back */
  2066. X            u_gold->nobj = invent;
  2067. X            invent = u_gold;
  2068. X            }
  2069. X            used = (askchain((struct obj **)&invent,
  2070. X                (one_by_one ? (char *)0 : select), allflag,
  2071. X                in_container, ck_bag, 0, "nodot") > 0);
  2072. X            if (u_gold && invent && invent->otyp == GOLD_PIECE) {
  2073. X            /* didn't stash [all of] it */
  2074. X            u_gold = invent;
  2075. X            invent = u_gold->nobj;
  2076. X            dealloc_obj(u_gold);
  2077. X            }
  2078. X        }
  2079. X    }
  2080. X
  2081. X    return used;
  2082. X}
  2083. X
  2084. X/*pickup.c*/
  2085. END_OF_FILE
  2086. if test 26706 -ne `wc -c <'src/pickup.c'`; then
  2087.     echo shar: \"'src/pickup.c'\" unpacked with wrong size!
  2088. fi
  2089. # end of 'src/pickup.c'
  2090. fi
  2091. echo shar: End of archive 80 \(of 108\).
  2092. cp /dev/null ark80isdone
  2093. MISSING=""
  2094. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
  2095. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
  2096. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
  2097. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
  2098. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
  2099. 101 102 103 104 105 106 107 108 ; do
  2100.     if test ! -f ark${I}isdone ; then
  2101.     MISSING="${MISSING} ${I}"
  2102.     fi
  2103. done
  2104. if test "${MISSING}" = "" ; then
  2105.     echo You have unpacked all 108 archives.
  2106.     echo "Now execute 'rebuild.sh'"
  2107.     rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
  2108. else
  2109.     echo You still need to unpack the following archives:
  2110.     echo "        " ${MISSING}
  2111. fi
  2112. ##  End of shell archive.
  2113. exit 0
  2114.