ftp.nice.ch/pub/next/games/strategic/NetHack.s.tar.gz#/NetHackSource/src/pickup.c

This is pickup.c in view mode; [Download] [Up]

/*	SCCS Id: @(#)pickup.c	3.0	88/07/12
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

/*
 *	Contains code for picking objects up, and container use.
 */

#include	"hack.h"
#ifndef OVERLAY
static int FDECL(in_container,(struct obj *));
static int FDECL(ck_container,(struct obj *));
static int FDECL(ck_bag,(struct obj *));
static int FDECL(out_container,(struct obj *));
#else
int FDECL(in_container,(struct obj *));
int FDECL(ck_container,(struct obj *));
int FDECL(ck_bag,(struct obj *));
int FDECL(out_container,(struct obj *));
#endif
void FDECL(explode_bag,(struct obj *));

#ifdef OVLB

static const char nearloadmsg[] = "have a little trouble lifting";

void
pickup(all)
int all;
{
	register struct gold *gold = g_at(u.ux, u.uy);
	register struct obj *obj, *obj2;
	register int wt;
	char buf[BUFSZ];
	register char *ip;
	register char sym;
	register int oletct = 0, iletct = 0;
	boolean all_of_a_type = FALSE, selective = FALSE;
	char olets[20], ilets[20];
	struct obj dummygold;

	dummygold.ox = u.ux;
	dummygold.oy = u.uy;
	dummygold.olet = GOLD_SYM;
	dummygold.nobj = fobj;
	dummygold.nexthere = level.objects[u.ux][u.uy];
	dummygold.cobj = 0;

	if(Levitation) {
		if ((multi && !flags.run) || (all && !flags.pickup))
			read_engr_at(u.ux,u.uy);
		return;
	}
	/* multi && !flags.run means they are in the middle of some other
	 * action, or possibly paralyzed, sleeping, etc.... and they just
	 * teleported onto the object.  They shouldn't pick it up.
	 */
	if ((multi && !flags.run) || (all && !flags.pickup)) {
		int ct = 0;

		for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
			if(!obj->cobj && obj != uchain)
				ct++;

		/* Stop on a zorkmid */
		if (gold) ct++;

		/* If there are objects here, take a look.
		 */
		if (ct) {
			if (flags.run)
				nomul(0);
			nscr();
			if (ct < 5)
				(void) dolook();
			else {
				read_engr_at(u.ux,u.uy);
				pline("There are several objects here.");
			}
		} else read_engr_at(u.ux,u.uy);
		return;
	}

	/* check for more than one object */
	if(!all) {
		register int ct = 0;

		if (gold) ct++;
		for(obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
			if(!obj->cobj) ct++;
		if(ct < 2)
			all++;
		else
			pline("There are several objects here.");
	}

	/* added by GAN 10/24/86 to allow selective picking up */
	if(!all)  {
		register struct obj *otmp = level.objects[u.ux][u.uy];

		ilets[iletct] = 0;
		if(gold) {
			ilets[iletct++] = GOLD_SYM;
			ilets[iletct] = 0;
		}
		while(otmp) {
			if(!index(ilets, otmp->olet) && !otmp->cobj) {
				ilets[iletct++] = otmp->olet;
				ilets[iletct] = 0;
			}
			otmp = otmp->nexthere;
		}
		if(iletct == 1)
			Strcpy(buf,ilets);
		else  {
			ilets[iletct++] = ' ';
			ilets[iletct++] = 'a';
			ilets[iletct++] = 'A';
			ilets[iletct] = 0;

			pline("What kinds of thing do you want to pick up? [%s] ", ilets);
			getlin(buf);
			if(buf[0] == '\033') {
				clrlin();
				return;
			}
			else if(!buf[0]) selective = TRUE;
		}
		ip = buf;
		olets[0] = 0;
		while(sym = *ip++){
			/* new A function (selective all) added by
			 * GAN 01/09/87
			 */
			if(sym == ' ') continue;
			if(sym == 'A') selective = TRUE;
			else if(sym == 'a') all_of_a_type = TRUE;
			else if(index(ilets, sym)){
				if(!index(olets, sym)){
					olets[oletct++] = sym;
					olets[oletct] = 0;
				}
			}
			else pline("There are no %c's here.", sym);
		}
	}
	if(all_of_a_type && !olets[0]) all = TRUE;

	for(obj = (gold ? &dummygold : level.objects[u.ux][u.uy]); obj;
			obj = obj2) {
	    obj2 = obj->nexthere;   /* perhaps obj will be picked up */
	    if(!obj->cobj) {
		if(flags.run) nomul(0);

		if(!all)  {
			char c;

			if(!selective && !index(olets,obj->olet)) continue;

			if (!all_of_a_type) {
				if (obj == &dummygold)
					pline("Pick up %ld gold piece%s? ",
					    gold->amount, plur(gold->amount));
				else pline("Pick up %s? ", doname(obj));
				if((c = ynaq()) == 'q') return;
				if(c == 'n') continue;
				if(c == 'a') {
					all_of_a_type = TRUE;
					if (selective) {
						selective = FALSE;
						olets[0] = obj->olet;
						olets[1] = 0;
						/* oletct = 1; */
					}
				}
			}
		}

		if(obj == &dummygold) {
		    int iw = inv_weight();
		    long gold_capacity;

#ifndef lint /* long/int conversion */
		    iw -= (int)((u.ugold + 500)/1000);
#endif
		    gold_capacity = ((-iw) * 1000L) - 500 + 999 - u.ugold;
		    if (gold_capacity <= 0L) {
	 pline("There %s %ld gold piece%s here, but you cannot carry any more.",
				(gold->amount == 1) ? "is" : "are",
				gold->amount, plur(gold->amount));
			continue;
		    }
		    if (gold_capacity >= gold->amount) {
			u.ugold += gold->amount;
			if (inv_weight() > -5)
				You(nearloadmsg);
			pline("%ld gold piece%s.",
				gold->amount, plur(gold->amount));
			freegold(gold);
			if(Invisible) newsym(u.ux,u.uy);
		    } else {
		You("can only carry %s of the %ld gold pieces lying here.",
			    gold_capacity == 1L ? "one" : "some", gold->amount);
			You(nearloadmsg);
			pline("%ld gold piece%s.",
				 gold_capacity, plur(gold_capacity));
			u.ugold += gold_capacity;
			gold->amount -= gold_capacity;
		    }
		    flags.botl = 1;
		    if(flags.run) nomul(0);
		    continue;
		}

		if((obj->otyp == CORPSE && obj->corpsenm == PM_COCKATRICE) &&
		   !uarmg
#ifdef POLYSELF
			&& !resists_ston(uasmon)
#endif
						) {
		    pline("Touching the dead cockatrice is a fatal mistake.");
		    You("turn to stone.");
		    You("die...");
		    killer_format = KILLED_BY_AN;
		    killer = "cockatrice corpse";
		    done(STONING);
		}

		if(obj->otyp == SCR_SCARE_MONSTER){
		  if(obj->blessed) obj->blessed = 0;
		  else if(!obj->spe && !obj->cursed) obj->spe = 1;
		  else {
		    pline("The scroll%s turn%s to dust as you pick %s up.",
				plur((long)obj->quan), (obj->quan==1) ? "s":"",
				(obj->quan==1) ? "it" : "them");
			if(!(objects[SCR_SCARE_MONSTER].oc_name_known) &&
			   !(objects[SCR_SCARE_MONSTER].oc_uname))
				docall(obj);
		    useupf(obj);
		    continue;
		  }
		}

		/* do not pick up uchain */
		if(obj == uchain)
			continue;

		wt = inv_weight() + (int)obj->owt;
		if (obj->otyp == LOADSTONE)
			goto lift_some; /* pick it up even if too heavy */
#ifdef POLYSELF
		if (obj->otyp == BOULDER && throws_rocks(uasmon)) {
			wt = inv_weight();
			goto lift_some;
		}
#endif
		if(wt > 0) {
			if(obj->quan > 1) {
				/* see how many we can lift */
				int savequan = obj->quan;
				int iw = inv_weight();
				int qq;
				for(qq = 1; qq < savequan; qq++){
					obj->quan = qq;
					if(iw + weight(obj) > 0)
						break;
				}
				obj->quan = savequan;
				qq--;
				/* we can carry qq of them */
				if(qq) {
				    register struct obj *obj3;

				You("can only carry %s of the %s lying here.",
					    (qq == 1) ? "one" : "some",
					    doname(obj));
				    obj3 = splitobj(obj, qq);
				    if(obj3->otyp == SCR_SCARE_MONSTER)
					    if(obj3->spe) obj->spe = 0;
				    goto lift_some;
				}
			}
			pline("There %s %s here, but %s.",
				(obj->quan == 1) ? "is" : "are",
				doname(obj),
				!invent ? "it is too heavy for you to lift"
					: "you cannot carry any more");
				if(obj->otyp == SCR_SCARE_MONSTER)
					if(obj->spe) obj->spe = 0;
			break;
		}
	lift_some:
		if(inv_cnt() >= 52) {
			Your("knapsack cannot accommodate any more items.");
			if(obj->otyp == SCR_SCARE_MONSTER)
				if(obj->spe) obj->spe = 0;
			break;
		}
		{ int pickquan = obj->quan;
		  int mergquan;

		  obj = pick_obj(obj);
		  if(wt > -5) You(nearloadmsg);
		  if(!Blind) obj->dknown = 1;
		  mergquan = obj->quan;
		  obj->quan = pickquan; /* to fool prinv() */
		  if(uwep && uwep == obj) mrg_to_wielded = TRUE;
		  prinv(obj);
		  mrg_to_wielded = FALSE;
		  obj->quan = mergquan;
		}
	    }
	}
}

struct obj *
pick_obj(otmp)
register struct obj *otmp;
{
	if (otmp != uball)	     /* don't charge for this - kd, 1/17/90 */
		addtobill(otmp, TRUE);       /* sets obj->unpaid if necessary */
	freeobj(otmp);
	if(Invisible) newsym(u.ux,u.uy);
	return(addinv(otmp));    /* might merge it with other objects */
}

int
doloot() {	/* loot a container on the floor. */

	register struct obj *cobj;
	register int c;

	if (Levitation) {
		You("cannot reach the floor.");
		return(0);
	}
	for(cobj = level.objects[u.ux][u.uy]; cobj; cobj = cobj->nexthere) {
		if(Is_container(cobj)) {

		    pline("There is %s here, loot it? ", doname(cobj));
		    c = ynq();
		    if(c == 'q') return 0;
		    if(c == 'n') continue;

		    if(cobj->olocked) {

			pline("Hmmm, it seems to be locked.");
			continue;
		    }
		    if(cobj->otyp == BAG_OF_TRICKS) {

			You("carefully open the bag...");
			pline("It develops a huge set of teeth and bites you!");
			losehp(rnd(10), "carnivorous bag", KILLED_BY_AN);
			makeknown(BAG_OF_TRICKS);
			continue;
		    }

		    You("carefully open the %s...", xname(cobj));
		    if(cobj->otrapped) chest_trap(cobj, FINGER);
		    if(multi < 0) return 0; /* a paralysis trap */

		    use_container(cobj, 0);
		}
	}
	return 0;
}

static
struct obj *current_container;	/* a local variable of use_container, to be
				used by its local procedures in/ck_container */
#define Icebox (current_container->otyp == ICE_BOX)
int baggone;	/* used in askchain so bag isn't used after explosion */

#endif /* OVLB */
#ifdef OVL0

void
inc_cwt(cobj, obj)
register struct obj *cobj, *obj;
{
	if (cobj->otyp == BAG_OF_HOLDING)
		cobj->owt += (cobj->cursed?(obj->owt*2):(obj->owt/(cobj->blessed?4:2)) + 1);
	else	cobj->owt += obj->owt;
}

#endif /* OVL0 */
#ifdef OVLB

#ifndef OVERLAY
static 
#endif
int
in_container(obj)
register struct obj *obj;
{
	char buf[BUFSZ];

	if(obj == uball || obj == uchain) {
		You("must be kidding.");
		return(0);
	}
	if(obj == current_container) {
		pline("That would be an interesting topological exercise.");
		return(0);
	}
	if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) {
		You("cannot %s something you are wearing.",
			Icebox ? "refrigerate" : "stash");
		return(0);
	}
	if((obj->otyp == LOADSTONE) && obj->cursed) {
		obj->bknown = 1;
		pline("The stone%s won't leave your person.",
			plur((long)obj->quan));
		return(0);
	}
	/* Prohibit Amulets in containers; if you allow it, monsters can't
	 * steal them.  It also becomes a pain to check to see if someone
	 * has the Amulet.
	 */
	if(obj->otyp == AMULET_OF_YENDOR && !obj->spe) {
	    pline("The Amulet of Yendor cannot be confined in such trappings.");
	    return(0);
	}
	/* no nested containers - they do not save/restore properly. */
	/* magic bag -> magic bag will self destruct later on. */
	if(Is_container(obj) && Is_container(current_container) &&
	    (!Is_mbag(obj) || !Is_mbag(current_container))) {
		pline("The %s won't go in.", xname(obj));
		return(1);	/* be careful! */
	}
	if(obj == uwep) {
		if(welded(obj)) {
			weldmsg(obj, FALSE);
			return(0);
		}
		setuwep((struct obj *) 0);
		if (uwep) return(0); /* unwielded, died, rewielded */
	}
#ifdef WALKIES
	if(obj->otyp == LEASH && obj->leashmon != 0) {
		pline("The %s is attached to your pet.", xname(obj));
		return(0);
	}
#endif
	inc_cwt(current_container, obj);
	freeinv(obj);

	obj->cobj = current_container;
	obj->nobj = fcobj;
	fcobj = obj;
	Strcpy(buf, xname(obj->cobj));
	You("put %s into the %s.", doname(obj), buf);

	if(Icebox) obj->age = monstermoves - obj->age; /* actual age */

	else if(Is_mbag(obj->cobj) &&
		(Is_mbag(obj) ||
		 (obj->otyp == WAN_CANCELLATION && (obj->spe > 0)) )) {
		explode_bag(obj);
		You("are blasted by a magical explosion!");
		losehp(d(6,6),"magical explosion", KILLED_BY_AN);
		baggone = 1;
	}
	return(1);
}

#ifndef OVERLAY
static 
#endif
int
ck_container(obj)
register struct obj *obj;
{
	return(obj->cobj == current_container);
}

/* ck_bag() needs a formal argument to make the overlay/prototype mechanism
 * work right */
/*ARGSUSED*/
#ifndef OVERLAY
static 
#endif
int
ck_bag(obj)
struct obj *obj;
{
	return(!baggone);
}

#ifndef OVERLAY
static 
#endif
int
out_container(obj)
register struct obj *obj;
{
	register struct obj *otmp;
	register boolean near_capacity = (inv_weight() > -5);

	if(inv_cnt() >= 52) {
		pline("You have no room to hold anything else.");
		return(0);
	}
	if(obj->otyp != LOADSTONE && inv_weight() + (int)obj->owt > 0) {
		char buf[BUFSZ];

		Strcpy(buf, doname(obj));
		pline("There %s %s in the %s, but %s.",
			obj->quan==1 ? "is" : "are",
			buf, xname(current_container),
			invent ? "you cannot carry any more"
			: "it is too heavy for you to carry");
		/* "too heavy for you to lift" is not right if you're carrying
		   the container... */
		return(0);
	}
	if(obj == fcobj) fcobj = fcobj->nobj;
	else {
		for(otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj)
			if(!otmp->nobj) panic("out_container");
		otmp->nobj = obj->nobj;
	}
	dec_cwt(current_container, obj);
	obj->cobj = (struct obj *) 0;

	if (Icebox) obj->age = monstermoves - obj->age;
	/* simulated point of time */

	(void) addinv(obj);
	if (near_capacity) You("have a little trouble removing");
	prinv(obj);
	return 0;
}

void
get_all_from_box() {
	register struct obj *otmp, *cobj, *ootmp, *nxobj;

	for(otmp = invent; otmp; otmp = otmp->nobj) {
	    cobj = otmp;
	    if(Is_container(otmp)) {
		current_container = otmp;
		for(ootmp=fcobj,nxobj=(fcobj ? fcobj->nobj : 0); ootmp;
			    ootmp=nxobj,nxobj=(ootmp ? ootmp->nobj : 0) )
		    if(ootmp->cobj == cobj)
			(void)out_container(ootmp);
	    }
	}
	return;
}

/* for getobj: 0: allow cnt; #: allow all types; %: expect food */
static const char frozen_food[] = { '0', '#', FOOD_SYM, 0 };

void
use_container(obj, held)
register struct obj *obj;
register int held;
{
	register int cnt = 0;
	register struct obj *otmp;
	register struct obj *backobj;

	current_container = obj;	/* for use by in/out_container */
	if(current_container->olocked) {
		pline("The %s seems to be locked.", xname(current_container));
		return;
	}
	for(otmp = fcobj, backobj = (struct obj *) 0; otmp;
	    backobj = otmp, otmp = otmp->nobj)
		if(otmp->cobj == obj)
		    if(Is_mbag(obj) && obj->cursed && !rn2(13)) {
			if (otmp->known)
				pline("The %s to have vanished!",
							aobjnam(otmp,"seem"));
			else You("%s %s disappear.",
				Blind ? "notice" : "see",
				doname(otmp));
			if(!backobj) {
			    fcobj = otmp->nobj;
			    dec_cwt(current_container, otmp);
			    obfree(otmp, (struct obj *) 0);
			    otmp = fcobj;
			} else {
			    backobj->nobj = otmp->nobj;
			    dec_cwt(current_container, otmp);
			    obfree(otmp, (struct obj *) 0);
			    otmp = backobj->nobj;
			}
			if (!otmp) break;
			if(otmp->cobj == obj) cnt++;
		    } else cnt++;
	if(!cnt)
	    pline("%s %s is empty.", (held) ? "Your" : "The", xname(obj));
	else if (inv_cnt() < 52) {
	    pline("Do you want to take something out of the %s? ",
		  xname(obj));
	    if(yn() != 'n')
		if(askchain(fcobj, FALSE, NULL, 0, out_container, ck_container, 0, "nodot"))
		    return;
	}
	if(!invent) return;
	pline("Do you wish to put something in? ");
	if(yn() != 'y') return;
	if (Icebox && current_container->dknown) {
		otmp = getobj(frozen_food, "put in");
		if(!otmp || !in_container(otmp))
			flags.move = multi = 0;
	} else {
		baggone = 0; /* might be set by in_container */
		if(askchain(invent, TRUE, NULL, 0, in_container, ck_bag, 0, "nodot"))
		  return;
	}
	return;
}

void
delete_contents(obj)
register struct obj *obj;
{
	register struct obj *otmp, *notmp;

	while (fcobj && fcobj->cobj == obj) {
		otmp = fcobj;
		fcobj = fcobj->nobj;
		obfree(otmp,(struct obj *)0);
	}
	if (fcobj) {
		otmp = fcobj;
		while(otmp->nobj)
			if (otmp->nobj->cobj == obj) {
				notmp = otmp->nobj;
				otmp->nobj = notmp->nobj;
				obfree(notmp,(struct obj *)0);
			} else
				otmp = otmp->nobj;
	}
}

void
explode_bag(obj)
struct obj *obj;
{
	struct obj *otmp, *cobj;

	cobj = obj->cobj;
	delete_contents(cobj);

	for (otmp = invent; otmp; otmp = otmp->nobj)
		if (otmp == cobj) break;

	if (otmp) {
		You("see your %s blow apart!", xname(otmp));
		useup(otmp);
		/*return(0);*/
	} else	panic("explode_bag: bag not in invent.");
}

void
dec_cwt(cobj, obj)
register struct obj *cobj, *obj;
{
	if (Is_mbag(cobj))
		cobj->owt -= (cobj->cursed?(obj->owt*2):(obj->owt/(cobj->blessed?4:2)) + 1);
	else	cobj->owt -= obj->owt;

	if(cobj->owt < objects[cobj->otyp].oc_weight)
		cobj->owt = objects[cobj->otyp].oc_weight;
}

#endif /* OVLB */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.