Edit

IABSD.fr/src/games/hack/hack.c

Branch :

  • Show log

    Commit

  • Author : mestre
    Date : 2016-01-10 15:12:20
    Hash : 8ae737b1
    Message : #ifdef QUEST then a few functions won't work, because of that include <stdlib.h> if we are on a QUEST OK tb@

  • games/hack/hack.c
  • /*	$OpenBSD: hack.c,v 1.11 2016/01/10 15:12:20 mestre Exp $	*/
    
    /*
     * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
     * Amsterdam
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions are
     * met:
     *
     * - Redistributions of source code must retain the above copyright notice,
     * this list of conditions and the following disclaimer.
     *
     * - Redistributions in binary form must reproduce the above copyright
     * notice, this list of conditions and the following disclaimer in the
     * documentation and/or other materials provided with the distribution.
     *
     * - Neither the name of the Stichting Centrum voor Wiskunde en
     * Informatica, nor the names of its contributors may be used to endorse or
     * promote products derived from this software without specific prior
     * written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
     * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    /*
     * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     * 1. Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     * 3. The name of the author may not be used to endorse or promote products
     *    derived from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
     * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdio.h>
    #ifdef QUEST
    #include <stdlib.h>
    #endif
    
    #include "hack.h"
    
    extern char *nomovemsg;
    extern char *exclam();
    
    static void movobj(struct obj *, int, int);
    #ifdef QUEST
    static int rroom(int, int);
    #endif
    static int inv_cnt(void);
    
    /* called on movement:
     *	1. when throwing ball+chain far away
     *	2. when teleporting
     *	3. when walking out of a lit room
     */
    void
    unsee(void)
    {
    	int x,y;
    	struct rm *lev;
    
    /*
    	if(u.udispl){
    		u.udispl = 0;
    		newsym(u.udisx, u.udisy);
    	}
    */
    #ifndef QUEST
    	if(seehx){
    		seehx = 0;
    	} else
    #endif /* QUEST */
    	for(x = u.ux-1; x < u.ux+2; x++)
    	  for(y = u.uy-1; y < u.uy+2; y++) {
    		if(!isok(x, y)) continue;
    		lev = &levl[x][y];
    		if(!lev->lit && lev->scrsym == '.') {
    			lev->scrsym =' ';
    			lev->new = 1;
    			on_scr(x,y);
    		}
    	}
    }
    
    /* called:
     *	in hack.eat.c: seeoff(0) - blind after eating rotten food
     *	in hack.mon.c: seeoff(0) - blinded by a yellow light
     *	in hack.mon.c: seeoff(1) - swallowed
     *	in hack.do.c:  seeoff(0) - blind after drinking potion
     *	in hack.do.c:  seeoff(1) - go up or down the stairs
     *	in hack.trap.c:seeoff(1) - fall through trapdoor
     */
    void
    seeoff(int mode)	/* 1 to redo @, 0 to leave them */
    {	/* 1 means misc movement, 0 means blindness */
    	int x,y;
    	struct rm *lev;
    
    	if(u.udispl && mode){
    		u.udispl = 0;
    		levl[(int)u.udisx][(int)u.udisy].scrsym = news0(u.udisx,u.udisy);
    	}
    #ifndef QUEST
    	if(seehx) {
    		seehx = 0;
    	} else
    #endif /* QUEST */
    	if(!mode) {
    		for(x = u.ux-1; x < u.ux+2; x++)
    			for(y = u.uy-1; y < u.uy+2; y++) {
    				if(!isok(x, y)) continue;
    				lev = &levl[x][y];
    				if(!lev->lit && lev->scrsym == '.')
    					lev->seen = 0;
    			}
    	}
    }
    
    void
    domove(void)
    {
    	xchar oldx,oldy;
    	struct monst *mtmp;
    	struct rm *tmpr,*ust;
    	struct trap *trap;
    	struct obj *otmp;
    
    	u_wipe_engr(rnd(5));
    
    	if(inv_weight() > 0){
    		pline("You collapse under your load.");
    		nomul(0);
    		return;
    	}
    	if(u.uswallow) {
    		u.dx = u.dy = 0;
    		u.ux = u.ustuck->mx;
    		u.uy = u.ustuck->my;
    	} else {
    		if(Confusion) {
    			do {
    				confdir();
    			} while(!isok(u.ux+u.dx, u.uy+u.dy) ||
    			    IS_ROCK(levl[u.ux+u.dx][u.uy+u.dy].typ));
    		}
    		if(!isok(u.ux+u.dx, u.uy+u.dy)){
    			nomul(0);
    			return;
    		}
    	}
    
    	ust = &levl[(int)u.ux][(int)u.uy];
    	oldx = u.ux;
    	oldy = u.uy;
    	if(!u.uswallow && (trap = t_at(u.ux+u.dx, u.uy+u.dy)) && trap->tseen)
    		nomul(0);
    	if(u.ustuck && !u.uswallow && (u.ux+u.dx != u.ustuck->mx ||
    		u.uy+u.dy != u.ustuck->my)) {
    		if(dist(u.ustuck->mx, u.ustuck->my) > 2){
    			/* perhaps it fled (or was teleported or ... ) */
    			u.ustuck = 0;
    		} else {
    			if(Blind) pline("You cannot escape from it!");
    			else pline("You cannot escape from %s!",
    				monnam(u.ustuck));
    			nomul(0);
    			return;
    		}
    	}
    	if(u.uswallow || (mtmp = m_at(u.ux+u.dx,u.uy+u.dy))) {
    	/* attack monster */
    
    		nomul(0);
    		gethungry();
    		if(multi < 0) return;	/* we just fainted */
    
    		/* try to attack; note that it might evade */
    		if(attack(u.uswallow ? u.ustuck : mtmp))
    			return;
    	}
    	/* not attacking an animal, so we try to move */
    	if(u.utrap) {
    		if(u.utraptype == TT_PIT) {
    			pline("You are still in a pit.");
    			u.utrap--;
    		} else {
    			pline("You are caught in a beartrap.");
    			if((u.dx && u.dy) || !rn2(5)) u.utrap--;
    		}
    		return;
    	}
    	tmpr = &levl[u.ux+u.dx][u.uy+u.dy];
    	if(IS_ROCK(tmpr->typ) ||
    	   (u.dx && u.dy && (tmpr->typ == DOOR || ust->typ == DOOR))){
    		flags.move = 0;
    		nomul(0);
    		return;
    	}
    	while ((otmp = sobj_at(ENORMOUS_ROCK, u.ux+u.dx, u.uy+u.dy))) {
    		xchar rx = u.ux+2*u.dx, ry = u.uy+2*u.dy;
    		struct trap *ttmp;
    		nomul(0);
    		if (isok(rx,ry) && !IS_ROCK(levl[(int)rx][(int)ry].typ) &&
    		    (levl[(int)rx][(int)ry].typ != DOOR || !(u.dx && u.dy)) &&
    		    !sobj_at(ENORMOUS_ROCK, rx, ry)) {
    			if(m_at(rx,ry)) {
    			    pline("You hear a monster behind the rock.");
    			    pline("Perhaps that's why you cannot move it.");
    			    goto cannot_push;
    			}
    			if ((ttmp = t_at(rx,ry)))
    			    switch(ttmp->ttyp) {
    			    case PIT:
    				pline("You push the rock into a pit!");
    				deltrap(ttmp);
    				delobj(otmp);
    				pline("It completely fills the pit!");
    				continue;
    			    case TELEP_TRAP:
    				pline("You push the rock and suddenly it disappears!");
    				delobj(otmp);
    				continue;
    			    }
    			if (levl[(int)rx][(int)ry].typ == POOL) {
    				levl[(int)rx][(int)ry].typ = ROOM;
    				mnewsym(rx,ry);
    				prl(rx,ry);
    				pline("You push the rock into the water.");
    				pline("Now you can cross the water!");
    				delobj(otmp);
    				continue;
    			}
    			otmp->ox = rx;
    			otmp->oy = ry;
    			/* pobj(otmp); */
    			if(cansee(rx,ry)) atl(rx,ry,otmp->olet);
    			if(Invisible) newsym(u.ux+u.dx, u.uy+u.dy);
    
    			{ static long lastmovetime;
    			/* note: this var contains garbage initially and
    			   after a restore */
    			if(moves > lastmovetime+2 || moves < lastmovetime)
    			pline("With great effort you move the enormous rock.");
    			lastmovetime = moves;
    			}
    		} else {
    		    pline("You try to move the enormous rock, but in vain.");
    	    cannot_push:
    		    if((!invent || inv_weight()+90 <= 0) &&
    			(!u.dx || !u.dy || (IS_ROCK(levl[(int)u.ux][u.uy+u.dy].typ)
    					&& IS_ROCK(levl[u.ux+u.dx][(int)u.uy].typ)))){
    			pline("However, you can squeeze yourself into a small opening.");
    			break;
    		    } else
    			return;
    		}
    	    }
    	if(u.dx && u.dy && IS_ROCK(levl[(int)u.ux][u.uy+u.dy].typ) &&
    	    IS_ROCK(levl[u.ux+u.dx][(int)u.uy].typ) &&
    		invent && inv_weight()+40 > 0) {
    		pline("You are carrying too much to get through.");
    		nomul(0);
    		return;
    	}
    	if(Punished &&
    	   DIST(u.ux+u.dx, u.uy+u.dy, uchain->ox, uchain->oy) > 2){
    		if(carried(uball)) {
    			movobj(uchain, u.ux, u.uy);
    			goto nodrag;
    		}
    
    		if(DIST(u.ux+u.dx, u.uy+u.dy, uball->ox, uball->oy) < 3){
    			/* leave ball, move chain under/over ball */
    			movobj(uchain, uball->ox, uball->oy);
    			goto nodrag;
    		}
    
    		if(inv_weight() + (int) uball->owt/2 > 0) {
    			pline("You cannot %sdrag the heavy iron ball.",
    			invent ? "carry all that and also " : "");
    			nomul(0);
    			return;
    		}
    
    		movobj(uball, uchain->ox, uchain->oy);
    		unpobj(uball);		/* BAH %% */
    		uchain->ox = u.ux;
    		uchain->oy = u.uy;
    		nomul(-2);
    		nomovemsg = "";
    	nodrag:	;
    	}
    	u.ux += u.dx;
    	u.uy += u.dy;
    	if(flags.run) {
    		if(tmpr->typ == DOOR ||
    		(xupstair == u.ux && yupstair == u.uy) ||
    		(xdnstair == u.ux && ydnstair == u.uy))
    			nomul(0);
    	}
    
    	if(tmpr->typ == POOL && !Levitation)
    		drown();	/* not necessarily fatal */
    
    /*
    	if(u.udispl) {
    		u.udispl = 0;
    		newsym(oldx,oldy);
    	}
    */
    	if(!Blind) {
    #ifdef QUEST
    		setsee();
    #else
    		if(ust->lit) {
    			if(tmpr->lit) {
    				if(tmpr->typ == DOOR)
    					prl1(u.ux+u.dx,u.uy+u.dy);
    				else if(ust->typ == DOOR)
    					nose1(oldx-u.dx,oldy-u.dy);
    			} else {
    				unsee();
    				prl1(u.ux+u.dx,u.uy+u.dy);
    			}
    		} else {
    			if(tmpr->lit) setsee();
    			else {
    				prl1(u.ux+u.dx,u.uy+u.dy);
    				if(tmpr->typ == DOOR) {
    					if(u.dy) {
    						prl(u.ux-1,u.uy);
    						prl(u.ux+1,u.uy);
    					} else {
    						prl(u.ux,u.uy-1);
    						prl(u.ux,u.uy+1);
    					}
    				}
    			}
    			nose1(oldx-u.dx,oldy-u.dy);
    		}
    #endif /* QUEST */
    	} else {
    		pru();
    	}
    	if(!flags.nopick) pickup(1);
    	if(trap) dotrap(trap);		/* fall into pit, arrow trap, etc. */
    	(void) inshop();
    	if(!Blind) read_engr_at(u.ux,u.uy);
    }
    
    static void
    movobj(struct obj *obj, int ox, int oy)
    {
    	/* Some dirty programming to get display right */
    	freeobj(obj);
    	unpobj(obj);
    	obj->nobj = fobj;
    	fobj = obj;
    	obj->ox = ox;
    	obj->oy = oy;
    }
    
    int
    dopickup(void)
    {
    	if(!g_at(u.ux,u.uy) && !o_at(u.ux,u.uy)) {
    		pline("There is nothing here to pick up.");
    		return(0);
    	}
    	if(Levitation) {
    		pline("You cannot reach the floor.");
    		return(1);
    	}
    	pickup(0);
    	return(1);
    }
    
    void
    pickup(int all)
    {
    	struct gold *gold;
    	struct obj *obj, *obj2;
    	int wt;
    
    	if (Levitation)
    		return;
    	while ((gold = g_at(u.ux,u.uy))) {
    		pline("%ld gold piece%s.", gold->amount, plur(gold->amount));
    		u.ugold += gold->amount;
    		flags.botl = 1;
    		freegold(gold);
    		if(flags.run) nomul(0);
    		if(Invisible) newsym(u.ux,u.uy);
    	}
    
    	/* check for more than one object */
    	if(!all) {
    		int ct = 0;
    
    		for(obj = fobj; obj; obj = obj->nobj)
    			if(obj->ox == u.ux && obj->oy == u.uy)
    				if(!Punished || obj != uchain)
    					ct++;
    		if(ct < 2)
    			all++;
    		else
    			pline("There are several objects here.");
    	}
    
    	for(obj = fobj; obj; obj = obj2) {
    	    obj2 = obj->nobj;	/* perhaps obj will be picked up */
    	    if(obj->ox == u.ux && obj->oy == u.uy) {
    		if(flags.run) nomul(0);
    
    		/* do not pick up uchain */
    		if(Punished && obj == uchain)
    			continue;
    
    		if(!all) {
    			char c;
    
    			pline("Pick up %s ? [ynaq]", doname(obj));
    			while(!strchr("ynaq ", (c = readchar())))
    				hackbell();
    			if(c == 'q') return;
    			if(c == 'n') continue;
    			if(c == 'a') all = 1;
    		}
    
    		if(obj->otyp == DEAD_COCKATRICE && !uarmg){
    		    pline("Touching the dead cockatrice is a fatal mistake.");
    		    pline("You turn to stone.");
    		    killer = "cockatrice cadaver";
    		    done("died");
    		}
    
    		if(obj->otyp == SCR_SCARE_MONSTER){
    		  if(!obj->spe) obj->spe = 1;
    		  else {
    		    /* Note: perhaps the 1st pickup failed: you cannot
    			carry anymore, and so we never dropped it -
    			let's assume that treading on it twice also
    			destroys the scroll */
    		    pline("The scroll turns to dust as you pick it up.");
    		    delobj(obj);
    		    continue;
    		  }
    		}
    
    		wt = inv_weight() + obj->owt;
    		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) goto too_heavy;
    			pline("You can only carry %s of the %s lying here.",
    					(qq == 1) ? "one" : "some",
    					doname(obj));
    				(void) splitobj(obj, qq);
    				/* note: obj2 is set already, so we'll never
    				 * encounter the other half; if it should be
    				 * otherwise then write
    				 *	obj2 = splitobj(obj,qq);
    				 */
    				goto lift_some;
    			}
    		too_heavy:
    			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 anymore");
    			break;
    		}
    	lift_some:
    		if(inv_cnt() >= 52) {
    		    pline("Your knapsack cannot accommodate anymore items.");
    		    break;
    		}
    		if(wt > -5) pline("You have a little trouble lifting");
    		freeobj(obj);
    		if(Invisible) newsym(u.ux,u.uy);
    		addtobill(obj);       /* sets obj->unpaid if necessary */
    		{ int pickquan = obj->quan;
    		  int mergquan;
    		if(!Blind) obj->dknown = 1;	/* this is done by prinv(),
    				 but addinv() needs it already for merging */
    		obj = addinv(obj);    /* might merge it with other objects */
    		  mergquan = obj->quan;
    		  obj->quan = pickquan;	/* to fool prinv() */
    		prinv(obj);
    		  obj->quan = mergquan;
    		}
    	    }
    	}
    }
    
    /* stop running if we see something interesting */
    /* turn around a corner if that is the only way we can proceed */
    /* do not turn left or right twice */
    void
    lookaround(void)
    {
    	int x, y, i, x0, y0, m0, i0 = 9;
    	int corrct = 0, noturn = 0;
    	struct monst *mtmp;
    
    	if (Blind || flags.run == 0) return;
    	if (flags.run == 1 && levl[(int)u.ux][(int)u.uy].typ == ROOM)
    		return;
    #ifdef QUEST
    	if(u.ux0 == u.ux+u.dx && u.uy0 == u.uy+u.dy) goto stop;
    #endif /* QUEST */
    	for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){
    		if(x == u.ux && y == u.uy) continue;
    		if(!levl[x][y].typ) continue;
    		if((mtmp = m_at(x,y)) && !mtmp->mimic &&
    		    (!mtmp->minvis || See_invisible)){
    			if(!mtmp->mtame || (x == u.ux+u.dx && y == u.uy+u.dy))
    				goto stop;
    		} else mtmp = 0; /* invisible M cannot influence us */
    		if(x == u.ux-u.dx && y == u.uy-u.dy) continue;
    		switch(levl[x][y].scrsym){
    		case '|':
    		case '-':
    		case '.':
    		case ' ':
    			break;
    		case '+':
    			if(x != u.ux && y != u.uy) break;
    			if(flags.run != 1) goto stop;
    			/* fall into next case */
    		case CORR_SYM:
    		corr:
    			if(flags.run == 1 || flags.run == 3) {
    				i = DIST(x,y,u.ux+u.dx,u.uy+u.dy);
    				if(i > 2) break;
    				if(corrct == 1 && DIST(x,y,x0,y0) != 1)
    					noturn = 1;
    				if(i < i0) {
    					i0 = i;
    					x0 = x;
    					y0 = y;
    					m0 = mtmp ? 1 : 0;
    				}
    			}
    			corrct++;
    			break;
    		case '^':
    			if(flags.run == 1) goto corr;	/* if you must */
    			if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop;
    			break;
    		default:	/* e.g. objects or trap or stairs */
    			if(flags.run == 1) goto corr;
    			if(mtmp) break;		/* d */
    		stop:
    			nomul(0);
    			return;
    		}
    	}
    #ifdef QUEST
    	if(corrct > 0 && (flags.run == 4 || flags.run == 5)) goto stop;
    #endif /* QUEST */
    	if(corrct > 1 && flags.run == 2) goto stop;
    	if((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 &&
    		(corrct == 1 || (corrct == 2 && i0 == 1))) {
    		/* make sure that we do not turn too far */
    		if(i0 == 2) {
    		    if(u.dx == y0-u.uy && u.dy == u.ux-x0)
    			i = 2;		/* straight turn right */
    		    else
    			i = -2;		/* straight turn left */
    		} else if(u.dx && u.dy) {
    		    if((u.dx == u.dy && y0 == u.uy) ||
    			(u.dx != u.dy && y0 != u.uy))
    			i = -1;		/* half turn left */
    		    else
    			i = 1;		/* half turn right */
    		} else {
    		    if((x0-u.ux == y0-u.uy && !u.dy) ||
    			(x0-u.ux != y0-u.uy && u.dy))
    			i = 1;		/* half turn right */
    		    else
    			i = -1;		/* half turn left */
    		}
    		i += u.last_str_turn;
    		if(i <= 2 && i >= -2) {
    			u.last_str_turn = i;
    			u.dx = x0-u.ux, u.dy = y0-u.uy;
    		}
    	}
    }
    
    /* something like lookaround, but we are not running */
    /* react only to monsters that might hit us */
    int
    monster_nearby(void)
    {
    	int x,y;
    	struct monst *mtmp;
    
    	if(!Blind)
    	for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++){
    		if(x == u.ux && y == u.uy) continue;
    		if((mtmp = m_at(x,y)) && !mtmp->mimic && !mtmp->mtame &&
    			!mtmp->mpeaceful && !strchr("Ea", mtmp->data->mlet) &&
    			!mtmp->mfroz && !mtmp->msleep &&  /* aplvax!jcn */
    			(!mtmp->minvis || See_invisible))
    			return(1);
    	}
    	return(0);
    }
    
    #ifdef QUEST
    int
    cansee(xchar x, xchar y)
    {
    	int dx,dy,adx,ady,sdx,sdy,dmax,d;
    
    	if(Blind) return(0);
    	if(!isok(x,y)) return(0);
    	d = dist(x,y);
    	if(d < 3) return(1);
    	if(d > u.uhorizon*u.uhorizon) return(0);
    	if(!levl[x][y].lit)
    		return(0);
    	dx = x - u.ux;	adx = abs(dx);	sdx = sgn(dx);
    	dy = y - u.uy;  ady = abs(dy);	sdy = sgn(dy);
    	if(dx == 0 || dy == 0 || adx == ady){
    		dmax = (dx == 0) ? ady : adx;
    		for(d = 1; d <= dmax; d++)
    			if(!rroom(sdx*d,sdy*d))
    				return(0);
    		return(1);
    	} else if(ady > adx){
    		for(d = 1; d <= ady; d++){
    			if(!rroom(sdx*( (d*adx)/ady ), sdy*d) ||
    			   !rroom(sdx*( (d*adx-1)/ady+1 ), sdy*d))
    				return(0);
    		}
    		return(1);
    	} else {
    		for(d = 1; d <= adx; d++){
    			if(!rroom(sdx*d, sdy*( (d*ady)/adx )) ||
    			   !rroom(sdx*d, sdy*( (d*ady-1)/adx+1 )))
    				return(0);
    		}
    		return(1);
    	}
    }
    
    static int
    rroom(int x, int y)
    {
    	return(IS_ROOM(levl[u.ux+x][u.uy+y].typ));
    }
    
    #else
    
    int
    cansee(xchar x, xchar y)
    {
    	if (Blind || u.uswallow)
    		return(0);
    	if (dist(x,y) < 3)
    		return(1);
    	if (levl[(int)x][(int)y].lit && seelx <= x && x <= seehx &&
    	    seely <= y && y <= seehy)
    		return(1);
    	return(0);
    }
    #endif /* QUEST */
    
    int
    sgn(int a)
    {
    	return((a > 0) ? 1 : (a == 0) ? 0 : -1);
    }
    
    #ifdef QUEST
    void
    setsee(void)
    {
    	int x,y;
    
    	if(Blind) {
    		pru();
    		return;
    	}
    	for(y = u.uy-u.uhorizon; y <= u.uy+u.uhorizon; y++)
    		for(x = u.ux-u.uhorizon; x <= u.ux+u.uhorizon; x++) {
    			if(cansee(x,y))
    				prl(x,y);
    	}
    }
    
    #else
    void
    setsee(void)
    {
    	int x,y;
    
    	if (Blind) {
    		pru();
    		return;
    	}
    	if (!levl[(int)u.ux][(int)u.uy].lit) {
    		seelx = u.ux-1;
    		seehx = u.ux+1;
    		seely = u.uy-1;
    		seehy = u.uy+1;
    	} else {
    		for(seelx = u.ux; levl[seelx-1][(int)u.uy].lit; seelx--);
    		for(seehx = u.ux; levl[seehx+1][(int)u.uy].lit; seehx++);
    		for(seely = u.uy; levl[(int)u.ux][seely-1].lit; seely--);
    		for(seehy = u.uy; levl[(int)u.ux][seehy+1].lit; seehy++);
    	}
    	for (y = seely; y <= seehy; y++)
    		for (x = seelx; x <= seehx; x++) {
    			prl(x,y);
    	}
    	if (!levl[(int)u.ux][(int)u.uy].lit)
    		seehx = 0; /* seems necessary elsewhere */
    	else {
    	    if(seely == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seely-1);
    	    if(seehy == u.uy) for(x = u.ux-1; x <= u.ux+1; x++) prl(x,seehy+1);
    	    if(seelx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seelx-1,y);
    	    if(seehx == u.ux) for(y = u.uy-1; y <= u.uy+1; y++) prl(seehx+1,y);
    	}
    }
    #endif /* QUEST */
    
    void
    nomul(int nval)
    {
    	if(multi < 0) return;
    	multi = nval;
    	flags.mv = flags.run = 0;
    }
    
    int
    abon(void)
    {
    	if(u.ustr == 3) return(-3);
    	else if(u.ustr < 6) return(-2);
    	else if(u.ustr < 8) return(-1);
    	else if(u.ustr < 17) return(0);
    	else if(u.ustr < 69) return(1);	/* up to 18/50 */
    	else if(u.ustr < 118) return(2);
    	else return(3);
    }
    
    int
    dbon(void)
    {
    	if(u.ustr < 6) return(-1);
    	else if(u.ustr < 16) return(0);
    	else if(u.ustr < 18) return(1);
    	else if(u.ustr == 18) return(2);	/* up to 18 */
    	else if(u.ustr < 94) return(3);		/* up to 18/75 */
    	else if(u.ustr < 109) return(4);	/* up to 18/90 */
    	else if(u.ustr < 118) return(5);	/* up to 18/99 */
    	else return(6);
    }
    
    void
    losestr(int num)	/* may kill you; cause may be poison or monster like 'A' */
    {
    	u.ustr -= num;
    	while(u.ustr < 3) {
    		u.ustr++;
    		u.uhp -= 6;
    		u.uhpmax -= 6;
    	}
    	flags.botl = 1;
    }
    
    void
    losehp(int n, char *knam)
    {
    	u.uhp -= n;
    	if(u.uhp > u.uhpmax)
    		u.uhpmax = u.uhp;	/* perhaps n was negative */
    	flags.botl = 1;
    	if(u.uhp < 1) {
    		killer = knam;	/* the thing that killed you */
    		done("died");
    	}
    }
    
    void
    losehp_m(int n, struct monst *mtmp)
    {
    	u.uhp -= n;
    	flags.botl = 1;
    	if(u.uhp < 1)
    		done_in_by(mtmp);
    }
    
    /* hit by V or W */
    void
    losexp(void)
    {
    	int num;
    
    	if(u.ulevel > 1)
    		pline("Goodbye level %u.", u.ulevel--);
    	else
    		u.uhp = -1;
    	num = rnd(10);
    	u.uhp -= num;
    	u.uhpmax -= num;
    	u.uexp = newuexp();
    	flags.botl = 1;
    }
    
    int
    inv_weight(void)
    {
    	struct obj *otmp = invent;
    	int wt = (u.ugold + 500)/1000;
    	int carrcap;
    
    	if(Levitation)			/* pugh@cornell */
    		carrcap = MAX_CARR_CAP;
    	else {
    		carrcap = 5*(((u.ustr > 18) ? 20 : u.ustr) + u.ulevel);
    		if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
    		if(Wounded_legs & LEFT_SIDE) carrcap -= 10;
    		if(Wounded_legs & RIGHT_SIDE) carrcap -= 10;
    	}
    	while(otmp){
    		wt += otmp->owt;
    		otmp = otmp->nobj;
    	}
    	return(wt - carrcap);
    }
    
    static int
    inv_cnt(void)
    {
    	struct obj *otmp = invent;
    	int ct = 0;
    
    	while(otmp){
    		ct++;
    		otmp = otmp->nobj;
    	}
    	return(ct);
    }
    
    long
    newuexp(void)
    {
    	return(10*(1L << (u.ulevel-1)));
    }