home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume16 / nethck31 / part47 < prev    next >
Encoding:
Internet Message Format  |  1993-01-31  |  58.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: v16i055:  nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part47/108
  5. Message-ID: <4349@master.CNA.TEK.COM>
  6. Date: 30 Jan 93 01:14:23 GMT
  7. Sender: news@master.CNA.TEK.COM
  8. Lines: 2205
  9. Approved: billr@saab.CNA.TEK.COM
  10. Xref: uunet comp.sources.games:1604
  11.  
  12. Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
  13. Posting-number: Volume 16, Issue 55
  14. Archive-name: nethack31/Part47
  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 47 (of 108)."
  27. # Contents:  src/pager.c src/shk.c1
  28. # Wrapped by billr@saab on Wed Jan 27 16:09:04 1993
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'src/pager.c' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'src/pager.c'\"
  32. else
  33. echo shar: Extracting \"'src/pager.c'\" \(16869 characters\)
  34. sed "s/^X//" >'src/pager.c' <<'END_OF_FILE'
  35. X/*    SCCS Id: @(#)pager.c    3.1    92/09/01          */
  36. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  37. X/* NetHack may be freely redistributed.  See license for details. */
  38. X
  39. X/* This file contains the command routines dowhatis() and dohelp() and */
  40. X/* a few other help related facilities */
  41. X
  42. X#include    "hack.h"
  43. X
  44. X#ifndef SEEK_SET
  45. X#define SEEK_SET 0
  46. X#endif
  47. X
  48. Xstatic boolean FDECL(is_swallow_sym, (UCHAR_P));
  49. Xstatic int FDECL(append_str, (char *, const char *));
  50. Xstatic void FDECL(lookat, (int, int, char *));
  51. Xstatic void FDECL(checkfile, (char *, BOOLEAN_P));
  52. Xstatic int FDECL(do_look, (BOOLEAN_P));
  53. Xstatic char NDECL(help_menu);
  54. X#ifdef PORT_HELP
  55. Xextern void NDECL(port_help);
  56. X#endif
  57. X
  58. X/* Returns "true" for characters that could represent a monster's stomach. */
  59. Xstatic boolean
  60. Xis_swallow_sym(c)
  61. X    uchar c;
  62. X{
  63. X    int i;
  64. X    for (i = S_sw_tl; i <= S_sw_br; i++)
  65. X    if (showsyms[i] == c) return TRUE;
  66. X    return FALSE;
  67. X}
  68. X
  69. X/*
  70. X * Append new_str to the end of buf if new_str doesn't already exist as
  71. X * a substring of buf.  Return 1 if the string was appended, 0 otherwise.
  72. X * It is expected that buf is of size BUFSZ.
  73. X */
  74. Xstatic int
  75. Xappend_str(buf, new_str)
  76. X    char *buf;
  77. X    const char *new_str;
  78. X{
  79. X    int space_left;    /* space remaining in buf */
  80. X
  81. X    if (strstri(buf, new_str)) return 0;
  82. X
  83. X    space_left = BUFSZ - strlen(buf) - 1;
  84. X    (void) strncat(buf, " or ", space_left);
  85. X    (void) strncat(buf, new_str, space_left - 4);
  86. X    return 1;
  87. X}
  88. X
  89. X/*
  90. X * Return the name of the glyph found at (x,y).
  91. X */
  92. Xstatic void
  93. Xlookat(x, y, buf)
  94. X    int x, y;
  95. X    char *buf;
  96. X{
  97. X    register struct monst *mtmp;
  98. X    struct trap *trap;
  99. X    register char *s, *t;
  100. X    int glyph;
  101. X
  102. X    buf[0] = 0;
  103. X    glyph = glyph_at(x,y);
  104. X    if (u.ux == x && u.uy == y && canseeself()) {
  105. X    Sprintf(buf, "%s called %s",
  106. X#ifdef POLYSELF
  107. X        u.mtimedone ? mons[u.umonnum].mname :
  108. X#endif
  109. X        player_mon()->mname, plname);
  110. X    }
  111. X    else if (u.uswallow) {
  112. X    /* all locations when swallowed other than the hero are the monster */
  113. X    Sprintf(buf, "interior of %s",
  114. X                    Blind ? "a monster" : a_monnam(u.ustuck));
  115. X    }
  116. X    else if (glyph_is_monster(glyph)) {
  117. X    bhitpos.x = x;
  118. X    bhitpos.y = y;
  119. X    mtmp = m_at(x,y);
  120. X    if(mtmp != (struct monst *) 0) {
  121. X        register boolean hp = (mtmp->data == &mons[PM_HIGH_PRIEST]);
  122. X
  123. X        Sprintf(buf, "%s%s%s",
  124. X            (!hp && mtmp->mtame && !Hallucination) ? "tame " :
  125. X            (!hp && mtmp->mpeaceful && !Hallucination) ?
  126. X                                                  "peaceful " : "",
  127. X            (hp ? "high priest" : l_monnam(mtmp)),
  128. X            u.ustuck == mtmp ?
  129. X#ifdef POLYSELF
  130. X            (u.mtimedone ? ", being held" :
  131. X#endif
  132. X            ", holding you"
  133. X#ifdef POLYSELF
  134. X            )
  135. X#endif
  136. X            : "");
  137. X    }
  138. X    }
  139. X    else if (glyph_is_object(glyph)) {
  140. X    struct obj *otmp = vobj_at(x,y);
  141. X
  142. X    if(otmp == (struct obj *) 0 || otmp->otyp != glyph_to_obj(glyph)) {
  143. X        if(glyph_to_obj(glyph) != STRANGE_OBJECT) {
  144. X        otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE);
  145. X        if(otmp->oclass == GOLD_CLASS)
  146. X            otmp->quan = 2L; /* to force pluralization */
  147. X        Strcpy(buf, distant_name(otmp, xname));
  148. X        dealloc_obj(otmp);
  149. X        }
  150. X    } else
  151. X        Strcpy(buf, distant_name(otmp, xname));
  152. X    }
  153. X    else if (glyph_is_trap(glyph)) {
  154. X    if (trap = t_at(x, y)) {
  155. X        if (trap->ttyp == WEB)
  156. X        Strcpy(buf, "web");
  157. X        else {
  158. X        Strcpy(buf, traps[ Hallucination ?
  159. X                     rn2(TRAPNUM-3)+3 : trap->ttyp]);
  160. X        /* strip leading garbage */
  161. X        for (s = buf; *s && *s != ' '; s++) ;
  162. X        if (*s) ++s;
  163. X        for (t = buf; *t++ = *s++; ) ;
  164. X        }
  165. X    }
  166. X    }
  167. X    else if(!glyph_is_cmap(glyph))
  168. X    Strcpy(buf,"dark part of a room");
  169. X    else switch(glyph_to_cmap(glyph)) {
  170. X    case S_altar:
  171. X        if(!In_endgame(&u.uz))
  172. X        Sprintf(buf, "%s altar",
  173. X        align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE)));
  174. X    else Sprintf(buf, "aligned altar");
  175. X    break;
  176. X    case S_ndoor:
  177. X    if((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
  178. X        Strcpy(buf,"broken door");
  179. X    else
  180. X        Strcpy(buf,"doorway");
  181. X    break;
  182. X    default:
  183. X    Strcpy(buf,defsyms[glyph_to_cmap(glyph)].explanation);
  184. X    break;
  185. X    }
  186. X}
  187. X
  188. X/*
  189. X * Look in the "data" file for more info.  Called if the user typed in the
  190. X * whole name (user_typed_name == TRUE), or we've found a possible match
  191. X * with a character/glyph and flags.help is TRUE.
  192. X *
  193. X * NOTE: when (user_typed_name == FALSE), inp is considered read-only and 
  194. X *     must not be changed directly, e.g. via lcase(). Permitted are
  195. X *     functions, e.g. makesingular(), which operate on a copy of inp.
  196. X */
  197. Xstatic void
  198. Xcheckfile(inp, user_typed_name)
  199. X    char *inp;
  200. X    boolean user_typed_name;
  201. X{
  202. X    FILE *fp;
  203. X    char buf[BUFSZ];
  204. X    char *ep;
  205. X    long txt_offset;
  206. X    boolean found_in_file = FALSE;
  207. X
  208. X    fp = fopen_datafile(DATAFILE, "r");
  209. X    if (!fp) {
  210. X    pline("Cannot open data file!");
  211. X    return;
  212. X    }
  213. X
  214. X    if (!strncmp(inp, "interior of ", 12))
  215. X    inp += 12;
  216. X    if (!strncmp(inp, "a ", 2))
  217. X    inp += 2;
  218. X    else if (!strncmp(inp, "an ", 3))
  219. X    inp += 3;
  220. X    else if (!strncmp(inp, "the ", 4))
  221. X    inp += 4;
  222. X    if (!strncmp(inp, "tame ", 5))
  223. X    inp += 5;
  224. X    else if (!strncmp(inp, "peaceful ", 9))
  225. X    inp += 9;
  226. X    if (!strncmp(inp, "invisible ", 10))
  227. X    inp += 10;
  228. X
  229. X    /* Make sure the name is non-empty. */
  230. X    if (*inp) {
  231. X    /* adjust the input to remove "named " and convert to lower case */
  232. X    char *alt = 0;    /* alternate description */
  233. X    if ((ep = strstri(inp, " named ")) != 0)
  234. X        alt = ep + 7;
  235. X    else
  236. X        ep = strstri(inp, " called ");
  237. X    if (ep) *ep = '\0';
  238. X    if (user_typed_name)
  239. X        (void) lcase(inp);
  240. X
  241. X    /*
  242. X     * If the object is named, then the name is the alternate description;
  243. X     * otherwise, the result of makesingular() applied to the name is. This
  244. X     * isn't strictly optimal, but named objects of interest to the user
  245. X     * will usually be found under their name, rather than under their
  246. X     * object type, so looking for a singular form is pointless.
  247. X     */
  248. X
  249. X    if (!alt)
  250. X        alt = makesingular(inp);
  251. X    else
  252. X        if (user_typed_name)
  253. X            (void) lcase(alt);
  254. X
  255. X    /* skip first record; read second */
  256. X    txt_offset = 0L;
  257. X    if (!fgets(buf, BUFSZ, fp) || !fgets(buf, BUFSZ, fp)) {
  258. X        impossible("can't read 'data' file");
  259. X        (void) fclose(fp);
  260. X        return;
  261. X    } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0)
  262. X        goto bad_data_file;
  263. X
  264. X    /* look for the appropriate entry */
  265. X    while (fgets(buf,BUFSZ,fp)) {
  266. X        if (*buf == '.') break;  /* we passed last entry without success */
  267. X
  268. X        if (!digit(*buf)) {
  269. X        if (!(ep = index(buf, '\n'))) goto bad_data_file;
  270. X        *ep = 0;
  271. X        if (pmatch(buf, inp) || (alt && pmatch(buf, alt))) {
  272. X            found_in_file = TRUE;
  273. X            break;
  274. X        }
  275. X        }
  276. X    }
  277. X    }
  278. X
  279. X    if(found_in_file) {
  280. X    long entry_offset;
  281. X    int  entry_count;
  282. X    int  i;
  283. X
  284. X    /* skip over other possible matches for the info */
  285. X    do {
  286. X        if (!fgets(buf, BUFSZ, fp)) goto bad_data_file;
  287. X    } while (!digit(*buf));
  288. X    if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) {
  289. Xbad_data_file:    impossible("'data' file in wrong format");
  290. X        (void) fclose(fp);
  291. X        return;
  292. X    }
  293. X
  294. X    if (user_typed_name || yn("More info?") == 'y') {
  295. X        winid datawin;
  296. X
  297. X        if (fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) {
  298. X        pline("? Seek error on 'data' file!");
  299. X        (void) fclose(fp);
  300. X        return;
  301. X        }
  302. X        datawin = create_nhwindow(NHW_TEXT);
  303. X        for (i = 0; i < entry_count; i++) {
  304. X        if (!fgets(buf, BUFSZ, fp)) goto bad_data_file;
  305. X        if ((ep = index(buf, '\n')) != 0) *ep = 0;
  306. X        if (index(buf+1, '\t') != 0) (void) tabexpand(buf+1);
  307. X        putstr(datawin, 0, buf+1);
  308. X        }
  309. X        display_nhwindow(datawin, FALSE);
  310. X        destroy_nhwindow(datawin);
  311. X    }
  312. X    } else if (user_typed_name)
  313. X    pline("I don't have any information on those things.");
  314. X
  315. X    (void) fclose(fp);
  316. X}
  317. X
  318. Xstatic int
  319. Xdo_look(quick)
  320. X    boolean quick;    /* use cursor && don't search for "more info" */
  321. X{
  322. X    char    out_str[BUFSZ], look_buf[BUFSZ];
  323. X    const char    *firstmatch = 0;
  324. X    int     i;
  325. X    int     sym;        /* typed symbol or converted glyph */
  326. X    int        found;        /* count of matching syms found */
  327. X    coord   cc;            /* screen pos of unknown glyph */
  328. X    boolean save_verbose;    /* saved value of flags.verbose */
  329. X    boolean from_screen;    /* question from the screen */
  330. X    boolean need_to_look;    /* need to get explan. from glyph */
  331. X    static const char *mon_interior = "the interior of a monster";
  332. X
  333. X#ifdef GCC_WARN
  334. X    sym = 0;
  335. X#endif
  336. X
  337. X    if (quick) {
  338. X    from_screen = TRUE;    /* yes, we want to use the cursor */
  339. X    } else {
  340. X    i = ynq("Specify unknown object by cursor?");
  341. X    if (i == 'q') return 0;
  342. X    from_screen = (i == 'y');
  343. X    }
  344. X
  345. X    if (from_screen) {
  346. X    cc.x = u.ux;
  347. X    cc.y = u.uy;
  348. X    } else {
  349. X    getlin("Specify what? (type the word)", out_str);
  350. X    if (out_str[0] == '\033')
  351. X        return 0;
  352. X
  353. X    if (out_str[1]) {    /* user typed in a complete string */
  354. X        checkfile(out_str, TRUE);
  355. X        return 0;
  356. X    }
  357. X    sym = out_str[0];
  358. X    }
  359. X
  360. X    /* Save the verbose flag, we change it later. */
  361. X    save_verbose = flags.verbose;
  362. X    flags.verbose = flags.verbose && !quick;
  363. X    /*
  364. X     * The user typed one letter, or we're identifying from the screen.
  365. X     */
  366. X    do {
  367. X    /* Reset some variables. */
  368. X    need_to_look = FALSE;
  369. X    found = 0;
  370. X    out_str[0] = '\0';
  371. X
  372. X    if (from_screen) {
  373. X        int glyph;    /* glyph at selected position */
  374. X
  375. X        if (flags.verbose)
  376. X        pline("Please move the cursor to an unknown object.");
  377. X        else
  378. X        pline("Pick an object.");
  379. X
  380. X        getpos(&cc, FALSE, "an unknown object");
  381. X        if (cc.x < 0) {
  382. X        flags.verbose = save_verbose;
  383. X        return 0;    /* done */
  384. X        }
  385. X        flags.verbose = FALSE;    /* only print long question once */
  386. X
  387. X        /* Convert the glyph at the selected position to a symbol. */
  388. X        glyph = glyph_at(cc.x,cc.y);
  389. X        if (glyph_is_cmap(glyph)) {
  390. X        sym = showsyms[glyph_to_cmap(glyph)];
  391. X        } else if (glyph_is_trap(glyph)) {
  392. X        sym = showsyms[(glyph_to_trap(glyph) == WEB) ? S_web : S_trap];
  393. X        } else if (glyph_is_object(glyph)) {
  394. X        sym = oc_syms[objects[glyph_to_obj(glyph)].oc_class];
  395. X        } else if (glyph_is_monster(glyph)) {
  396. X        sym = monsyms[mons[glyph_to_mon(glyph)].mlet];
  397. X        } else if (glyph_is_swallow(glyph)) {
  398. X        sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl];
  399. X        } else {
  400. X        impossible("do_look:  bad glyph %d at (%d,%d)",
  401. X                        glyph, (int)cc.x, (int)cc.y);
  402. X        sym = ' ';
  403. X        }
  404. X    }
  405. X
  406. X    /*
  407. X     * Check all the possibilities, saving all explanations in a buffer.
  408. X     * When all have been checked then the string is printed.
  409. X     */
  410. X
  411. X    /* Check for monsters */
  412. X    for (i = 0; i < MAXMCLASSES; i++) {
  413. X        if (sym == (from_screen ? monsyms[i] : def_monsyms[i])) {
  414. X        need_to_look = TRUE;
  415. X        if (!found) {
  416. X            Sprintf(out_str, "%c       %s", sym, an(monexplain[i]));
  417. X            firstmatch = monexplain[i];
  418. X            found++;
  419. X        } else {
  420. X            found += append_str(out_str, an(monexplain[i]));
  421. X        }
  422. X        }
  423. X    }
  424. X
  425. X    /*
  426. X     * Special case: if identifying from the screen, and we're swallowed,
  427. X     * and looking at something other than our own symbol, then just say
  428. X     * "the interior of a monster".
  429. X     */
  430. X    if (u.uswallow && from_screen && is_swallow_sym((uchar) sym)) {
  431. X        if (!found) {
  432. X        Sprintf(out_str, "%c       %s", sym, mon_interior);
  433. X        firstmatch = mon_interior;
  434. X        } else {
  435. X        found += append_str(out_str, mon_interior);
  436. X        }
  437. X        need_to_look = TRUE;
  438. X    }
  439. X
  440. X    /* Now check for objects */
  441. X    for (i = 1; i < MAXOCLASSES; i++) {
  442. X        if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) {
  443. X        need_to_look = TRUE;
  444. X        if (!found) {
  445. X            Sprintf(out_str, "%c       %s", sym, an(objexplain[i]));
  446. X            firstmatch = objexplain[i];
  447. X            found++;
  448. X        } else {
  449. X            found += append_str(out_str, an(objexplain[i]));
  450. X        }
  451. X        }
  452. X    }
  453. X
  454. X    /* Now check for graphics symbols */
  455. X    for (i = 0; i < MAXPCHARS; i++) {
  456. X        if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) &&
  457. X                        (*defsyms[i].explanation)) {
  458. X        if (!found) {
  459. X            Sprintf(out_str, "%c       %s",
  460. X                        sym, an(defsyms[i].explanation));
  461. X            firstmatch = defsyms[i].explanation;
  462. X            found++;
  463. X        } else if (!u.uswallow) {
  464. X            found += append_str(out_str, an(defsyms[i].explanation));
  465. X        }
  466. X
  467. X        if (i == S_altar || i == S_trap || i == S_web)
  468. X            need_to_look = TRUE;
  469. X        }
  470. X    }
  471. X
  472. X    /*
  473. X     * If we are looking at the screen, follow multiple posibilities or
  474. X     * an ambigious explanation by something more detailed.
  475. X     */
  476. X    if (from_screen) {
  477. X        if (found > 1 || need_to_look) {
  478. X        lookat(cc.x, cc.y, look_buf);
  479. X        firstmatch = look_buf;
  480. X        if (*firstmatch) {
  481. X            char temp_buf[BUFSZ];
  482. X            Sprintf(temp_buf, " (%s)", firstmatch);
  483. X            (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
  484. X            found = 1;    /* we have something to look up */
  485. X        }
  486. X        }
  487. X    }
  488. X
  489. X    /* Finally, print out our explanation. */
  490. X    if (found) {
  491. X        pline(out_str);
  492. X        /* check the data file for information about this thing */
  493. X        if (found == 1 && !quick && flags.help) {
  494. X        char temp_buf[BUFSZ];
  495. X        Strcpy(temp_buf, firstmatch);
  496. X        checkfile(temp_buf, FALSE);
  497. X        }
  498. X    } else {
  499. X        pline("I've never heard of such things.");
  500. X    }
  501. X
  502. X    } while (from_screen && !quick);
  503. X
  504. X    flags.verbose = save_verbose;
  505. X    return 0;
  506. X}
  507. X
  508. X
  509. Xint
  510. Xdowhatis()
  511. X{
  512. X    return do_look(FALSE);
  513. X}
  514. X
  515. Xint
  516. Xdoquickwhatis()
  517. X{
  518. X    return do_look(TRUE);
  519. X}
  520. X
  521. Xint
  522. Xdoidtrap()
  523. X{
  524. X    register struct trap *trap;
  525. X    register int x,y;
  526. X
  527. X    if(!getdir(NULL)) return 0;
  528. X    x = u.ux + u.dx;
  529. X    y = u.uy + u.dy;
  530. X    for(trap = ftrap; trap; trap = trap->ntrap)
  531. X        if(trap->tx == x && trap->ty == y && trap->tseen) {
  532. X            if(u.dz) {
  533. X            if(u.dz < 0 && trap->ttyp == TRAPDOOR)
  534. X                continue;
  535. X                if(u.dz > 0 && trap->ttyp == ROCKTRAP)
  536. X                continue;
  537. X            }
  538. X            pline("That is a%s.",
  539. X              traps[ Hallucination ? rn1(TRAPNUM-3, 3) :
  540. X                trap->ttyp]);
  541. X            return 0;
  542. X        }
  543. X    pline("I can't see a trap there.");
  544. X    return 0;
  545. X}
  546. X
  547. Xint
  548. Xdowhatdoes()
  549. X{
  550. X    FILE *fp;
  551. X    char bufr[BUFSZ+6];
  552. X    register char *buf = &bufr[6], *ep, q, ctrl, meta;
  553. X
  554. X    fp = fopen_datafile(CMDHELPFILE, "r");
  555. X    if (!fp) {
  556. X        pline("Cannot open data file!");
  557. X        return 0;
  558. X    }
  559. X
  560. X#if defined(UNIX) || defined(VMS)
  561. X    introff();
  562. X#endif
  563. X    q = yn_function("What command?", NULL, '\0');
  564. X#if defined(UNIX) || defined(VMS)
  565. X    intron();
  566. X#endif
  567. X    ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
  568. X    meta = ((0x80 & q) ? (0x7f & q) : 0);
  569. X    while(fgets(buf,BUFSZ,fp))
  570. X        if ((ctrl && *buf=='^' && *(buf+1)==ctrl) ||
  571. X        (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) ||
  572. X        *buf==q) {
  573. X        ep = index(buf, '\n');
  574. X        if(ep) *ep = 0;
  575. X        if (ctrl && buf[2] == '\t'){
  576. X            buf = bufr + 1;
  577. X            (void) strncpy(buf, "^?      ", 8);
  578. X            buf[1] = ctrl;
  579. X        } else if (meta && buf[3] == '\t'){
  580. X            buf = bufr + 2;
  581. X            (void) strncpy(buf, "M-?     ", 8);
  582. X            buf[2] = meta;
  583. X        } else if(buf[1] == '\t'){
  584. X            buf = bufr;
  585. X            buf[0] = q;
  586. X            (void) strncpy(buf+1, "       ", 7);
  587. X        }
  588. X        pline("%s", buf);
  589. X        (void) fclose(fp);
  590. X        return 0;
  591. X        }
  592. X    pline("I've never heard of such commands.");
  593. X    (void) fclose(fp);
  594. X    return 0;
  595. X}
  596. X
  597. X/* data for help_menu() */
  598. Xstatic const char *help_menu_items[] = {
  599. X    "Information available:",
  600. X    "",
  601. X    "a.  Long description of the game and commands.",
  602. X    "b.  List of game commands.",
  603. X    "c.  Concise history of NetHack.",
  604. X    "d.  Info on a character in the game display.",
  605. X    "e.  Info on what a given key does.",
  606. X    "f.  List of game options.",
  607. X    "g.  Longer explanation of game options.",
  608. X    "h.  List of extended commands.",
  609. X    "i.  The NetHack license.",
  610. X#ifdef PORT_HELP
  611. X    "j.  %s-specific help and commands.",
  612. X#endif
  613. X#ifdef WIZARD
  614. X# ifdef PORT_HELP
  615. X# define WIZHLP_SLOT 12    /* assumed to be next to last by code below */
  616. X    "k.  List of wizard-mode commands.",
  617. X# else
  618. X# define WIZHLP_SLOT 11    /* assumed to be next to last by code below */
  619. X    "j.  List of wizard-mode commands.",
  620. X# endif
  621. X#endif
  622. X    "",
  623. X    NULL
  624. X};
  625. X
  626. Xstatic char
  627. Xhelp_menu()
  628. X{
  629. X    winid tmpwin = create_nhwindow(NHW_MENU);
  630. X#ifdef PORT_HELP
  631. X    char helpbuf[QBUFSZ];
  632. X#endif
  633. X    char hc;
  634. X    register int i;
  635. X
  636. X    start_menu(tmpwin);
  637. X#ifdef WIZARD
  638. X    if (!wizard) help_menu_items[WIZHLP_SLOT] = "",
  639. X             help_menu_items[WIZHLP_SLOT+1] = NULL;
  640. X#endif
  641. X    for (i = 0; help_menu_items[i]; i++)
  642. X#ifdef PORT_HELP
  643. X        /* port-specific line has a %s in it for the PORT_ID */
  644. X        if (index(help_menu_items[i], '%')) {
  645. X        Sprintf(helpbuf, help_menu_items[i], PORT_ID);
  646. X        add_menu(tmpwin, helpbuf[0], 0, helpbuf);
  647. X        } else
  648. X#endif
  649. X        {
  650. X        add_menu(tmpwin, i ? *help_menu_items[i] : 0, 0,
  651. X             help_menu_items[i]);
  652. X        }
  653. X    end_menu(tmpwin, '\033', "\033", "Select one item or ESC: ");
  654. X    hc = select_menu(tmpwin);
  655. X    destroy_nhwindow(tmpwin);
  656. X    return hc;
  657. X}
  658. X
  659. Xint
  660. Xdohelp()
  661. X{
  662. X    char hc = help_menu();
  663. X    if (!index(quitchars, hc)) {
  664. X        switch(hc) {
  665. X            case 'a':  display_file(HELP, TRUE);  break;
  666. X            case 'b':  display_file(SHELP, TRUE);  break;
  667. X            case 'c':  (void) dohistory();  break;
  668. X            case 'd':  (void) dowhatis();  break;
  669. X            case 'e':  (void) dowhatdoes();  break;
  670. X            case 'f':  option_help();  break;
  671. X            case 'g':  display_file(OPTIONFILE, TRUE);  break;
  672. X            case 'h':  (void) doextlist();  break;
  673. X            case 'i':  display_file(LICENSE, TRUE);  break;
  674. X#ifdef PORT_HELP
  675. X            case 'j':  port_help();  break;
  676. X# ifdef WIZARD
  677. X            case 'k':  display_file(DEBUGHELP, TRUE);  break;
  678. X# endif
  679. X#else
  680. X# ifdef WIZARD
  681. X            case 'j':  display_file(DEBUGHELP, TRUE);  break;
  682. X# endif
  683. X#endif
  684. X        }
  685. X    }
  686. X    return 0;
  687. X}
  688. X
  689. Xint
  690. Xdohistory()
  691. X{
  692. X    display_file(HISTORY, TRUE);
  693. X    return 0;
  694. X}
  695. X
  696. X/*pager.c*/
  697. END_OF_FILE
  698. if test 16869 -ne `wc -c <'src/pager.c'`; then
  699.     echo shar: \"'src/pager.c'\" unpacked with wrong size!
  700. fi
  701. # end of 'src/pager.c'
  702. fi
  703. if test -f 'src/shk.c1' -a "${1}" != "-c" ; then 
  704.   echo shar: Will not clobber existing file \"'src/shk.c1'\"
  705. else
  706. echo shar: Extracting \"'src/shk.c1'\" \(37947 characters\)
  707. sed "s/^X//" >'src/shk.c1' <<'END_OF_FILE'
  708. X/*    SCCS Id: @(#)shk.c    3.1    93/01/12    */
  709. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  710. X/* NetHack may be freely redistributed.  See license for details. */
  711. X
  712. X#include "hack.h"
  713. X#include "eshk.h"
  714. X
  715. X/*#define DEBUG*/
  716. X
  717. X#define PAY_SOME    2
  718. X#define PAY_BUY     1
  719. X#define PAY_CANT    0    /* too poor */
  720. X#define PAY_SKIP  (-1)
  721. X#define PAY_BROKE (-2)
  722. X
  723. X#ifdef KOPS
  724. XSTATIC_DCL void FDECL(makekops, (coord *));
  725. XSTATIC_DCL void FDECL(call_kops, (struct monst *,BOOLEAN_P));
  726. X# ifdef OVLB
  727. Xstatic void FDECL(kops_gone, (BOOLEAN_P));
  728. X# endif /* OVLB */
  729. X#endif /* KOPS */
  730. X
  731. X#define IS_SHOP(x)    (rooms[x].rtype >= SHOPBASE)
  732. X
  733. Xextern const struct shclass shtypes[];    /* defined in shknam.c */
  734. X
  735. XSTATIC_VAR long int NEARDATA followmsg;    /* last time of follow message */
  736. X
  737. XSTATIC_DCL void FDECL(setpaid, (struct monst *));
  738. XSTATIC_DCL long FDECL(addupbill, (struct monst *));
  739. XSTATIC_DCL void FDECL(pacify_shk, (struct monst *));
  740. X
  741. X#ifdef OVLB
  742. X
  743. Xstatic void FDECL(clear_unpaid,(struct obj *));
  744. Xstatic struct bill_x *FDECL(onbill, (struct obj *, struct monst *, BOOLEAN_P));
  745. Xstatic long FDECL(check_credit, (long, struct monst *));
  746. Xstatic void FDECL(pay, (long, struct monst *));
  747. Xstatic long FDECL(get_cost, (struct obj *, struct monst *));
  748. Xstatic long FDECL(set_cost, (struct obj *, struct monst *));
  749. Xstatic const char *FDECL(shk_embellish, (struct obj *, long));
  750. Xstatic long FDECL(cost_per_charge, (struct obj *));
  751. Xstatic long FDECL(cheapest_item, (struct monst *));
  752. Xstatic int FDECL(dopayobj, (struct monst *, struct bill_x *,
  753. X                struct obj *, int, BOOLEAN_P));
  754. Xstatic long FDECL(stolen_container, (struct obj *, struct monst *, long,
  755. X                     BOOLEAN_P));
  756. Xstatic long FDECL(getprice, (struct obj *));
  757. Xstatic struct obj *FDECL(bp_to_obj, (struct bill_x *));
  758. Xstatic boolean FDECL(inherits, (struct monst *, int, BOOLEAN_P));
  759. Xstatic struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P));
  760. Xstatic boolean NDECL(angry_shk_exists);
  761. Xstatic void FDECL(rile_shk, (struct monst *));
  762. Xstatic void FDECL(remove_damage, (struct monst *, BOOLEAN_P));
  763. Xstatic void FDECL(sub_one_frombill, (struct obj *, struct monst *));
  764. Xstatic void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P));
  765. Xstatic void FDECL(dropped_container, (struct obj *));
  766. Xstatic void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P,
  767. X                     struct monst *));
  768. X
  769. X/*
  770. X    invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
  771. X        obj->quan <= bp->bquan
  772. X */
  773. X
  774. Xstatic struct monst *
  775. Xnext_shkp(shkp, withbill)
  776. Xregister struct monst *shkp;
  777. Xregister boolean withbill;
  778. X{
  779. X    for (; shkp; shkp = shkp->nmon)
  780. X        if (shkp->isshk)
  781. X        if (ESHK(shkp)->billct || !withbill) break;
  782. X
  783. X    if (shkp) {
  784. X        if (NOTANGRY(shkp)) {
  785. X        if (ESHK(shkp)->surcharge) pacify_shk(shkp);
  786. X        } else {
  787. X        if (!ESHK(shkp)->surcharge) rile_shk(shkp);
  788. X        }
  789. X    }
  790. X    return(shkp);
  791. X}
  792. X
  793. Xchar *
  794. Xshkname(mtmp)                /* called in do_name.c */
  795. Xregister struct monst *mtmp;
  796. X{
  797. X    return(ESHK(mtmp)->shknam);
  798. X}
  799. X
  800. Xvoid
  801. Xshkgone(mtmp)                /* called in mon.c */
  802. Xregister struct monst *mtmp;
  803. X{
  804. X    register struct eshk *eshk = ESHK(mtmp);
  805. X
  806. X    if(on_level(&(eshk->shoplevel), &u.uz)) {
  807. X        remove_damage(mtmp, TRUE);
  808. X        rooms[eshk->shoproom - ROOMOFFSET].resident
  809. X                          = (struct monst *)0;
  810. X        if(!search_special(ANY_SHOP))
  811. X            level.flags.has_shop = 0;
  812. X    }
  813. X    /* make sure bill is set only when the
  814. X     * dead shk is the resident shk.    */
  815. X    if(*u.ushops == eshk->shoproom) {
  816. X        setpaid(mtmp);
  817. X        /* dump core when referenced */
  818. X        ESHK(mtmp)->bill_p = (struct bill_x *) -1000;
  819. X        u.ushops[0] = '\0';
  820. X    }
  821. X}
  822. X
  823. Xvoid
  824. Xset_residency(shkp, zero_out)
  825. Xregister struct monst *shkp;
  826. Xregister boolean zero_out;
  827. X{
  828. X    if (on_level(&(ESHK(shkp)->shoplevel), &u.uz))
  829. X        rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident =
  830. X        (zero_out)? (struct monst *)0 : shkp;
  831. X}
  832. X
  833. Xvoid
  834. Xreplshk(mtmp,mtmp2)
  835. Xregister struct monst *mtmp, *mtmp2;
  836. X{
  837. X    if(inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) {
  838. X        ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]);
  839. X    }
  840. X}
  841. X
  842. X/* do shopkeeper specific structure munging -dlc */
  843. Xvoid
  844. Xrestshk(mtmp)
  845. Xregister struct monst *mtmp;
  846. X{
  847. X    if(ESHK(mtmp)->bill_p != (struct bill_x *) -1000)
  848. X    ESHK(mtmp)->bill_p = &(ESHK(mtmp)->bill[0]);
  849. X}
  850. X
  851. X/* Clear the unpaid bit on all of the objects in the list. */
  852. Xstatic void
  853. Xclear_unpaid(list)
  854. Xregister struct obj *list;
  855. X{
  856. X    while (list) {
  857. X    if (Is_container(list)) clear_unpaid(list->cobj);
  858. X    list->unpaid = 0;
  859. X    list = list->nobj;
  860. X    }
  861. X}
  862. X
  863. XSTATIC_OVL void
  864. Xsetpaid(shkp)    /* either you paid or left the shop or the shopkeeper died */
  865. Xregister struct monst *shkp;
  866. X{
  867. X    register struct obj *obj;
  868. X    register struct monst *mtmp;
  869. X
  870. X    clear_unpaid(invent);
  871. X    clear_unpaid(fobj);
  872. X    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  873. X        clear_unpaid(mtmp->minvent);
  874. X    for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
  875. X        clear_unpaid(mtmp->minvent);
  876. X
  877. X    while ((obj = billobjs) != 0) {
  878. X        billobjs = obj->nobj;
  879. X        dealloc_obj(obj);
  880. X    }
  881. X    if(shkp) {
  882. X        ESHK(shkp)->billct = 0;
  883. X        ESHK(shkp)->credit = 0L;
  884. X        ESHK(shkp)->debit = 0L;
  885. X        ESHK(shkp)->loan = 0L;
  886. X    }
  887. X}
  888. X
  889. XSTATIC_OVL long
  890. Xaddupbill(shkp)
  891. Xregister struct monst *shkp;
  892. X{
  893. X    register int ct = ESHK(shkp)->billct;
  894. X    register struct bill_x *bp = ESHK(shkp)->bill_p;
  895. X    register long total = 0L;
  896. X
  897. X    while(ct--){
  898. X        total += bp->price * bp->bquan;
  899. X        bp++;
  900. X    }
  901. X    return(total);
  902. X}
  903. X
  904. X#endif /* OVLB */
  905. X#ifdef OVL1
  906. X
  907. X#ifdef KOPS
  908. XSTATIC_OVL void
  909. Xcall_kops(shkp, nearshop)
  910. Xregister struct monst *shkp;
  911. Xregister boolean nearshop;
  912. X{
  913. X    /* Keystone Kops srt@ucla */
  914. X    register boolean nokops;
  915. X
  916. X    if(!shkp) return;
  917. X
  918. X    if (flags.soundok)
  919. X        pline("An alarm sounds!");
  920. X
  921. X    nokops = ((mons[PM_KEYSTONE_KOP].geno & (G_GENOD | G_EXTINCT)) &&
  922. X          (mons[PM_KOP_SERGEANT].geno & (G_GENOD | G_EXTINCT)) &&
  923. X          (mons[PM_KOP_LIEUTENANT].geno & (G_GENOD | G_EXTINCT)) &&
  924. X          (mons[PM_KOP_KAPTAIN].geno & (G_GENOD | G_EXTINCT)));
  925. X
  926. X    if(!angry_guards(!flags.soundok) && nokops) {
  927. X        if(flags.verbose && flags.soundok)
  928. X        pline("But no one seems to respond to it.");
  929. X        return;
  930. X    }
  931. X
  932. X    if(nokops) return;
  933. X
  934. X    {
  935. X        coord mm;
  936. X
  937. X        if (nearshop) {
  938. X        /* Create swarm around you, if you merely "stepped out" */
  939. X        if (flags.verbose)
  940. X            pline("The Keystone Kops appear!");
  941. X        mm.x = u.ux;
  942. X        mm.y = u.uy;
  943. X        makekops(&mm);
  944. X        return;
  945. X        }
  946. X        if (flags.verbose)
  947. X         pline("The Keystone Kops are after you!");
  948. X        /* Create swarm near down staircase (hinders return to level) */
  949. X        mm.x = xdnstair;
  950. X        mm.y = ydnstair;
  951. X        makekops(&mm);
  952. X        /* Create swarm near shopkeeper (hinders return to shop) */
  953. X        mm.x = shkp->mx;
  954. X        mm.y = shkp->my;
  955. X        makekops(&mm);
  956. X    }
  957. X}
  958. X#endif    /* KOPS */
  959. X
  960. X/* x,y is strictly inside shop */
  961. Xchar
  962. Xinside_shop(x, y)
  963. Xregister xchar x, y;
  964. X{
  965. X    register char rno;
  966. X
  967. X    rno = levl[x][y].roomno;
  968. X    if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno-ROOMOFFSET))
  969. X        return(NO_ROOM);
  970. X    else
  971. X        return(rno);
  972. X}
  973. X
  974. Xvoid
  975. Xu_left_shop(leavestring, newlev)
  976. Xregister char *leavestring;
  977. Xregister boolean newlev;
  978. X{
  979. X    register struct monst *shkp;
  980. X    register struct eshk *eshkp;
  981. X    register long total;
  982. X
  983. X    /*
  984. X     * IF player
  985. X     * ((didn't leave outright) AND
  986. X     *  ((he is now strictly-inside the shop) OR
  987. X     *   (he wasn't strictly-inside last turn anyway)))
  988. X     * THEN (there's nothing to do, so just return)
  989. X     */
  990. X    if(!*leavestring &&
  991. X       (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge))
  992. X        return;
  993. X
  994. X    shkp = shop_keeper(*u.ushops0);
  995. X
  996. X    if(!shkp || !inhishop(shkp))
  997. X                /* shk died, teleported, changed levels... */
  998. X        return;
  999. X
  1000. X    eshkp = ESHK(shkp);
  1001. X
  1002. X    if(!eshkp->billct && !eshkp->debit)    /* bill is settled */
  1003. X        return;
  1004. X
  1005. X    if(!*leavestring) {
  1006. X        /*
  1007. X         * Player just stepped onto shop-boundary (known from above logic).
  1008. X         * Try to intimidate him into paying his bill
  1009. X         */
  1010. X
  1011. X        verbalize(NOTANGRY(shkp) ?
  1012. X              "%s!  Please pay before leaving." :
  1013. X              "%s!  Don't you leave without paying!",
  1014. X              plname);
  1015. X        return;
  1016. X    }
  1017. X        /* by this point, we know an actual robbery has taken place */
  1018. X    You("escaped the shop without paying!");
  1019. X    total = (addupbill(shkp) + eshkp->debit);
  1020. X    eshkp->robbed += total;
  1021. X    eshkp->credit = 0L;
  1022. X    eshkp->debit = 0L;
  1023. X    setpaid(shkp);
  1024. X    You("stole %ld zorkmid%s worth of merchandise.",
  1025. X        total, plur(total));
  1026. X    if (pl_character[0] != 'R') /* stealing is unlawful */
  1027. X        adjalign(-sgn(u.ualign.type));
  1028. X
  1029. X    hot_pursuit(shkp);
  1030. X#ifdef KOPS
  1031. X    call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
  1032. X#else
  1033. X    (void) angry_guards(FALSE);
  1034. X#endif
  1035. X}
  1036. X
  1037. Xvoid
  1038. Xu_entered_shop(enterstring)
  1039. Xregister char *enterstring;
  1040. X{
  1041. X
  1042. X    register int rt;
  1043. X    register struct monst *shkp;
  1044. X    register struct eshk *eshkp;
  1045. X    static const char no_shk[] = "This shop appears to be deserted.";
  1046. X    static char empty_shops[5];
  1047. X
  1048. X    if(!*enterstring)
  1049. X        return;
  1050. X
  1051. X    if(!(shkp = shop_keeper(*enterstring))) {
  1052. X        if (!index(empty_shops, *enterstring) &&
  1053. X        in_rooms(u.ux, u.uy, SHOPBASE) !=
  1054. X                  in_rooms(u.ux0, u.uy0, SHOPBASE))
  1055. X        pline(no_shk);
  1056. X        Strcpy(empty_shops, u.ushops);
  1057. X        u.ushops[0] = '\0';
  1058. X        return;
  1059. X    }
  1060. X
  1061. X    eshkp = ESHK(shkp);
  1062. X
  1063. X    if (!inhishop(shkp)) {
  1064. X        /* dump core when referenced */
  1065. X        eshkp->bill_p = (struct bill_x *) -1000;
  1066. X        if (!index(empty_shops, *enterstring))
  1067. X        pline(no_shk);
  1068. X        Strcpy(empty_shops, u.ushops);
  1069. X        u.ushops[0] = '\0';
  1070. X        return;
  1071. X    }
  1072. X
  1073. X    eshkp->bill_p = &(eshkp->bill[0]);
  1074. X
  1075. X    if (!eshkp->visitct || strncmpi(eshkp->customer, plname, PL_NSIZ)) {
  1076. X        /* You seem to be new here */
  1077. X        eshkp->visitct = 0;
  1078. X        eshkp->following = 0;
  1079. X        (void) strncpy(eshkp->customer,plname,PL_NSIZ);
  1080. X        pacify_shk(shkp);
  1081. X    }
  1082. X
  1083. X    if (eshkp->following)
  1084. X        return;
  1085. X
  1086. X    if (Invis) {
  1087. X        pline("%s senses your presence.", shkname(shkp));
  1088. X        verbalize("Invisible customers are not welcome!");
  1089. X        return;
  1090. X    }
  1091. X
  1092. X    rt = rooms[*enterstring - ROOMOFFSET].rtype;
  1093. X
  1094. X    if (ANGRY(shkp)) {
  1095. X        verbalize("So, %s, you dare return to %s %s?!",
  1096. X              plname,
  1097. X              s_suffix(shkname(shkp)),
  1098. X              shtypes[rt - SHOPBASE].name);
  1099. X    } else if (eshkp->robbed) {
  1100. X        verbalize("Beware, %s!  I am upset about missing stock!",
  1101. X              plname);
  1102. X    } else {
  1103. X        verbalize("Hello, %s!  Welcome%s to %s %s!",
  1104. X              plname,
  1105. X              eshkp->visitct++ ? " again" : "",
  1106. X              s_suffix(shkname(shkp)),
  1107. X              shtypes[rt - SHOPBASE].name);
  1108. X    }
  1109. X    if(carrying(PICK_AXE) != (struct obj *)0 &&
  1110. X                 /* can't do anything if teleported in */
  1111. X                 !inside_shop(u.ux, u.uy)) {
  1112. X        verbalize(NOTANGRY(shkp) ?
  1113. X              "Will you please leave your pick-axe outside?" :
  1114. X              "Leave the pick-axe outside.");
  1115. X        (void) dochug(shkp);
  1116. X    }
  1117. X    return;
  1118. X}
  1119. X
  1120. X#endif /* OVL1 */
  1121. X#ifdef OVLB
  1122. X
  1123. Xint
  1124. Xinhishop(mtmp)
  1125. Xregister struct monst *mtmp;
  1126. X{
  1127. X    return(index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE),
  1128. X             ESHK(mtmp)->shoproom) &&
  1129. X        on_level(&(ESHK(mtmp)->shoplevel), &u.uz));
  1130. X}
  1131. X
  1132. Xstruct monst *
  1133. Xshop_keeper(rmno)
  1134. Xregister char rmno;
  1135. X{
  1136. X    struct monst *shkp = rmno >= ROOMOFFSET ?
  1137. X                rooms[rmno - ROOMOFFSET].resident : 0;
  1138. X
  1139. X    if (shkp) {
  1140. X        if (NOTANGRY(shkp)) {
  1141. X        if (ESHK(shkp)->surcharge) pacify_shk(shkp);
  1142. X        } else {
  1143. X        if (!ESHK(shkp)->surcharge) rile_shk(shkp);
  1144. X        }
  1145. X    }
  1146. X    return shkp;
  1147. X}
  1148. X
  1149. X#ifdef SOUNDS
  1150. Xboolean
  1151. Xtended_shop(sroom)
  1152. Xregister struct mkroom *sroom;
  1153. X{
  1154. X    register struct monst *mtmp = sroom->resident;
  1155. X
  1156. X    if (!mtmp)
  1157. X        return(FALSE);
  1158. X    else
  1159. X        return(inhishop(mtmp));
  1160. X}
  1161. X#endif    /* SOUNDS */
  1162. X
  1163. Xstatic struct bill_x *
  1164. Xonbill(obj, shkp, silent)
  1165. Xregister struct obj *obj;
  1166. Xregister struct monst *shkp;
  1167. Xregister boolean silent;
  1168. X{
  1169. X    if (shkp) {
  1170. X        register struct bill_x *bp = ESHK(shkp)->bill_p;
  1171. X        register int ct = ESHK(shkp)->billct;
  1172. X
  1173. X        while (--ct >= 0)
  1174. X            if (bp->bo_id == obj->o_id) {
  1175. X            if (!obj->unpaid) pline("onbill: paid obj on bill?");
  1176. X            return bp;
  1177. X            } else bp++;
  1178. X    }
  1179. X    if(obj->unpaid & !silent) pline("onbill: unpaid obj not on bill?");
  1180. X    return (struct bill_x *)0;
  1181. X}
  1182. X
  1183. X/* Delete the contents of the given object. */
  1184. Xvoid
  1185. Xdelete_contents(obj)
  1186. Xregister struct obj *obj;
  1187. X{
  1188. X    register struct obj *curr, *next;
  1189. X
  1190. X    for (curr = obj->cobj; curr; curr = next) {
  1191. X        next = curr->nobj;
  1192. X        obfree(curr, (struct obj *)0);
  1193. X    }
  1194. X    obj->cobj = (struct obj *) 0;
  1195. X}
  1196. X
  1197. X/* called with two args on merge */
  1198. Xvoid
  1199. Xobfree(obj, merge)
  1200. Xregister struct obj *obj, *merge;
  1201. X{
  1202. X    register struct bill_x *bp;
  1203. X    register struct bill_x *bpm;
  1204. X    register struct monst *shkp;
  1205. X
  1206. X    if(obj->oclass == FOOD_CLASS) food_disappears(obj);
  1207. X
  1208. X    if (obj->cobj) delete_contents(obj);
  1209. X
  1210. X    shkp = shop_keeper(*u.ushops);
  1211. X
  1212. X    if ((bp = onbill(obj, shkp, FALSE)) != 0) {
  1213. X        if(!merge){
  1214. X            bp->useup = 1;
  1215. X            obj->unpaid = 0;    /* only for doinvbill */
  1216. X            obj->nobj = billobjs;
  1217. X            billobjs = obj;
  1218. X            return;
  1219. X        }
  1220. X        bpm = onbill(merge, shkp, FALSE);
  1221. X        if(!bpm){
  1222. X            /* this used to be a rename */
  1223. X            impossible("obfree: not on bill??");
  1224. X            return;
  1225. X        } else {
  1226. X            /* this was a merger */
  1227. X            bpm->bquan += bp->bquan;
  1228. X            ESHK(shkp)->billct--;
  1229. X#ifdef DUMB
  1230. X            {
  1231. X            /* DRS/NS 2.2.6 messes up -- Peter Kendell */
  1232. X                int indx = ESHK(shkp)->billct;
  1233. X                *bp = ESHK(shkp)->bill_p[indx];
  1234. X            }
  1235. X#else
  1236. X            *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
  1237. X#endif
  1238. X        }
  1239. X    }
  1240. X    dealloc_obj(obj);
  1241. X}
  1242. X
  1243. Xstatic long
  1244. Xcheck_credit(tmp, shkp)
  1245. Xlong tmp;
  1246. Xregister struct monst *shkp;
  1247. X{
  1248. X    long credit = ESHK(shkp)->credit;
  1249. X
  1250. X    if(credit == 0L) return(tmp);
  1251. X    if(credit >= tmp) {
  1252. X        pline("The price is deducted from your credit.");
  1253. X        ESHK(shkp)->credit -=tmp;
  1254. X        tmp = 0L;
  1255. X    } else {
  1256. X        pline("The price is partially covered by your credit.");
  1257. X        ESHK(shkp)->credit = 0L;
  1258. X        tmp -= credit;
  1259. X    }
  1260. X    return(tmp);
  1261. X}
  1262. X
  1263. Xstatic void
  1264. Xpay(tmp,shkp)
  1265. Xlong tmp;
  1266. Xregister struct monst *shkp;
  1267. X{
  1268. X    long robbed = ESHK(shkp)->robbed;
  1269. X    long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp));
  1270. X
  1271. X    u.ugold -= balance;
  1272. X    shkp->mgold += balance;
  1273. X    flags.botl = 1;
  1274. X    if(robbed) {
  1275. X        robbed -= tmp;
  1276. X        if(robbed < 0) robbed = 0L;
  1277. X        ESHK(shkp)->robbed = robbed;
  1278. X    }
  1279. X}
  1280. X
  1281. X/* return shkp to home position */
  1282. Xvoid
  1283. Xhome_shk(shkp, killkops)
  1284. Xregister struct monst *shkp;
  1285. Xregister boolean killkops;
  1286. X{
  1287. X    register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
  1288. X
  1289. X    (void) mnearto(shkp, x, y, TRUE);
  1290. X    level.flags.has_shop = 1;
  1291. X    if (killkops) {
  1292. X#ifdef KOPS
  1293. X        kops_gone(TRUE);
  1294. X#else
  1295. X        You("feel vaguely apprehensive.");
  1296. X#endif
  1297. X        pacify_guards();
  1298. X    }
  1299. X}
  1300. X
  1301. Xstatic boolean
  1302. Xangry_shk_exists()
  1303. X{
  1304. X    register struct monst *shkp;
  1305. X
  1306. X    for (shkp = next_shkp(fmon, FALSE);
  1307. X        shkp; shkp = next_shkp(shkp->nmon, FALSE))
  1308. X        if (ANGRY(shkp)) return(TRUE);
  1309. X    return(FALSE);
  1310. X}
  1311. X
  1312. X/* remove previously applied surcharge from all billed items */
  1313. XSTATIC_OVL void
  1314. Xpacify_shk(shkp)
  1315. Xregister struct monst *shkp;
  1316. X{
  1317. X    NOTANGRY(shkp) = TRUE;    /* make peaceful */
  1318. X    if (ESHK(shkp)->surcharge) {
  1319. X        register struct bill_x *bp = ESHK(shkp)->bill_p;
  1320. X        register int ct = ESHK(shkp)->billct;
  1321. X
  1322. X        ESHK(shkp)->surcharge = FALSE;
  1323. X        while (ct-- > 0) {
  1324. X            register long reduction = (bp->price + 3L) / 4L;
  1325. X            bp->price -= reduction;        /* undo 33% increase */
  1326. X            bp++;
  1327. X        }
  1328. X    }
  1329. X}
  1330. X
  1331. X/* add aggravation surcharge to all billed items */
  1332. Xstatic void
  1333. Xrile_shk(shkp)
  1334. Xregister struct monst *shkp;
  1335. X{
  1336. X    NOTANGRY(shkp) = FALSE;    /* make angry */
  1337. X    if (!ESHK(shkp)->surcharge) {
  1338. X        register struct bill_x *bp = ESHK(shkp)->bill_p;
  1339. X        register int ct = ESHK(shkp)->billct;
  1340. X
  1341. X        ESHK(shkp)->surcharge = TRUE;
  1342. X        while (ct-- > 0) {
  1343. X            register long surcharge = (bp->price + 2L) / 3L;
  1344. X            bp->price += surcharge;
  1345. X            bp++;
  1346. X        }
  1347. X    }
  1348. X}
  1349. X
  1350. Xvoid
  1351. Xmake_happy_shk(shkp, silentkops)
  1352. Xregister struct monst *shkp;
  1353. Xregister boolean silentkops;
  1354. X{
  1355. X    register boolean wasmad = ANGRY(shkp);
  1356. X
  1357. X    pacify_shk(shkp);
  1358. X    ESHK(shkp)->following = 0;
  1359. X    ESHK(shkp)->robbed = 0L;
  1360. X    if (pl_character[0] != 'R')
  1361. X        adjalign(sgn(u.ualign.type));
  1362. X    if(!inhishop(shkp)) {
  1363. X        pline("Satisfied, %s suddenly disappears!", mon_nam(shkp));
  1364. X        if(on_level(&(ESHK(shkp)->shoplevel), &u.uz))
  1365. X            home_shk(shkp, FALSE);
  1366. X        else
  1367. X            migrate_to_level(shkp,
  1368. X                 ledger_no(&(ESHK(shkp)->shoplevel)), 0);
  1369. X    } else if(wasmad)
  1370. X        pline("%s calms down.", Monnam(shkp));
  1371. X
  1372. X    if(!angry_shk_exists()) {
  1373. X#ifdef KOPS
  1374. X        kops_gone(silentkops);
  1375. X#endif
  1376. X        pacify_guards();
  1377. X    }
  1378. X}
  1379. X
  1380. Xvoid
  1381. Xhot_pursuit(shkp)
  1382. Xregister struct monst *shkp;
  1383. X{
  1384. X    if(!shkp->isshk) return;
  1385. X
  1386. X    rile_shk(shkp);
  1387. X    ESHK(shkp)->following = 1;
  1388. X}
  1389. X
  1390. X/* used when the shkp is teleported out of his shop,
  1391. X * or when the player is not on a costly_spot and he
  1392. X * damages something inside the shop.  these conditions
  1393. X * must be checked by the calling function.
  1394. X */
  1395. Xvoid
  1396. Xmake_angry_shk(shkp, ox, oy)
  1397. Xregister struct monst *shkp;
  1398. Xregister xchar ox,oy;
  1399. X{
  1400. X    if(index(in_rooms(ox, oy, SHOPBASE), ESHK(shkp)->shoproom) &&
  1401. X        !ANGRY(shkp)) {
  1402. X        ESHK(shkp)->robbed += (addupbill(shkp) +
  1403. X                       ESHK(shkp)->debit + ESHK(shkp)->loan);
  1404. X        ESHK(shkp)->robbed -= ESHK(shkp)->credit;
  1405. X        if(ESHK(shkp)->robbed < 0L)
  1406. X            ESHK(shkp)->robbed = 0L;
  1407. X        ESHK(shkp)->credit = 0L;
  1408. X        setpaid(shkp);
  1409. X    }
  1410. X    if(!ANGRY(shkp)) pline("%s gets angry!", Monnam(shkp));
  1411. X    else pline("%s is furious!", Monnam(shkp));
  1412. X    hot_pursuit(shkp);
  1413. X}
  1414. X
  1415. Xstatic const char no_money[] = "Moreover, you%s have no money.";
  1416. X
  1417. Xstatic long
  1418. Xcheapest_item(shkp)   /* delivers the cheapest item on the list */
  1419. Xregister struct monst *shkp;
  1420. X{
  1421. X    register int ct = ESHK(shkp)->billct;
  1422. X    register struct bill_x *bp = ESHK(shkp)->bill_p;
  1423. X    register long gmin = (bp->price * bp->bquan);
  1424. X
  1425. X    while(ct--){
  1426. X        if(bp->price * bp->bquan < gmin)
  1427. X            gmin = bp->price * bp->bquan;
  1428. X        bp++;
  1429. X    }
  1430. X    return(gmin);
  1431. X}
  1432. X
  1433. Xint
  1434. Xdopay()
  1435. X{
  1436. X    long ltmp;
  1437. X    register struct monst *nxtm = (struct monst *)0;
  1438. X    register struct monst *shkp, *resident = (struct monst *)0;
  1439. X    register struct eshk *eshkp;
  1440. X    int pass, tmp, sk = 0, seensk = 0;
  1441. X    register boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L);
  1442. X
  1443. X    multi = 0;
  1444. X
  1445. X    /* find how many shk's there are, how many are in */
  1446. X    /* sight, and are you in a shop room with one.    */
  1447. X    for (shkp = next_shkp(fmon, FALSE);
  1448. X        shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
  1449. X        sk++;
  1450. X        if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2) nxtm = shkp;
  1451. X        if (canseemon(shkp) || sensemon(shkp)) seensk++;
  1452. X        if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom))
  1453. X        resident = shkp;
  1454. X    }
  1455. X
  1456. X    if (nxtm) {            /* Player should always appease an */
  1457. X         shkp = nxtm;        /* irate shk standing next to them. */
  1458. X         goto proceed;
  1459. X    }
  1460. X
  1461. X    if ((!sk && (!Blind || Telepat)) || (!Blind && !seensk)) {
  1462. X      pline("There appears to be no shopkeeper here to receive your payment.");
  1463. X        return(0);
  1464. X    }
  1465. X
  1466. X    if(!seensk) {
  1467. X        You("can't see...");
  1468. X        return(0);
  1469. X    }
  1470. X
  1471. X    /* the usual case.  allow paying at a distance when */
  1472. X    /* inside a tended shop.  should we change that?    */
  1473. X    if(sk == 1 && resident) {
  1474. X        shkp = resident;
  1475. X        goto proceed;
  1476. X    }
  1477. X
  1478. X    if (seensk == 1) {
  1479. X        for (shkp = next_shkp(fmon, FALSE);
  1480. X            shkp; shkp = next_shkp(shkp->nmon, FALSE))
  1481. X            if (canseemon(shkp) || sensemon(shkp)) break;
  1482. X        if (shkp != resident && distu(shkp->mx, shkp->my) > 2) {
  1483. X            pline("%s is not near enough to receive your payment.",
  1484. X                         Monnam(shkp));
  1485. X            return(0);
  1486. X        }
  1487. X    } else {
  1488. X        struct monst *mtmp;
  1489. X        coord cc;
  1490. X        int cx, cy;
  1491. X
  1492. X        pline("Pay whom?");
  1493. X        cc.x = u.ux;
  1494. X        cc.y = u.uy;
  1495. X        getpos(&cc, TRUE, "the creature you want to pay");
  1496. X        cx = cc.x;
  1497. X        cy = cc.y;
  1498. X        if(cx == -10) return(0); /* player pressed esc */
  1499. X        if(cx < 0) {
  1500. X             pline("Try again...");
  1501. X             return(0);
  1502. X        }
  1503. X        if(u.ux == cx && u.uy == cy) {
  1504. X             You("are generous to yourself.");
  1505. X             return(0);
  1506. X        }
  1507. X        mtmp = m_at(cx, cy);
  1508. X        if(!mtmp) {
  1509. X             pline("There is no one there to receive your payment.");
  1510. X             return(0);
  1511. X        }
  1512. X        if(!mtmp->isshk) {
  1513. X             pline("%s is not interested in your payment.",
  1514. X                    Monnam(mtmp));
  1515. X             return(0);
  1516. X        }
  1517. X        if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) {
  1518. X             pline("%s is too far to receive your payment.",
  1519. X                    Monnam(mtmp));
  1520. X             return(0);
  1521. X        }
  1522. X        shkp = mtmp;
  1523. X    }
  1524. X
  1525. X    if(!shkp) {
  1526. X#ifdef DEBUG
  1527. X        pline("dopay: null shkp.");
  1528. X#endif
  1529. X        return(0);
  1530. X    }
  1531. Xproceed:
  1532. X    eshkp = ESHK(shkp);
  1533. X
  1534. X    ltmp = eshkp->robbed;
  1535. X    if(shkp != resident && NOTANGRY(shkp)) {
  1536. X        if(!ltmp)
  1537. X            You("do not owe %s anything.", mon_nam(shkp));
  1538. X        else if(!u.ugold) {
  1539. X            You("%shave no money.", stashed_gold ? "seem to " : "");
  1540. X            if(stashed_gold)
  1541. X            pline("But you have some gold stashed away.");
  1542. X        } else {
  1543. X            const char *pronoun = shkp->female ? "she" : "he";
  1544. X            long ugold = u.ugold;
  1545. X
  1546. X            if(ugold > ltmp) {
  1547. X            You("give %s the %ld gold piece%s %s asked for.",
  1548. X                mon_nam(shkp), ltmp, plur(ltmp), pronoun);
  1549. X            pay(ltmp, shkp);
  1550. X            } else {
  1551. X            You("give %s all your%s gold.", mon_nam(shkp),
  1552. X                    stashed_gold ? " openly kept" : "");
  1553. X            pay(u.ugold, shkp);
  1554. X            if (stashed_gold) pline("But you have hidden gold!");
  1555. X            }
  1556. X            if((ugold < ltmp/2L) || (ugold < ltmp && stashed_gold))
  1557. X            pline("Unfortunately, %s doesn't look satisfied.",
  1558. X                pronoun);
  1559. X            else
  1560. X            make_happy_shk(shkp, FALSE);
  1561. X        }
  1562. X        return(1);
  1563. X    }
  1564. X
  1565. X    /* ltmp is still eshkp->robbed here */
  1566. X    if (!eshkp->billct && !eshkp->debit) {
  1567. X        const char *pronoun = shkp->female ? "her" : "him";
  1568. X        const char *possessive = shkp->female ? "her" : "his";
  1569. X
  1570. X        if(!ltmp && NOTANGRY(shkp)) {
  1571. X            You("do not owe %s anything.", mon_nam(shkp));
  1572. X            if(!u.ugold) pline(no_money, stashed_gold ?
  1573. X                       " seem to" : "");
  1574. X        } else if(ltmp) {
  1575. X            pline("%s is after blood, not money!", Monnam(shkp));
  1576. X            if(u.ugold < ltmp/2L ||
  1577. X                (u.ugold < ltmp && stashed_gold)) {
  1578. X            if(!u.ugold) pline(no_money, stashed_gold ?
  1579. X                               " seem to" : "");
  1580. X            else pline("Besides, you don't have enough to interest %s.",
  1581. X                pronoun);
  1582. X            return(1);
  1583. X            }
  1584. X            pline("But since %s shop has been robbed recently,",
  1585. X            possessive);
  1586. X            pline("you %scompensate %s for %s losses.",
  1587. X            (u.ugold < ltmp) ? "partially " : "",
  1588. X            mon_nam(shkp), possessive);
  1589. X            pay(u.ugold < ltmp ? u.ugold : ltmp, shkp);
  1590. X            make_happy_shk(shkp, FALSE);
  1591. X        } else {
  1592. X            /* shopkeeper is angry, but has not been robbed --
  1593. X             * door broken, attacked, etc. */
  1594. X            pline("%s is after your hide, not your money!",
  1595. X                             mon_nam(shkp));
  1596. X            if(u.ugold < 1000L) {
  1597. X            if(!u.ugold) pline(no_money, stashed_gold ?
  1598. X                         " seem to" : "");
  1599. X            else pline("Besides, you don't have enough to interest %s.",
  1600. X                    pronoun);
  1601. X            return(1);
  1602. X            }
  1603. X            You("try to appease %s by giving %s 1000 gold pieces.",
  1604. X            x_monnam(shkp, 1, "angry", 0), pronoun);
  1605. X            pay(1000L,shkp);
  1606. X            if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3))
  1607. X            make_happy_shk(shkp, FALSE);
  1608. X            else
  1609. X            pline("But %s is as angry as ever.", mon_nam(shkp));
  1610. X        }
  1611. X        return(1);
  1612. X    }
  1613. X    if(shkp != resident) {
  1614. X        impossible("dopay: not to shopkeeper?");
  1615. X        if(resident) setpaid(resident);
  1616. X        return(0);
  1617. X    }
  1618. X    /* pay debt, if any, first */
  1619. X    if(eshkp->debit) {
  1620. X        long dtmp = eshkp->debit;
  1621. X        long loan = eshkp->loan;
  1622. X        char sbuf[BUFSZ];
  1623. X
  1624. X        Sprintf(sbuf, "You owe %s %ld zorkmid%s ",
  1625. X                       shkname(shkp), dtmp, plur(dtmp));
  1626. X        if(loan) {
  1627. X            if(loan == dtmp)
  1628. X            Strcat(sbuf, "you picked up in the store.");
  1629. X            else Strcat(sbuf,
  1630. X               "for gold picked up and the use of merchandise.");
  1631. X        } else Strcat(sbuf, "for the use of merchandise.");
  1632. X        pline(sbuf);
  1633. X        if (u.ugold + eshkp->credit < dtmp) {
  1634. X            pline("But you don't%s have enough gold%s.",
  1635. X            stashed_gold ? " seem to" : "",
  1636. X            eshkp->credit ? " or credit" : "");
  1637. X            return(1);
  1638. X        } else {
  1639. X            if (eshkp->credit >= dtmp) {
  1640. X            eshkp->credit -= dtmp;
  1641. X            eshkp->debit = 0L;
  1642. X            eshkp->loan = 0L;
  1643. X            Your("debt is covered by your credit.");
  1644. X            } else if (!eshkp->credit) {
  1645. X            u.ugold -= dtmp;
  1646. X            shkp->mgold += dtmp;
  1647. X            eshkp->debit = 0L;
  1648. X            eshkp->loan = 0L;
  1649. X            You("pay that debt.");
  1650. X            flags.botl = 1;
  1651. X            } else {
  1652. X            dtmp -= eshkp->credit;
  1653. X            eshkp->credit = 0L;
  1654. X            u.ugold -= dtmp;
  1655. X            shkp->mgold += dtmp;
  1656. X            eshkp->debit = 0L;
  1657. X            eshkp->loan = 0L;
  1658. X            pline("That debt is partially offset by your credit.");
  1659. X            You("pay the remainder.");
  1660. X            flags.botl = 1;
  1661. X            }
  1662. X            paid = TRUE;
  1663. X        }
  1664. X    }
  1665. X    /* now check items on bill */
  1666. X    if (eshkp->billct) {
  1667. X        register boolean itemize;
  1668. X
  1669. X        if (!u.ugold && !eshkp->credit) {
  1670. X        You("%shave no money or credit%s.",
  1671. X                    stashed_gold ? "seem to " : "",
  1672. X                    paid ? " left" : "");
  1673. X        return(0);
  1674. X        }
  1675. X        if ((u.ugold + eshkp->credit) < cheapest_item(shkp)) {
  1676. X        You("don't have enough money to buy%s the item%s you picked.",
  1677. X            eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct));
  1678. X        if(stashed_gold)
  1679. X            pline("Maybe you have some gold stashed away?");
  1680. X        return(0);
  1681. X        }
  1682. X
  1683. X        /* this isn't quite right; it itemizes without asking if the
  1684. X         * single item on the bill is partly used up and partly unpaid */
  1685. X        itemize = (eshkp->billct > 1 ? yn("Itemized billing?") == 'y' : 1);
  1686. X
  1687. X        for (pass = 0; pass <= 1; pass++) {
  1688. X        tmp = 0;
  1689. X        while (tmp < eshkp->billct) {
  1690. X            register struct obj *otmp;
  1691. X            register struct bill_x *bp = &(eshkp->bill_p[tmp]);
  1692. X
  1693. X            /* find the object on one of the lists */
  1694. X            if (!(otmp = bp_to_obj(bp))) {
  1695. X            impossible("Shopkeeper administration out of order.");
  1696. X            setpaid(shkp);    /* be nice to the player */
  1697. X            return 1;
  1698. X            }
  1699. X            if (pass == bp->useup && otmp->quan == bp->bquan) {
  1700. X            /* pay for used-up items on first pass and others
  1701. X             * on second, so player will be stuck in the store
  1702. X             * less often; things which are partly used up
  1703. X             * are processed on both passes */
  1704. X            tmp++;
  1705. X            } else {
  1706. X            switch (dopayobj(shkp, bp, otmp, pass, itemize)) {
  1707. X              case PAY_CANT:
  1708. X                return 1;    /*break*/
  1709. X              case PAY_BROKE:
  1710. X                paid = TRUE;
  1711. X                goto thanks;    /*break*/
  1712. X              case PAY_SKIP:
  1713. X                tmp++;
  1714. X                continue;    /*break*/
  1715. X              case PAY_SOME:
  1716. X                paid = TRUE;
  1717. X                if (itemize) bot();
  1718. X                continue;    /*break*/
  1719. X              case PAY_BUY:
  1720. X                paid = TRUE;
  1721. X                break;
  1722. X            }
  1723. X            if (itemize) bot();
  1724. X            *bp = eshkp->bill_p[--eshkp->billct];
  1725. X            }
  1726. X        }
  1727. X        }
  1728. X    }
  1729. Xthanks:
  1730. X    if(!ANGRY(shkp) && paid)
  1731. X        verbalize("Thank you for shopping in %s %s!",
  1732. X        s_suffix(shkname(shkp)),
  1733. X        shtypes[rooms[eshkp->shoproom - ROOMOFFSET].rtype - SHOPBASE].name);
  1734. X    return(1);
  1735. X}
  1736. X
  1737. X/* return 2 if used-up portion paid */
  1738. X/*      1 if paid successfully    */
  1739. X/*      0 if not enough money     */
  1740. X/*     -1 if skip this object     */
  1741. X/*     -2 if no money/credit left */
  1742. Xstatic int
  1743. Xdopayobj(shkp, bp, obj, which, itemize)
  1744. Xregister struct monst *shkp;
  1745. Xregister struct bill_x *bp;
  1746. Xregister struct obj *obj;
  1747. Xint    which;        /* 0 => used-up item, 1 => other (unpaid or lost) */
  1748. Xboolean itemize;
  1749. X{
  1750. X    long ltmp, quan, save_quan;
  1751. X    int buy;
  1752. X    boolean stashed_gold = (hidden_gold() > 0L),
  1753. X        consumed = (which == 0);
  1754. X
  1755. X    if(!obj->unpaid && !bp->useup){
  1756. X        impossible("Paid object on bill??");
  1757. X        return PAY_BUY;
  1758. X    }
  1759. X    if(itemize && u.ugold + ESHK(shkp)->credit == 0L){
  1760. X        You("%shave no money or credit left.",
  1761. X                 stashed_gold ? "seem to " : "");
  1762. X        return PAY_BROKE;
  1763. X    }
  1764. X    /* we may need to temporarily adjust the object, if part of the
  1765. X       original quantity has been used up but part remains unpaid  */
  1766. X    save_quan = obj->quan;
  1767. X    if (consumed) {
  1768. X        /* either completely used up (simple), or split needed */
  1769. X        quan = bp->bquan;
  1770. X        if (quan > obj->quan)    /* difference is amount used up */
  1771. X        quan -= obj->quan;
  1772. X    } else {
  1773. X        /* dealing with ordinary unpaid item */
  1774. X        quan = obj->quan;
  1775. X    }
  1776. X    obj->quan = quan;    /* to be used by doname() */
  1777. X    obj->unpaid = 0;    /* ditto */
  1778. X    ltmp = bp->price * quan;
  1779. X    buy = PAY_BUY;        /* flag; if changed then return early */
  1780. X
  1781. X    if (itemize) {
  1782. X        char qbuf[BUFSZ];
  1783. X        Sprintf(qbuf,"%s for %ld zorkmid%s.  Pay?", quan == 1L ?
  1784. X            Doname2(obj) : doname(obj), ltmp, plur(ltmp));
  1785. X        if (yn(qbuf) == 'n') {
  1786. X        buy = PAY_SKIP;        /* don't want to buy */
  1787. X        } else if (quan < bp->bquan && !consumed) { /* partly used goods */
  1788. X        obj->quan = bp->bquan - save_quan;    /* used up amount */
  1789. X        verbalize("%s for the other %s before buying %s.",
  1790. X              ANGRY(shkp) ? "Pay" : "Please pay", xname(obj),
  1791. X              save_quan > 1L ? "these" : "this one");
  1792. X        buy = PAY_SKIP;        /* shk won't sell */
  1793. X        }
  1794. X    }
  1795. X    if (buy == PAY_BUY && u.ugold + ESHK(shkp)->credit < ltmp) {
  1796. X        You("don't%s have gold%s enough to pay for %s.",
  1797. X        stashed_gold ? " seem to" : "",
  1798. X        (ESHK(shkp)->credit > 0L) ? " or credit" : "",
  1799. X        doname(obj));
  1800. X        buy = itemize ? PAY_SKIP : PAY_CANT;
  1801. X    }
  1802. X
  1803. X    if (buy != PAY_BUY) {
  1804. X        /* restore unpaid object to original state */
  1805. X        obj->quan = save_quan;
  1806. X        obj->unpaid = 1;
  1807. X        return buy;
  1808. X    }
  1809. X
  1810. X    pay(ltmp, shkp);
  1811. X    You("bought %s for %ld gold piece%s.",
  1812. X        doname(obj), ltmp, plur(ltmp));
  1813. X    obj->quan = save_quan;        /* restore original count */
  1814. X    /* quan => amount just bought, save_quan => remaining unpaid count */
  1815. X    if (consumed) {
  1816. X        if (quan != save_quan) {
  1817. X        /* eliminate used-up portion; remainder is still unpaid */
  1818. X        bp->bquan = obj->quan;
  1819. X        obj->unpaid = 1;
  1820. X        bp->useup = 0;
  1821. X        } else {    /* completely used-up, so get rid of it */
  1822. X        register struct obj *otmp = billobjs;
  1823. X        if(obj == billobjs)
  1824. X            billobjs = obj->nobj;
  1825. X        else {
  1826. X            while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
  1827. X            if(otmp) otmp->nobj = obj->nobj;
  1828. X            else impossible("Error in shopkeeper administration.");
  1829. X        }
  1830. X        dealloc_obj(obj);
  1831. X        }
  1832. X    }
  1833. X    return quan != save_quan ? PAY_SOME : PAY_BUY;
  1834. X}
  1835. X
  1836. X/* routine called after dying (or quitting) */
  1837. Xboolean
  1838. Xpaybill(croaked)
  1839. Xregister boolean croaked;
  1840. X{
  1841. X    register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0;
  1842. X    register boolean taken = FALSE;
  1843. X    register int numsk = 0;
  1844. X
  1845. X    /* give shopkeeper first crack */
  1846. X    if ((mtmp = shop_keeper(*u.ushops)) && inhishop(mtmp)) {
  1847. X        numsk++;
  1848. X        resident = mtmp;
  1849. X        taken = inherits(resident, numsk, croaked);
  1850. X    }
  1851. X    for (mtmp = next_shkp(fmon, FALSE);
  1852. X        mtmp; mtmp = next_shkp(mtmp2, FALSE)) {
  1853. X        mtmp2 = mtmp->nmon;
  1854. X        if (mtmp != resident) {
  1855. X        /* for bones: we don't want a shopless shk around */
  1856. X        if(!on_level(&(ESHK(mtmp)->shoplevel), &u.uz))
  1857. X            mongone(mtmp);
  1858. X        else {
  1859. X            numsk++;
  1860. X            taken |= inherits(mtmp, numsk, croaked);
  1861. X        }
  1862. X        }
  1863. X    }
  1864. X    if(numsk == 0) return(FALSE);
  1865. X    return(taken);
  1866. X}
  1867. X
  1868. Xstatic boolean
  1869. Xinherits(shkp, numsk, croaked)
  1870. Xregister struct monst *shkp;
  1871. Xregister int numsk;
  1872. Xregister boolean croaked;
  1873. X{
  1874. X    register long loss = 0L;
  1875. X    register struct obj *otmp;
  1876. X    register struct eshk *eshkp = ESHK(shkp);
  1877. X    register xchar ox, oy;
  1878. X    register boolean take = FALSE, taken = FALSE;
  1879. X    register int roomno = *u.ushops;
  1880. X
  1881. X    /* the simplifying principle is that first-come */
  1882. X    /* already took everything you had.        */
  1883. X    if(numsk > 1) {
  1884. X        if(cansee(shkp->mx, shkp->my) && croaked)
  1885. X        pline("%s %slooks at your corpse%s%s", Monnam(shkp),
  1886. X             (shkp->msleep || shkp->mfrozen) ?
  1887. X                   "wakes up, " : "",
  1888. X             !rn2(2) ? (shkp->female ? ", shakes her head," :
  1889. X                 ", shakes his head,") : "",
  1890. X             !inhishop(shkp) ? " and disappears. " : " and sighs.");
  1891. X        taken = (roomno == eshkp->shoproom);
  1892. X        goto skip;
  1893. X    }
  1894. X
  1895. X    /* get one case out of the way: you die in the shop, the */
  1896. X    /* shopkeeper is peaceful, nothing stolen, nothing owed. */
  1897. X    if(roomno == eshkp->shoproom && inhishop(shkp) &&
  1898. X        !IS_DOOR(levl[u.ux][u.uy].typ) && !eshkp->billct &&
  1899. X        !eshkp->robbed && !eshkp->debit &&
  1900. X         NOTANGRY(shkp) && !eshkp->following) {
  1901. X        if (invent)
  1902. X            pline("%s gratefully inherits all your possessions.",
  1903. X                shkname(shkp));
  1904. X        goto clear;
  1905. X    }
  1906. X
  1907. X    if (eshkp->billct || eshkp->debit || eshkp->robbed) {
  1908. X        register long total = 0L;
  1909. X
  1910. X        if(roomno == eshkp->shoproom && inhishop(shkp))
  1911. X            total = (addupbill(shkp) + eshkp->debit);
  1912. X        loss = ((total >= eshkp->robbed) ? total : eshkp->robbed);
  1913. X        take = TRUE;
  1914. X    }
  1915. X
  1916. X    if (eshkp->following || ANGRY(shkp) || take) {
  1917. X
  1918. X        if(!invent && !u.ugold) goto skip;
  1919. X
  1920. X        if((loss > u.ugold) || !loss) {
  1921. X            pline("%s %s%stakes all your possessions.",
  1922. X                shkname(shkp),
  1923. X                (shkp->msleep || shkp->mfrozen) ?
  1924. X                   "wakes up and " : "",
  1925. X                (distu(shkp->mx, shkp->my) > 2) ?
  1926. X                    "comes and " : "");
  1927. X            taken = TRUE;
  1928. X            shkp->mgold += u.ugold;
  1929. X            u.ugold = 0L;
  1930. X            /* in case bones: make it be for real... */
  1931. X            if(!*u.ushops ||
  1932. X                 IS_DOOR(levl[u.ux][u.uy].typ)) {
  1933. X                /* shk.x,shk.y is the position immediately in
  1934. X                 * front of the door -- move in one more space
  1935. X                 */
  1936. X                ox = eshkp->shk.x;
  1937. X                oy = eshkp->shk.y;
  1938. X                ox += sgn(ox - eshkp->shd.x);
  1939. X                oy += sgn(oy - eshkp->shd.y);
  1940. X            } else {
  1941. X                ox = u.ux;
  1942. X                oy = u.uy;
  1943. X            }
  1944. X
  1945. X            if (invent) {
  1946. X                for(otmp = invent; otmp; otmp = otmp->nobj)
  1947. X                place_object(otmp, ox, oy);
  1948. X
  1949. X                /* add to main object list at end so invent is
  1950. X                   still good */
  1951. X                if (fobj) {
  1952. X                otmp = fobj;
  1953. X                while(otmp->nobj)
  1954. X                    otmp = otmp->nobj;
  1955. X                otmp->nobj = invent;
  1956. X                } else
  1957. X                fobj = invent;
  1958. X            }
  1959. X        } else {
  1960. X            u.ugold -= loss;
  1961. X            shkp->mgold += loss;
  1962. X            pline("%s %sand takes %ld zorkmid%s %sowed %s.",
  1963. X                  Monnam(shkp),
  1964. X                  (shkp->msleep || shkp->mfrozen) ?
  1965. X                    "wakes up " : "comes ",
  1966. X                  loss, plur(loss),
  1967. X                  strncmp(eshkp->customer,
  1968. X                       plname, PL_NSIZ) ? "" : "you ",
  1969. X                  shkp->female ? "her" : "him");
  1970. X        }
  1971. Xskip:
  1972. X        /* in case we create bones */
  1973. X        if(!inhishop(shkp))
  1974. X            home_shk(shkp, FALSE);
  1975. X    }
  1976. Xclear:
  1977. X    setpaid(shkp);
  1978. X    return(taken);
  1979. X}
  1980. X
  1981. X/* find obj on one of the lists */
  1982. Xstatic struct obj *
  1983. Xbp_to_obj(bp)
  1984. Xregister struct bill_x *bp;
  1985. X{
  1986. X    register struct obj *obj;
  1987. X    register struct monst *mtmp;
  1988. X    register unsigned int id = bp->bo_id;
  1989. X
  1990. X    if(bp->useup)
  1991. X        obj = o_on(id, billobjs);
  1992. X    else if(!(obj = o_on(id, invent)) &&
  1993. X        !(obj = o_on(id, fobj)) &&
  1994. X        !(obj = o_on(id, migrating_objs))) {
  1995. X            for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  1996. X            if ((obj = o_on(id, mtmp->minvent)) != 0)
  1997. X                return obj;
  1998. X            for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
  1999. X            if ((obj = o_on(id, mtmp->minvent)) != 0)
  2000. X                return obj;
  2001. X        }
  2002. X    return(obj);
  2003. X}
  2004. X
  2005. X/* calculate the value that the shk will charge for [one of] an object */
  2006. Xstatic long
  2007. Xget_cost(obj, shkp)
  2008. Xregister struct obj *obj;
  2009. Xregister struct monst *shkp;    /* if angry, impose a surcharge */
  2010. X{
  2011. X    register long tmp = getprice(obj);
  2012. X
  2013. X    if (!tmp) tmp = 5L;
  2014. X    /* shopkeeper may notice if the player isn't very knowledgeable -
  2015. X       especially when gem prices are concerned */
  2016. X    if (!objects[obj->otyp].oc_name_known)
  2017. X        if (obj->oclass == GEM_CLASS) {
  2018. X            /* all gems are priced high - real or not */
  2019. X            if (objects[obj->otyp].oc_material == GLASS) {
  2020. X                /* real gem's cost (worthless gems come
  2021. X                   after jade but before luckstone) */
  2022. X                tmp = (long)objects[
  2023. X                    obj->otyp - LUCKSTONE + JADE + 1].oc_cost;
  2024. X            }
  2025. X        } else if (!(obj->o_id % 4)) /* arbitrarily impose surcharge */
  2026. X            tmp += tmp / 3L;
  2027. X#ifdef TOURIST
  2028. X    if((pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
  2029. X        || (uarmu && !uarm && !uarmc))    /* Hawaiian shirt visible */
  2030. X        tmp += tmp / 3L;
  2031. X#endif
  2032. X    if (ACURR(A_CHA) > 18)        tmp /= 2L;
  2033. X    else if (ACURR(A_CHA) > 17)    tmp -= tmp / 3L;
  2034. X    else if (ACURR(A_CHA) > 15)    tmp -= tmp / 4L;
  2035. X    else if (ACURR(A_CHA) < 6)    tmp *= 2L;
  2036. X    else if (ACURR(A_CHA) < 8)    tmp += tmp / 2L;
  2037. X    else if (ACURR(A_CHA) < 11)    tmp += tmp / 3L;
  2038. X    if (tmp <= 0L) tmp = 1L;
  2039. X    else if (obj->oartifact) tmp *= 4L;
  2040. X    /* anger surcharge should match rile_shk's */
  2041. X    if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L;
  2042. X    return tmp;
  2043. X}
  2044. X
  2045. X/* returns the price of a container's content.  the price
  2046. X * of the "top" container is added in the calling functions.
  2047. X * a different price quoted for selling as vs. buying.
  2048. X */
  2049. Xlong
  2050. Xcontained_cost(obj, shkp, price, usell)
  2051. Xregister struct obj *obj;
  2052. Xregister struct monst *shkp;
  2053. Xlong price;
  2054. Xregister boolean usell;
  2055. X{
  2056. X    register struct obj *otmp;
  2057. X
  2058. X    /* the price of contained objects */
  2059. X    for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
  2060. X        register boolean goods = saleable(rooms[ESHK(shkp)->shoproom -
  2061. X                       ROOMOFFSET].rtype-SHOPBASE, otmp);
  2062. X
  2063. X        if(otmp->otyp == GOLD_PIECE) continue;
  2064. X
  2065. X        /* the "top" container is evaluated by caller */
  2066. X        if(usell) {
  2067. X        if(goods && !otmp->unpaid &&
  2068. X            otmp->oclass != BALL_CLASS &&
  2069. X            !(otmp->oclass == FOOD_CLASS && otmp->oeaten) &&
  2070. X            !(Is_candle(otmp) && otmp->age <
  2071. X                20L * (long)objects[otmp->otyp].oc_cost))
  2072. X            price += set_cost(otmp, shkp);
  2073. X        } else if(!otmp->no_charge) {
  2074. X            price += get_cost(otmp, shkp);
  2075. X        }
  2076. X
  2077. X        if(Is_container(otmp))
  2078. X            price += contained_cost(otmp, shkp, price, usell);
  2079. X    }
  2080. X
  2081. X    return(price);
  2082. X}
  2083. X
  2084. Xlong
  2085. Xcontained_gold(obj)
  2086. Xregister struct obj *obj;
  2087. X{
  2088. X    register struct obj *otmp;
  2089. X    register long value = 0L;
  2090. X
  2091. X    /* accumulate contained gold */
  2092. X    for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
  2093. X        if (otmp->otyp == GOLD_PIECE)
  2094. X        value += otmp->quan;
  2095. X        else if (Is_container(otmp))
  2096. X        value += contained_gold(otmp);
  2097. X
  2098. X    return(value);
  2099. X}
  2100. X
  2101. Xstatic void
  2102. Xdropped_container(obj)
  2103. Xregister struct obj *obj;
  2104. X{
  2105. X    register struct obj *otmp;
  2106. X
  2107. X    /* the "top" container is treated in the calling fn */
  2108. X    for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
  2109. X
  2110. X        if(otmp->otyp == GOLD_PIECE) continue;
  2111. X
  2112. X        if(!otmp->unpaid)
  2113. X        otmp->no_charge = 1;
  2114. X
  2115. X        if(Is_container(otmp))
  2116. X        dropped_container(otmp);
  2117. X    }
  2118. X}
  2119. X
  2120. Xvoid
  2121. Xpicked_container(obj)
  2122. Xregister struct obj *obj;
  2123. X{
  2124. X    register struct obj *otmp;
  2125. X
  2126. X    /* the "top" container is treated in the calling fn */
  2127. X    for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
  2128. X
  2129. X        if(otmp->otyp == GOLD_PIECE) continue;
  2130. X
  2131. X        if(otmp->no_charge)
  2132. X        otmp->no_charge = 0;
  2133. X
  2134. X        if(Is_container(otmp))
  2135. X        picked_container(otmp);
  2136. X    }
  2137. X}
  2138. X
  2139. X/* calculate how much the shk will pay when buying [all of] an object */
  2140. Xstatic long
  2141. Xset_cost(obj, shkp)
  2142. Xregister struct obj *obj;
  2143. Xregister struct monst *shkp;
  2144. X{
  2145. X    long tmp = getprice(obj) * obj->quan;
  2146. X
  2147. X#ifdef TOURIST
  2148. X    if ((pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
  2149. X        || (uarmu && !uarm && !uarmc))    /* Hawaiian shirt visible */
  2150. X        tmp /= 3L;
  2151. X    else
  2152. X#endif
  2153. X        tmp /= 2L;
  2154. X    /* shopkeeper may notice if the player isn't very knowledgeable -
  2155. X       especially when gem prices are concerned */
  2156. X    if (!objects[obj->otyp].oc_name_known) {
  2157. X        if (obj->oclass == GEM_CLASS) {
  2158. X            /* different shop keepers give different prices */
  2159. X            if (objects[obj->otyp].oc_material == GEMSTONE ||
  2160. X                objects[obj->otyp].oc_material == GLASS) {
  2161. X                tmp = (obj->otyp % (6 - shkp->m_id % 3));
  2162. X                tmp = (tmp + 3) * obj->quan;
  2163. X            }
  2164. X        } else if (tmp > 1L && !rn2(4))
  2165. X            tmp -= tmp / 4L;
  2166. X    }
  2167. X    return tmp;
  2168. X}
  2169. X
  2170. X/* called from doinv(invent.c) for inventory of unpaid objects */
  2171. Xlong
  2172. Xunpaid_cost(unp_obj)
  2173. Xregister struct obj *unp_obj;    /* known to be unpaid */
  2174. X{
  2175. X    register struct bill_x *bp = (struct bill_x *)0;
  2176. X    register struct monst *shkp;
  2177. X
  2178. X    for(shkp = next_shkp(fmon, TRUE); shkp;
  2179. X                    shkp = next_shkp(shkp->nmon, TRUE))
  2180. X        if ((bp = onbill(unp_obj, shkp, TRUE)) != 0) break;
  2181. X
  2182. X    /* onbill() gave no message if unexpected problem occurred */
  2183. X    if(!bp) impossible("unpaid_cost: object wasn't on any bill!");
  2184. X
  2185. X    return bp ? unp_obj->quan * bp->price : 0L;
  2186. X}
  2187. X
  2188. END_OF_FILE
  2189. if test 37947 -ne `wc -c <'src/shk.c1'`; then
  2190.     echo shar: \"'src/shk.c1'\" unpacked with wrong size!
  2191. fi
  2192. # end of 'src/shk.c1'
  2193. fi
  2194. echo shar: End of archive 47 \(of 108\).
  2195. cp /dev/null ark47isdone
  2196. MISSING=""
  2197. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
  2198. 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
  2199. 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
  2200. 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
  2201. 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
  2202. 101 102 103 104 105 106 107 108 ; do
  2203.     if test ! -f ark${I}isdone ; then
  2204.     MISSING="${MISSING} ${I}"
  2205.     fi
  2206. done
  2207. if test "${MISSING}" = "" ; then
  2208.     echo You have unpacked all 108 archives.
  2209.     echo "Now execute 'rebuild.sh'"
  2210.     rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
  2211. else
  2212.     echo You still need to unpack the following archives:
  2213.     echo "        " ${MISSING}
  2214. fi
  2215. ##  End of shell archive.
  2216. exit 0
  2217.