home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume7
/
nethack3
/
part07
< prev
next >
Wrap
Internet Message Format
|
1989-07-31
|
56KB
Path: uunet!zephyr.ens.tek.com!tektronix!tekgen!tekred!saab!billr
From: billr@saab.CNA.TEK.COM (Bill Randle)
Newsgroups: comp.sources.games
Subject: v07i062: NetHack3 - display oriented dungeons & dragons (Ver. 3.0), Part07/38
Message-ID: <4315@tekred.CNA.TEK.COM>
Date: 24 Jul 89 05:00:38 GMT
Sender: nobody@tekred.CNA.TEK.COM
Lines: 2123
Approved: billr@saab.CNA.TEK.COM
Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 7, Issue 62
Archive-name: NetHack3/Part07
#! /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 7 (of 38)."
# Contents: src/pickup.c src/shk.c
# Wrapped by billr@saab on Sun Jul 23 21:32:50 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/pickup.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/pickup.c'\"
else
echo shar: Extracting \"'src/pickup.c'\" \(14035 characters\)
sed "s/^X//" >'src/pickup.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)pickup.c 3.0 88/07/12
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X/*
X * Contains code for picking objects up, and container use.
X */
X
X#include "hack.h"
X
Xvoid explode_bag();
X
Xvoid
Xpickup(all)
Xint all;
X{
X register struct gold *gold = g_at(u.ux, u.uy);
X register struct obj *obj, *obj2;
X register int wt;
X char buf[BUFSZ];
X register char *ip;
X register char sym;
X register int oletct = 0, iletct = 0;
X boolean all_of_a_type = FALSE, selective = FALSE;
X char olets[20], ilets[20];
X struct obj dummygold;
X
X dummygold.ox = u.ux;
X dummygold.oy = u.uy;
X dummygold.olet = GOLD_SYM;
X dummygold.nobj = fobj;
X dummygold.cobj = 0;
X
X if(Levitation) return;
X if (all && !flags.pickup) {
X int ct = 0;
X
X for (obj = fobj; obj; obj = obj->nobj)
X if(obj->ox == u.ux && obj->oy == u.uy)
X if(!obj->cobj)
X if (obj != uchain)
X ct++;
X
X /* Stop on a zorkmid */
X if (gold) ct++;
X
X /* If there are objects here, take a look.
X */
X if (ct) {
X if (flags.run)
X nomul(0);
X nscr();
X if (ct < 5)
X (void) dolook();
X else {
X read_engr_at(u.ux,u.uy);
X pline("There are several objects here.");
X }
X } else read_engr_at(u.ux,u.uy);
X return;
X }
X
X /* check for more than one object */
X if(!all) {
X register int ct = 0;
X
X if (gold) ct++;
X for(obj = fobj; obj; obj = obj->nobj)
X if(obj->ox == u.ux && obj->oy == u.uy)
X if(!obj->cobj) ct++;
X if(ct < 2)
X all++;
X else
X pline("There are several objects here.");
X }
X
X /* added by GAN 10/24/86 to allow selective picking up */
X if(!all) {
X register struct obj *otmp = fobj;
X
X ilets[iletct] = 0;
X if(gold) {
X ilets[iletct++] = GOLD_SYM;
X ilets[iletct] = 0;
X }
X while(otmp) {
X if(!index(ilets, otmp->olet) && !otmp->cobj &&
X otmp->ox == u.ux && otmp->oy == u.uy) {
X ilets[iletct++] = otmp->olet;
X ilets[iletct] = 0;
X }
X otmp = otmp->nobj;
X }
X if(iletct == 1)
X Strcpy(buf,ilets);
X else {
X ilets[iletct++] = ' ';
X ilets[iletct++] = 'a';
X ilets[iletct++] = 'A';
X ilets[iletct] = 0;
X
X pline("What kinds of thing do you want to pick up? [%s] ", ilets);
X getlin(buf);
X if(buf[0] == '\033') {
X clrlin();
X return;
X }
X else if(!buf[0]) selective = TRUE;
X }
X ip = buf;
X olets[0] = 0;
X while(sym = *ip++){
X /* new A function (selective all) added by
X * GAN 01/09/87
X */
X if(sym == ' ') continue;
X if(sym == 'A') selective = TRUE;
X else if(sym == 'a') all_of_a_type = TRUE;
X else if(index(ilets, sym)){
X if(!index(olets, sym)){
X olets[oletct++] = sym;
X olets[oletct] = 0;
X }
X }
X else pline("There are no %c's here.", sym);
X }
X }
X if(all_of_a_type && !olets[0]) all = TRUE;
X
X for(obj = (gold ? &dummygold : fobj); obj; obj = obj2) {
X obj2 = obj->nobj; /* perhaps obj will be picked up */
X if(!obj->cobj && obj->ox == u.ux && obj->oy == u.uy) {
X if(flags.run) nomul(0);
X
X if(!all) {
X char c;
X
X if(!selective && !index(olets,obj->olet)) continue;
X
X if (!all_of_a_type) {
X if (obj == &dummygold)
X pline("Pick up %ld gold piece%s? ",
X gold->amount, plur(gold->amount));
X else pline("Pick up %s? ", doname(obj));
X if((c = ynaq()) == 'q') return;
X if(c == 'n') continue;
X if(c == 'a') {
X all_of_a_type = TRUE;
X if (selective) {
X selective = FALSE;
X olets[0] = obj->olet;
X olets[1] = 0;
X /* oletct = 1; */
X }
X }
X }
X }
X
X if(obj == &dummygold) {
X int iw = inv_weight();
X long gold_capacity;
X
X#ifndef lint /* long/int conversion */
X iw -= (int)((u.ugold + 500)/1000);
X#endif
X gold_capacity = ((-iw) * 1000L) - 500 + 999 - u.ugold;
X if (gold_capacity <= 0L) {
X pline("There %s %ld gold piece%s here, but you cannot carry any more.",
X (gold->amount == 1) ? "is" : "are",
X gold->amount, plur(gold->amount));
X continue;
X }
X if (gold_capacity >= gold->amount) {
X pline("%ld gold piece%s.",
X gold->amount, plur(gold->amount));
X u.ugold += gold->amount;
X freegold(gold);
X if(Invisible) newsym(u.ux,u.uy);
X } else {
X pline("You can only carry %s of the %ld gold pieces lying here.",
X gold_capacity == 1L ? "one" : "some", gold->amount);
X pline("%ld gold piece%s.",
X gold_capacity, plur(gold_capacity));
X u.ugold += gold_capacity;
X gold->amount -= gold_capacity;
X }
X flags.botl = 1;
X if(flags.run) nomul(0);
X continue;
X }
X
X if((obj->otyp == CORPSE && obj->corpsenm == PM_COCKATRICE) &&
X !uarmg
X#ifdef POLYSELF
X && !resists_ston(uasmon)
X#endif
X ) {
X pline("Touching the dead cockatrice is a fatal mistake.");
X You("turn to stone.");
X You("die...");
X killer = "cockatrice cadaver";
X done("stoned");
X }
X
X if(obj->otyp == SCR_SCARE_MONSTER){
X if(!obj->spe) obj->spe = 1;
X else {
X pline("The scroll turns to dust as you pick it up.");
X if(!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
X !(objects[SCR_SCARE_MONSTER].oc_uname))
X docall(obj);
X delobj(obj);
X continue;
X }
X }
X
X /* do not pick up uchain */
X if(obj == uchain)
X continue;
X
X wt = inv_weight() + obj->owt;
X if (obj->otyp == LOADSTONE)
X goto lift_some; /* pick it up even if too heavy */
X#ifdef POLYSELF
X if (obj->otyp == BOULDER && throws_rocks(uasmon)) {
X wt = inv_weight();
X goto lift_some;
X }
X#endif
X if(wt > 0) {
X if(obj->quan > 1) {
X /* see how many we can lift */
X int savequan = obj->quan;
X int iw = inv_weight();
X int qq;
X for(qq = 1; qq < savequan; qq++){
X obj->quan = qq;
X if(iw + weight(obj) > 0)
X break;
X }
X obj->quan = savequan;
X qq--;
X /* we can carry qq of them */
X if(!qq) goto too_heavy;
X You("can only carry %s of the %s lying here.",
X (qq == 1) ? "one" : "some",
X doname(obj));
X {
X register struct obj *obj3;
X
X obj3 = splitobj(obj, qq);
X if(obj3->otyp == SCR_SCARE_MONSTER)
X if(obj3->spe) obj->spe = 0;
X }
X goto lift_some;
X }
X too_heavy:
X pline("There %s %s here, but %s.",
X (obj->quan == 1) ? "is" : "are",
X doname(obj),
X !invent ? "it is too heavy for you to lift"
X : "you cannot carry any more");
X if(obj->otyp == SCR_SCARE_MONSTER)
X if(obj->spe) obj->spe = 0;
X break;
X }
X lift_some:
X if(inv_cnt() >= 52) {
X Your("knapsack cannot accommodate any more items.");
X if(obj->otyp == SCR_SCARE_MONSTER)
X if(obj->spe) obj->spe = 0;
X break;
X }
X freeobj(obj);
X if(Invisible) newsym(u.ux,u.uy);
X addtobill(obj, TRUE); /* sets obj->unpaid if necessary */
X if(wt > -5) You("have a little trouble lifting");
X { int pickquan = obj->quan;
X int mergquan;
X if(!Blind) obj->dknown = 1;
X obj = addinv(obj); /* might merge it with other objects */
X mergquan = obj->quan;
X obj->quan = pickquan; /* to fool prinv() */
X prinv(obj);
X obj->quan = mergquan;
X }
X }
X }
X set_omask(u.ux, u.uy);
X}
X
Xint
Xdoloot() { /* loot a container on the floor. */
X
X register struct obj *cobj;
X register int c;
X
X if (Levitation) {
X pline("You cannot reach the floor.");
X return(0);
X }
X if(levl[u.ux][u.uy].omask)
X for(cobj = fobj; cobj; cobj = cobj->nobj) {
X
X if(cobj->ox == u.ux && cobj->oy == u.uy)
X if(Is_container(cobj)) {
X
X pline("There is %s here, loot it? ", doname(cobj));
X c = ynq();
X if(c == 'q') return 0;
X if(c == 'n') continue;
X
X if(cobj->olocked) {
X
X pline("Hmmm, it seems to be locked.");
X continue;
X }
X if(cobj->otyp == BAG_OF_TRICKS) {
X
X You("carefully open the bag...");
X pline("It develops a huge set of teeth and bites you!");
X losehp(rnd(10), "carnivorous bag");
X makeknown(BAG_OF_TRICKS);
X continue;
X }
X
X You("carefully open the %s...", xname(cobj));
X if(cobj->otrapped) chest_trap(cobj, FINGER);
X
X use_container(cobj, 0);
X }
X }
X return 0;
X}
X
Xstatic
Xstruct obj *current_container; /* a local variable of use_container, to be
X used by its local procedures in/ck_container */
X#define Icebox (current_container->otyp == ICE_BOX)
Xint baggone; /* used in askchain so bag isn't used after explosion */
X
Xvoid
Xinc_cwt(cobj, obj)
Xregister struct obj *cobj, *obj;
X{
X if (cobj->otyp == BAG_OF_HOLDING)
X cobj->owt += (obj->owt/2 + 1);
X else cobj->owt += obj->owt;
X}
X
Xstatic int
Xin_container(obj)
Xregister struct obj *obj;
X{
X if(obj == uball || obj == uchain) {
X You("must be kidding.");
X return(0);
X }
X if(obj == current_container) {
X pline("That would be an interesting topological exercise.");
X return(0);
X }
X if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
X You("cannot %s something you are wearing.",
X Icebox ? "refrigerate" : "stash");
X return(0);
X }
X if((obj->otyp == LOADSTONE) && obj->cursed) {
X obj->bknown = 1;
X pline("The stone%s won't leave your person.",
X obj->quan==1 ? "" : "s");
X return(0);
X }
X /* Prohibit Amulets in containers; if you allow it, monsters can't
X * steal them. It also becomes a pain to check to see if someone
X * has the Amulet.
X */
X if(obj->otyp == AMULET_OF_YENDOR && !obj->spe) {
X pline("The Amulet of Yendor cannot be confined in such trappings.");
X return(0);
X }
X /* no nested containers - they do not save/restore properly. */
X /* magic bag -> magic bag will self destruct later on. */
X if(Is_container(obj) && Is_container(current_container) &&
X (!Is_mbag(obj) || !Is_mbag(current_container))) {
X pline("It won't go in.");
X return(1); /* be careful! */
X }
X if(obj == uwep) {
X if(welded(obj)) {
X weldmsg(obj, FALSE);
X return(0);
X }
X setuwep((struct obj *) 0);
X if (uwep) return(0); /* unwielded, died, rewielded */
X }
X#ifdef WALKIES
X if(obj->otyp == LEASH && obj->leashmon != 0) {
X pline("It is attached to your pet.");
X return(0);
X }
X#endif
X inc_cwt(current_container, obj);
X freeinv(obj);
X
X obj->cobj = current_container;
X obj->nobj = fcobj;
X fcobj = obj;
X
X if(Icebox) obj->age = moves - obj->age; /* actual age */
X
X else if(Is_mbag(obj->cobj) &&
X (Is_mbag(obj) ||
X (obj->otyp == WAN_CANCELLATION && (obj->spe > 0)) )) {
X explode_bag(obj);
X You("are blasted by a magical explosion!");
X losehp(d(6,6),"magical explosion");
X baggone = 1;
X }
X return(1);
X}
X
Xstatic int
Xck_container(obj)
Xregister struct obj *obj;
X{
X return(obj->cobj == current_container);
X}
X
Xstatic int
Xck_bag()
X{
X return(!baggone);
X}
X
Xstatic int
Xout_container(obj)
Xregister struct obj *obj;
X{
X register struct obj *otmp;
X
X if(inv_cnt() >= 52) {
X pline("You have no room to hold anything else.");
X return(0);
X }
X if(obj == fcobj) fcobj = fcobj->nobj;
X else {
X for(otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj)
X if(!otmp->nobj) panic("out_container");
X otmp->nobj = obj->nobj;
X }
X dec_cwt(current_container, obj);
X obj->cobj = (struct obj *) 0;
X
X if (Icebox)
X obj->age = moves - obj->age; /* simulated point of time */
X
X (void) addinv(obj);
X return 0;
X}
X
Xvoid
Xget_all_from_box() {
X register struct obj *otmp, *cobj, *ootmp, *nxobj;
X
X for(otmp = invent; otmp; otmp = otmp->nobj) {
X cobj = otmp;
X if(Is_container(otmp))
X for(ootmp=fcobj,nxobj=(fcobj ? fcobj->nobj : 0); ootmp;
X ootmp=nxobj,nxobj=(ootmp ? ootmp->nobj : 0) )
X if(ootmp->cobj == cobj)
X (void)out_container(ootmp);
X }
X return;
X}
X
X/* for getobj: 0: allow cnt; #: allow all types; %: expect food */
Xstatic const char frozen_food[] = { '0', '#', FOOD_SYM, 0 };
X
Xvoid
Xuse_container(obj, held)
Xregister struct obj *obj;
Xregister int held;
X{
X register int cnt = 0;
X register struct obj *otmp;
X register struct obj *backobj;
X
X current_container = obj; /* for use by in/out_container */
X if(current_container->olocked) {
X pline("The %s seems to be locked.", xname(current_container));
X return;
X }
X for(otmp = fcobj, backobj = (struct obj *) 0; otmp;
X backobj = otmp, otmp = otmp->nobj)
X if(otmp->cobj == obj)
X if(Is_mbag(obj) && obj->cursed && !rn2(13)) {
X if (otmp->known)
X pline("The %s to have vanished!",
X aobjnam(otmp,"seem"));
X else You("%s %s disappear.",
X Blind ? "notice" : "see",
X doname(otmp));
X if(!backobj) {
X fcobj = otmp->nobj;
X dec_cwt(current_container, otmp);
X obfree(otmp, (struct obj *) 0);
X otmp = fcobj;
X } else {
X backobj->nobj = otmp->nobj;
X dec_cwt(current_container, otmp);
X obfree(otmp, (struct obj *) 0);
X otmp = backobj->nobj;
X }
X if (!otmp) break;
X if(otmp->cobj == obj) cnt++;
X } else cnt++;
X if(!cnt)
X pline("%s %s is empty.", (held) ? "Your" : "The", xname(obj));
X else if (inv_cnt() < 52) {
X pline("Do you want to take something out of the %s? ",
X xname(obj));
X if(yn() != 'n')
X if(askchain(fcobj, FALSE, NULL, 0, out_container, ck_container, 0, "nodot"))
X return;
X }
X if(!invent) return;
X pline("Do you wish to put something in? ");
X if(yn() != 'y') return;
X if (Icebox && current_container->dknown) {
X otmp = getobj(frozen_food, "put in");
X if(!otmp || !in_container(otmp))
X flags.move = multi = 0;
X } else {
X baggone = 0; /* might be set by in_container */
X if(askchain(invent, TRUE, NULL, 0, in_container, ck_bag, 0, "nodot"))
X return;
X }
X return;
X}
X
Xvoid
Xdelete_contents(obj)
Xregister struct obj *obj;
X{
X register struct obj *otmp, *notmp;
X
X while (fcobj && fcobj->cobj == obj) {
X otmp = fcobj;
X fcobj = fcobj->nobj;
X obfree(otmp,(struct obj *)0);
X }
X if (fcobj) {
X otmp = fcobj;
X while(otmp->nobj)
X if (otmp->nobj->cobj == obj) {
X notmp = otmp->nobj;
X otmp->nobj = notmp->nobj;
X obfree(notmp,(struct obj *)0);
X } else
X otmp = otmp->nobj;
X }
X}
X
Xvoid
Xexplode_bag(obj)
Xstruct obj *obj;
X{
X struct obj *otmp, *cobj;
X
X cobj = obj->cobj;
X delete_contents(cobj);
X
X for (otmp = invent; otmp; otmp = otmp->nobj)
X if (otmp == cobj) break;
X
X if (otmp) {
X You("see your %s blow apart!", xname(otmp));
X useup(otmp);
X /*return(0);*/
X } else panic("explode_bag: bag not in invent.");
X}
X
Xvoid
Xdec_cwt(cobj, obj)
Xregister struct obj *cobj, *obj;
X{
X if (Is_mbag(cobj))
X cobj->owt -= (obj->owt/2 + 1);
X else cobj->owt -= obj->owt;
X
X if(cobj->owt < objects[cobj->otyp].oc_weight)
X cobj->owt = objects[cobj->otyp].oc_weight;
X}
END_OF_FILE
if test 14035 -ne `wc -c <'src/pickup.c'`; then
echo shar: \"'src/pickup.c'\" unpacked with wrong size!
fi
# end of 'src/pickup.c'
fi
if test -f 'src/shk.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/shk.c'\"
else
echo shar: Extracting \"'src/shk.c'\" \(37207 characters\)
sed "s/^X//" >'src/shk.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)shk.c 3.0 89/02/10
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X/* block some unused #defines to avoid overloading some cpp's */
X#define MONATTK_H
X#include "hack.h"
X
X#include "eshk.h"
X
X#ifdef KOPS
Xstatic int makekops();
Xstatic void kops_gone();
X#endif /* KOPS */
X
X#define NOTANGRY(mon) mon->mpeaceful
X#define ANGRY(mon) !NOTANGRY(mon)
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 void setpaid(), findshk P((int));
Xstatic int dopayobj P((struct bill_x *)), getprice P((struct obj *));
Xstatic struct obj *bp_to_obj P((struct bill_x *));
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
Xvoid
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
Xvoid
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 void
Xsetpaid(){ /* caller has checked that shopkeeper exists */
X /* either we paid or left the shop or he just died */
X register struct obj *obj;
X register 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((genericptr_t) obj);
X }
X if(shopkeeper) {
X ESHK(shopkeeper)->billct = 0;
X ESHK(shopkeeper)->credit = 0L;
X ESHK(shopkeeper)->debit = 0L;
X }
X}
X
Xstatic void
Xaddupbill(){ /* delivers result in total */
X /* caller has checked that shopkeeper exists */
X register int ct = ESHK(shopkeeper)->billct;
X register struct bill_x *bp = bill;
X total = 0;
X while(ct--){
X total += bp->price * bp->bquan;
X bp++;
X }
X}
X
Xint
Xinshop() {
X register int 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 || ESHK(shopkeeper)->debit) {
X if(inroom(shopkeeper->mx, shopkeeper->my)
X == u.uinshop - 1) /* ab@unido */
X You("escaped the shop without paying!");
X addupbill();
X total += ESHK(shopkeeper)->debit;
X You("stole %ld zorkmids worth of merchandise.",
X total);
X ESHK(shopkeeper)->robbed += total;
X ESHK(shopkeeper)->credit = 0L;
X ESHK(shopkeeper)->debit = 0L;
X if (pl_character[0] != 'R') /* stealing is unlawful */
X adjalign(-sgn(u.ualigntyp));
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
X if (flags.soundok)
X pline("An alarm sounds throughout the dungeon!");
X if(flags.verbose) {
X if((mons[PM_KEYSTONE_KOP].geno & G_GENOD) &&
X (mons[PM_KOP_SERGEANT].geno & G_GENOD) &&
X (mons[PM_KOP_LIEUTENANT].geno & G_GENOD) &&
X (mons[PM_KOP_KAPTAIN].geno & G_GENOD)) {
X if (flags.soundok)
X pline("But no one seems to respond to it.");
X } else
X pline("The Keystone Kops are after you!");
X }
X /* Create a swarm near the staircase */
X mm.x = xdnstair;
X mm.y = ydnstair;
X (void) makekops(&mm);
X /* Create a swarm near the shopkeeper */
X mm.x = shopkeeper->mx;
X mm.y = shopkeeper->my;
X (void) makekops(&mm);
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 /* This counts everything except shops and vaults
X -- vault.c insists that a vault remain a VAULT */
X if(roomno >= 0) {
X register int rt = rooms[roomno].rtype;
X register struct monst *mtmp;
X
X switch (rt) {
X case ZOO:
X pline("Welcome to David's treasure zoo!");
X break;
X case SWAMP:
X pline("It looks rather muddy down here.");
X break;
X#ifdef THRONES
X case COURT:
X You("enter an opulent throne room!");
X break;
X#endif
X case MORGUE:
X if(midnight())
X pline("Run away! Run away!");
X else
X You("have an uncanny feeling...");
X break;
X case BEEHIVE:
X You("enter a giant beehive!");
X break;
X#ifdef ARMY
X case BARRACKS:
X if(!((mons[PM_SOLDIER].geno & G_GENOD) &&
X (mons[PM_SERGEANT].geno & G_GENOD) &&
X (mons[PM_LIEUTENANT].geno & G_GENOD) &&
X (mons[PM_CAPTAIN].geno & G_GENOD)))
X You("enter a military barracks!");
X else You("enter an abandoned barracks.");
X break;
X#endif
X#ifdef ORACLE
X case DELPHI:
X if(!(mons[PM_ORACLE].geno & G_GENOD))
X pline("\"Hello, %s, welcome to Delphi!\"", plname);
X break;
X#endif
X default:
X rt = 0;
X }
X
X if(rt != 0) {
X rooms[roomno].rtype = OROOM;
X if(rt==COURT || rt==SWAMP || rt==MORGUE || rt==ZOO)
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X /* was if(rt != ZOO || !rn2(3)) -- why should ZOO
X be different from COURT or MORGUE? */
X if(!Stealth && !rn2(3))
X mtmp->msleep = 0;
X }
X }
X#if defined(ALTARS) && defined(THEOLOGY)
X if(roomno >= 0 && rooms[roomno].rtype == TEMPLE) {
X intemple();
X }
X#endif
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 /* 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 && inhishop(shopkeeper)) {
X if(ANGRY(shopkeeper))
X pline("\"So, %s, you dare return to %s's %s?!\"",
X plname,
X shkname(shopkeeper),
X shtypes[rt - SHOPBASE].name);
X else
X if(ESHK(shopkeeper)->robbed)
X pline("\"Beware, %s! I am upset about missing stock!\"",
X plname);
X else
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 if(carrying(PICK_AXE) != (struct obj *)0) {
X pline(NOTANGRY(shopkeeper) ?
X "\"Will you please leave your pick-axe outside?\"" :
X "\"Leave the pick-axe outside.\"");
X if(dochug(shopkeeper)) {
X u.uinshop = 0; /* he died moving */
X return(0);
X }
X }
X }
X u.uinshop = (unsigned int)(roomno + 1);
X }
X }
X return (int)u.uinshop;
X}
X
Xint
Xinhishop(mtmp)
Xregister struct monst *mtmp;
X{
X return((ESHK(mtmp)->shoproom == inroom(mtmp->mx, mtmp->my) &&
X ESHK(mtmp)->shoplevel == dlevel));
X}
X
Xstatic void
Xfindshk(roomno)
Xregister int roomno;
X{
X register struct monst *mtmp;
X
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)
Xregister struct obj *obj;
X{
X register struct bill_x *bp;
X if(!shopkeeper) return (struct bill_x *)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 (struct bill_x *)0;
X}
X
X/* called with two args on merge */
Xvoid
Xobfree(obj, merge)
Xregister struct obj *obj, *merge;
X{
X register struct bill_x *bp = onbill(obj);
X register 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((genericptr_t) obj);
X}
X
Xstatic long
Xcheck_credit(tmp, shkp)
Xlong tmp;
Xregister struct monst *shkp;
X{
X long credit = ESHK(shkp)->credit;
X
X if(credit == 0L) return(tmp);
X if(credit >= tmp) {
X pline("The price is deducted from your credit.");
X ESHK(shkp)->credit -=tmp;
X tmp = 0L;
X } else {
X pline("The price is partially covered by your credit.");
X ESHK(shkp)->credit = 0L;
X tmp -= credit;
X }
X return(tmp);
X}
X
Xstatic void
Xpay(tmp,shkp)
Xlong tmp;
Xregister struct monst *shkp;
X{
X long robbed = ESHK(shkp)->robbed;
X long balance = ((tmp <= 0) ? tmp : check_credit(tmp, shkp));
X
X u.ugold -= balance;
X shkp->mgold += balance;
X flags.botl = 1;
X if(robbed) {
X robbed -= tmp;
X if(robbed < 0) robbed = 0;
X ESHK(shkp)->robbed = robbed;
X }
X}
X
X/* return shkp to home position */
Xvoid
Xhome_shk(shkp)
Xregister struct monst *shkp;
X{
X register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y;
X if(levl[x][y].mmask)
X mnearto(m_at(x,y), x, y, FALSE);
X levl[shkp->mx][shkp->my].mmask = 0;
X shkp->mx = x;
X shkp->my = y;
X levl[shkp->mx][shkp->my].mmask = 1;
X unpmon(shkp);
X}
X
Xvoid
Xmake_happy_shk(shkp)
Xstruct monst *shkp;
X{
X register boolean wasmad = ANGRY(shkp);
X
X NOTANGRY(shkp) = 1;
X ESHK(shkp)->following = 0;
X ESHK(shkp)->robbed = 0;
X if (pl_character[0] != 'R')
X adjalign(sgn(u.ualigntyp));
X if(!inhishop(shkp)) {
X pline("Satisfied, %s suddenly disappears!", mon_nam(shkp));
X if(ESHK(shkp)->shoplevel == dlevel)
X home_shk(shkp);
X else
X fall_down(shkp, ESHK(shkp)->shoplevel);
X } else if(wasmad)
X pline("%s calms down.", Monnam(shkp));
X#ifdef KOPS
X kops_gone();
X#endif
X}
X
Xstatic const char no_money[] = "Moreover, you have no money.";
X
Xint
Xdopay()
X{
X long ltmp;
X register struct bill_x *bp;
X register struct monst *shkp;
X int 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 && inhishop(shopkeeper))
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 You("do not owe %s anything.", mon_nam(shkp));
X else if(!u.ugold)
X You("have no money.");
X else {
X long ugold = u.ugold;
X
X if(ugold > ltmp) {
X You("give %s the %ld gold pieces %s asked for.",
X mon_nam(shkp), ltmp,
X ESHK(shkp)->ismale ? "he" : "she");
X pay(ltmp, shkp);
X } else {
X You("give %s all your gold.", mon_nam(shkp));
X pay(u.ugold, shkp);
X }
X if(ugold < ltmp/2)
X pline("Unfortunately, %s doesn't look satisfied.",
X ESHK(shkp)->ismale ? "he" : "she");
X else
X make_happy_shk(shkp);
X }
X return(1);
X }
X
X /* ltmp is still ESHK(shkp)->robbed here */
X if(!ESHK(shkp)->billct) {
X if(!ltmp && NOTANGRY(shkp)) {
X You("do not owe %s anything.", mon_nam(shkp));
X if(!u.ugold) pline(no_money);
X } else if(ltmp) {
X pline("%s is after blood, not money!", mon_nam(shkp));
X if(u.ugold < ltmp/2) {
X if(!u.ugold) pline(no_money);
X else pline("Besides, you don't have enough to interest %s.",
X ESHK(shkp)->ismale ? "him" : "her");
X return(1);
X }
X pline("But since %s shop has been robbed recently,",
X ESHK(shkp)->ismale ? "his" : "her");
X pline("you %scompensate %s for %s losses.",
X (u.ugold < ltmp) ? "partially " : "",
X mon_nam(shkp),
X ESHK(shkp)->ismale ? "his" : "her");
X pay(u.ugold < ltmp ? u.ugold : ltmp, shkp);
X make_happy_shk(shkp);
X } else {
X /* shopkeeper is angry, but has not been robbed --
X * door broken, attacked, etc. */
X pline("%s is after your hide, not your money!",
X mon_nam(shkp));
X if(u.ugold < 1000) {
X if(!u.ugold) pline(no_money);
X else
X pline("Besides, you don't have enough to interest %s.",
X ESHK(shkp)->ismale ? "him" : "her");
X return(1);
X }
X You("try to appease %s by giving %s 1000 gold pieces.",
X a_monnam(shkp, "angry"),
X ESHK(shkp)->ismale ? "him" : "her");
X pay(1000L,shkp);
X if(strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)
X || rn2(3))
X make_happy_shk(shkp);
X else
X pline("But %s is as angry as ever.", 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 /* pay debt, if any, first */
X if(ESHK(shopkeeper)->debit) {
X You("owe %s %ld zorkmids for the use of merchandise.",
X shkname(shopkeeper), ESHK(shopkeeper)->debit);
X if(u.ugold + ESHK(shopkeeper)->credit <
X ESHK(shopkeeper)->debit) {
X pline("But you don't have enough gold%s.",
X ESHK(shopkeeper)->credit ? " or credit" : "");
X return(1);
X } else {
X long dtmp = ESHK(shopkeeper)->debit;
X
X if(ESHK(shopkeeper)->credit >= dtmp) {
X ESHK(shopkeeper)->credit -= dtmp;
X ESHK(shopkeeper)->debit = 0L;
X Your("debt is covered by your credit.");
X } else if(!ESHK(shopkeeper)->credit) {
X u.ugold -= dtmp;
X shopkeeper->mgold += dtmp;
X ESHK(shopkeeper)->debit = 0L;
X You("pay that debt.");
X flags.botl = 1;
X } else {
X dtmp -= ESHK(shopkeeper)->credit;
X ESHK(shopkeeper)->credit = 0L;
X u.ugold -= dtmp;
X shopkeeper->mgold += dtmp;
X ESHK(shopkeeper)->debit = 0L;
X pline("That debt is partially offset by your credit.");
X You("pay the remainder.");
X flags.botl = 1;
X }
X }
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 int
Xdopayobj(bp)
Xregister struct bill_x *bp;
X{
X register struct obj *obj;
X long 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 + ESHK(shopkeeper)->credit < ltmp){
X You("don't have gold%s enough to pay for %s.",
X (ESHK(shopkeeper)->credit > 0L) ? " or credit" : "",
X doname(obj));
X obj->unpaid = 1;
X return(0);
X }
X pay(ltmp, shopkeeper);
X 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((genericptr_t) obj);
X }
X return(1);
X}
X
X/* routine called after dying (or quitting) with nonempty bill or upset shk */
Xboolean
Xpaybill(){
X register struct monst *mtmp;
X register int loss = 0;
X register struct obj *otmp;
X register xchar ox, oy;
X register boolean take = FALSE;
X register boolean taken = FALSE;
X
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->isshk) {
X /* for bones: we don't want a shopless shk around */
X if(ESHK(mtmp)->shoplevel != dlevel) mongone(mtmp);
X else shopkeeper = mtmp;
X }
X
X if(!shopkeeper) return(FALSE);
X
X /* get one case out of the way: you die in the shop, the */
X /* shopkeeper is peaceful, nothing stolen, nothing owed. */
X if(in_shop(u.ux,u.uy) && !IS_DOOR(levl[u.ux][u.uy].typ) &&
X !ESHK(shopkeeper)->billct && !ESHK(shopkeeper)->robbed &&
X inhishop(shopkeeper) && NOTANGRY(shopkeeper) &&
X !ESHK(shopkeeper)->following) {
X pline("%s gratefully inherits all your possessions.",
X Monnam(shopkeeper));
X goto clear;
X }
X
X if(ESHK(shopkeeper)->billct || ESHK(shopkeeper)->robbed) {
X addupbill();
X loss = ((total >= ESHK(shopkeeper)->robbed) ? total :
X ESHK(shopkeeper)->robbed);
X take = TRUE;
X }
X
X if(ESHK(shopkeeper)->following || ANGRY(shopkeeper) || take) {
X if((loss > u.ugold) || !loss) {
X pline("%s comes and takes all your possessions.",
X Monnam(shopkeeper));
X taken = TRUE;
X shopkeeper->mgold += u.ugold;
X u.ugold = 0;
X /* in case bones: make it be for real... */
X if(!in_shop(u.ux, u.uy) || IS_DOOR(levl[u.ux][u.uy].typ)) {
X /* shk.x,shk.y is the position immediately in
X * front of the door -- move in one more space
X */
X ox = ESHK(shopkeeper)->shk.x;
X oy = ESHK(shopkeeper)->shk.y;
X ox += sgn(ox - ESHK(shopkeeper)->shd.x);
X oy += sgn(oy - ESHK(shopkeeper)->shd.y);
X } else {
X ox = u.ux;
X oy = u.uy;
X }
X
X if (invent) {
X levl[ox][oy].omask = 1;
X for(otmp = invent; otmp; otmp = otmp->nobj) {
X otmp->ox = ox;
X otmp->oy = oy;
X otmp->age = 0;
X }
X
X /* add to main object list at end so invent is
X still good */
X if (fobj) {
X otmp = fobj;
X while(otmp->nobj)
X otmp = otmp->nobj;
X otmp->nobj = invent;
X } else
X fobj = invent;
X }
X } else {
X u.ugold -= loss;
X shopkeeper->mgold += loss;
X pline("%s comes and takes %ld zorkmids %sowed %s.",
X Monnam(shopkeeper),
X loss,
X strncmp(ESHK(shopkeeper)->customer, plname, PL_NSIZ) ? "" : "you ",
X ESHK(shopkeeper)->ismale ? "him" : "her");
X }
X
X /* in case we create bones */
X if(!inhishop(shopkeeper))
X home_shk(shopkeeper);
X }
Xclear:
X setpaid();
X return(taken);
X}
X
X/* find obj on one of the lists */
Xstatic struct obj *
Xbp_to_obj(bp)
Xregister struct bill_x *bp;
X{
X register struct obj *obj;
X register struct monst *mtmp;
X register unsigned int id = bp->bo_id;
X
X if(bp->useup)
X obj = o_on(id, billobjs);
X else if(!(obj = o_on(id, invent)) &&
X !(obj = o_on(id, fobj)) &&
X !(obj = o_on(id, 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
Xstatic long
Xget_cost(obj)
Xregister struct obj *obj;
X{
X register long tmp;
X
X tmp = getprice(obj);
X if (!tmp) tmp = 5;
X if (ANGRY(shopkeeper) ||
X (pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
X#ifdef SHIRT
X || (uarmu && !uarm) /* wearing just a Hawaiian shirt */
X#endif
X )
X tmp += tmp/3;
X if (ACURR(A_CHA) > 18) tmp /= 2;
X else if (ACURR(A_CHA) > 17) tmp = (tmp * 2)/3;
X else if (ACURR(A_CHA) > 15) tmp = (tmp * 3)/4;
X else if (ACURR(A_CHA) < 11) tmp = (tmp * 4)/3;
X else if (ACURR(A_CHA) < 8) tmp = (tmp * 3)/2;
X else if (ACURR(A_CHA) < 6) tmp *= 2;
X return(tmp);
X}
X
X
X/* called in hack.c when we pickup an object */
Xvoid
Xaddtobill(obj, ininv)
Xregister struct obj *obj;
Xregister boolean ininv;
X{
X register struct bill_x *bp;
X char buf[40];
X if(!shopkeeper || !inhishop(shopkeeper)) return;
X
X if(!costly_spot(obj->ox,obj->oy) || /* either pickup or kick */
X onbill(obj) /* perhaps we threw it away earlier */
X ) return;
X if(ESHK(shopkeeper)->billct == BILLSZ) {
X You("got that for free!");
X return;
X }
X /* To recognize objects the shopkeeper is not interested in. -dgk
X */
X if (obj->no_charge) {
X obj->no_charge = 0;
X return;
X }
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 = get_cost(obj);
X Strcpy(buf, "\"For you, ");
X if (ANGRY(shopkeeper)) Strcat(buf, "scum ");
X else {
X switch(rnd(4)
X#ifdef HARD
X + u.udemigod
X#endif
X ) {
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: if (u.ualigntyp == U_CHAOTIC) Strcat(buf, "un");
X Strcat(buf, "holy");
X break;
X }
X#ifdef POLYSELF
X if(!is_human(uasmon)) Strcat(buf, " creature");
X else
X#endif
X Strcat(buf, (flags.female) ? " lady" : " sir");
X }
X obj->dknown = 1; /* after all, the shk is telling you what it is */
X if(ininv) {
X obj->quan = 1; /* fool xname() into giving singular */
X pline("%s; only %d %s %s.\"", buf, bp->price,
X (bp->bquan > 1) ? "per" : "for this", xname(obj));
X obj->quan = bp->bquan;
X } else pline("The %s will cost you %d zorkmids%s.",
X xname(obj), bp->price,
X (bp->bquan > 1) ? " each" : "");
X ESHK(shopkeeper)->billct++;
X obj->unpaid = 1;
X}
X
Xvoid
Xsplitbill(obj, otmp)
Xregister struct obj *obj, *otmp;
X{
X /* otmp has been split off from obj */
X register struct bill_x *bp;
X register 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 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
Xvoid
Xsubfrombill(obj)
Xregister struct obj *obj;
X{
X long ltmp;
X /* register int tmp; /* use of tmp commented out below */
X register struct obj *otmp;
X register struct bill_x *bp;
X if(!costly_spot(u.ux,u.uy))
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 if(inhishop(shopkeeper))
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 || !inhishop(shopkeeper))
X return;
X ltmp = getprice(obj) * obj->quan;
X if(ESHK(shopkeeper)->billct == BILLSZ
X || !saleable(rooms[ESHK(shopkeeper)->shoproom].rtype-SHOPBASE, obj)
X || otmp->olet == BALL_SYM || ltmp == 0L) {
X pline("%s seems not interested.", Monnam(shopkeeper));
X obj->no_charge = 1;
X return;
X }
X if (ANGRY(shopkeeper) || (pl_character[0] == 'T' && u.ulevel < (MAXULEV/2))
X#ifdef SHIRT
X || (uarmu && !uarm) /* wearing just a Hawaiian shirt */
X#endif
X ) {
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 obj->no_charge = 1;
X } else
X You("sold %s for %ld gold piece%s.", doname(obj), ltmp,
X plur(ltmp));
X}
X
Xint
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 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 Sprintf(&buf[cnt], " %5ld zorkmids", thisused);
X if(page_line(buf))
X goto quit;
X }
X }
X 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
X#define HUNGRY 2
Xstatic int
Xgetprice(obj)
Xregister struct obj *obj;
X{
X register int tmp = objects[obj->otyp].oc_cost;
X
X switch(obj->olet) {
X case AMULET_SYM:
X if(obj->otyp == AMULET_OF_YENDOR) {
X /* don't let the player get rich selling fakes */
X tmp = (obj->spe < 0 ? 0 : 3500);
X }
X break;
X case FOOD_SYM:
X /* simpler hunger check, (2-4)*cost */
X if (u.uhs >= HUNGRY) tmp *= u.uhs;
X break;
X case WAND_SYM:
X if (obj->spe == -1) tmp = 0;
X break;
X case POTION_SYM:
X if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed)
X tmp = 0;
X break;
X case ARMOR_SYM:
X if (u.uac > 0) tmp += u.uac * 2;
X case WEAPON_SYM:
X if (obj->spe > 0) tmp += 10 * obj->spe;
X break;
X case CHAIN_SYM:
X pline("Strange... carrying a chain?");
X break;
X }
X return(tmp);
X}
X
Xint
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 didn't -1: let m_move do it -2: died
X */
Xint
Xshk_move(shkp)
Xregister struct monst *shkp;
X{
X register xchar gx,gy,omx,omy;
X register int udist;
X register schar appr;
X int z;
X schar shkroom;
X boolean uondoor, satdoor, avoid, badinv;
X
X omx = shkp->mx;
X omy = shkp->my;
X
X if((udist = dist(omx,omy)) < 3) {
X if(ANGRY(shkp)) {
X if(Displaced)
X Your("displaced image doesn't fool %s!",
X Monnam(shkp));
X (void) mattacku(shkp);
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(moves > followmsg+4) {
X pline("\"Hello, %s! Didn't you forget to pay?\"",
X plname);
X followmsg = moves;
X#ifdef HARD
X if (!rn2(4)) {
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 struct obj *saveUblindf = ublindf;
X Blinded = 0;
X ublindf = (struct obj *)0;
X if(shkp->mcansee && !Invis && cansee(omx,omy)) {
X gx = u.ux;
X gy = u.uy;
X }
X Blinded = saveBlind;
X ublindf = saveUblindf;
X avoid = FALSE;
X } else {
X#define GDIST(x,y) (dist2(x,y,gx,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 && inhishop(shkp))
X pline(NOTANGRY(shkp) ?
X "\"Hello, %s! Will you please pay before leaving?\"" :
X "\"Hey, %s! Don't leave without paying!\"",
X plname);
X badinv = (!!carrying(PICK_AXE));
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
X return(move_special(shkp,shkroom,appr,uondoor,avoid,omx,omy,gx,gy));
X}
X
Xint
Xonline(x,y) /* New version to speed things up.
X * Compiler dependant, may not always work.
X */
Xregister 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/* for use in levl_follower (mondata.c) */
Xboolean
Xis_fshk(mtmp)
Xregister struct monst *mtmp;
X{
X return(mtmp->isshk && ESHK(mtmp)->following);
X}
X
X/* He is digging in the shop. */
Xvoid
Xshopdig(fall)
Xregister int fall;
X{
X if(!shopkeeper) return;
X if(!inhishop(shopkeeper)) {
X if (pl_character[0] == 'K') adjalign(-sgn(u.ualigntyp));
X return;
X }
X
X if(!fall) {
X if(u.utraptype == TT_PIT)
X pline("\"Be careful, %s, or you might fall through the floor.\"",
X flags.female ? "madam" : "sir");
X else
X pline("\"%s, do not damage the floor here!\"",
X flags.female ? "Madam" : "Sir");
X if (pl_character[0] == 'K') adjalign(-sgn(u.ualigntyp));
X } else if(um_dist(shopkeeper->mx, shopkeeper->my, 2)) {
X register struct obj *obj, *obj2;
X
X if(dist(shopkeeper->mx, shopkeeper->my) > 2) {
X mnexto(shopkeeper);
X /* for some reason he can't come next to you */
X if(dist(shopkeeper->mx, shopkeeper->my) > 2) {
X pline("%s curses you in anger and frustration!",
X shkname(shopkeeper));
X NOTANGRY(shopkeeper) = 0;
X return;
X } else pline("%s leaps, and grabs your backpack!",
X shkname(shopkeeper));
X } else pline("%s grabs your backpack!", shkname(shopkeeper));
X
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}
X
X#ifdef KOPS
Xstatic int
Xmakekops(mm) /* returns the number of (all types of) Kops made */
Xcoord *mm;
X{
X register int cnt = dlevel + rnd(5);
X register int scnt = (cnt / 3) + 1; /* at least one sarge */
X register int lcnt = (cnt / 6); /* maybe a lieutenant */
X register int kcnt = (cnt / 9); /* and maybe a kaptain */
X
X while(cnt--) {
X enexto(mm, mm->x, mm->y);
X (void) makemon(&mons[PM_KEYSTONE_KOP], mm->x, mm->y);
X }
X while(scnt--) {
X enexto(mm, mm->x, mm->y);
X (void) makemon(&mons[PM_KOP_SERGEANT], mm->x, mm->y);
X }
X while(lcnt--) {
X enexto(mm, mm->x, mm->y);
X (void) makemon(&mons[PM_KOP_LIEUTENANT], mm->x, mm->y);
X }
X while(kcnt--) {
X enexto(mm, mm->x, mm->y);
X (void) makemon(&mons[PM_KOP_KAPTAIN], mm->x, mm->y);
X }
X return(cnt + scnt + lcnt + kcnt);
X}
X#endif
X
Xboolean
Xin_shop(x,y)
Xregister int x, y;
X{
X register int roomno = inroom(x, y);
X
X if (roomno < 0) return(FALSE);
X return (IS_SHOP(rooms[roomno]));
X}
X
Xvoid
Xpay_for_door(x,y,dmgstr)
Xregister int x, y;
Xregister char *dmgstr;
X{
X register struct monst *mtmp;
X register int ox, oy;
X register int roomno = inroom(x, y);
X register int damage = (ACURR(A_STR) > 18) ? 400 : 20 * ACURR(A_STR);
X
X /* make sure this function is not used in the wrong place */
X if(!(IS_DOOR(levl[x][y].typ) && in_shop(x, y))) return;
X
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 }
X
X if(!shopkeeper) return;
X
X /* not the best introduction to the shk... */
X (void) strncpy(ESHK(shopkeeper)->customer,plname,PL_NSIZ);
X
X /* if he is already on the war path, be sure it's all out */
X if(ANGRY(shopkeeper) || ESHK(shopkeeper)->following) {
X NOTANGRY(shopkeeper) = 0;
X ESHK(shopkeeper)->following = 1;
X return;
X }
X
X ox = shopkeeper->mx;
X oy = shopkeeper->my;
X
X /* if he's not in his shop.. */
X if(!in_shop(ox, oy)) return;
X
X /* if a !shopkeeper shows up at the door, move him */
X if(levl[x][y].mmask && (mtmp = m_at(x, y)) != shopkeeper) {
X if(flags.soundok) {
X You("hear an angry voice: \"Out of my way, scum!\"");
X (void) fflush(stdout);
X#if defined(SYSV) || defined(ULTRIX)
X (void)
X#endif
X#ifdef UNIX
X sleep(1);
X#endif
X }
X mnearto(mtmp, x, y, FALSE);
X }
X
X /* make shk show up at the door */
X levl[shopkeeper->mx][shopkeeper->my].mmask = 0;
X levl[x][y].mmask = 1;
X shopkeeper->mx = x;
X shopkeeper->my = y;
X pmon(shopkeeper);
X
X if(um_dist(x, y, 1)) goto chase;
X
X if(u.ugold < damage || !rn2(50)) {
Xchase:
X if(um_dist(x, y, 1))
X pline("%s shouts: \"Who dared %s my door?\"",
X shkname(shopkeeper), dmgstr);
X else pline("\"How dare you %s my door?\"", dmgstr);
X NOTANGRY(shopkeeper) = 0;
X ESHK(shopkeeper)->following = 1;
X return;
X }
X
X pline("\"Cad! You did %d zorkmids worth of damage!\" Pay? ", damage);
X if(yn() != 'n') {
X u.ugold -= damage;
X shopkeeper->mgold += damage;
X flags.botl = 1;
X pline("Mollified, %s accepts your restitution.",
X shkname(shopkeeper));
X
X /* clear ox oy of another monster, if one got there somehow */
X if(levl[ox][oy].mmask) mnearto(m_at(ox,oy),ox,oy,FALSE);
X
X /* move shk back to his orig loc */
X levl[shopkeeper->mx][shopkeeper->my].mmask = 0;
X levl[ox][oy].mmask = 1;
X shopkeeper->mx = ox;
X shopkeeper->my = oy;
X unpmon(shopkeeper);
X NOTANGRY(shopkeeper) = 1;
X }
X else {
X pline("\"Oh, yes! You'll pay!\"");
X ESHK(shopkeeper)->following = 1;
X NOTANGRY(shopkeeper) = 0;
X adjalign(-sgn(u.ualigntyp));
X }
X}
X
X/* called in dokick.c when we kick an object in a store */
Xboolean
Xcostly_spot(x, y)
Xregister int x, y;
X{
X register struct monst *shkp = shopkeeper;
X
X if(!shkp) return(FALSE);
X
X return(in_shop(x, y) && levl[x][y].typ != DOOR &&
X !(x == ESHK(shkp)->shk.x && y == ESHK(shkp)->shk.y));
X}
X
X#ifdef KOPS
Xstatic void
Xkops_gone()
X{
X register int cnt = 0;
X register struct monst *mtmp, *mtmp2;
X
X /* turn off automatic resurrection of kops */
X allow_kops = FALSE;
X
X for(mtmp = fmon; mtmp; mtmp = mtmp2) {
X mtmp2 = mtmp->nmon;
X if(mtmp->data->mlet == S_KOP) {
X mongone(mtmp);
X cnt++;
X }
X }
X if(cnt) pline("The Kops (disappointed) disappear into thin air.");
X allow_kops = TRUE;
X}
X#endif
X
Xstatic long
Xcost_per_charge(otmp)
Xregister struct obj *otmp;
X{
X register long tmp = get_cost(otmp);
X
X /* The idea is to make the exhaustive use of */
X /* an unpaid item more expansive than buying */
X /* outright. */
X if(otmp->otyp == MAGIC_LAMP) { /* 1 */
X tmp += (tmp/3L);
X } else if(otmp->otyp == MAGIC_MARKER) { /* 70 - 100 */
X /* no way to determine in advance */
X /* how many charges will be wasted. */
X /* so, arbitrarily, one half of the */
X /* price per use. */
X tmp = (tmp/2L);
X } else if(otmp->otyp == BAG_OF_TRICKS) { /* 1 - 20 */
X tmp = (tmp/5L);
X } else if(otmp->otyp == CRYSTAL_BALL || /* 1 - 5 */
X otmp->otyp == LAMP || /* 1-10 */
X#ifdef MUSIC
X (otmp->otyp >= MAGIC_FLUTE &&
X otmp->otyp <= DRUM_OF_EARTHQUAKE) || /* 5 - 9 */
X#endif
X otmp->olet == WAND_SYM) { /* 3 - 11 */
X if(otmp->spe == 1) tmp += (tmp/3L);
X else tmp = (tmp/4L);
X }
X else return(0L);
X return(tmp);
X}
X
X/* for using charges of unpaid objects */
Xvoid
Xcheck_unpaid(otmp)
Xregister struct obj *otmp;
X{
X if(!in_shop(u.ux, u.uy)) return;
X
X if(otmp->spe <= 0) return;
X
X if(otmp->unpaid) {
X ESHK(shopkeeper)->debit += cost_per_charge(otmp);
X }
X}
END_OF_FILE
if test 37207 -ne `wc -c <'src/shk.c'`; then
echo shar: \"'src/shk.c'\" unpacked with wrong size!
fi
# end of 'src/shk.c'
fi
echo shar: End of archive 7 \(of 38\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 38 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