Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!uunet!tektronix!tekgen!tekred!games-request
From: games-request@tekred.TEK.COM
Newsgroups: comp.sources.games
Subject: v03i004: NetHack2.2 - display oriented dungeons and dragons, Part04/20
Message-ID: <1887@tekred.TEK.COM>
Date: Tue, 1-Dec-87 19:39:05 EST
Article-I.D.: tekred.1887
Posted: Tue Dec 1 19:39:05 1987
Date-Received: Sat, 5-Dec-87 06:43:38 EST
Sender: billr@tekred.TEK.COM
Lines: 2258
Approved: billr@tekred.TEK.COM
Submitted by: mike@genat.UUCP (Mike Stephenson)
Comp.sources.games: Volume 3, Issue 4
Archive-name: nethack2.2/Part04
#! /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 invent.c <<'END_OF_invent.c'
X/* SCCS Id: @(#)invent.c 2.1 87/10/19
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X#include
X#include "hack.h"
Xextern struct obj *splitobj();
Xextern struct obj zeroobj;
Xextern char morc;
Xextern char quitchars[];
Xstatic char *xprname();
X
X#ifndef NOWORM
X#include "wseg.h"
Xextern struct wseg *wsegs[32];
X#endif
X
X#define NOINVSYM '#'
X
Xint lastinvnr = 51; /* 0 ... 51 */
X
Xstatic
Xassigninvlet(otmp)
Xregister struct obj *otmp;
X{
X boolean inuse[52];
X register int i;
X register struct obj *obj;
X
X for(i = 0; i < 52; i++) inuse[i] = FALSE;
X for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
X i = obj->invlet;
X if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
X if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
X if(i == otmp->invlet) otmp->invlet = 0;
X }
X if((i = otmp->invlet) &&
X (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
X return;
X for(i = lastinvnr+1; i != lastinvnr; i++) {
X if(i == 52) { i = -1; continue; }
X if(!inuse[i]) break;
X }
X otmp->invlet = (inuse[i] ? NOINVSYM :
X (i < 26) ? ('a'+i) : ('A'+i-26));
X lastinvnr = i;
X}
X
Xstruct obj *
Xaddinv(obj)
Xregister struct obj *obj;
X{
X register struct obj *otmp;
X
X /* merge or attach to end of chain */
X if(!invent) {
X invent = obj;
X otmp = 0;
X } else
X for(otmp = invent; /* otmp */; otmp = otmp->nobj) {
X if(merged(otmp, obj, 0))
X return(otmp);
X if(!otmp->nobj) {
X otmp->nobj = obj;
X break;
X }
X }
X obj->nobj = 0;
X
X if(flags.invlet_constant) {
X assigninvlet(obj);
X /*
X * The ordering of the chain is nowhere significant
X * so in case you prefer some other order than the
X * historical one, change the code below.
X */
X if(otmp) { /* find proper place in chain */
X otmp->nobj = 0;
X if((invent->invlet ^ 040) > (obj->invlet ^ 040)) {
X obj->nobj = invent;
X invent = obj;
X } else
X for(otmp = invent; ; otmp = otmp->nobj) {
X if(!otmp->nobj ||
X (otmp->nobj->invlet ^ 040) > (obj->invlet ^ 040)){
X obj->nobj = otmp->nobj;
X otmp->nobj = obj;
X break;
X }
X }
X }
X }
X
X return(obj);
X}
X
Xuseup(obj)
Xregister struct obj *obj;
X{
X if(obj->quan > 1){
X obj->quan--;
X obj->owt = weight(obj);
X } else {
X setnotworn(obj);
X freeinv(obj);
X obfree(obj, (struct obj *) 0);
X }
X}
X
Xfreeinv(obj)
Xregister struct obj *obj;
X{
X register struct obj *otmp;
X
X if(obj == invent)
X invent = invent->nobj;
X else {
X for(otmp = invent; otmp->nobj != obj; otmp = otmp->nobj)
X if(!otmp->nobj) panic("freeinv");
X otmp->nobj = obj->nobj;
X }
X}
X
X/* destroy object in fobj chain (if unpaid, it remains on the bill) */
Xdelobj(obj) register struct obj *obj; {
X freeobj(obj);
X unpobj(obj);
X obfree(obj, (struct obj *) 0);
X}
X
X/* unlink obj from chain starting with fobj */
Xfreeobj(obj) register struct obj *obj; {
X register struct obj *otmp;
X
X if(obj == fobj) fobj = fobj->nobj;
X else {
X for(otmp = fobj; otmp->nobj != obj; otmp = otmp->nobj)
X if(!otmp) panic("error in freeobj");
X otmp->nobj = obj->nobj;
X }
X}
X
X/* Note: freegold throws away its argument! */
Xfreegold(gold) register struct gold *gold; {
X register struct gold *gtmp;
X
X if(gold == fgold) fgold = gold->ngold;
X else {
X for(gtmp = fgold; gtmp->ngold != gold; gtmp = gtmp->ngold)
X if(!gtmp) panic("error in freegold");
X gtmp->ngold = gold->ngold;
X }
X free((char *) gold);
X}
X
Xdeltrap(trap)
Xregister struct trap *trap;
X{
X register struct trap *ttmp;
X
X if(trap == ftrap)
X ftrap = ftrap->ntrap;
X else {
X for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ;
X ttmp->ntrap = trap->ntrap;
X }
X free((char *) trap);
X}
X
Xstruct wseg *m_atseg;
X
Xstruct monst *
Xm_at(x,y)
Xregister x,y;
X{
X register struct monst *mtmp;
X#ifndef NOWORM
X register struct wseg *wtmp;
X#endif
X
X m_atseg = 0;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon){
X if(mtmp->mx == x && mtmp->my == y)
X return(mtmp);
X#ifndef NOWORM
X if(mtmp->wormno){
X for(wtmp = wsegs[mtmp->wormno]; wtmp; wtmp = wtmp->nseg)
X if(wtmp->wx == x && wtmp->wy == y){
X m_atseg = wtmp;
X return(mtmp);
X }
X }
X#endif
X }
X return(0);
X}
X
Xstruct obj *
Xo_at(x,y)
Xregister x,y;
X{
X register struct obj *otmp;
X
X for(otmp = fobj; otmp; otmp = otmp->nobj)
X if(otmp->ox == x && otmp->oy == y) return(otmp);
X return(0);
X}
X
Xstruct obj *
Xsobj_at(n,x,y)
Xregister n,x,y;
X{
X register struct obj *otmp;
X
X for(otmp = fobj; otmp; otmp = otmp->nobj)
X if(otmp->ox == x && otmp->oy == y && otmp->otyp == n)
X return(otmp);
X return(0);
X}
X
Xcarried(obj) register struct obj *obj; {
Xregister struct obj *otmp;
X for(otmp = invent; otmp; otmp = otmp->nobj)
X if(otmp == obj) return(1);
X return(0);
X}
X
Xstruct obj *
Xcarrying(type)
Xregister int type;
X{
X register struct obj *otmp;
X
X for(otmp = invent; otmp; otmp = otmp->nobj)
X if(otmp->otyp == type)
X return(otmp);
X return((struct obj *) 0);
X}
X
Xstruct obj *
Xo_on(id, objchn) unsigned int id; register struct obj *objchn; {
X while(objchn) {
X if(objchn->o_id == id) return(objchn);
X objchn = objchn->nobj;
X }
X return((struct obj *) 0);
X}
X
Xstruct trap *
Xt_at(x,y)
Xregister x,y;
X{
X register struct trap *trap = ftrap;
X while(trap) {
X if(trap->tx == x && trap->ty == y) return(trap);
X trap = trap->ntrap;
X }
X return(0);
X}
X
Xstruct gold *
Xg_at(x,y)
Xregister x,y;
X{
X register struct gold *gold = fgold;
X while(gold) {
X if(gold->gx == x && gold->gy == y) return(gold);
X gold = gold->ngold;
X }
X return(0);
X}
X
X/* make dummy object structure containing gold - for temporary use only */
Xstruct obj *
Xmkgoldobj(q)
Xregister long q;
X{
X register struct obj *otmp;
X
X otmp = newobj(0);
X /* should set o_id etc. but otmp will be freed soon */
X otmp->olet = GOLD_SYM;
X u.ugold -= q;
X OGOLD(otmp) = q;
X flags.botl = 1;
X return(otmp);
X}
X
X/*
X * getobj returns:
X * struct obj *xxx: object to do something with.
X * (struct obj *) 0 error return: no object.
X * &zeroobj explicitly no object (as in w-).
X */
Xstruct obj *
Xgetobj(let,word)
Xregister char *let,*word;
X{
X register struct obj *otmp;
X register char ilet,ilet1,ilet2;
X char buf[BUFSZ];
X char lets[BUFSZ];
X register int foo = 0, foo2;
X register char *bp = buf;
X xchar allowcnt = 0; /* 0, 1 or 2 */
X boolean allowgold = FALSE;
X boolean allowall = FALSE;
X boolean allownone = FALSE;
X xchar foox = 0;
X long cnt;
X
X if(*let == '0') let++, allowcnt = 1;
X if(*let == GOLD_SYM) let++, allowgold = TRUE;
X if(*let == '#') let++, allowall = TRUE;
X if(*let == '-') let++, allownone = TRUE;
X if(allownone) *bp++ = '-';
X if(allowgold) *bp++ = GOLD_SYM;
X if(bp > buf && bp[-1] == '-') *bp++ = ' ';
X
X ilet = 'a';
X for(otmp = invent; otmp; otmp = otmp->nobj){
X if(!*let || index(let, otmp->olet)) {
X bp[foo++] = flags.invlet_constant ? otmp->invlet : ilet;
X
X /* ugly check: remove inappropriate things */
X if((!strcmp(word, "take off") &&
X !(otmp->owornmask & (W_ARMOR - W_ARM2)))
X || (!strcmp(word, "wear") &&
X (otmp->owornmask & (W_ARMOR | W_RING)))
X || (!strcmp(word, "wield") &&
X (otmp->owornmask & W_WEP))
X#ifdef MARKER
X || (!strcmp(word, "write with") &&
X (otmp->olet == TOOL_SYM && otmp->otyp != MAGIC_MARKER))
X#endif
X ) {
X foo--;
X foox++;
X }
X }
X if(ilet == 'z') ilet = 'A'; else ilet++;
X }
X bp[foo] = 0;
X if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
X (void) strcpy(lets, bp); /* necessary since we destroy buf */
X if(foo > 5) { /* compactify string */
X foo = foo2 = 1;
X ilet2 = bp[0];
X ilet1 = bp[1];
X while(ilet = bp[++foo2] = bp[++foo]){
X if(ilet == ilet1+1){
X if(ilet1 == ilet2+1)
X bp[foo2 - 1] = ilet1 = '-';
X else if(ilet2 == '-') {
X bp[--foo2] = ++ilet1;
X continue;
X }
X }
X ilet2 = ilet1;
X ilet1 = ilet;
X }
X }
X if(!foo && !allowall && !allowgold && !allownone) {
X pline("You don't have anything %sto %s.",
X foox ? "else " : "", word);
X return(0);
X }
X for(;;) {
X if(!buf[0]) {
X#ifdef REDO
X if(!in_doagain)
X#endif
X pline("What do you want to %s [*]? ", word);
X } else {
X#ifdef REDO
X if(!in_doagain)
X#endif
X pline("What do you want to %s [%s or ?*]? ",
X word, buf);
X }
X cnt = 0;
X ilet = readchar();
X while(digit(ilet) && allowcnt) {
X#ifdef REDO
X if (ilet != '?' && ilet != '*') savech(ilet);
X#endif
X cnt = 10*cnt + (ilet - '0');
X allowcnt = 2; /* signal presence of cnt */
X ilet = readchar();
X }
X if(digit(ilet)) {
X pline("No count allowed with this command.");
X continue;
X }
X if(index(quitchars,ilet)) {
X pline("Never mind.");
X return((struct obj *)0);
X }
X if(ilet == '-') {
X return(allownone ? &zeroobj : (struct obj *) 0);
X }
X if(ilet == GOLD_SYM) {
X if(!allowgold){
X pline("You cannot %s gold.", word);
X continue;
X }
X if(!(allowcnt == 2 && cnt < u.ugold))
X cnt = u.ugold;
X return(mkgoldobj(cnt));
X }
X if(ilet == '?') {
X doinv(lets);
X if(!(ilet = morc)) continue;
X /* he typed a letter (not a space) to more() */
X } else if(ilet == '*') {
X doinv((char *) 0);
X if(!(ilet = morc)) continue;
X /* ... */
X }
X#ifdef REDO
X if (ilet != '?' && ilet != '*') savech(ilet);
X#endif
X if(flags.invlet_constant) {
X for(otmp = invent; otmp; otmp = otmp->nobj)
X if(otmp->invlet == ilet) break;
X } else {
X if(ilet >= 'A' && ilet <= 'Z') ilet += 'z'-'A'+1;
X ilet -= 'a';
X for(otmp = invent; otmp && ilet;
X ilet--, otmp = otmp->nobj) ;
X }
X if(!otmp) {
X pline("You don't have that object.");
X continue;
X }
X if(cnt < 0 || otmp->quan < cnt) {
X pline("You don't have that many! [You have %u]"
X , otmp->quan);
X continue;
X }
X break;
X }
X if(!allowall && let && !index(let,otmp->olet)) {
X pline("That is a silly thing to %s.",word);
X return(0);
X }
X if(allowcnt == 2) { /* cnt given */
X if(cnt == 0) return(0);
X if(cnt != otmp->quan) {
X register struct obj *obj;
X obj = splitobj(otmp, (int) cnt);
X if(otmp == uwep) setuwep(obj);
X }
X }
X return(otmp);
X}
X
Xckunpaid(otmp) register struct obj *otmp; {
X return( otmp->unpaid );
X}
X
X/* interactive version of getobj - used for Drop and Identify */
X/* return the number of times fn was called successfully */
Xggetobj(word, fn, max)
Xchar *word;
Xint (*fn)(), max;
X{
Xchar buf[BUFSZ];
Xregister char *ip;
Xregister char sym;
Xregister int oletct = 0, iletct = 0;
Xregister boolean allflag = FALSE;
Xchar olets[20], ilets[20];
Xint (*ckfn)() = (int (*)()) 0;
Xxchar allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0; /* BAH */
X if(!invent && !allowgold){
X pline("You have nothing to %s.", word);
X return(0);
X } else {
X register struct obj *otmp = invent;
X register int uflg = 0;
X
X if(allowgold) ilets[iletct++] = GOLD_SYM;
X ilets[iletct] = 0;
X while(otmp) {
X if(!index(ilets, otmp->olet)){
X ilets[iletct++] = otmp->olet;
X ilets[iletct] = 0;
X }
X if(otmp->unpaid) uflg = 1;
X otmp = otmp->nobj;
X }
X ilets[iletct++] = ' ';
X if(uflg) ilets[iletct++] = 'u';
X if(invent) ilets[iletct++] = 'a';
X ilets[iletct] = 0;
X }
X pline("What kinds of thing do you want to %s? [%s] ",
X word, ilets);
X getlin(buf);
X if(buf[0] == '\033') {
X clrlin();
X return(0);
X }
X ip = buf;
X olets[0] = 0;
X while(sym = *ip++){
X if(sym == ' ') continue;
X if(sym == GOLD_SYM) {
X if(allowgold == 1)
X (*fn)(mkgoldobj(u.ugold));
X else if(!u.ugold)
X pline("You have no gold.");
X allowgold = 2;
X } else
X if(sym == 'a' || sym == 'A') allflag = TRUE; else
X if(sym == 'u' || sym == 'U') ckfn = ckunpaid; else
X#ifdef SPELLS
X if(index("!%?[()=*/+\"0", sym)){
X#else
X if(index("!%?[()=*/\"0", sym)){
X#endif
X if(!index(olets, sym)){
X olets[oletct++] = sym;
X olets[oletct] = 0;
X }
X }
X else pline("You don't have any %c's.", sym);
X }
X if(allowgold == 2 && !oletct)
X return(1); /* he dropped gold (or at least tried to) */
X else
X return(askchain(invent, olets, allflag, fn, ckfn, max));
X}
X
X/*
X * Walk through the chain starting at objchn and ask for all objects
X * with olet in olets (if nonNULL) and satisfying ckfn (if nonNULL)
X * whether the action in question (i.e., fn) has to be performed.
X * If allflag then no questions are asked. Max gives the max nr of
X * objects to be treated. Return the number of objects treated.
X */
Xaskchain(objchn, olets, allflag, fn, ckfn, max)
Xstruct obj *objchn;
Xregister char *olets;
Xint allflag;
Xint (*fn)(), (*ckfn)();
Xint max;
X{
Xregister struct obj *otmp, *otmp2;
Xregister char sym, ilet;
Xregister int cnt = 0;
X#ifdef SORTING
X /* changes so the askchain is interrogated in the order specified.
X * For example, if a person specifies =/ then first all rings will be
X * asked about followed by all wands -dgk
X */
Xnextclass:
X#endif
X ilet = 'a'-1;
X for(otmp = objchn; otmp; otmp = otmp2){
X if(ilet == 'z') ilet = 'A'; else ilet++;
X otmp2 = otmp->nobj;
X#ifdef SORTING
X if (olets && *olets && otmp->olet != *olets) continue;
X#else
X if(olets && *olets && !index(olets, otmp->olet)) continue;
X#endif
X if(ckfn && !(*ckfn)(otmp)) continue;
X if(!allflag) {
X pline(xprname(otmp, ilet));
X addtopl(" [nyaq]? ");
X sym = readchar();
X }
X else sym = 'y';
X
X switch(sym){
X case 'a':
X allflag = 1;
X case 'y':
X cnt += (*fn)(otmp);
X if(--max == 0) goto ret;
X case 'n':
X default:
X break;
X case 'q':
X goto ret;
X }
X }
X#ifdef SORTING
X if (olets && *olets && *++olets)
X goto nextclass;
X#endif
X pline(cnt ? "That was all." : "No applicable objects.");
Xret:
X return(cnt);
X}
X
Xobj_to_let(obj) /* should of course only be called for things in invent */
Xregister struct obj *obj;
X{
X register struct obj *otmp;
X register char ilet;
X
X if(flags.invlet_constant)
X return(obj->invlet);
X ilet = 'a';
X for(otmp = invent; otmp && otmp != obj; otmp = otmp->nobj)
X if(++ilet > 'z') ilet = 'A';
X return(otmp ? ilet : NOINVSYM);
X}
X
Xprinv(obj)
Xregister struct obj *obj;
X{
X pline(xprname(obj, obj_to_let(obj)));
X}
X
Xstatic char *
Xxprname(obj,let)
Xregister struct obj *obj;
Xregister char let;
X{
X static char li[BUFSZ];
X
X (void) sprintf(li, "%c - %s.",
X flags.invlet_constant ? obj->invlet : let,
X doname(obj));
X return(li);
X}
X
Xddoinv()
X{
X doinv((char *) 0);
X return(0);
X}
X
X#ifdef SORTING
X# ifdef SPELLS
Xchar inv_order[] = "\")[%?+/=!(*0_`"; /* to be safe, include _ and ` */
X# else
Xchar inv_order[] = "\")[%?/=!(*0_`";
X# endif
Xextern char *let_to_name();
X#endif
X
X/* called with 0 or "": all objects in inventory */
X/* otherwise: all objects with (serial) letter in lets */
Xdoinv(lets)
Xregister char *lets;
X{
X register struct obj *otmp;
X register char ilet;
X int ct = 0;
X char any[BUFSZ];
X#ifdef SORTING
X char *invlet = inv_order;
X int classcount = 0;
X#endif /* SORTING /**/
X
X morc = 0; /* just to be sure */
X
X if(!invent){
X pline("Not carrying anything.");
X return;
X }
X
X cornline(0, (char *) 0);
X#ifdef SORTING
Xnextclass:
X classcount = 0;
X ilet = 'a';
X for(otmp = invent; otmp; otmp = otmp->nobj) {
X if(flags.invlet_constant) ilet = otmp->invlet;
X if(!lets || !*lets || index(lets, ilet)) {
X if (!flags.sortpack || otmp->olet == *invlet) {
X if (flags.sortpack && !classcount) {
X cornline(1, let_to_name(*invlet));
X classcount++;
X }
X cornline(1, xprname(otmp, ilet));
X any[ct++] = ilet;
X }
X }
X if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
X }
X if (flags.sortpack && *++invlet) goto nextclass;
X#else
X ilet = 'a';
X for(otmp = invent; otmp; otmp = otmp->nobj) {
X if(flags.invlet_constant) ilet = otmp->invlet;
X if(!lets || !*lets || index(lets, ilet)) {
X cornline(1, xprname(otmp, ilet));
X any[ct++] = ilet;
X }
X if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
X }
X#endif /* SORTING /**/
X any[ct] = 0;
X cornline(2, any);
X}
X
Xdotypeinv () /* free after Robert Viduya */
X/* Changed to one type only, so he doesnt have to type cr */
X{
X char c, ilet;
X char stuff[BUFSZ];
X register int stct;
X register struct obj *otmp;
X boolean billx = inshop() && doinvbill(0);
X boolean unpd = FALSE;
X
X if (!invent && !u.ugold && !billx) {
X pline ("You aren't carrying anything.");
X return(0);
X }
X
X stct = 0;
X if(u.ugold) stuff[stct++] = GOLD_SYM;
X stuff[stct] = 0;
X for(otmp = invent; otmp; otmp = otmp->nobj) {
X if (!index (stuff, otmp->olet)) {
X stuff[stct++] = otmp->olet;
X stuff[stct] = 0;
X }
X if(otmp->unpaid)
X unpd = TRUE;
X }
X if(unpd) stuff[stct++] = 'u';
X if(billx) stuff[stct++] = 'x';
X stuff[stct] = 0;
X
X if(stct > 1) {
X#ifdef REDO
X if (!in_doagain)
X#endif
X pline ("What type of object [%s] do you want an inventory of? ",
X stuff);
X c = readchar();
X#ifdef REDO
X savech(c);
X#endif
X if(index(quitchars,c)) {
X clrlin();
X return(0);
X }
X } else
X c = stuff[0];
X
X if(c == GOLD_SYM)
X return(doprgold());
X
X if(c == 'x' || c == 'X') {
X if(billx)
X (void) doinvbill(1);
X else
X pline("No used-up objects on the shopping bill.");
X return(0);
X }
X
X if((c == 'u' || c == 'U') && !unpd) {
X pline("You are not carrying any unpaid objects.");
X return(0);
X }
X
X stct = 0;
X ilet = 'a';
X for (otmp = invent; otmp; otmp = otmp -> nobj) {
X if(flags.invlet_constant) ilet = otmp->invlet;
X if (c == otmp -> olet || (c == 'u' && otmp -> unpaid))
X stuff[stct++] = ilet;
X if(!flags.invlet_constant) if(++ilet > 'z') ilet = 'A';
X }
X stuff[stct] = '\0';
X if(stct == 0)
X pline("You have no such objects.");
X else
X doinv (stuff);
X
X return(0);
X}
X
X/* look at what is here */
Xdolook() {
X register struct obj *otmp, *otmp0;
X register struct gold *gold;
X char *verb = Blind ? "feel" : "see";
X int ct = 0;
X int fd = 0;
X
X#ifdef KAA
X read_engr_at(u.ux, u.uy); /* Eric Backus */
X#endif
X if(!u.uswallow) {
X otmp0 = o_at(u.ux, u.uy);
X gold = g_at(u.ux, u.uy);
X } else {
X pline("You %s no objects here.", verb);
X return(!!Blind);
X }
X
X /* added by GAN 10/30/86 */
X#ifdef FOUNTAINS
X if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) {
X fd++;
X pline("There is a fountain here.");
X }
X#endif
X#ifdef NEWCLASS
X if(IS_THRONE(levl[u.ux][u.uy].typ)) {
X fd++;
X pline("There is an opulent throne here.");
X }
X#endif
X if(u.ux == xupstair && u.uy == yupstair) {
X fd++;
X pline("There is a stairway up here.");
X }
X if(u.ux == xdnstair && u.uy == ydnstair) {
X fd++;
X pline("There is a stairway down here.");
X }
X if(Blind) {
X pline("You try to feel what is lying here on the floor.");
X if(Levitation) {
X pline("But you can't reach it!");
X return(0);
X }
X }
X
X if(!otmp0 && !gold) {
X if(Blind || !fd)
X pline("You %s no objects here.", verb);
X return(!!Blind);
X }
X
X cornline(0, "Things that are here:");
X for(otmp = otmp0; otmp; otmp = otmp->nobj) {
X if(otmp->ox == u.ux && otmp->oy == u.uy) {
X ct++;
X cornline(1, doname(otmp));
X
X if(Blind && otmp->otyp == DEAD_COCKATRICE && !uarmg) {
X pline("Touching the dead cockatrice is a fatal mistake ...");
X pline("You die ...");
X killer = "dead cockatrice";
X done("died");
X }
X }
X }
X
X if(gold) {
X char gbuf[30];
X
X (void) sprintf(gbuf, "%ld gold piece%s",
X gold->amount, plur(gold->amount));
X if(!ct++)
X pline("You %s here %s.", verb, gbuf);
X else
X cornline(1, gbuf);
X }
X
X if(ct == 1 && !gold) {
X pline("You %s here %s.", verb, doname(otmp0));
X cornline(3, (char *) 0);
X }
X if(ct > 1)
X cornline(2, (char *) 0);
X return(!!Blind);
X}
X
Xstackobj(obj) register struct obj *obj; {
Xregister struct obj *otmp = fobj;
X for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp != obj)
X if(otmp->ox == obj->ox && otmp->oy == obj->oy &&
X merged(obj,otmp,1))
X return;
X}
X
X/* merge obj with otmp and delete obj if types agree */
Xmerged(otmp,obj,lose) register struct obj *otmp, *obj; {
X if(obj->otyp == otmp->otyp &&
X obj->unpaid == otmp->unpaid &&
X obj->spe == otmp->spe &&
X obj->dknown == otmp->dknown &&
X obj->cursed == otmp->cursed &&
X#ifdef SPELLS
X (index("%*?!+", obj->olet) ||
X#else
X (index("%*?!", obj->olet) ||
X#endif
X (obj->known == otmp->known &&
X (obj->olet == WEAPON_SYM && obj->otyp < BOOMERANG)))) {
X otmp->quan += obj->quan;
X otmp->owt += obj->owt;
X if(lose) freeobj(obj);
X obfree(obj,otmp); /* free(obj), bill->otmp */
X return(1);
X } else return(0);
X}
X
X/*
X * Gold is no longer displayed; in fact, when you have a lot of money,
X * it may take a while before you have counted it all.
X * [Bug: d$ and pickup still tell you how much it was.]
X */
Xextern int (*occupation)();
Xextern char *occtxt;
Xstatic long goldcounted;
X
Xcountgold(){
X if((goldcounted += 100*(u.ulevel + 1)) >= u.ugold) {
X long eps = 0;
X if(!rn2(2)) eps = rnd((int) (u.ugold/100 + 1));
X pline("You probably have about %ld gold pieces.",
X u.ugold + eps);
X return(0); /* done */
X }
X return(1); /* continue */
X}
X
Xdoprgold(){
X if(!u.ugold)
X pline("You do not carry any gold.");
X else if(u.ugold <= 500)
X pline("You are carrying %ld gold piece%s.", u.ugold, plur(u.ugold));
X else {
X pline("You sit down in order to count your gold pieces.");
X goldcounted = 500;
X occupation = countgold;
X occtxt = "counting your gold";
X }
X return(1);
X}
X
X/* --- end of gold counting section --- */
X
Xdoprwep(){
X if(!uwep) pline("You are empty handed.");
X else prinv(uwep);
X return(0);
X}
X
Xdoprarm(){
X if(!uarm && !uarmg && !uarms && !uarmh)
X pline("You are not wearing any armor.");
X else {
X char lets[6];
X register int ct = 0;
X
X if(uarm) lets[ct++] = obj_to_let(uarm);
X if(uarm2) lets[ct++] = obj_to_let(uarm2);
X if(uarmh) lets[ct++] = obj_to_let(uarmh);
X if(uarms) lets[ct++] = obj_to_let(uarms);
X if(uarmg) lets[ct++] = obj_to_let(uarmg);
X lets[ct] = 0;
X doinv(lets);
X }
X return(0);
X}
X
Xdoprring(){
X if(!uleft && !uright)
X pline("You are not wearing any rings.");
X else {
X char lets[3];
X register int ct = 0;
X
X if(uleft) lets[ct++] = obj_to_let(uleft);
X if(uright) lets[ct++] = obj_to_let(uright);
X lets[ct] = 0;
X doinv(lets);
X }
X return(0);
X}
X
Xdigit(c) char c; {
X return(c >= '0' && c <= '9');
X}
X
X/*
X * useupf(obj)
X * uses up an object that's on the floor
X */
Xuseupf(obj)
Xregister struct obj *obj;
X{
X if(obj->quan > 1) {
X obj->quan--;
X obj->owt = weight(obj);
X } else delobj(obj);
X}
X
X#ifdef SORTING
X/*
X * Convert from a symbol to a string for printing object classes
X *
X * Names from objects.h
X * char obj_symbols[] = {
X * ILLOBJ_SYM, AMULET_SYM, FOOD_SYM, WEAPON_SYM, TOOL_SYM,
X * BALL_SYM, CHAIN_SYM, ROCK_SYM, ARMOR_SYM, POTION_SYM, SCROLL_SYM,
X * WAND_SYM, [SPBOOK_SYM], RING_SYM, GEM_SYM, 0 };
X */
X#define Sprintf (void) sprintf
X
Xextern char obj_symbols[];
Xstatic char *names[] = {"Illegal objects", "Amulets", "Comestibles", "Weapons",
X "Tools", "Iron balls", "Chains", "Rocks", "Armor",
X "Potions", "Scrolls", "Wands",
X#ifdef SPELLS
X "Spellbooks",
X#endif
X "Rings", "Gems"};
Xchar *
Xlet_to_name(let)
Xchar let;
X{
X char *pos = index(obj_symbols, let);
X extern char *HI, *HE;
X /* arbitrary buffer size by Tom May (tom@uw-warp) */
X static char *buf = NULL;
X
X if (buf == NULL)
X buf = (char *) alloc (strlen(HI) + strlen(HE) + 15 + 1);
X
X if (pos == NULL) pos = obj_symbols;
X if (HI && HE)
X Sprintf(buf, "%s%s%s", HI, names[pos - obj_symbols], HE);
X else
X Sprintf(buf, "%s", names[pos - obj_symbols]);
X return (buf);
X}
X#endif /* SORTING /**/
X
Xreassign ()
X{
X register int i;
X register struct obj *obj;
X
X for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
X obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
X lastinvnr = i;
X}
END_OF_invent.c
if test 22894 -ne `wc -c shk.c <<'END_OF_shk.c'
X/* SCCS Id: @(#)shk.c 2.1 87/08/23
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X
X#include "hack.h"
X#ifdef QUEST
Xint shlevel = 0;
Xstruct monst *shopkeeper = 0;
Xstruct obj *billobjs = 0;
Xobfree(obj,merge) register struct obj *obj, *merge; {
X free((char *) obj);
X}
Xinshop(){ return(0); }
Xaddtobill(){}
Xsubfrombill(){}
Xsplitbill(){}
Xdopay(){ return(0); }
Xpaybill(){}
Xdoinvbill(){ return(0); }
Xshkdead(){}
Xshkcatch(){ return(0); }
Xshk_move(){ return(0); }
Xreplshk(mtmp,mtmp2) struct monst *mtmp, *mtmp2; {}
Xchar *shkname(){ return(""); }
X
X#else
X#include "mfndpos.h"
X#include "mkroom.h"
X#include "eshk.h"
X
X#define ESHK(mon) ((struct eshk *)(&(mon->mextra[0])))
X#define NOTANGRY(mon) mon->mpeaceful
X#define ANGRY(mon) !NOTANGRY(mon)
X
Xextern char plname[], *xname();
Xextern struct monst *makemon();
Xextern struct obj *o_on(), *bp_to_obj(),
X *carrying();
X
X/* Descriptor of current shopkeeper. Note that the bill need not be
X per-shopkeeper, since it is valid only when in a shop. */
Xstatic struct monst *shopkeeper = 0;
Xstatic struct bill_x *bill;
Xstatic int shlevel = 0; /* level of this shopkeeper */
X struct obj *billobjs; /* objects on bill with bp->useup */
X /* only accessed here and by save & restore */
Xstatic long int total; /* filled by addupbill() */
Xstatic long int followmsg; /* last time of follow message */
Xstatic setpaid(), findshk(), dopayobj(), getprice(), realhunger();
X
X/*
X invariants: obj->unpaid iff onbill(obj) [unless bp->useup]
X obj->quan <= bp->bquan
X */
X
Xchar *
Xshkname(mtmp) /* called in do_name.c */
Xregister struct monst *mtmp;
X{
X return(ESHK(mtmp)->shknam);
X}
X
Xshkdead(mtmp) /* called in mon.c */
Xregister struct monst *mtmp;
X{
X register struct eshk *eshk = ESHK(mtmp);
X
X if(eshk->shoplevel == dlevel)
X rooms[eshk->shoproom].rtype = OROOM;
X if(mtmp == shopkeeper) {
X setpaid();
X shopkeeper = 0;
X bill = (struct bill_x *) -1000; /* dump core when referenced */
X }
X}
X
Xreplshk(mtmp,mtmp2)
Xregister struct monst *mtmp, *mtmp2;
X{
X if(mtmp == shopkeeper) {
X shopkeeper = mtmp2;
X bill = &(ESHK(shopkeeper)->bill[0]);
X }
X}
X
Xstatic
Xsetpaid(){ /* caller has checked that shopkeeper exists */
X /* either we paid or left the shop or he just died */
Xregister struct obj *obj;
Xregister struct monst *mtmp;
X for(obj = invent; obj; obj = obj->nobj)
X obj->unpaid = 0;
X for(obj = fobj; obj; obj = obj->nobj)
X obj->unpaid = 0;
X for(obj = fcobj; obj; obj = obj->nobj)
X obj->unpaid = 0;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X for(obj = mtmp->minvent; obj; obj = obj->nobj)
X obj->unpaid = 0;
X for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
X for(obj = mtmp->minvent; obj; obj = obj->nobj)
X obj->unpaid = 0;
X while(obj = billobjs){
X billobjs = obj->nobj;
X free((char *) obj);
X }
X ESHK(shopkeeper)->billct = 0;
X}
X
Xstatic
Xaddupbill(){ /* delivers result in total */
X /* caller has checked that shopkeeper exists */
Xregister ct = ESHK(shopkeeper)->billct;
Xregister struct bill_x *bp = bill;
X total = 0;
X while(ct--){
X total += bp->price * bp->bquan;
X bp++;
X }
X}
X
Xinshop(){
Xregister roomno = inroom(u.ux,u.uy);
X
X /* Did we just leave a shop? */
X if(u.uinshop &&
X (u.uinshop != roomno + 1 || shlevel != dlevel || !shopkeeper)) {
X
X /* This is part of the bugfix for shopkeepers not having their
X * bill paid. As reported by ab@unido -dgk
X * I made this standard due to the KOPS code below. -mrs
X */
X if(shopkeeper) {
X if(ESHK(shopkeeper)->billct) {
X if(inroom(shopkeeper->mx, shopkeeper->my)
X == u.uinshop - 1) /* ab@unido */
X pline("Somehow you escaped the shop without paying!");
X addupbill();
X pline("You stole for a total worth of %ld zorkmids.",
X total);
X ESHK(shopkeeper)->robbed += total;
X setpaid();
X if((rooms[ESHK(shopkeeper)->shoproom].rtype == SHOPBASE)
X == (rn2(3) == 0))
X ESHK(shopkeeper)->following = 1;
X#ifdef KOPS
X { /* Keystone Kops srt@ucla */
X coord mm;
X register int cnt = dlevel + rnd(3);
X /* Create a swarm near the staircase */
X pline("An alarm sounds throughout the dungeon!");
X pline("The Keystone Kops are after you!");
X mm.x = xdnstair;
X mm.y = ydnstair;
X while(cnt--) {
X (void) enexto(&mm, mm.x, mm.y);
X (void) mkmon_at('K', mm.x, mm.y);
X }
X /* Create a swarm near the shopkeeper */
X cnt = dlevel + rnd(3);
X mm.x = shopkeeper->mx;
X mm.y = shopkeeper->my;
X while(cnt--) {
X (void) enexto(&mm, mm.x, mm.y);
X (void) mkmon_at('K', mm.x, mm.y);
X }
X }
X#endif
X }
X shopkeeper = 0;
X shlevel = 0;
X }
X u.uinshop = 0;
X }
X
X /* Did we just enter a zoo of some kind? */
X if(roomno >= 0) {
X register int rt = rooms[roomno].rtype;
X register struct monst *mtmp;
X if(rt == ZOO) {
X pline("Welcome to David's treasure zoo!");
X } else
X if(rt == SWAMP) {
X pline("It looks rather muddy down here.");
X } else
X if(rt == COURT) {
X pline("You are in an opulent throne room!");
X } else
X if(rt == MORGUE) {
X if(midnight())
X pline("Go away! Go away!");
X else
X pline("You get an uncanny feeling ...");
X } else
X rt = 0;
X if(rt != 0) {
X rooms[roomno].rtype = OROOM;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(rt != ZOO || !rn2(3))
X mtmp->msleep = 0;
X }
X }
X
X /* Did we just enter a shop? */
X if(roomno >= 0 && rooms[roomno].rtype >= SHOPBASE) {
X register int rt = rooms[roomno].rtype;
X
X if(shlevel != dlevel || !shopkeeper
X || ESHK(shopkeeper)->shoproom != roomno)
X findshk(roomno);
X if(!shopkeeper) {
X rooms[roomno].rtype = OROOM;
X u.uinshop = 0;
X } else if(!u.uinshop){
X if(!ESHK(shopkeeper)->visitct ||
X strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ)){
X
X /* He seems to be new here */
X ESHK(shopkeeper)->visitct = 0;
X ESHK(shopkeeper)->following = 0;
X (void) strncpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
X NOTANGRY(shopkeeper) = 1;
X }
X if(!ESHK(shopkeeper)->following) {
X boolean box, pick;
X
X pline("Hello %s! Welcome%s to %s's %s!",
X plname,
X ESHK(shopkeeper)->visitct++ ? " again" : "",
X shkname(shopkeeper),
X shtypes[rt - SHOPBASE].name);
X/* shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype - SHOPBASE].name);
X*/
X box = carrying(ICE_BOX) != (struct obj *)0;
X pick = carrying(PICK_AXE) != (struct obj *)0;
X if(box || pick) {
X if(dochug(shopkeeper)) {
X u.uinshop = 0; /* he died moving */
X return(0);
X }
X pline("Will you please leave your %s outside?",
X (box && pick) ? "box and pick-axe" :
X box ? "box" : "pick-axe");
X }
X }
X u.uinshop = roomno + 1;
X }
X }
X return(u.uinshop);
X}
X
Xstatic
Xfindshk(roomno)
Xregister roomno;
X{
Xregister struct monst *mtmp;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->isshk && ESHK(mtmp)->shoproom == roomno
X && ESHK(mtmp)->shoplevel == dlevel) {
X shopkeeper = mtmp;
X bill = &(ESHK(shopkeeper)->bill[0]);
X shlevel = dlevel;
X if(ANGRY(shopkeeper) &&
X strncmp(ESHK(shopkeeper)->customer,plname,PL_NSIZ))
X NOTANGRY(shopkeeper) = 1;
X /* billobjs = 0; -- this is wrong if we save in a shop */
X /* (and it is harmless to have too many things in billobjs) */
X return;
X }
X shopkeeper = 0;
X shlevel = 0;
X bill = (struct bill_x *) -1000; /* dump core when referenced */
X}
X
Xstatic struct bill_x *
Xonbill(obj) register struct obj *obj; {
Xregister struct bill_x *bp;
X if(!shopkeeper) return(0);
X for(bp = bill; bp < &bill[ESHK(shopkeeper)->billct]; bp++)
X if(bp->bo_id == obj->o_id) {
X if(!obj->unpaid) pline("onbill: paid obj on bill?");
X return(bp);
X }
X if(obj->unpaid) pline("onbill: unpaid obj not on bill?");
X return(0);
X}
X
X/* called with two args on merge */
Xobfree(obj,merge) register struct obj *obj, *merge; {
Xregister struct bill_x *bp = onbill(obj);
Xregister struct bill_x *bpm;
X if(bp) {
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);
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(shopkeeper)->billct--;
X *bp = bill[ESHK(shopkeeper)->billct];
X }
X }
X free((char *) obj);
X}
X
Xstatic
Xpay(tmp,shkp)
Xlong tmp;
Xregister struct monst *shkp;
X{
X long robbed = ESHK(shkp)->robbed;
X
X u.ugold -= tmp;
X shkp->mgold += tmp;
X flags.botl = 1;
X if(robbed) {
X robbed -= tmp;
X if(robbed < 0) robbed = 0;
X ESHK(shkp)->robbed = robbed;
X }
X}
X
Xdopay(){
Xlong ltmp;
Xregister struct bill_x *bp;
Xregister struct monst *shkp;
Xint pass, tmp;
X
X multi = 0;
X (void) inshop();
X for(shkp = fmon; shkp; shkp = shkp->nmon)
X if(shkp->isshk && dist(shkp->mx,shkp->my) < 3)
X break;
X if(!shkp && u.uinshop &&
X inroom(shopkeeper->mx,shopkeeper->my) == ESHK(shopkeeper)->shoproom)
X shkp = shopkeeper;
X
X if(!shkp) {
X pline("There is nobody here to receive your payment.");
X return(0);
X }
X ltmp = ESHK(shkp)->robbed;
X if(shkp != shopkeeper && NOTANGRY(shkp)) {
X if(!ltmp) {
X pline("You do not owe %s anything.", monnam(shkp));
X } else
X if(!u.ugold) {
X pline("You have no money.");
X } else {
X long ugold = u.ugold;
X
X if(u.ugold > ltmp) {
X pline("You give %s the %ld gold pieces %s asked for.",
X monnam(shkp), ltmp, index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
X ? "he" : (index("nN", shkp->data->mlet) ? "she" : "it"));
X pay(ltmp, shkp);
X } else {
X pline("You give %s all your gold.", monnam(shkp));
X pay(u.ugold, shkp);
X }
X if(ugold < ltmp/2) {
X pline("Unfortunately, %s doesn't look satisfied.",
X index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
X ? "he" : (index("nN", shkp->data->mlet) ? "she" : "it"));
X } else {
X ESHK(shkp)->robbed = 0;
X ESHK(shkp)->following = 0;
X if(ESHK(shkp)->shoplevel != dlevel) {
X /* For convenience's sake, let him disappear */
X shkp->minvent = 0; /* %% */
X shkp->mgold = 0;
X mondead(shkp);
X }
X }
X }
X return(1);
X }
X
X if(!ESHK(shkp)->billct){
X pline("You do not owe %s anything.", monnam(shkp));
X if(!u.ugold){
X pline("Moreover, you have no money.");
X return(1);
X }
X if(ESHK(shkp)->robbed){
X pline("But since %s shop has been robbed recently,",
X index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
X ? "his" : (index("nN", shkp->data->mlet) ? "her" : "its"));
X pline("you %srepay %s's expenses.",
X (u.ugold < ESHK(shkp)->robbed) ? "partially " : "",
X monnam(shkp));
X pay(min(u.ugold, ESHK(shkp)->robbed), shkp);
X ESHK(shkp)->robbed = 0;
X return(1);
X }
X if(ANGRY(shkp)){
X pline("But in order to appease %s,",
X amonnam(shkp, "angry"));
X if(u.ugold >= 1000){
X ltmp = 1000;
X pline(" you give %s 1000 gold pieces.",
X index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
X ? "him" : (index("nN", shkp->data->mlet) ? "her" : "it"));
X } else {
X ltmp = u.ugold;
X pline(" you give %s all your money.",
X index("@CGHKLOQTVWZ&ehimt", shkp->data->mlet)
X ? "him" : (index("nN", shkp->data->mlet) ? "her" : "it"));
X }
X pay(ltmp, shkp);
X if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)
X || rn2(3)){
X pline("%s calms down.", Monnam(shkp));
X NOTANGRY(shkp) = 1;
X } else pline("%s is as angry as ever.",
X Monnam(shkp));
X }
X return(1);
X }
X if(shkp != shopkeeper) {
X impossible("dopay: not to shopkeeper?");
X if(shopkeeper) setpaid();
X return(0);
X }
X for(pass = 0; pass <= 1; pass++) {
X tmp = 0;
X while(tmp < ESHK(shopkeeper)->billct) {
X bp = &bill[tmp];
X if(!pass && !bp->useup) {
X tmp++;
X continue;
X }
X if(!dopayobj(bp)) return(1);
X#ifdef MSDOS
X *bp = bill[--ESHK(shopkeeper)->billct];
X#else
X bill[tmp] = bill[--ESHK(shopkeeper)->billct];
X#endif /* MSDOS /**/
X }
X }
X pline("Thank you for shopping in %s's %s!",
X shkname(shopkeeper),
X shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype - SHOPBASE].name);
X NOTANGRY(shopkeeper) = 1;
X return(1);
X}
X
X/* return 1 if paid successfully */
X/* 0 if not enough money */
X/* -1 if object could not be found (but was paid) */
Xstatic
Xdopayobj(bp) register struct bill_x *bp; {
Xregister struct obj *obj;
Xlong ltmp;
X
X /* find the object on one of the lists */
X obj = bp_to_obj(bp);
X
X if(!obj) {
X impossible("Shopkeeper administration out of order.");
X setpaid(); /* be nice to the player */
X return(0);
X }
X
X if(!obj->unpaid && !bp->useup){
X impossible("Paid object on bill??");
X return(1);
X }
X obj->unpaid = 0;
X ltmp = bp->price * bp->bquan;
X if(ANGRY(shopkeeper)) ltmp += ltmp/3;
X if(u.ugold < ltmp){
X pline("You don't have gold enough to pay %s.",
X doname(obj));
X obj->unpaid = 1;
X return(0);
X }
X pay(ltmp, shopkeeper);
X pline("You bought %s for %ld gold piece%s.",
X doname(obj), ltmp, plur(ltmp));
X if(bp->useup) {
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 pline("Error in shopkeeper administration.");
X }
X free((char *) obj);
X }
X return(1);
X}
X
X/* routine called after dying (or quitting) with nonempty bill */
Xpaybill(){
X if(shlevel == dlevel && shopkeeper && ESHK(shopkeeper)->billct){
X addupbill();
X if(total > u.ugold){
X shopkeeper->mgold += u.ugold;
X u.ugold = 0;
X pline("%s comes and takes all your possessions.",
X Monnam(shopkeeper));
X } else {
X u.ugold -= total;
X shopkeeper->mgold += total;
X pline("%s comes and takes the %ld zorkmids you owed him.",
X Monnam(shopkeeper), total);
X }
X setpaid(); /* in case we create bones */
X }
X}
X
X/* find obj on one of the lists */
Xstruct obj *
Xbp_to_obj(bp)
Xregister struct bill_x *bp;
X{
X register struct obj *obj;
X register struct monst *mtmp;
X register unsigned 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, fcobj))) {
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(obj = o_on(id, mtmp->minvent))
X break;
X for(mtmp = fallen_down; mtmp; mtmp = mtmp->nmon)
X if(obj = o_on(id, mtmp->minvent))
X break;
X }
X return(obj);
X}
X
X/* called in hack.c when we pickup an object */
Xaddtobill(obj) register struct obj *obj; {
Xregister struct bill_x *bp;
Xchar buf[40];
X if(!inshop() ||
X (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
X (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y) ||
X onbill(obj) /* perhaps we threw it away earlier */
X ) return;
X if(ESHK(shopkeeper)->billct == BILLSZ){
X pline("You got that for free!");
X return;
X }
X#ifdef DGKMOD
X /* To recognize objects the showkeeper is not interested in. -dgk
X */
X if (obj->no_charge) {
X obj->no_charge = 0;
X return;
X }
X#endif
X bp = &bill[ESHK(shopkeeper)->billct];
X bp->bo_id = obj->o_id;
X bp->bquan = obj->quan;
X bp->useup = 0;
X bp->price = getprice(obj);
X strcpy(buf, "For you, ");
X if (ANGRY(shopkeeper)) strcat(buf, "scum ");
X else {
X switch(rnd(4) + u.udemigod) {
X case 1: strcat(buf, "good");
X break;
X case 2: strcat(buf, "honored");
X break;
X case 3: strcat(buf, "most gracious");
X break;
X case 4: strcat(buf, "esteemed");
X break;
X case 5: strcat(buf, "holy");
X break;
X }
X if(u.usym != '@') strcat(buf, " creature");
X else strcat(buf, (flags.female) ? " lady" : " sir");
X }
X pline("%s; only %d %s %s.", buf, bp->price,
X (bp->bquan > 1) ? "per" : "for this",
X typename(obj->otyp));
X
X ESHK(shopkeeper)->billct++;
X obj->unpaid = 1;
X}
X
Xsplitbill(obj,otmp) register struct obj *obj, *otmp; {
X /* otmp has been split off from obj */
Xregister struct bill_x *bp;
Xregister int tmp;
X bp = onbill(obj);
X if(!bp) {
X impossible("splitbill: not on bill?");
X return;
X }
X if(bp->bquan < otmp->quan) {
X impossible("Negative quantity on bill??");
X }
X if(bp->bquan == otmp->quan) {
X impossible("Zero quantity on bill??");
X }
X bp->bquan -= otmp->quan;
X
X /* addtobill(otmp); */
X if(ESHK(shopkeeper)->billct == BILLSZ) otmp->unpaid = 0;
X else {
X tmp = bp->price;
X bp = &bill[ESHK(shopkeeper)->billct];
X bp->bo_id = otmp->o_id;
X bp->bquan = otmp->quan;
X bp->useup = 0;
X bp->price = tmp;
X ESHK(shopkeeper)->billct++;
X }
X}
X
Xsubfrombill(obj) register struct obj *obj; {
Xlong ltmp;
Xregister int tmp;
Xregister struct obj *otmp;
Xregister struct bill_x *bp;
X if(!inshop() || (u.ux == ESHK(shopkeeper)->shk.x && u.uy == ESHK(shopkeeper)->shk.y) ||
X (u.ux == ESHK(shopkeeper)->shd.x && u.uy == ESHK(shopkeeper)->shd.y))
X return;
X if((bp = onbill(obj)) != 0){
X obj->unpaid = 0;
X if(bp->bquan > obj->quan){
X otmp = newobj(0);
X *otmp = *obj;
X bp->bo_id = otmp->o_id = flags.ident++;
X otmp->quan = (bp->bquan -= obj->quan);
X otmp->owt = 0; /* superfluous */
X otmp->onamelth = 0;
X bp->useup = 1;
X otmp->nobj = billobjs;
X billobjs = otmp;
X return;
X }
X ESHK(shopkeeper)->billct--;
X *bp = bill[ESHK(shopkeeper)->billct];
X return;
X }
X if(obj->unpaid){
X pline("%s didn't notice.", Monnam(shopkeeper));
X obj->unpaid = 0;
X return; /* %% */
X }
X /* he dropped something of his own - probably wants to sell it */
X if(shopkeeper->msleep || shopkeeper->mfroz ||
X inroom(shopkeeper->mx,shopkeeper->my) != ESHK(shopkeeper)->shoproom)
X return;
X if(ESHK(shopkeeper)->billct == BILLSZ
X || !saleable(rooms[ESHK(shopkeeper)->shoproom].rtype-SHOPBASE, obj)
X/*
X ((tmp = shtypes[rooms[ESHK(shopkeeper)->shoproom].rtype-SHOPBASE].symb) && tmp != obj->olet)
X*/
X || index("_0", obj->olet)) {
X pline("%s seems not interested.", Monnam(shopkeeper));
X#ifdef DGKMOD
X obj->no_charge = 1;
X#endif
X return;
X }
X ltmp = getprice(obj) * obj->quan;
X if(ANGRY(shopkeeper)) {
X ltmp /= 3;
X NOTANGRY(shopkeeper) = 1;
X } else ltmp /= 2;
X if(ESHK(shopkeeper)->robbed){
X if((ESHK(shopkeeper)->robbed -= ltmp) < 0)
X ESHK(shopkeeper)->robbed = 0;
Xpline("Thank you for your contribution to restock this recently plundered shop.");
X return;
X }
X if(ltmp > shopkeeper->mgold)
X ltmp = shopkeeper->mgold;
X pay(-ltmp, shopkeeper);
X if(!ltmp) {
X pline("%s gladly accepts %s but cannot pay you at present.",
X Monnam(shopkeeper), doname(obj));
X#ifdef DGKMOD
X obj->no_charge = 1;
X#endif
X } else
X pline("You sold %s and got %ld gold piece%s.", doname(obj), ltmp,
X plur(ltmp));
X}
X
Xdoinvbill(mode)
Xint mode; /* 0: deliver count 1: paged */
X{
X register struct bill_x *bp;
X register struct obj *obj;
X long totused, thisused;
X char buf[BUFSZ];
X
X if(mode == 0) {
X register int cnt = 0;
X
X if(shopkeeper)
X for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++)
X if(bp->useup ||
X ((obj = bp_to_obj(bp)) && obj->quan < bp->bquan))
X cnt++;
X return(cnt);
X }
X
X if(!shopkeeper) {
X impossible("doinvbill: no shopkeeper?");
X return(0);
X }
X
X set_pager(0);
X if(page_line("Unpaid articles already used up:") || page_line(""))
X goto quit;
X
X totused = 0;
X for(bp = bill; bp - bill < ESHK(shopkeeper)->billct; bp++) {
X obj = bp_to_obj(bp);
X if(!obj) {
X impossible("Bad shopkeeper administration.");
X goto quit;
X }
X if(bp->useup || bp->bquan > obj->quan) {
X register int cnt, oquan, uquan;
X
X oquan = obj->quan;
X uquan = (bp->useup ? bp->bquan : bp->bquan - oquan);
X thisused = bp->price * uquan;
X totused += thisused;
X obj->quan = uquan; /* cheat doname */
X (void) sprintf(buf, "x - %s", doname(obj));
X obj->quan = oquan; /* restore value */
X for(cnt = 0; buf[cnt]; cnt++);
X while(cnt < 50)
X buf[cnt++] = ' ';
X (void) sprintf(&buf[cnt], " %5ld zorkmids", thisused);
X if(page_line(buf))
X goto quit;
X }
X }
X (void) sprintf(buf, "Total:%50ld zorkmids", totused);
X if(page_line("") || page_line(buf))
X goto quit;
X set_pager(1);
X return(0);
Xquit:
X set_pager(2);
X return(0);
X}
X
Xstatic
Xgetprice(obj) register struct obj *obj; {
Xregister int tmp, ac;
X switch(obj->olet){
X case AMULET_SYM:
X tmp = rn1(1500, 3500);
X break;
X case TOOL_SYM:
X switch(obj->otyp) {
X case EXPENSIVE_CAMERA: tmp = rn1(400, 200);
X break;
X#ifdef MARKER
X case MAGIC_MARKER: tmp = rn1(100,50);
X break;
X#endif
X#ifdef WALKIES
X case LEASH: tmp = rn1(40,20);
X break;
X#endif
X#ifdef RPH
X case BLINDFOLD: tmp = rn1(40,20);
X break;
X case MIRROR: tmp = rn1(80,40);
X break;
X#endif
X case STETHOSCOPE: tmp = rn1(100,80);
X break;
X case CAN_OPENER: tmp = rn1(50,30);
X break;
X default: tmp = rn1(20,10);
X break;
X }
X break;
X case RING_SYM:
X tmp = rn1(200,100);
X break;
X case WAND_SYM:
X tmp = rn1(300,150);
X break;
X case SCROLL_SYM:
X#ifdef MAIL
X if(obj->otyp == SCR_MAIL)
X tmp = rn1(5,5);
X else
X#endif
X tmp = rn1(200,100);
X break;
X case POTION_SYM:
X tmp = rn1(200,100);
X break;
X#ifdef SPELLS
X case SPBOOK_SYM:
X tmp = rn1(500,500);
X break;
X#endif
X case FOOD_SYM:
X
X tmp = (2000+objects[obj->otyp].nutrition)/realhunger();
X tmp = rn1((tmp < 10) ? 10 : tmp,
X objects[obj->otyp].nutrition/20 + 5);
X break;
X case GEM_SYM:
X tmp = rn1(120,60);
X break;
X case ARMOR_SYM:
X ac = ARM_BONUS(obj);
X if(ac <= -10) /* probably impossible */
X ac = -9;
X tmp = ac*ac+10*rn1(10+ac,10);
X break;
X case WEAPON_SYM:
X if(obj->otyp < BOOMERANG)
X tmp = rn1(4,2);
X else if(obj->otyp == BOOMERANG ||
X obj->otyp == DAGGER ||
X obj->otyp == CLUB ||
X obj->otyp == SLING)
X tmp = rn1(50,50);
X else if(obj->otyp == KATANA)
X tmp = rn1(700,800);
X else if(obj->otyp == LONG_SWORD ||
X obj->otyp == TWO_HANDED_SWORD ||
X obj->otyp == BROAD_SWORD)
X tmp = rn1(500,500);
X else tmp = rn1(150,100);
X break;
X case CHAIN_SYM:
X pline("Strange ..., carrying a chain?");
X case BALL_SYM:
X tmp = 10;
X break;
X default:
X tmp = 10000;
X }
X return(tmp);
X}
X
Xstatic
Xrealhunger(){ /* not completely foolproof */
Xregister tmp = u.uhunger;
Xregister struct obj *otmp = invent;
X while(otmp){
X if(otmp->olet == FOOD_SYM && !otmp->unpaid)
X tmp += objects[otmp->otyp].nutrition;
X otmp = otmp->nobj;
X }
X return((tmp <= 0) ? 1 : tmp);
X}
X
Xshkcatch(obj)
Xregister struct obj *obj;
X{
X register struct monst *shkp = shopkeeper;
X
X if(u.uinshop && shkp && !shkp->mfroz && !shkp->msleep &&
X u.dx && u.dy &&
X inroom(u.ux+u.dx, u.uy+u.dy) + 1 == u.uinshop &&
X shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y &&
X u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y) {
X pline("%s nimbly catches the %s.", Monnam(shkp), xname(obj));
X obj->nobj = shkp->minvent;
X shkp->minvent = obj;
X return(1);
X }
X return(0);
X}
X
X/*
X * shk_move: return 1: he moved 0: he didnt -1: let m_move do it
X */
Xshk_move(shkp)
Xregister struct monst *shkp;
X{
X register struct monst *mtmp;
X register struct permonst *mdat = shkp->data;
X register xchar gx,gy,omx,omy,nx,ny,nix,niy;
X register schar appr,i;
X register int udist;
X int z;
X schar shkroom,chi,chcnt,cnt;
X boolean uondoor, satdoor, avoid, badinv;
X coord poss[9];
X long info[9];
X struct obj *ib = 0;
X
X omx = shkp->mx;
X omy = shkp->my;
X
X if((udist = dist(omx,omy)) < 3) {
X if(ANGRY(shkp)) {
X (void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
X return(0);
X }
X if(ESHK(shkp)->following) {
X if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)){
X pline("Hello %s! I was looking for %s.",
X plname, ESHK(shkp)->customer);
X ESHK(shkp)->following = 0;
X return(0);
X }
X if(!ESHK(shkp)->robbed) { /* impossible? */
X ESHK(shkp)->following = 0;
X return(0);
X }
X if(moves > followmsg+4) {
X pline("Hello %s! Didn't you forget to pay?",
X plname);
X followmsg = moves;
X#ifdef HARD
X if (!rn2(5)) {
X pline ("%s doesn't like customers who don't pay.", Monnam(shkp));
X NOTANGRY(shkp) = 0;
X }
X#endif
X }
X if(udist < 2)
X return(0);
X }
X }
X
X shkroom = inroom(omx,omy);
X appr = 1;
X gx = ESHK(shkp)->shk.x;
X gy = ESHK(shkp)->shk.y;
X satdoor = (gx == omx && gy == omy);
X if(ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){
X gx = u.ux;
X gy = u.uy;
X if(shkroom < 0 || shkroom != inroom(u.ux,u.uy))
X if(udist > 4)
X return(-1); /* leave it to m_move */
X } else if(ANGRY(shkp)) {
X long saveBlind = Blinded;
X long saveBlindf = Blindfolded;
X Blinded = Blindfolded = 0;
X if(shkp->mcansee && !Invis && cansee(omx,omy)) {
X gx = u.ux;
X gy = u.uy;
X }
X Blinded = saveBlind;
X Blindfolded = saveBlindf;
X avoid = FALSE;
X } else {
X#define GDIST(x,y) ((x-gx)*(x-gx)+(y-gy)*(y-gy))
X if(Invis)
X avoid = FALSE;
X else {
X uondoor = (u.ux == ESHK(shkp)->shd.x &&
X u.uy == ESHK(shkp)->shd.y);
X if(uondoor) {
X if(ESHK(shkp)->billct)
X pline("Hello %s! Will you please pay before leaving?",
X plname);
X badinv = (carrying(PICK_AXE) || carrying(ICE_BOX));
X if(satdoor && badinv)
X return(0);
X avoid = !badinv;
X } else {
X avoid = (u.uinshop && dist(gx,gy) > 8);
X badinv = FALSE;
X }
X
X if(((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid)
X && GDIST(omx,omy) < 3){
X if(!badinv && !online(omx,omy))
X return(0);
X if(satdoor)
X appr = gx = gy = 0;
X }
X }
X }
X if(omx == gx && omy == gy)
X return(0);
X if(shkp->mconf) {
X avoid = FALSE;
X appr = 0;
X }
X nix = omx;
X niy = omy;
X cnt = mfndpos(shkp,poss,info,ALLOW_SSM);
X if(avoid && uondoor) { /* perhaps we cannot avoid him */
X for(i=0; ishoproom
X || ESHK(shkp)->following) {
X#ifdef STUPID
X /* cater for stupid compilers */
X register int zz;
X#endif
X if(uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) {
X nix = nx; niy = ny; chi = i; break;
X }
X if(avoid && (info[i] & NOTONL))
X continue;
X if((!appr && !rn2(++chcnt)) ||
X#ifdef STUPID
X (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny))
X#else
X (appr && GDIST(nx,ny) < GDIST(nix,niy))
X#endif
X ) {
X nix = nx;
X niy = ny;
X chi = i;
X }
X }
X }
X if(nix != omx || niy != omy){
X if(info[chi] & ALLOW_M){
X mtmp = m_at(nix,niy);
X if(hitmm(shkp,mtmp) == 1 && rn2(3) &&
X hitmm(mtmp,shkp) == 2) return(2);
X return(0);
X } else if(info[chi] & ALLOW_U){
X (void) hitu(shkp, d(mdat->damn, mdat->damd)+1);
X return(0);
X }
X shkp->mx = nix;
X shkp->my = niy;
X pmon(shkp);
X if(ib) {
X freeobj(ib);
X mpickobj(shkp, ib);
X }
X return(1);
X }
X return(0);
X}
X#endif /* QUEST /**/
X
Xonline(x,y) /* New version to speed things up.
X * Compiler dependant, may not always work.
X */
X register xchar x, y;
X{
X return((x-=u.ux) == 0 || (y-=u.uy) == 0 || x == y || (x+=y) == 0);
X}
X
X/* Original version, just in case...
X *online(x,y) {
X * return(x==u.ux || y==u.uy || (x-u.ux)*(x-u.ux) == (y-u.uy)*(y-u.uy));
X *}
X */
X
X/* Does this monster follow me downstairs? */
Xfollower(mtmp)
Xregister struct monst *mtmp;
X{
X return( mtmp->mtame || index("1TVWZi&, ", mtmp->data->mlet) ||
X (mtmp->isshk && ESHK(mtmp)->following) );
X}
X
X/* He is digging in the shop. */
Xshopdig(fall)
Xregister int fall;
X{
X if(!fall) {
X if(u.utraptype == TT_PIT)
X pline("\"Be careful, sir, or you might fall through the floor.\"");
X else
X pline("\"Please, do not damage the floor here.\"");
X } else if(dist(shopkeeper->mx, shopkeeper->my) < 3) {
X register struct obj *obj, *obj2;
X
X pline("%s grabs your backpack!", shkname(shopkeeper));
X for(obj = invent; obj; obj = obj2) {
X obj2 = obj->nobj;
X if(obj->owornmask) continue;
X freeinv(obj);
X obj->nobj = shopkeeper->minvent;
X shopkeeper->minvent = obj;
X if(obj->unpaid)
X subfrombill(obj);
X }
X }
X}
END_OF_shk.c
if test 27302 -ne `wc -c trap.h <<'END_OF_trap.h'
X/* SCCS Id: @(#)trap.h 1.4 87/08/08
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* trap.h - version 1.0.2 */
X
Xstruct trap {
X struct trap *ntrap;
X xchar tx,ty;
X Bitfield(ttyp,5);
X Bitfield(tseen,1);
X Bitfield(once,1);
X};
X
Xextern struct trap *ftrap;
Xstruct trap *t_at();
X#define newtrap() (struct trap *) alloc(sizeof(struct trap))
X
X/* Standard Hack traps. */
X#define NO_TRAP 0
X#define BEAR_TRAP 1
X#define ARROW_TRAP 2
X#define DART_TRAP 3
X#define TRAPDOOR 4
X#define TELEP_TRAP 5
X#define PIT 6
X#define SLP_GAS_TRAP 7
X#define PIERC 8
X#define MIMIC 9
X
X/* Defines below this line are automatically added by makedefs (-t option) */
X/* if you add any additional code below the next line, it will disappear. */
X/* DO NOT REMOVE THIS LINE */
X
X#define MGTRP 10
X#define SQBRD 11
X#define WEB 12
X#define SPIKED_PIT 13
X#define LEVEL_TELEP 14
X#define ANTI_MAGIC 15
X#define RUST_TRAP 16
X#define POLY_TRAP 17
X
X#define TRAPNUM 18
END_OF_trap.h
if test 1012 -ne `wc -c