home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!news.tek.com!master!saab!billr
- From: billr@saab.CNA.TEK.COM (Bill Randle)
- Newsgroups: comp.sources.games
- Subject: v16i055: nethack31 - display oriented dungeons & dragons (Ver. 3.1), Part47/108
- Message-ID: <4349@master.CNA.TEK.COM>
- Date: 30 Jan 93 01:14:23 GMT
- Sender: news@master.CNA.TEK.COM
- Lines: 2205
- Approved: billr@saab.CNA.TEK.COM
- Xref: uunet comp.sources.games:1604
-
- Submitted-by: izchak@linc.cis.upenn.edu (Izchak Miller)
- Posting-number: Volume 16, Issue 55
- Archive-name: nethack31/Part47
- Supersedes: nethack3p9: Volume 10, Issue 46-102
- Environment: Amiga, Atari, Mac, MS-DOS, OS2, Unix, VMS, X11
-
-
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 47 (of 108)."
- # Contents: src/pager.c src/shk.c1
- # Wrapped by billr@saab on Wed Jan 27 16:09:04 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'src/pager.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/pager.c'\"
- else
- echo shar: Extracting \"'src/pager.c'\" \(16869 characters\)
- sed "s/^X//" >'src/pager.c' <<'END_OF_FILE'
- X/* SCCS Id: @(#)pager.c 3.1 92/09/01 */
- X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
- X/* NetHack may be freely redistributed. See license for details. */
- X
- X/* This file contains the command routines dowhatis() and dohelp() and */
- X/* a few other help related facilities */
- X
- X#include "hack.h"
- X
- X#ifndef SEEK_SET
- X#define SEEK_SET 0
- X#endif
- X
- Xstatic boolean FDECL(is_swallow_sym, (UCHAR_P));
- Xstatic int FDECL(append_str, (char *, const char *));
- Xstatic void FDECL(lookat, (int, int, char *));
- Xstatic void FDECL(checkfile, (char *, BOOLEAN_P));
- Xstatic int FDECL(do_look, (BOOLEAN_P));
- Xstatic char NDECL(help_menu);
- X#ifdef PORT_HELP
- Xextern void NDECL(port_help);
- X#endif
- X
- X/* Returns "true" for characters that could represent a monster's stomach. */
- Xstatic boolean
- Xis_swallow_sym(c)
- X uchar c;
- X{
- X int i;
- X for (i = S_sw_tl; i <= S_sw_br; i++)
- X if (showsyms[i] == c) return TRUE;
- X return FALSE;
- X}
- X
- X/*
- X * Append new_str to the end of buf if new_str doesn't already exist as
- X * a substring of buf. Return 1 if the string was appended, 0 otherwise.
- X * It is expected that buf is of size BUFSZ.
- X */
- Xstatic int
- Xappend_str(buf, new_str)
- X char *buf;
- X const char *new_str;
- X{
- X int space_left; /* space remaining in buf */
- X
- X if (strstri(buf, new_str)) return 0;
- X
- X space_left = BUFSZ - strlen(buf) - 1;
- X (void) strncat(buf, " or ", space_left);
- X (void) strncat(buf, new_str, space_left - 4);
- X return 1;
- X}
- X
- X/*
- X * Return the name of the glyph found at (x,y).
- X */
- Xstatic void
- Xlookat(x, y, buf)
- X int x, y;
- X char *buf;
- X{
- X register struct monst *mtmp;
- X struct trap *trap;
- X register char *s, *t;
- X int glyph;
- X
- X buf[0] = 0;
- X glyph = glyph_at(x,y);
- X if (u.ux == x && u.uy == y && canseeself()) {
- X Sprintf(buf, "%s called %s",
- X#ifdef POLYSELF
- X u.mtimedone ? mons[u.umonnum].mname :
- X#endif
- X player_mon()->mname, plname);
- X }
- X else if (u.uswallow) {
- X /* all locations when swallowed other than the hero are the monster */
- X Sprintf(buf, "interior of %s",
- X Blind ? "a monster" : a_monnam(u.ustuck));
- X }
- X else if (glyph_is_monster(glyph)) {
- X bhitpos.x = x;
- X bhitpos.y = y;
- X mtmp = m_at(x,y);
- X if(mtmp != (struct monst *) 0) {
- X register boolean hp = (mtmp->data == &mons[PM_HIGH_PRIEST]);
- X
- X Sprintf(buf, "%s%s%s",
- X (!hp && mtmp->mtame && !Hallucination) ? "tame " :
- X (!hp && mtmp->mpeaceful && !Hallucination) ?
- X "peaceful " : "",
- X (hp ? "high priest" : l_monnam(mtmp)),
- X u.ustuck == mtmp ?
- X#ifdef POLYSELF
- X (u.mtimedone ? ", being held" :
- X#endif
- X ", holding you"
- X#ifdef POLYSELF
- X )
- X#endif
- X : "");
- X }
- X }
- X else if (glyph_is_object(glyph)) {
- X struct obj *otmp = vobj_at(x,y);
- X
- X if(otmp == (struct obj *) 0 || otmp->otyp != glyph_to_obj(glyph)) {
- X if(glyph_to_obj(glyph) != STRANGE_OBJECT) {
- X otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE);
- X if(otmp->oclass == GOLD_CLASS)
- X otmp->quan = 2L; /* to force pluralization */
- X Strcpy(buf, distant_name(otmp, xname));
- X dealloc_obj(otmp);
- X }
- X } else
- X Strcpy(buf, distant_name(otmp, xname));
- X }
- X else if (glyph_is_trap(glyph)) {
- X if (trap = t_at(x, y)) {
- X if (trap->ttyp == WEB)
- X Strcpy(buf, "web");
- X else {
- X Strcpy(buf, traps[ Hallucination ?
- X rn2(TRAPNUM-3)+3 : trap->ttyp]);
- X /* strip leading garbage */
- X for (s = buf; *s && *s != ' '; s++) ;
- X if (*s) ++s;
- X for (t = buf; *t++ = *s++; ) ;
- X }
- X }
- X }
- X else if(!glyph_is_cmap(glyph))
- X Strcpy(buf,"dark part of a room");
- X else switch(glyph_to_cmap(glyph)) {
- X case S_altar:
- X if(!In_endgame(&u.uz))
- X Sprintf(buf, "%s altar",
- X align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE)));
- X else Sprintf(buf, "aligned altar");
- X break;
- X case S_ndoor:
- X if((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN)
- X Strcpy(buf,"broken door");
- X else
- X Strcpy(buf,"doorway");
- X break;
- X default:
- X Strcpy(buf,defsyms[glyph_to_cmap(glyph)].explanation);
- X break;
- X }
- X}
- X
- X/*
- X * Look in the "data" file for more info. Called if the user typed in the
- X * whole name (user_typed_name == TRUE), or we've found a possible match
- X * with a character/glyph and flags.help is TRUE.
- X *
- X * NOTE: when (user_typed_name == FALSE), inp is considered read-only and
- X * must not be changed directly, e.g. via lcase(). Permitted are
- X * functions, e.g. makesingular(), which operate on a copy of inp.
- X */
- Xstatic void
- Xcheckfile(inp, user_typed_name)
- X char *inp;
- X boolean user_typed_name;
- X{
- X FILE *fp;
- X char buf[BUFSZ];
- X char *ep;
- X long txt_offset;
- X boolean found_in_file = FALSE;
- X
- X fp = fopen_datafile(DATAFILE, "r");
- X if (!fp) {
- X pline("Cannot open data file!");
- X return;
- X }
- X
- X if (!strncmp(inp, "interior of ", 12))
- X inp += 12;
- X if (!strncmp(inp, "a ", 2))
- X inp += 2;
- X else if (!strncmp(inp, "an ", 3))
- X inp += 3;
- X else if (!strncmp(inp, "the ", 4))
- X inp += 4;
- X if (!strncmp(inp, "tame ", 5))
- X inp += 5;
- X else if (!strncmp(inp, "peaceful ", 9))
- X inp += 9;
- X if (!strncmp(inp, "invisible ", 10))
- X inp += 10;
- X
- X /* Make sure the name is non-empty. */
- X if (*inp) {
- X /* adjust the input to remove "named " and convert to lower case */
- X char *alt = 0; /* alternate description */
- X if ((ep = strstri(inp, " named ")) != 0)
- X alt = ep + 7;
- X else
- X ep = strstri(inp, " called ");
- X if (ep) *ep = '\0';
- X if (user_typed_name)
- X (void) lcase(inp);
- X
- X /*
- X * If the object is named, then the name is the alternate description;
- X * otherwise, the result of makesingular() applied to the name is. This
- X * isn't strictly optimal, but named objects of interest to the user
- X * will usually be found under their name, rather than under their
- X * object type, so looking for a singular form is pointless.
- X */
- X
- X if (!alt)
- X alt = makesingular(inp);
- X else
- X if (user_typed_name)
- X (void) lcase(alt);
- X
- X /* skip first record; read second */
- X txt_offset = 0L;
- X if (!fgets(buf, BUFSZ, fp) || !fgets(buf, BUFSZ, fp)) {
- X impossible("can't read 'data' file");
- X (void) fclose(fp);
- X return;
- X } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0)
- X goto bad_data_file;
- X
- X /* look for the appropriate entry */
- X while (fgets(buf,BUFSZ,fp)) {
- X if (*buf == '.') break; /* we passed last entry without success */
- X
- X if (!digit(*buf)) {
- X if (!(ep = index(buf, '\n'))) goto bad_data_file;
- X *ep = 0;
- X if (pmatch(buf, inp) || (alt && pmatch(buf, alt))) {
- X found_in_file = TRUE;
- X break;
- X }
- X }
- X }
- X }
- X
- X if(found_in_file) {
- X long entry_offset;
- X int entry_count;
- X int i;
- X
- X /* skip over other possible matches for the info */
- X do {
- X if (!fgets(buf, BUFSZ, fp)) goto bad_data_file;
- X } while (!digit(*buf));
- X if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) {
- Xbad_data_file: impossible("'data' file in wrong format");
- X (void) fclose(fp);
- X return;
- X }
- X
- X if (user_typed_name || yn("More info?") == 'y') {
- X winid datawin;
- X
- X if (fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) {
- X pline("? Seek error on 'data' file!");
- X (void) fclose(fp);
- X return;
- X }
- X datawin = create_nhwindow(NHW_TEXT);
- X for (i = 0; i < entry_count; i++) {
- X if (!fgets(buf, BUFSZ, fp)) goto bad_data_file;
- X if ((ep = index(buf, '\n')) != 0) *ep = 0;
- X if (index(buf+1, '\t') != 0) (void) tabexpand(buf+1);
- X putstr(datawin, 0, buf+1);
- X }
- X display_nhwindow(datawin, FALSE);
- X destroy_nhwindow(datawin);
- X }
- X } else if (user_typed_name)
- X pline("I don't have any information on those things.");
- X
- X (void) fclose(fp);
- X}
- X
- Xstatic int
- Xdo_look(quick)
- X boolean quick; /* use cursor && don't search for "more info" */
- X{
- X char out_str[BUFSZ], look_buf[BUFSZ];
- X const char *firstmatch = 0;
- X int i;
- X int sym; /* typed symbol or converted glyph */
- X int found; /* count of matching syms found */
- X coord cc; /* screen pos of unknown glyph */
- X boolean save_verbose; /* saved value of flags.verbose */
- X boolean from_screen; /* question from the screen */
- X boolean need_to_look; /* need to get explan. from glyph */
- X static const char *mon_interior = "the interior of a monster";
- X
- X#ifdef GCC_WARN
- X sym = 0;
- X#endif
- X
- X if (quick) {
- X from_screen = TRUE; /* yes, we want to use the cursor */
- X } else {
- X i = ynq("Specify unknown object by cursor?");
- X if (i == 'q') return 0;
- X from_screen = (i == 'y');
- X }
- X
- X if (from_screen) {
- X cc.x = u.ux;
- X cc.y = u.uy;
- X } else {
- X getlin("Specify what? (type the word)", out_str);
- X if (out_str[0] == '\033')
- X return 0;
- X
- X if (out_str[1]) { /* user typed in a complete string */
- X checkfile(out_str, TRUE);
- X return 0;
- X }
- X sym = out_str[0];
- X }
- X
- X /* Save the verbose flag, we change it later. */
- X save_verbose = flags.verbose;
- X flags.verbose = flags.verbose && !quick;
- X /*
- X * The user typed one letter, or we're identifying from the screen.
- X */
- X do {
- X /* Reset some variables. */
- X need_to_look = FALSE;
- X found = 0;
- X out_str[0] = '\0';
- X
- X if (from_screen) {
- X int glyph; /* glyph at selected position */
- X
- X if (flags.verbose)
- X pline("Please move the cursor to an unknown object.");
- X else
- X pline("Pick an object.");
- X
- X getpos(&cc, FALSE, "an unknown object");
- X if (cc.x < 0) {
- X flags.verbose = save_verbose;
- X return 0; /* done */
- X }
- X flags.verbose = FALSE; /* only print long question once */
- X
- X /* Convert the glyph at the selected position to a symbol. */
- X glyph = glyph_at(cc.x,cc.y);
- X if (glyph_is_cmap(glyph)) {
- X sym = showsyms[glyph_to_cmap(glyph)];
- X } else if (glyph_is_trap(glyph)) {
- X sym = showsyms[(glyph_to_trap(glyph) == WEB) ? S_web : S_trap];
- X } else if (glyph_is_object(glyph)) {
- X sym = oc_syms[objects[glyph_to_obj(glyph)].oc_class];
- X } else if (glyph_is_monster(glyph)) {
- X sym = monsyms[mons[glyph_to_mon(glyph)].mlet];
- X } else if (glyph_is_swallow(glyph)) {
- X sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl];
- X } else {
- X impossible("do_look: bad glyph %d at (%d,%d)",
- X glyph, (int)cc.x, (int)cc.y);
- X sym = ' ';
- X }
- X }
- X
- X /*
- X * Check all the possibilities, saving all explanations in a buffer.
- X * When all have been checked then the string is printed.
- X */
- X
- X /* Check for monsters */
- X for (i = 0; i < MAXMCLASSES; i++) {
- X if (sym == (from_screen ? monsyms[i] : def_monsyms[i])) {
- X need_to_look = TRUE;
- X if (!found) {
- X Sprintf(out_str, "%c %s", sym, an(monexplain[i]));
- X firstmatch = monexplain[i];
- X found++;
- X } else {
- X found += append_str(out_str, an(monexplain[i]));
- X }
- X }
- X }
- X
- X /*
- X * Special case: if identifying from the screen, and we're swallowed,
- X * and looking at something other than our own symbol, then just say
- X * "the interior of a monster".
- X */
- X if (u.uswallow && from_screen && is_swallow_sym((uchar) sym)) {
- X if (!found) {
- X Sprintf(out_str, "%c %s", sym, mon_interior);
- X firstmatch = mon_interior;
- X } else {
- X found += append_str(out_str, mon_interior);
- X }
- X need_to_look = TRUE;
- X }
- X
- X /* Now check for objects */
- X for (i = 1; i < MAXOCLASSES; i++) {
- X if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) {
- X need_to_look = TRUE;
- X if (!found) {
- X Sprintf(out_str, "%c %s", sym, an(objexplain[i]));
- X firstmatch = objexplain[i];
- X found++;
- X } else {
- X found += append_str(out_str, an(objexplain[i]));
- X }
- X }
- X }
- X
- X /* Now check for graphics symbols */
- X for (i = 0; i < MAXPCHARS; i++) {
- X if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) &&
- X (*defsyms[i].explanation)) {
- X if (!found) {
- X Sprintf(out_str, "%c %s",
- X sym, an(defsyms[i].explanation));
- X firstmatch = defsyms[i].explanation;
- X found++;
- X } else if (!u.uswallow) {
- X found += append_str(out_str, an(defsyms[i].explanation));
- X }
- X
- X if (i == S_altar || i == S_trap || i == S_web)
- X need_to_look = TRUE;
- X }
- X }
- X
- X /*
- X * If we are looking at the screen, follow multiple posibilities or
- X * an ambigious explanation by something more detailed.
- X */
- X if (from_screen) {
- X if (found > 1 || need_to_look) {
- X lookat(cc.x, cc.y, look_buf);
- X firstmatch = look_buf;
- X if (*firstmatch) {
- X char temp_buf[BUFSZ];
- X Sprintf(temp_buf, " (%s)", firstmatch);
- X (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1);
- X found = 1; /* we have something to look up */
- X }
- X }
- X }
- X
- X /* Finally, print out our explanation. */
- X if (found) {
- X pline(out_str);
- X /* check the data file for information about this thing */
- X if (found == 1 && !quick && flags.help) {
- X char temp_buf[BUFSZ];
- X Strcpy(temp_buf, firstmatch);
- X checkfile(temp_buf, FALSE);
- X }
- X } else {
- X pline("I've never heard of such things.");
- X }
- X
- X } while (from_screen && !quick);
- X
- X flags.verbose = save_verbose;
- X return 0;
- X}
- X
- X
- Xint
- Xdowhatis()
- X{
- X return do_look(FALSE);
- X}
- X
- Xint
- Xdoquickwhatis()
- X{
- X return do_look(TRUE);
- X}
- X
- Xint
- Xdoidtrap()
- X{
- X register struct trap *trap;
- X register int x,y;
- X
- X if(!getdir(NULL)) return 0;
- X x = u.ux + u.dx;
- X y = u.uy + u.dy;
- X for(trap = ftrap; trap; trap = trap->ntrap)
- X if(trap->tx == x && trap->ty == y && trap->tseen) {
- X if(u.dz) {
- X if(u.dz < 0 && trap->ttyp == TRAPDOOR)
- X continue;
- X if(u.dz > 0 && trap->ttyp == ROCKTRAP)
- X continue;
- X }
- X pline("That is a%s.",
- X traps[ Hallucination ? rn1(TRAPNUM-3, 3) :
- X trap->ttyp]);
- X return 0;
- X }
- X pline("I can't see a trap there.");
- X return 0;
- X}
- X
- Xint
- Xdowhatdoes()
- X{
- X FILE *fp;
- X char bufr[BUFSZ+6];
- X register char *buf = &bufr[6], *ep, q, ctrl, meta;
- X
- X fp = fopen_datafile(CMDHELPFILE, "r");
- X if (!fp) {
- X pline("Cannot open data file!");
- X return 0;
- X }
- X
- X#if defined(UNIX) || defined(VMS)
- X introff();
- X#endif
- X q = yn_function("What command?", NULL, '\0');
- X#if defined(UNIX) || defined(VMS)
- X intron();
- X#endif
- X ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
- X meta = ((0x80 & q) ? (0x7f & q) : 0);
- X while(fgets(buf,BUFSZ,fp))
- X if ((ctrl && *buf=='^' && *(buf+1)==ctrl) ||
- X (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) ||
- X *buf==q) {
- X ep = index(buf, '\n');
- X if(ep) *ep = 0;
- X if (ctrl && buf[2] == '\t'){
- X buf = bufr + 1;
- X (void) strncpy(buf, "^? ", 8);
- X buf[1] = ctrl;
- X } else if (meta && buf[3] == '\t'){
- X buf = bufr + 2;
- X (void) strncpy(buf, "M-? ", 8);
- X buf[2] = meta;
- X } else if(buf[1] == '\t'){
- X buf = bufr;
- X buf[0] = q;
- X (void) strncpy(buf+1, " ", 7);
- X }
- X pline("%s", buf);
- X (void) fclose(fp);
- X return 0;
- X }
- X pline("I've never heard of such commands.");
- X (void) fclose(fp);
- X return 0;
- X}
- X
- X/* data for help_menu() */
- Xstatic const char *help_menu_items[] = {
- X "Information available:",
- X "",
- X "a. Long description of the game and commands.",
- X "b. List of game commands.",
- X "c. Concise history of NetHack.",
- X "d. Info on a character in the game display.",
- X "e. Info on what a given key does.",
- X "f. List of game options.",
- X "g. Longer explanation of game options.",
- X "h. List of extended commands.",
- X "i. The NetHack license.",
- X#ifdef PORT_HELP
- X "j. %s-specific help and commands.",
- X#endif
- X#ifdef WIZARD
- X# ifdef PORT_HELP
- X# define WIZHLP_SLOT 12 /* assumed to be next to last by code below */
- X "k. List of wizard-mode commands.",
- X# else
- X# define WIZHLP_SLOT 11 /* assumed to be next to last by code below */
- X "j. List of wizard-mode commands.",
- X# endif
- X#endif
- X "",
- X NULL
- X};
- X
- Xstatic char
- Xhelp_menu()
- X{
- X winid tmpwin = create_nhwindow(NHW_MENU);
- X#ifdef PORT_HELP
- X char helpbuf[QBUFSZ];
- X#endif
- X char hc;
- X register int i;
- X
- X start_menu(tmpwin);
- X#ifdef WIZARD
- X if (!wizard) help_menu_items[WIZHLP_SLOT] = "",
- X help_menu_items[WIZHLP_SLOT+1] = NULL;
- X#endif
- X for (i = 0; help_menu_items[i]; i++)
- X#ifdef PORT_HELP
- X /* port-specific line has a %s in it for the PORT_ID */
- X if (index(help_menu_items[i], '%')) {
- X Sprintf(helpbuf, help_menu_items[i], PORT_ID);
- X add_menu(tmpwin, helpbuf[0], 0, helpbuf);
- X } else
- X#endif
- X {
- X add_menu(tmpwin, i ? *help_menu_items[i] : 0, 0,
- X help_menu_items[i]);
- X }
- X end_menu(tmpwin, '\033', "\033", "Select one item or ESC: ");
- X hc = select_menu(tmpwin);
- X destroy_nhwindow(tmpwin);
- X return hc;
- X}
- X
- Xint
- Xdohelp()
- X{
- X char hc = help_menu();
- X if (!index(quitchars, hc)) {
- X switch(hc) {
- X case 'a': display_file(HELP, TRUE); break;
- X case 'b': display_file(SHELP, TRUE); break;
- X case 'c': (void) dohistory(); break;
- X case 'd': (void) dowhatis(); break;
- X case 'e': (void) dowhatdoes(); break;
- X case 'f': option_help(); break;
- X case 'g': display_file(OPTIONFILE, TRUE); break;
- X case 'h': (void) doextlist(); break;
- X case 'i': display_file(LICENSE, TRUE); break;
- X#ifdef PORT_HELP
- X case 'j': port_help(); break;
- X# ifdef WIZARD
- X case 'k': display_file(DEBUGHELP, TRUE); break;
- X# endif
- X#else
- X# ifdef WIZARD
- X case 'j': display_file(DEBUGHELP, TRUE); break;
- X# endif
- X#endif
- X }
- X }
- X return 0;
- X}
- X
- Xint
- Xdohistory()
- X{
- X display_file(HISTORY, TRUE);
- X return 0;
- X}
- X
- X/*pager.c*/
- END_OF_FILE
- if test 16869 -ne `wc -c <'src/pager.c'`; then
- echo shar: \"'src/pager.c'\" unpacked with wrong size!
- fi
- # end of 'src/pager.c'
- fi
- if test -f 'src/shk.c1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'src/shk.c1'\"
- else
- echo shar: Extracting \"'src/shk.c1'\" \(37947 characters\)
- sed "s/^X//" >'src/shk.c1' <<'END_OF_FILE'
- X/* SCCS Id: @(#)shk.c 3.1 93/01/12 */
- X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
- X/* NetHack may be freely redistributed. See license for details. */
- X
- X#include "hack.h"
- X#include "eshk.h"
- X
- X/*#define DEBUG*/
- X
- X#define PAY_SOME 2
- X#define PAY_BUY 1
- X#define PAY_CANT 0 /* too poor */
- X#define PAY_SKIP (-1)
- X#define PAY_BROKE (-2)
- X
- X#ifdef KOPS
- XSTATIC_DCL void FDECL(makekops, (coord *));
- XSTATIC_DCL void FDECL(call_kops, (struct monst *,BOOLEAN_P));
- X# ifdef OVLB
- Xstatic void FDECL(kops_gone, (BOOLEAN_P));
- X# endif /* OVLB */
- X#endif /* KOPS */
- X
- X#define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE)
- X
- Xextern const struct shclass shtypes[]; /* defined in shknam.c */
- X
- XSTATIC_VAR long int NEARDATA followmsg; /* last time of follow message */
- X
- XSTATIC_DCL void FDECL(setpaid, (struct monst *));
- XSTATIC_DCL long FDECL(addupbill, (struct monst *));
- XSTATIC_DCL void FDECL(pacify_shk, (struct monst *));
- X
- X#ifdef OVLB
- X
- Xstatic void FDECL(clear_unpaid,(struct obj *));
- Xstatic struct bill_x *FDECL(onbill, (struct obj *, struct monst *, BOOLEAN_P));
- Xstatic long FDECL(check_credit, (long, struct monst *));
- Xstatic void FDECL(pay, (long, struct monst *));
- Xstatic long FDECL(get_cost, (struct obj *, struct monst *));
- Xstatic long FDECL(set_cost, (struct obj *, struct monst *));
- Xstatic const char *FDECL(shk_embellish, (struct obj *, long));
- Xstatic long FDECL(cost_per_charge, (struct obj *));
- Xstatic long FDECL(cheapest_item, (struct monst *));
- Xstatic int FDECL(dopayobj, (struct monst *, struct bill_x *,
- X struct obj *, int, BOOLEAN_P));
- Xstatic long FDECL(stolen_container, (struct obj *, struct monst *, long,
- X BOOLEAN_P));
- Xstatic long FDECL(getprice, (struct obj *));
- Xstatic struct obj *FDECL(bp_to_obj, (struct bill_x *));
- Xstatic boolean FDECL(inherits, (struct monst *, int, BOOLEAN_P));
- Xstatic struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P));
- Xstatic boolean NDECL(angry_shk_exists);
- Xstatic void FDECL(rile_shk, (struct monst *));
- Xstatic void FDECL(remove_damage, (struct monst *, BOOLEAN_P));
- Xstatic void FDECL(sub_one_frombill, (struct obj *, struct monst *));
- Xstatic void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P));
- Xstatic void FDECL(dropped_container, (struct obj *));
- Xstatic void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P,
- X struct monst *));
- X
- X/*
- X invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
- X obj->quan <= bp->bquan
- X */
- X
- Xstatic struct monst *
- Xnext_shkp(shkp, withbill)
- Xregister struct monst *shkp;
- Xregister boolean withbill;
- X{
- X for (; shkp; shkp = shkp->nmon)
- X if (shkp->isshk)
- X if (ESHK(shkp)->billct || !withbill) break;
- X
- X if (shkp) {
- X if (NOTANGRY(shkp)) {
- X if (ESHK(shkp)->surcharge) pacify_shk(shkp);
- X } else {
- X if (!ESHK(shkp)->surcharge) rile_shk(shkp);
- X }
- X }
- X return(shkp);
- X}
- X
- Xchar *
- Xshkname(mtmp) /* called in do_name.c */
- Xregister struct monst *mtmp;
- X{
- X return(ESHK(mtmp)->shknam);
- X}
- X
- Xvoid
- Xshkgone(mtmp) /* called in mon.c */
- Xregister struct monst *mtmp;
- X{
- X register struct eshk *eshk = ESHK(mtmp);
- X
- X if(on_level(&(eshk->shoplevel), &u.uz)) {
- X remove_damage(mtmp, TRUE);
- X rooms[eshk->shoproom - ROOMOFFSET].resident
- X = (struct monst *)0;
- X if(!search_special(ANY_SHOP))
- X level.flags.has_shop = 0;
- X }
- X /* make sure bill is set only when the
- X * dead shk is the resident shk. */
- X if(*u.ushops == eshk->shoproom) {
- X setpaid(mtmp);
- X /* dump core when referenced */
- X ESHK(mtmp)->bill_p = (struct bill_x *) -1000;
- X u.ushops[0] = '\0';
- X }
- X}
- X
- Xvoid
- Xset_residency(shkp, zero_out)
- Xregister struct monst *shkp;
- Xregister boolean zero_out;
- X{
- X if (on_level(&(ESHK(shkp)->shoplevel), &u.uz))
- X rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident =
- X (zero_out)? (struct monst *)0 : shkp;
- X}
- X
- Xvoid
- Xreplshk(mtmp,mtmp2)
- Xregister struct monst *mtmp, *mtmp2;
- X{
- X if(inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) {
- X ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]);
- X }
- X}
- X
- X/* do shopkeeper specific structure munging -dlc */
- Xvoid
- Xrestshk(mtmp)
- Xregister struct monst *mtmp;
- X{
- X if(ESHK(mtmp)->bill_p != (struct bill_x *) -1000)
- X ESHK(mtmp)->bill_p = &(ESHK(mtmp)->bill[0]);
- X}
- X
- X/* Clear the unpaid bit on all of the objects in the list. */
- Xstatic void
- Xclear_unpaid(list)
- Xregister struct obj *list;
- X{
- X while (list) {
- X if (Is_container(list)) clear_unpaid(list->cobj);
- X list->unpaid = 0;
- X list = list->nobj;
- X }
- X}
- X
- XSTATIC_OVL void
- Xsetpaid(shkp) /* either you paid or left the shop or the shopkeeper died */
- Xregister struct monst *shkp;
- X{
- X register struct obj *obj;
- X register struct monst *mtmp;
- X
- X clear_unpaid(invent);
- X clear_unpaid(fobj);
- X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- X clear_unpaid(mtmp->minvent);
- X for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
- X clear_unpaid(mtmp->minvent);
- X
- X while ((obj = billobjs) != 0) {
- X billobjs = obj->nobj;
- X dealloc_obj(obj);
- X }
- X if(shkp) {
- X ESHK(shkp)->billct = 0;
- X ESHK(shkp)->credit = 0L;
- X ESHK(shkp)->debit = 0L;
- X ESHK(shkp)->loan = 0L;
- X }
- X}
- X
- XSTATIC_OVL long
- Xaddupbill(shkp)
- Xregister struct monst *shkp;
- X{
- X register int ct = ESHK(shkp)->billct;
- X register struct bill_x *bp = ESHK(shkp)->bill_p;
- X register long total = 0L;
- X
- X while(ct--){
- X total += bp->price * bp->bquan;
- X bp++;
- X }
- X return(total);
- X}
- X
- X#endif /* OVLB */
- X#ifdef OVL1
- X
- X#ifdef KOPS
- XSTATIC_OVL void
- Xcall_kops(shkp, nearshop)
- Xregister struct monst *shkp;
- Xregister boolean nearshop;
- X{
- X /* Keystone Kops srt@ucla */
- X register boolean nokops;
- X
- X if(!shkp) return;
- X
- X if (flags.soundok)
- X pline("An alarm sounds!");
- X
- X nokops = ((mons[PM_KEYSTONE_KOP].geno & (G_GENOD | G_EXTINCT)) &&
- X (mons[PM_KOP_SERGEANT].geno & (G_GENOD | G_EXTINCT)) &&
- X (mons[PM_KOP_LIEUTENANT].geno & (G_GENOD | G_EXTINCT)) &&
- X (mons[PM_KOP_KAPTAIN].geno & (G_GENOD | G_EXTINCT)));
- X
- X if(!angry_guards(!flags.soundok) && nokops) {
- X if(flags.verbose && flags.soundok)
- X pline("But no one seems to respond to it.");
- X return;
- X }
- X
- X if(nokops) return;
- X
- X {
- X coord mm;
- X
- X if (nearshop) {
- X /* Create swarm around you, if you merely "stepped out" */
- X if (flags.verbose)
- X pline("The Keystone Kops appear!");
- X mm.x = u.ux;
- X mm.y = u.uy;
- X makekops(&mm);
- X return;
- X }
- X if (flags.verbose)
- X pline("The Keystone Kops are after you!");
- X /* Create swarm near down staircase (hinders return to level) */
- X mm.x = xdnstair;
- X mm.y = ydnstair;
- X makekops(&mm);
- X /* Create swarm near shopkeeper (hinders return to shop) */
- X mm.x = shkp->mx;
- X mm.y = shkp->my;
- X makekops(&mm);
- X }
- X}
- X#endif /* KOPS */
- X
- X/* x,y is strictly inside shop */
- Xchar
- Xinside_shop(x, y)
- Xregister xchar x, y;
- X{
- X register char rno;
- X
- X rno = levl[x][y].roomno;
- X if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno-ROOMOFFSET))
- X return(NO_ROOM);
- X else
- X return(rno);
- X}
- X
- Xvoid
- Xu_left_shop(leavestring, newlev)
- Xregister char *leavestring;
- Xregister boolean newlev;
- X{
- X register struct monst *shkp;
- X register struct eshk *eshkp;
- X register long total;
- X
- X /*
- X * IF player
- X * ((didn't leave outright) AND
- X * ((he is now strictly-inside the shop) OR
- X * (he wasn't strictly-inside last turn anyway)))
- X * THEN (there's nothing to do, so just return)
- X */
- X if(!*leavestring &&
- X (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge))
- X return;
- X
- X shkp = shop_keeper(*u.ushops0);
- X
- X if(!shkp || !inhishop(shkp))
- X /* shk died, teleported, changed levels... */
- X return;
- X
- X eshkp = ESHK(shkp);
- X
- X if(!eshkp->billct && !eshkp->debit) /* bill is settled */
- X return;
- X
- X if(!*leavestring) {
- X /*
- X * Player just stepped onto shop-boundary (known from above logic).
- X * Try to intimidate him into paying his bill
- X */
- X
- X verbalize(NOTANGRY(shkp) ?
- X "%s! Please pay before leaving." :
- X "%s! Don't you leave without paying!",
- X plname);
- X return;
- X }
- X /* by this point, we know an actual robbery has taken place */
- X You("escaped the shop without paying!");
- X total = (addupbill(shkp) + eshkp->debit);
- X eshkp->robbed += total;
- X eshkp->credit = 0L;
- X eshkp->debit = 0L;
- X setpaid(shkp);
- X You("stole %ld zorkmid%s worth of merchandise.",
- X total, plur(total));
- X if (pl_character[0] != 'R') /* stealing is unlawful */
- X adjalign(-sgn(u.ualign.type));
- X
- X hot_pursuit(shkp);
- X#ifdef KOPS
- X call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge));
- X#else
- X (void) angry_guards(FALSE);
- X#endif
- X}
- X
- Xvoid
- Xu_entered_shop(enterstring)
- Xregister char *enterstring;
- X{
- X
- X register int rt;
- X register struct monst *shkp;
- X register struct eshk *eshkp;
- X static const char no_shk[] = "This shop appears to be deserted.";
- X static char empty_shops[5];
- X
- X if(!*enterstring)
- X return;
- X
- X if(!(shkp = shop_keeper(*enterstring))) {
- X if (!index(empty_shops, *enterstring) &&
- X in_rooms(u.ux, u.uy, SHOPBASE) !=
- X in_rooms(u.ux0, u.uy0, SHOPBASE))
- X pline(no_shk);
- X Strcpy(empty_shops, u.ushops);
- X u.ushops[0] = '\0';
- X return;
- X }
- X
- X eshkp = ESHK(shkp);
- X
- X if (!inhishop(shkp)) {
- X /* dump core when referenced */
- X eshkp->bill_p = (struct bill_x *) -1000;
- X if (!index(empty_shops, *enterstring))
- X pline(no_shk);
- X Strcpy(empty_shops, u.ushops);
- X u.ushops[0] = '\0';
- X return;
- X }
- X
- X eshkp->bill_p = &(eshkp->bill[0]);
- X
- X if (!eshkp->visitct || strncmpi(eshkp->customer, plname, PL_NSIZ)) {
- X /* You seem to be new here */
- X eshkp->visitct = 0;
- X eshkp->following = 0;
- X (void) strncpy(eshkp->customer,plname,PL_NSIZ);
- X pacify_shk(shkp);
- X }
- X
- X if (eshkp->following)
- X return;
- X
- X if (Invis) {
- X pline("%s senses your presence.", shkname(shkp));
- X verbalize("Invisible customers are not welcome!");
- X return;
- X }
- X
- X rt = rooms[*enterstring - ROOMOFFSET].rtype;
- X
- X if (ANGRY(shkp)) {
- X verbalize("So, %s, you dare return to %s %s?!",
- X plname,
- X s_suffix(shkname(shkp)),
- X shtypes[rt - SHOPBASE].name);
- X } else if (eshkp->robbed) {
- X verbalize("Beware, %s! I am upset about missing stock!",
- X plname);
- X } else {
- X verbalize("Hello, %s! Welcome%s to %s %s!",
- X plname,
- X eshkp->visitct++ ? " again" : "",
- X s_suffix(shkname(shkp)),
- X shtypes[rt - SHOPBASE].name);
- X }
- X if(carrying(PICK_AXE) != (struct obj *)0 &&
- X /* can't do anything if teleported in */
- X !inside_shop(u.ux, u.uy)) {
- X verbalize(NOTANGRY(shkp) ?
- X "Will you please leave your pick-axe outside?" :
- X "Leave the pick-axe outside.");
- X (void) dochug(shkp);
- X }
- X return;
- X}
- X
- X#endif /* OVL1 */
- X#ifdef OVLB
- X
- Xint
- Xinhishop(mtmp)
- Xregister struct monst *mtmp;
- X{
- X return(index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE),
- X ESHK(mtmp)->shoproom) &&
- X on_level(&(ESHK(mtmp)->shoplevel), &u.uz));
- X}
- X
- Xstruct monst *
- Xshop_keeper(rmno)
- Xregister char rmno;
- X{
- X struct monst *shkp = rmno >= ROOMOFFSET ?
- X rooms[rmno - ROOMOFFSET].resident : 0;
- X
- X if (shkp) {
- X if (NOTANGRY(shkp)) {
- X if (ESHK(shkp)->surcharge) pacify_shk(shkp);
- X } else {
- X if (!ESHK(shkp)->surcharge) rile_shk(shkp);
- X }
- X }
- X return shkp;
- X}
- X
- X#ifdef SOUNDS
- Xboolean
- Xtended_shop(sroom)
- Xregister struct mkroom *sroom;
- X{
- X register struct monst *mtmp = sroom->resident;
- X
- X if (!mtmp)
- X return(FALSE);
- X else
- X return(inhishop(mtmp));
- X}
- X#endif /* SOUNDS */
- X
- Xstatic struct bill_x *
- Xonbill(obj, shkp, silent)
- Xregister struct obj *obj;
- Xregister struct monst *shkp;
- Xregister boolean silent;
- X{
- X if (shkp) {
- X register struct bill_x *bp = ESHK(shkp)->bill_p;
- X register int ct = ESHK(shkp)->billct;
- X
- X while (--ct >= 0)
- X if (bp->bo_id == obj->o_id) {
- X if (!obj->unpaid) pline("onbill: paid obj on bill?");
- X return bp;
- X } else bp++;
- X }
- X if(obj->unpaid & !silent) pline("onbill: unpaid obj not on bill?");
- X return (struct bill_x *)0;
- X}
- X
- X/* Delete the contents of the given object. */
- Xvoid
- Xdelete_contents(obj)
- Xregister struct obj *obj;
- X{
- X register struct obj *curr, *next;
- X
- X for (curr = obj->cobj; curr; curr = next) {
- X next = curr->nobj;
- X obfree(curr, (struct obj *)0);
- X }
- X obj->cobj = (struct obj *) 0;
- X}
- X
- X/* called with two args on merge */
- Xvoid
- Xobfree(obj, merge)
- Xregister struct obj *obj, *merge;
- X{
- X register struct bill_x *bp;
- X register struct bill_x *bpm;
- X register struct monst *shkp;
- X
- X if(obj->oclass == FOOD_CLASS) food_disappears(obj);
- X
- X if (obj->cobj) delete_contents(obj);
- X
- X shkp = shop_keeper(*u.ushops);
- X
- X if ((bp = onbill(obj, shkp, FALSE)) != 0) {
- X if(!merge){
- X bp->useup = 1;
- X obj->unpaid = 0; /* only for doinvbill */
- X obj->nobj = billobjs;
- X billobjs = obj;
- X return;
- X }
- X bpm = onbill(merge, shkp, FALSE);
- X if(!bpm){
- X /* this used to be a rename */
- X impossible("obfree: not on bill??");
- X return;
- X } else {
- X /* this was a merger */
- X bpm->bquan += bp->bquan;
- X ESHK(shkp)->billct--;
- X#ifdef DUMB
- X {
- X /* DRS/NS 2.2.6 messes up -- Peter Kendell */
- X int indx = ESHK(shkp)->billct;
- X *bp = ESHK(shkp)->bill_p[indx];
- X }
- X#else
- X *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct];
- X#endif
- X }
- X }
- X dealloc_obj(obj);
- X}
- X
- Xstatic long
- Xcheck_credit(tmp, shkp)
- Xlong tmp;
- Xregister struct monst *shkp;
- X{
- X long credit = ESHK(shkp)->credit;
- X
- X if(credit == 0L) return(tmp);
- X if(credit >= tmp) {
- X pline("The price is deducted from your credit.");
- X ESHK(shkp)->credit -=tmp;
- X tmp = 0L;
- X } else {
- X pline("The price is partially covered by your credit.");
- X ESHK(shkp)->credit = 0L;
- X tmp -= credit;
- X }
- X return(tmp);
- X}
- X
- Xstatic void
- Xpay(tmp,shkp)
- Xlong tmp;
- Xregister struct monst *shkp;
- X{
- X long robbed = ESHK(shkp)->robbed;
- X long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp));
- X
- X u.ugold -= balance;
- X shkp->mgold += balance;
- X flags.botl = 1;
- X if(robbed) {
- X robbed -= tmp;
- X if(robbed < 0) robbed = 0L;
- X ESHK(shkp)->robbed = robbed;
- X }
- X}
- X
- X/* return shkp to home position */
- Xvoid
- Xhome_shk(shkp, killkops)
- Xregister struct monst *shkp;
- Xregister boolean killkops;
- X{
- X register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
- X
- X (void) mnearto(shkp, x, y, TRUE);
- X level.flags.has_shop = 1;
- X if (killkops) {
- X#ifdef KOPS
- X kops_gone(TRUE);
- X#else
- X You("feel vaguely apprehensive.");
- X#endif
- X pacify_guards();
- X }
- X}
- X
- Xstatic boolean
- Xangry_shk_exists()
- X{
- X register struct monst *shkp;
- X
- X for (shkp = next_shkp(fmon, FALSE);
- X shkp; shkp = next_shkp(shkp->nmon, FALSE))
- X if (ANGRY(shkp)) return(TRUE);
- X return(FALSE);
- X}
- X
- X/* remove previously applied surcharge from all billed items */
- XSTATIC_OVL void
- Xpacify_shk(shkp)
- Xregister struct monst *shkp;
- X{
- X NOTANGRY(shkp) = TRUE; /* make peaceful */
- X if (ESHK(shkp)->surcharge) {
- X register struct bill_x *bp = ESHK(shkp)->bill_p;
- X register int ct = ESHK(shkp)->billct;
- X
- X ESHK(shkp)->surcharge = FALSE;
- X while (ct-- > 0) {
- X register long reduction = (bp->price + 3L) / 4L;
- X bp->price -= reduction; /* undo 33% increase */
- X bp++;
- X }
- X }
- X}
- X
- X/* add aggravation surcharge to all billed items */
- Xstatic void
- Xrile_shk(shkp)
- Xregister struct monst *shkp;
- X{
- X NOTANGRY(shkp) = FALSE; /* make angry */
- X if (!ESHK(shkp)->surcharge) {
- X register struct bill_x *bp = ESHK(shkp)->bill_p;
- X register int ct = ESHK(shkp)->billct;
- X
- X ESHK(shkp)->surcharge = TRUE;
- X while (ct-- > 0) {
- X register long surcharge = (bp->price + 2L) / 3L;
- X bp->price += surcharge;
- X bp++;
- X }
- X }
- X}
- X
- Xvoid
- Xmake_happy_shk(shkp, silentkops)
- Xregister struct monst *shkp;
- Xregister boolean silentkops;
- X{
- X register boolean wasmad = ANGRY(shkp);
- X
- X pacify_shk(shkp);
- X ESHK(shkp)->following = 0;
- X ESHK(shkp)->robbed = 0L;
- X if (pl_character[0] != 'R')
- X adjalign(sgn(u.ualign.type));
- X if(!inhishop(shkp)) {
- X pline("Satisfied, %s suddenly disappears!", mon_nam(shkp));
- X if(on_level(&(ESHK(shkp)->shoplevel), &u.uz))
- X home_shk(shkp, FALSE);
- X else
- X migrate_to_level(shkp,
- X ledger_no(&(ESHK(shkp)->shoplevel)), 0);
- X } else if(wasmad)
- X pline("%s calms down.", Monnam(shkp));
- X
- X if(!angry_shk_exists()) {
- X#ifdef KOPS
- X kops_gone(silentkops);
- X#endif
- X pacify_guards();
- X }
- X}
- X
- Xvoid
- Xhot_pursuit(shkp)
- Xregister struct monst *shkp;
- X{
- X if(!shkp->isshk) return;
- X
- X rile_shk(shkp);
- X ESHK(shkp)->following = 1;
- X}
- X
- X/* used when the shkp is teleported out of his shop,
- X * or when the player is not on a costly_spot and he
- X * damages something inside the shop. these conditions
- X * must be checked by the calling function.
- X */
- Xvoid
- Xmake_angry_shk(shkp, ox, oy)
- Xregister struct monst *shkp;
- Xregister xchar ox,oy;
- X{
- X if(index(in_rooms(ox, oy, SHOPBASE), ESHK(shkp)->shoproom) &&
- X !ANGRY(shkp)) {
- X ESHK(shkp)->robbed += (addupbill(shkp) +
- X ESHK(shkp)->debit + ESHK(shkp)->loan);
- X ESHK(shkp)->robbed -= ESHK(shkp)->credit;
- X if(ESHK(shkp)->robbed < 0L)
- X ESHK(shkp)->robbed = 0L;
- X ESHK(shkp)->credit = 0L;
- X setpaid(shkp);
- X }
- X if(!ANGRY(shkp)) pline("%s gets angry!", Monnam(shkp));
- X else pline("%s is furious!", Monnam(shkp));
- X hot_pursuit(shkp);
- X}
- X
- Xstatic const char no_money[] = "Moreover, you%s have no money.";
- X
- Xstatic long
- Xcheapest_item(shkp) /* delivers the cheapest item on the list */
- Xregister struct monst *shkp;
- X{
- X register int ct = ESHK(shkp)->billct;
- X register struct bill_x *bp = ESHK(shkp)->bill_p;
- X register long gmin = (bp->price * bp->bquan);
- X
- X while(ct--){
- X if(bp->price * bp->bquan < gmin)
- X gmin = bp->price * bp->bquan;
- X bp++;
- X }
- X return(gmin);
- X}
- X
- Xint
- Xdopay()
- X{
- X long ltmp;
- X register struct monst *nxtm = (struct monst *)0;
- X register struct monst *shkp, *resident = (struct monst *)0;
- X register struct eshk *eshkp;
- X int pass, tmp, sk = 0, seensk = 0;
- X register boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L);
- X
- X multi = 0;
- X
- X /* find how many shk's there are, how many are in */
- X /* sight, and are you in a shop room with one. */
- X for (shkp = next_shkp(fmon, FALSE);
- X shkp; shkp = next_shkp(shkp->nmon, FALSE)) {
- X sk++;
- X if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2) nxtm = shkp;
- X if (canseemon(shkp) || sensemon(shkp)) seensk++;
- X if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom))
- X resident = shkp;
- X }
- X
- X if (nxtm) { /* Player should always appease an */
- X shkp = nxtm; /* irate shk standing next to them. */
- X goto proceed;
- X }
- X
- X if ((!sk && (!Blind || Telepat)) || (!Blind && !seensk)) {
- X pline("There appears to be no shopkeeper here to receive your payment.");
- X return(0);
- X }
- X
- X if(!seensk) {
- X You("can't see...");
- X return(0);
- X }
- X
- X /* the usual case. allow paying at a distance when */
- X /* inside a tended shop. should we change that? */
- X if(sk == 1 && resident) {
- X shkp = resident;
- X goto proceed;
- X }
- X
- X if (seensk == 1) {
- X for (shkp = next_shkp(fmon, FALSE);
- X shkp; shkp = next_shkp(shkp->nmon, FALSE))
- X if (canseemon(shkp) || sensemon(shkp)) break;
- X if (shkp != resident && distu(shkp->mx, shkp->my) > 2) {
- X pline("%s is not near enough to receive your payment.",
- X Monnam(shkp));
- X return(0);
- X }
- X } else {
- X struct monst *mtmp;
- X coord cc;
- X int cx, cy;
- X
- X pline("Pay whom?");
- X cc.x = u.ux;
- X cc.y = u.uy;
- X getpos(&cc, TRUE, "the creature you want to pay");
- X cx = cc.x;
- X cy = cc.y;
- X if(cx == -10) return(0); /* player pressed esc */
- X if(cx < 0) {
- X pline("Try again...");
- X return(0);
- X }
- X if(u.ux == cx && u.uy == cy) {
- X You("are generous to yourself.");
- X return(0);
- X }
- X mtmp = m_at(cx, cy);
- X if(!mtmp) {
- X pline("There is no one there to receive your payment.");
- X return(0);
- X }
- X if(!mtmp->isshk) {
- X pline("%s is not interested in your payment.",
- X Monnam(mtmp));
- X return(0);
- X }
- X if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) {
- X pline("%s is too far to receive your payment.",
- X Monnam(mtmp));
- X return(0);
- X }
- X shkp = mtmp;
- X }
- X
- X if(!shkp) {
- X#ifdef DEBUG
- X pline("dopay: null shkp.");
- X#endif
- X return(0);
- X }
- Xproceed:
- X eshkp = ESHK(shkp);
- X
- X ltmp = eshkp->robbed;
- X if(shkp != resident && NOTANGRY(shkp)) {
- X if(!ltmp)
- X You("do not owe %s anything.", mon_nam(shkp));
- X else if(!u.ugold) {
- X You("%shave no money.", stashed_gold ? "seem to " : "");
- X if(stashed_gold)
- X pline("But you have some gold stashed away.");
- X } else {
- X const char *pronoun = shkp->female ? "she" : "he";
- X long ugold = u.ugold;
- X
- X if(ugold > ltmp) {
- X You("give %s the %ld gold piece%s %s asked for.",
- X mon_nam(shkp), ltmp, plur(ltmp), pronoun);
- X pay(ltmp, shkp);
- X } else {
- X You("give %s all your%s gold.", mon_nam(shkp),
- X stashed_gold ? " openly kept" : "");
- X pay(u.ugold, shkp);
- X if (stashed_gold) pline("But you have hidden gold!");
- X }
- X if((ugold < ltmp/2L) || (ugold < ltmp && stashed_gold))
- X pline("Unfortunately, %s doesn't look satisfied.",
- X pronoun);
- X else
- X make_happy_shk(shkp, FALSE);
- X }
- X return(1);
- X }
- X
- X /* ltmp is still eshkp->robbed here */
- X if (!eshkp->billct && !eshkp->debit) {
- X const char *pronoun = shkp->female ? "her" : "him";
- X const char *possessive = shkp->female ? "her" : "his";
- X
- X if(!ltmp && NOTANGRY(shkp)) {
- X You("do not owe %s anything.", mon_nam(shkp));
- X if(!u.ugold) pline(no_money, stashed_gold ?
- X " seem to" : "");
- X } else if(ltmp) {
- X pline("%s is after blood, not money!", Monnam(shkp));
- X if(u.ugold < ltmp/2L ||
- X (u.ugold < ltmp && stashed_gold)) {
- X if(!u.ugold) pline(no_money, stashed_gold ?
- X " seem to" : "");
- X else pline("Besides, you don't have enough to interest %s.",
- X pronoun);
- X return(1);
- X }
- X pline("But since %s shop has been robbed recently,",
- X possessive);
- X pline("you %scompensate %s for %s losses.",
- X (u.ugold < ltmp) ? "partially " : "",
- X mon_nam(shkp), possessive);
- X pay(u.ugold < ltmp ? u.ugold : ltmp, shkp);
- X make_happy_shk(shkp, FALSE);
- X } else {
- X /* shopkeeper is angry, but has not been robbed --
- X * door broken, attacked, etc. */
- X pline("%s is after your hide, not your money!",
- X mon_nam(shkp));
- X if(u.ugold < 1000L) {
- X if(!u.ugold) pline(no_money, stashed_gold ?
- X " seem to" : "");
- X else pline("Besides, you don't have enough to interest %s.",
- X pronoun);
- X return(1);
- X }
- X You("try to appease %s by giving %s 1000 gold pieces.",
- X x_monnam(shkp, 1, "angry", 0), pronoun);
- X pay(1000L,shkp);
- X if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3))
- X make_happy_shk(shkp, FALSE);
- X else
- X pline("But %s is as angry as ever.", mon_nam(shkp));
- X }
- X return(1);
- X }
- X if(shkp != resident) {
- X impossible("dopay: not to shopkeeper?");
- X if(resident) setpaid(resident);
- X return(0);
- X }
- X /* pay debt, if any, first */
- X if(eshkp->debit) {
- X long dtmp = eshkp->debit;
- X long loan = eshkp->loan;
- X char sbuf[BUFSZ];
- X
- X Sprintf(sbuf, "You owe %s %ld zorkmid%s ",
- X shkname(shkp), dtmp, plur(dtmp));
- X if(loan) {
- X if(loan == dtmp)
- X Strcat(sbuf, "you picked up in the store.");
- X else Strcat(sbuf,
- X "for gold picked up and the use of merchandise.");
- X } else Strcat(sbuf, "for the use of merchandise.");
- X pline(sbuf);
- X if (u.ugold + eshkp->credit < dtmp) {
- X pline("But you don't%s have enough gold%s.",
- X stashed_gold ? " seem to" : "",
- X eshkp->credit ? " or credit" : "");
- X return(1);
- X } else {
- X if (eshkp->credit >= dtmp) {
- X eshkp->credit -= dtmp;
- X eshkp->debit = 0L;
- X eshkp->loan = 0L;
- X Your("debt is covered by your credit.");
- X } else if (!eshkp->credit) {
- X u.ugold -= dtmp;
- X shkp->mgold += dtmp;
- X eshkp->debit = 0L;
- X eshkp->loan = 0L;
- X You("pay that debt.");
- X flags.botl = 1;
- X } else {
- X dtmp -= eshkp->credit;
- X eshkp->credit = 0L;
- X u.ugold -= dtmp;
- X shkp->mgold += dtmp;
- X eshkp->debit = 0L;
- X eshkp->loan = 0L;
- X pline("That debt is partially offset by your credit.");
- X You("pay the remainder.");
- X flags.botl = 1;
- X }
- X paid = TRUE;
- X }
- X }
- X /* now check items on bill */
- X if (eshkp->billct) {
- X register boolean itemize;
- X
- X if (!u.ugold && !eshkp->credit) {
- X You("%shave no money or credit%s.",
- X stashed_gold ? "seem to " : "",
- X paid ? " left" : "");
- X return(0);
- X }
- X if ((u.ugold + eshkp->credit) < cheapest_item(shkp)) {
- X You("don't have enough money to buy%s the item%s you picked.",
- X eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct));
- X if(stashed_gold)
- X pline("Maybe you have some gold stashed away?");
- X return(0);
- X }
- X
- X /* this isn't quite right; it itemizes without asking if the
- X * single item on the bill is partly used up and partly unpaid */
- X itemize = (eshkp->billct > 1 ? yn("Itemized billing?") == 'y' : 1);
- X
- X for (pass = 0; pass <= 1; pass++) {
- X tmp = 0;
- X while (tmp < eshkp->billct) {
- X register struct obj *otmp;
- X register struct bill_x *bp = &(eshkp->bill_p[tmp]);
- X
- X /* find the object on one of the lists */
- X if (!(otmp = bp_to_obj(bp))) {
- X impossible("Shopkeeper administration out of order.");
- X setpaid(shkp); /* be nice to the player */
- X return 1;
- X }
- X if (pass == bp->useup && otmp->quan == bp->bquan) {
- X /* pay for used-up items on first pass and others
- X * on second, so player will be stuck in the store
- X * less often; things which are partly used up
- X * are processed on both passes */
- X tmp++;
- X } else {
- X switch (dopayobj(shkp, bp, otmp, pass, itemize)) {
- X case PAY_CANT:
- X return 1; /*break*/
- X case PAY_BROKE:
- X paid = TRUE;
- X goto thanks; /*break*/
- X case PAY_SKIP:
- X tmp++;
- X continue; /*break*/
- X case PAY_SOME:
- X paid = TRUE;
- X if (itemize) bot();
- X continue; /*break*/
- X case PAY_BUY:
- X paid = TRUE;
- X break;
- X }
- X if (itemize) bot();
- X *bp = eshkp->bill_p[--eshkp->billct];
- X }
- X }
- X }
- X }
- Xthanks:
- X if(!ANGRY(shkp) && paid)
- X verbalize("Thank you for shopping in %s %s!",
- X s_suffix(shkname(shkp)),
- X shtypes[rooms[eshkp->shoproom - ROOMOFFSET].rtype - SHOPBASE].name);
- X return(1);
- X}
- X
- X/* return 2 if used-up portion paid */
- X/* 1 if paid successfully */
- X/* 0 if not enough money */
- X/* -1 if skip this object */
- X/* -2 if no money/credit left */
- Xstatic int
- Xdopayobj(shkp, bp, obj, which, itemize)
- Xregister struct monst *shkp;
- Xregister struct bill_x *bp;
- Xregister struct obj *obj;
- Xint which; /* 0 => used-up item, 1 => other (unpaid or lost) */
- Xboolean itemize;
- X{
- X long ltmp, quan, save_quan;
- X int buy;
- X boolean stashed_gold = (hidden_gold() > 0L),
- X consumed = (which == 0);
- X
- X if(!obj->unpaid && !bp->useup){
- X impossible("Paid object on bill??");
- X return PAY_BUY;
- X }
- X if(itemize && u.ugold + ESHK(shkp)->credit == 0L){
- X You("%shave no money or credit left.",
- X stashed_gold ? "seem to " : "");
- X return PAY_BROKE;
- X }
- X /* we may need to temporarily adjust the object, if part of the
- X original quantity has been used up but part remains unpaid */
- X save_quan = obj->quan;
- X if (consumed) {
- X /* either completely used up (simple), or split needed */
- X quan = bp->bquan;
- X if (quan > obj->quan) /* difference is amount used up */
- X quan -= obj->quan;
- X } else {
- X /* dealing with ordinary unpaid item */
- X quan = obj->quan;
- X }
- X obj->quan = quan; /* to be used by doname() */
- X obj->unpaid = 0; /* ditto */
- X ltmp = bp->price * quan;
- X buy = PAY_BUY; /* flag; if changed then return early */
- X
- X if (itemize) {
- X char qbuf[BUFSZ];
- X Sprintf(qbuf,"%s for %ld zorkmid%s. Pay?", quan == 1L ?
- X Doname2(obj) : doname(obj), ltmp, plur(ltmp));
- X if (yn(qbuf) == 'n') {
- X buy = PAY_SKIP; /* don't want to buy */
- X } else if (quan < bp->bquan && !consumed) { /* partly used goods */
- X obj->quan = bp->bquan - save_quan; /* used up amount */
- X verbalize("%s for the other %s before buying %s.",
- X ANGRY(shkp) ? "Pay" : "Please pay", xname(obj),
- X save_quan > 1L ? "these" : "this one");
- X buy = PAY_SKIP; /* shk won't sell */
- X }
- X }
- X if (buy == PAY_BUY && u.ugold + ESHK(shkp)->credit < ltmp) {
- X You("don't%s have gold%s enough to pay for %s.",
- X stashed_gold ? " seem to" : "",
- X (ESHK(shkp)->credit > 0L) ? " or credit" : "",
- X doname(obj));
- X buy = itemize ? PAY_SKIP : PAY_CANT;
- X }
- X
- X if (buy != PAY_BUY) {
- X /* restore unpaid object to original state */
- X obj->quan = save_quan;
- X obj->unpaid = 1;
- X return buy;
- X }
- X
- X pay(ltmp, shkp);
- X You("bought %s for %ld gold piece%s.",
- X doname(obj), ltmp, plur(ltmp));
- X obj->quan = save_quan; /* restore original count */
- X /* quan => amount just bought, save_quan => remaining unpaid count */
- X if (consumed) {
- X if (quan != save_quan) {
- X /* eliminate used-up portion; remainder is still unpaid */
- X bp->bquan = obj->quan;
- X obj->unpaid = 1;
- X bp->useup = 0;
- X } else { /* completely used-up, so get rid of it */
- X register struct obj *otmp = billobjs;
- X if(obj == billobjs)
- X billobjs = obj->nobj;
- X else {
- X while(otmp && otmp->nobj != obj) otmp = otmp->nobj;
- X if(otmp) otmp->nobj = obj->nobj;
- X else impossible("Error in shopkeeper administration.");
- X }
- X dealloc_obj(obj);
- X }
- X }
- X return quan != save_quan ? PAY_SOME : PAY_BUY;
- X}
- X
- X/* routine called after dying (or quitting) */
- Xboolean
- Xpaybill(croaked)
- Xregister boolean croaked;
- X{
- X register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0;
- X register boolean taken = FALSE;
- X register int numsk = 0;
- X
- X /* give shopkeeper first crack */
- X if ((mtmp = shop_keeper(*u.ushops)) && inhishop(mtmp)) {
- X numsk++;
- X resident = mtmp;
- X taken = inherits(resident, numsk, croaked);
- X }
- X for (mtmp = next_shkp(fmon, FALSE);
- X mtmp; mtmp = next_shkp(mtmp2, FALSE)) {
- X mtmp2 = mtmp->nmon;
- X if (mtmp != resident) {
- X /* for bones: we don't want a shopless shk around */
- X if(!on_level(&(ESHK(mtmp)->shoplevel), &u.uz))
- X mongone(mtmp);
- X else {
- X numsk++;
- X taken |= inherits(mtmp, numsk, croaked);
- X }
- X }
- X }
- X if(numsk == 0) return(FALSE);
- X return(taken);
- X}
- X
- Xstatic boolean
- Xinherits(shkp, numsk, croaked)
- Xregister struct monst *shkp;
- Xregister int numsk;
- Xregister boolean croaked;
- X{
- X register long loss = 0L;
- X register struct obj *otmp;
- X register struct eshk *eshkp = ESHK(shkp);
- X register xchar ox, oy;
- X register boolean take = FALSE, taken = FALSE;
- X register int roomno = *u.ushops;
- X
- X /* the simplifying principle is that first-come */
- X /* already took everything you had. */
- X if(numsk > 1) {
- X if(cansee(shkp->mx, shkp->my) && croaked)
- X pline("%s %slooks at your corpse%s%s", Monnam(shkp),
- X (shkp->msleep || shkp->mfrozen) ?
- X "wakes up, " : "",
- X !rn2(2) ? (shkp->female ? ", shakes her head," :
- X ", shakes his head,") : "",
- X !inhishop(shkp) ? " and disappears. " : " and sighs.");
- X taken = (roomno == eshkp->shoproom);
- X goto skip;
- X }
- X
- X /* get one case out of the way: you die in the shop, the */
- X /* shopkeeper is peaceful, nothing stolen, nothing owed. */
- X if(roomno == eshkp->shoproom && inhishop(shkp) &&
- X !IS_DOOR(levl[u.ux][u.uy].typ) && !eshkp->billct &&
- X !eshkp->robbed && !eshkp->debit &&
- X NOTANGRY(shkp) && !eshkp->following) {
- X if (invent)
- X pline("%s gratefully inherits all your possessions.",
- X shkname(shkp));
- X goto clear;
- X }
- X
- X if (eshkp->billct || eshkp->debit || eshkp->robbed) {
- X register long total = 0L;
- X
- X if(roomno == eshkp->shoproom && inhishop(shkp))
- X total = (addupbill(shkp) + eshkp->debit);
- X loss = ((total >= eshkp->robbed) ? total : eshkp->robbed);
- X take = TRUE;
- X }
- X
- X if (eshkp->following || ANGRY(shkp) || take) {
- X
- X if(!invent && !u.ugold) goto skip;
- X
- X if((loss > u.ugold) || !loss) {
- X pline("%s %s%stakes all your possessions.",
- X shkname(shkp),
- X (shkp->msleep || shkp->mfrozen) ?
- X "wakes up and " : "",
- X (distu(shkp->mx, shkp->my) > 2) ?
- X "comes and " : "");
- X taken = TRUE;
- X shkp->mgold += u.ugold;
- X u.ugold = 0L;
- X /* in case bones: make it be for real... */
- X if(!*u.ushops ||
- X IS_DOOR(levl[u.ux][u.uy].typ)) {
- X /* shk.x,shk.y is the position immediately in
- X * front of the door -- move in one more space
- X */
- X ox = eshkp->shk.x;
- X oy = eshkp->shk.y;
- X ox += sgn(ox - eshkp->shd.x);
- X oy += sgn(oy - eshkp->shd.y);
- X } else {
- X ox = u.ux;
- X oy = u.uy;
- X }
- X
- X if (invent) {
- X for(otmp = invent; otmp; otmp = otmp->nobj)
- X place_object(otmp, ox, oy);
- X
- X /* add to main object list at end so invent is
- X still good */
- X if (fobj) {
- X otmp = fobj;
- X while(otmp->nobj)
- X otmp = otmp->nobj;
- X otmp->nobj = invent;
- X } else
- X fobj = invent;
- X }
- X } else {
- X u.ugold -= loss;
- X shkp->mgold += loss;
- X pline("%s %sand takes %ld zorkmid%s %sowed %s.",
- X Monnam(shkp),
- X (shkp->msleep || shkp->mfrozen) ?
- X "wakes up " : "comes ",
- X loss, plur(loss),
- X strncmp(eshkp->customer,
- X plname, PL_NSIZ) ? "" : "you ",
- X shkp->female ? "her" : "him");
- X }
- Xskip:
- X /* in case we create bones */
- X if(!inhishop(shkp))
- X home_shk(shkp, FALSE);
- X }
- Xclear:
- X setpaid(shkp);
- X return(taken);
- X}
- X
- X/* find obj on one of the lists */
- Xstatic struct obj *
- Xbp_to_obj(bp)
- Xregister struct bill_x *bp;
- X{
- X register struct obj *obj;
- X register struct monst *mtmp;
- X register unsigned int id = bp->bo_id;
- X
- X if(bp->useup)
- X obj = o_on(id, billobjs);
- X else if(!(obj = o_on(id, invent)) &&
- X !(obj = o_on(id, fobj)) &&
- X !(obj = o_on(id, migrating_objs))) {
- X for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- X if ((obj = o_on(id, mtmp->minvent)) != 0)
- X return obj;
- X for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon)
- X if ((obj = o_on(id, mtmp->minvent)) != 0)
- X return obj;
- X }
- X return(obj);
- X}
- X
- X/* calculate the value that the shk will charge for [one of] an object */
- Xstatic long
- Xget_cost(obj, shkp)
- Xregister struct obj *obj;
- Xregister struct monst *shkp; /* if angry, impose a surcharge */
- X{
- X register long tmp = getprice(obj);
- X
- X if (!tmp) tmp = 5L;
- X /* shopkeeper may notice if the player isn't very knowledgeable -
- X especially when gem prices are concerned */
- X if (!objects[obj->otyp].oc_name_known)
- X if (obj->oclass == GEM_CLASS) {
- X /* all gems are priced high - real or not */
- X if (objects[obj->otyp].oc_material == GLASS) {
- X /* real gem's cost (worthless gems come
- X after jade but before luckstone) */
- X tmp = (long)objects[
- X obj->otyp - LUCKSTONE + JADE + 1].oc_cost;
- X }
- X } else if (!(obj->o_id % 4)) /* arbitrarily impose surcharge */
- X tmp += tmp / 3L;
- X#ifdef TOURIST
- X if((pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
- X || (uarmu && !uarm && !uarmc)) /* Hawaiian shirt visible */
- X tmp += tmp / 3L;
- X#endif
- X if (ACURR(A_CHA) > 18) tmp /= 2L;
- X else if (ACURR(A_CHA) > 17) tmp -= tmp / 3L;
- X else if (ACURR(A_CHA) > 15) tmp -= tmp / 4L;
- X else if (ACURR(A_CHA) < 6) tmp *= 2L;
- X else if (ACURR(A_CHA) < 8) tmp += tmp / 2L;
- X else if (ACURR(A_CHA) < 11) tmp += tmp / 3L;
- X if (tmp <= 0L) tmp = 1L;
- X else if (obj->oartifact) tmp *= 4L;
- X /* anger surcharge should match rile_shk's */
- X if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L;
- X return tmp;
- X}
- X
- X/* returns the price of a container's content. the price
- X * of the "top" container is added in the calling functions.
- X * a different price quoted for selling as vs. buying.
- X */
- Xlong
- Xcontained_cost(obj, shkp, price, usell)
- Xregister struct obj *obj;
- Xregister struct monst *shkp;
- Xlong price;
- Xregister boolean usell;
- X{
- X register struct obj *otmp;
- X
- X /* the price of contained objects */
- X for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
- X register boolean goods = saleable(rooms[ESHK(shkp)->shoproom -
- X ROOMOFFSET].rtype-SHOPBASE, otmp);
- X
- X if(otmp->otyp == GOLD_PIECE) continue;
- X
- X /* the "top" container is evaluated by caller */
- X if(usell) {
- X if(goods && !otmp->unpaid &&
- X otmp->oclass != BALL_CLASS &&
- X !(otmp->oclass == FOOD_CLASS && otmp->oeaten) &&
- X !(Is_candle(otmp) && otmp->age <
- X 20L * (long)objects[otmp->otyp].oc_cost))
- X price += set_cost(otmp, shkp);
- X } else if(!otmp->no_charge) {
- X price += get_cost(otmp, shkp);
- X }
- X
- X if(Is_container(otmp))
- X price += contained_cost(otmp, shkp, price, usell);
- X }
- X
- X return(price);
- X}
- X
- Xlong
- Xcontained_gold(obj)
- Xregister struct obj *obj;
- X{
- X register struct obj *otmp;
- X register long value = 0L;
- X
- X /* accumulate contained gold */
- X for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
- X if (otmp->otyp == GOLD_PIECE)
- X value += otmp->quan;
- X else if (Is_container(otmp))
- X value += contained_gold(otmp);
- X
- X return(value);
- X}
- X
- Xstatic void
- Xdropped_container(obj)
- Xregister struct obj *obj;
- X{
- X register struct obj *otmp;
- X
- X /* the "top" container is treated in the calling fn */
- X for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
- X
- X if(otmp->otyp == GOLD_PIECE) continue;
- X
- X if(!otmp->unpaid)
- X otmp->no_charge = 1;
- X
- X if(Is_container(otmp))
- X dropped_container(otmp);
- X }
- X}
- X
- Xvoid
- Xpicked_container(obj)
- Xregister struct obj *obj;
- X{
- X register struct obj *otmp;
- X
- X /* the "top" container is treated in the calling fn */
- X for(otmp = obj->cobj; otmp; otmp = otmp->nobj) {
- X
- X if(otmp->otyp == GOLD_PIECE) continue;
- X
- X if(otmp->no_charge)
- X otmp->no_charge = 0;
- X
- X if(Is_container(otmp))
- X picked_container(otmp);
- X }
- X}
- X
- X/* calculate how much the shk will pay when buying [all of] an object */
- Xstatic long
- Xset_cost(obj, shkp)
- Xregister struct obj *obj;
- Xregister struct monst *shkp;
- X{
- X long tmp = getprice(obj) * obj->quan;
- X
- X#ifdef TOURIST
- X if ((pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
- X || (uarmu && !uarm && !uarmc)) /* Hawaiian shirt visible */
- X tmp /= 3L;
- X else
- X#endif
- X tmp /= 2L;
- X /* shopkeeper may notice if the player isn't very knowledgeable -
- X especially when gem prices are concerned */
- X if (!objects[obj->otyp].oc_name_known) {
- X if (obj->oclass == GEM_CLASS) {
- X /* different shop keepers give different prices */
- X if (objects[obj->otyp].oc_material == GEMSTONE ||
- X objects[obj->otyp].oc_material == GLASS) {
- X tmp = (obj->otyp % (6 - shkp->m_id % 3));
- X tmp = (tmp + 3) * obj->quan;
- X }
- X } else if (tmp > 1L && !rn2(4))
- X tmp -= tmp / 4L;
- X }
- X return tmp;
- X}
- X
- X/* called from doinv(invent.c) for inventory of unpaid objects */
- Xlong
- Xunpaid_cost(unp_obj)
- Xregister struct obj *unp_obj; /* known to be unpaid */
- X{
- X register struct bill_x *bp = (struct bill_x *)0;
- X register struct monst *shkp;
- X
- X for(shkp = next_shkp(fmon, TRUE); shkp;
- X shkp = next_shkp(shkp->nmon, TRUE))
- X if ((bp = onbill(unp_obj, shkp, TRUE)) != 0) break;
- X
- X /* onbill() gave no message if unexpected problem occurred */
- X if(!bp) impossible("unpaid_cost: object wasn't on any bill!");
- X
- X return bp ? unp_obj->quan * bp->price : 0L;
- X}
- X
- END_OF_FILE
- if test 37947 -ne `wc -c <'src/shk.c1'`; then
- echo shar: \"'src/shk.c1'\" unpacked with wrong size!
- fi
- # end of 'src/shk.c1'
- fi
- echo shar: End of archive 47 \(of 108\).
- cp /dev/null ark47isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
- 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
- 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
- 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 \
- 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 \
- 101 102 103 104 105 106 107 108 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 108 archives.
- echo "Now execute 'rebuild.sh'"
- rm -f ark10[0-8]isdone ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-