games-request@tekred.TEK.COM (12/02/87)
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 <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 4 (of 20)." # Contents: invent.c shk.c trap.h # Wrapped by billr@tekred on Tue Dec 1 16:24:50 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f invent.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"invent.c\" else echo shar: Extracting \"invent.c\" \(22894 characters\) sed "s/^X//" >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 <stdio.h> 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 <invent.c`; then echo shar: \"invent.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f shk.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"shk.c\" else echo shar: Extracting \"shk.c\" \(27302 characters\) sed "s/^X//" >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; i<cnt; i++) X if(!(info[i] & NOTONL)) goto notonl_ok; X avoid = FALSE; X notonl_ok: X ; X } X chi = -1; X chcnt = 0; X for(i=0; i<cnt; i++){ X nx = poss[i].x; X ny = poss[i].y; X if(levl[nx][ny].typ == ROOM X || shkroom != ESHK(shkp)->shoproom 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 <shk.c`; then echo shar: \"shk.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f trap.h -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"trap.h\" else echo shar: Extracting \"trap.h\" \(1012 characters\) sed "s/^X//" >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 <trap.h`; then echo shar: \"trap.h\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 4 \(of 20\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 20 archives. rm -f 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