1    | /*	SCCS Id: @(#)hack.c	3.3	2000/04/22	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | 
7    | #ifdef OVL1
8    | static void NDECL(maybe_wail);
9    | #endif /*OVL1*/
10   | STATIC_DCL int NDECL(moverock);
11   | STATIC_DCL int FDECL(still_chewing,(XCHAR_P,XCHAR_P));
12   | #ifdef SINKS
13   | STATIC_DCL void NDECL(dosinkfall);
14   | #endif
15   | STATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int));
16   | 
17   | STATIC_DCL void FDECL(move_update, (BOOLEAN_P));
18   | 
19   | #define IS_SHOP(x)	(rooms[x].rtype >= SHOPBASE)
20   | 
21   | #ifdef OVL2
22   | 
23   | boolean
24   | revive_nasty(x, y, msg)
25   | int x,y;
26   | const char *msg;
27   | {
28   |     register struct obj *otmp, *otmp2;
29   |     struct monst *mtmp;
30   |     coord cc;
31   |     boolean revived = FALSE;
32   | 
33   |     for(otmp = level.objects[x][y]; otmp; otmp = otmp2) {
34   | 	otmp2 = otmp->nexthere;
35   | 	if (otmp->otyp == CORPSE &&
36   | 	    (is_rider(&mons[otmp->corpsenm]) ||
37   | 	     otmp->corpsenm == PM_WIZARD_OF_YENDOR)) {
38   | 	    /* move any living monster already at that location */
39   | 	    if((mtmp = m_at(x,y)) && enexto(&cc, x, y, mtmp->data))
40   | 		rloc_to(mtmp, cc.x, cc.y);
41   | 	    if(msg) Norep("%s", msg);
42   | 	    revived = revive_corpse(otmp);
43   | 	}
44   |     }
45   | 
46   |     /* this location might not be safe, if not, move revived monster */
47   |     if (revived) {
48   | 	mtmp = m_at(x,y);
49   | 	if (mtmp && !goodpos(x, y, mtmp) &&
50   | 	    enexto(&cc, x, y, mtmp->data)) {
51   | 	    rloc_to(mtmp, cc.x, cc.y);
52   | 	}
53   | 	/* else impossible? */
54   |     }
55   | 
56   |     return (revived);
57   | }
58   | 
59   | STATIC_OVL int
60   | moverock()
61   | {
62   |     register xchar rx, ry, sx, sy;
63   |     register struct obj *otmp;
64   |     register struct trap *ttmp;
65   |     register struct monst *mtmp;
66   | 
67   |     sx = u.ux + u.dx,  sy = u.uy + u.dy;	/* boulder starting position */
68   |     while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
69   | 	/* make sure that this boulder is visible as the top object */
70   | 	if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy);
71   | 
72   | 	rx = u.ux + 2 * u.dx;	/* boulder destination position */
73   | 	ry = u.uy + 2 * u.dy;
74   | 	nomul(0);
75   | 	if (Levitation || Is_airlevel(&u.uz)) {
76   | 	    if (Blind) feel_location(sx, sy);
77   | 	    You("don't have enough leverage to push %s.", the(xname(otmp)));
78   | 	    /* Give them a chance to climb over it? */
79   | 	    return -1;
80   | 	}
81   | 	if (verysmall(youmonst.data)
82   | #ifdef STEED
83   | 		 && !u.usteed
84   | #endif
85   | 				    ) {
86   | 	    if (Blind) feel_location(sx, sy);
87   | 	    pline("You're too small to push that %s.", xname(otmp));
88   | 	    goto cannot_push;
89   | 	}
90   | 	if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) &&
91   | 	    (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || (
92   | #ifdef REINCARNATION
93   | 		!Is_rogue_level(&u.uz) &&
94   | #endif
95   | 		(levl[rx][ry].doormask & ~D_BROKEN) == D_NODOOR)) &&
96   | 	    !sobj_at(BOULDER, rx, ry)) {
97   | 	    ttmp = t_at(rx, ry);
98   | 	    mtmp = m_at(rx, ry);
99   | 
100  | 		/* KMH -- Sokoban doesn't let you push boulders diagonally */
101  | 	    if (In_sokoban(&u.uz) && u.dx && u.dy) {
102  | 	    	if (Blind) feel_location(sx,sy);
103  | 	    	pline("%s won't roll diagonally on this %s.",
104  | 	        		The(xname(otmp)), surface(sx, sy));
105  | 	    	goto cannot_push;
106  | 	    }
107  | 
108  | 	    if (revive_nasty(rx, ry, "You sense movement on the other side."))
109  | 		return (-1);
110  | 
111  | 	    if (mtmp && !noncorporeal(mtmp->data) &&
112  | 		    (!mtmp->mtrapped ||
113  | 			 !(ttmp && ((ttmp->ttyp == PIT) ||
114  | 				    (ttmp->ttyp == SPIKED_PIT))))) {
115  | 		if (canspotmon(mtmp))
116  | 		    pline("There's %s on the other side.", mon_nam(mtmp));
117  | 		else {
118  | 		    if (Blind) feel_location(sx, sy);
119  | 		    You_hear("a monster behind %s.", the(xname(otmp)));
120  | 		    map_invisible(rx, ry);
121  | 		}
122  | 		if (flags.verbose)
123  | 		    pline("Perhaps that's why %s cannot move it.",
124  | #ifdef STEED
125  | 				u.usteed ? mon_nam(u.usteed) :
126  | #endif
127  | 				"you");
128  | 		goto cannot_push;
129  | 	    }
130  | 
131  | 	    if (ttmp)
132  | 		switch(ttmp->ttyp) {
133  | 		case LANDMINE:
134  | 		    if (rn2(10)) {
135  | 			pline("KAABLAMM!!!  %s triggers %s land mine.",
136  | 				The(xname(otmp)),
137  | 				ttmp->madeby_u ? "your" : "a");
138  | 			obj_extract_self(otmp);
139  | 			place_object(otmp, rx, ry);
140  | 			deltrap(ttmp);
141  | 			del_engr_at(rx,ry);
142  | 			scatter(rx,ry, 4,
143  | 				MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS,
144  | 				(struct obj *)0);
145  | 			if (cansee(rx,ry)) newsym(rx,ry);
146  | 			continue;
147  | 		    }
148  | 		    break;
149  | 		case SPIKED_PIT:
150  | 		case PIT:
151  | 		    obj_extract_self(otmp);
152  | 		    /* vision kludge to get messages right;
153  | 		       the pit will temporarily be seen even
154  | 		       if this is one among multiple boulders */
155  | 		    if (!Blind) viz_array[ry][rx] |= IN_SIGHT;
156  | 		    if (!flooreffects(otmp, rx, ry, "fall")) {
157  | 			place_object(otmp, rx, ry);
158  | 		    }
159  | 		    if (mtmp && !Blind) newsym(rx, ry);
160  | 		    continue;
161  | 		case HOLE:
162  | 		case TRAPDOOR:
163  | 		    pline("%s %s and plugs a %s in the %s!",
164  | 			  The(xname(otmp)),
165  | 			  (ttmp->ttyp == TRAPDOOR) ? "triggers" : "falls into",
166  | 			  (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole",
167  | 			  surface(rx, ry));
168  | 		    deltrap(ttmp);
169  | 		    delobj(otmp);
170  | 		    bury_objs(rx, ry);
171  | 		    if (cansee(rx,ry)) newsym(rx,ry);
172  | 		    continue;
173  | 		case LEVEL_TELEP:
174  | 		case TELEP_TRAP:
175  | #ifdef STEED
176  | 		    if (u.usteed)
177  | 			pline("%s pushes %s and suddenly it disappears!",
178  | 				Monnam(u.usteed), the(xname(otmp)));
179  | 		    else
180  | #endif
181  | 		    You("push %s and suddenly it disappears!",
182  | 			the(xname(otmp)));
183  | 		    if (ttmp->ttyp == TELEP_TRAP)
184  | 			rloco(otmp);
185  | 		    else {
186  | 			int newlev = random_teleport_level();
187  | 			d_level dest;
188  | 
189  | 			if (newlev == depth(&u.uz) || In_endgame(&u.uz))
190  | 			    continue;
191  | 			obj_extract_self(otmp);
192  | 			add_to_migration(otmp);
193  | 			get_level(&dest, newlev);
194  | 			otmp->ox = dest.dnum;
195  | 			otmp->oy = dest.dlevel;
196  | 			otmp->owornmask = (long)MIGR_RANDOM;
197  | 		    }
198  | 		    seetrap(ttmp);
199  | 		    continue;
200  | 		}
201  | 	    if (closed_door(rx, ry))
202  | 		goto nopushmsg;
203  | 	    if (boulder_hits_pool(otmp, rx, ry, TRUE))
204  | 		continue;
205  | 	    /*
206  | 	     * Re-link at top of fobj chain so that pile order is preserved
207  | 	     * when level is restored.
208  | 	     */
209  | 	    if (otmp != fobj) {
210  | 		remove_object(otmp);
211  | 		place_object(otmp, otmp->ox, otmp->oy);
212  | 	    }
213  | 
214  | 	    {
215  | #ifdef LINT /* static long lastmovetime; */
216  | 		long lastmovetime;
217  | 		lastmovetime = 0;
218  | #else
219  | 		static NEARDATA long lastmovetime;
220  | #endif
221  | 		/* note: this var contains garbage initially and
222  | 		   after a restore */
223  | #ifdef STEED
224  | 		if (!u.usteed) {
225  | #endif
226  | 		  if (moves > lastmovetime+2 || moves < lastmovetime)
227  | 		    pline("With %s effort you move %s.",
228  | 			  throws_rocks(youmonst.data) ? "little" : "great",
229  | 			  the(xname(otmp)));
230  | 		  exercise(A_STR, TRUE);
231  | #ifdef STEED
232  | 		} else 
233  | 		    pline("%s moves %s.", Monnam(u.usteed), the(xname(otmp)));
234  | #endif
235  | 		lastmovetime = moves;
236  | 	    }
237  | 
238  | 	    /* Move the boulder *after* the message. */
239  | 	    if (glyph_is_invisible(levl[rx][ry].glyph))
240  | 		unmap_object(rx, ry);
241  | 	    movobj(otmp, rx, ry);	/* does newsym(rx,ry) */
242  | 	    if (Blind) {
243  | 		feel_location(rx,ry);
244  | 		feel_location(sx, sy);
245  | 	    } else {
246  | 		newsym(sx, sy);
247  | 	    }
248  | 	} else {
249  | 	nopushmsg:
250  | #ifdef STEED
251  | 	  if (u.usteed)
252  | 	    pline("%s tries to move %s, but cannot.",
253  | 		  	Monnam(u.usteed), the(xname(otmp)));
254  | 	  else
255  | #endif
256  | 	    You("try to move %s, but in vain.", the(xname(otmp)));
257  | 	    if (Blind) feel_location(sx, sy);
258  | 	cannot_push:
259  | 	    if (throws_rocks(youmonst.data)) {
260  | #ifdef STEED
261  | 		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) {
262  | 		    You("aren't skilled enough to %s %s from %s.",
263  | 			(flags.pickup && !In_sokoban(&u.uz))
264  | 			    ? "pick up" : "push aside",
265  | 			the(xname(otmp)), mon_nam(u.usteed));
266  | 		} else
267  | #endif
268  | 		{
269  | 		    pline("However, you can easily %s.",
270  | 			(flags.pickup && !In_sokoban(&u.uz))
271  | 			    ? "pick it up" : "push it aside");
272  | 		    if (In_sokoban(&u.uz))
273  | 			change_luck(-1);	/* Sokoban guilt */
274  | 		    break;
275  | 		}
276  | 		break;
277  | 	    }
278  | 
279  | 	    if (
280  | #ifdef STEED
281  | 		!u.usteed &&
282  | #endif	    
283  | 		(((!invent || inv_weight() <= -850) &&
284  | 		 (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ)
285  | 				     && IS_ROCK(levl[sx][u.uy].typ))))
286  | 		|| verysmall(youmonst.data))) {
287  | 		pline("However, you can squeeze yourself into a small opening.");
288  | 		if (In_sokoban(&u.uz))
289  | 		    change_luck(-1);	/* Sokoban guilt */
290  | 		break;
291  | 	    } else
292  | 		return (-1);
293  | 	}
294  |     }
295  |     return (0);
296  | }
297  | 
298  | /*
299  |  *  still_chewing()
300  |  *
301  |  *  Chew on a wall, door, or boulder.  Returns TRUE if still eating, FALSE
302  |  *  when done.
303  |  */
304  | STATIC_OVL int
305  | still_chewing(x,y)
306  |     xchar x, y;
307  | {
308  |     struct rm *lev = &levl[x][y];
309  |     struct obj *boulder = sobj_at(BOULDER,x,y);
310  |     const char *digtxt = (char *)0, *dmgtxt = (char *)0;
311  | 
312  |     if (digging.down)		/* not continuing previous dig (w/ pick-axe) */
313  | 	(void) memset((genericptr_t)&digging, 0, sizeof digging);
314  | 
315  |     if (!boulder && IS_ROCK(lev->typ) && !may_dig(x,y)) {
316  | 	You("hurt your teeth on the hard stone.");
317  | 	nomul(0);
318  | 	return 1;
319  |     } else if (digging.pos.x != x || digging.pos.y != y ||
320  | 		!on_level(&digging.level, &u.uz)) {
321  | 	digging.down = FALSE;
322  | 	digging.chew = TRUE;
323  | 	digging.pos.x = x;
324  | 	digging.pos.y = y;
325  | 	assign_level(&digging.level, &u.uz);
326  | 	/* solid rock takes more work & time to dig through */
327  | 	digging.effort = (IS_ROCK(lev->typ) ? 30 : 60) + u.udaminc;
328  | 	You("start chewing %s %s.",
329  | 	    boulder ? "on a" : "a hole in the",
330  | 	    boulder ? "boulder" : IS_ROCK(lev->typ) ? "rock" : "door");
331  | 	return 1;
332  |     } else if ((digging.effort += (30 + u.udaminc)) <= 100)  {
333  | 	if (flags.verbose)
334  | 	    You("%s chewing on the %s.",
335  | 		digging.chew ? "continue" : "begin",
336  | 		boulder ? "boulder" : IS_ROCK(lev->typ) ? "rock" : "door");
337  | 	digging.chew = TRUE;
338  | 	return 1;
339  |     }
340  | 
341  |     /* Okay, you've chewed through something */
342  |     u.uconduct.food++;
343  |     u.uhunger += rnd(20);
344  | 
345  |     if (boulder) {
346  | 	delobj(boulder);		/* boulder goes bye-bye */
347  | 	You("eat the boulder.");	/* yum */
348  | 
349  | 	/*
350  | 	 *  The location could still block because of
351  | 	 *	1. More than one boulder
352  | 	 *	2. Boulder stuck in a wall/stone/door.
353  | 	 *
354  | 	 *  [perhaps use does_block() below (from vision.c)]
355  | 	 */
356  | 	if (IS_ROCK(lev->typ) || closed_door(x,y) || sobj_at(BOULDER,x,y)) {
357  | 	    block_point(x,y);	/* delobj will unblock the point */
358  | 	    /* reset dig state */
359  | 	    (void) memset((genericptr_t)&digging, 0, sizeof digging);
360  | 	    return 1;
361  | 	}
362  | 
363  |     } else if (IS_WALL(lev->typ)) {
364  | 	if (*in_rooms(x, y, SHOPBASE)) {
365  | 	    add_damage(x, y, 10L * ACURRSTR);
366  | 	    dmgtxt = "damage";
367  | 	}
368  | 	digtxt = "chew a hole in the wall.";
369  | 	if (level.flags.is_maze_lev) {
370  | 	    lev->typ = ROOM;
371  | 	} else if (level.flags.is_cavernous_lev) {
372  | 	    lev->typ = CORR;
373  | 	} else {
374  | 	    lev->typ = DOOR;
375  | 	    lev->doormask = D_NODOOR;
376  | 	}
377  |     } else if (lev->typ == SDOOR) {
378  | 	if (lev->doormask & D_TRAPPED) {
379  | 	    lev->doormask = D_NODOOR;
380  | 	    b_trapped("secret door", 0);
381  | 	} else {
382  | 	    digtxt = "chew through the secret door.";
383  | 	    lev->doormask = D_BROKEN;
384  | 	}
385  | 	lev->typ = DOOR;
386  | 
387  |     } else if (IS_DOOR(lev->typ)) {
388  | 	if (*in_rooms(x, y, SHOPBASE)) {
389  | 	    add_damage(x, y, 400L);
390  | 	    dmgtxt = "break";
391  | 	}
392  | 	if (lev->doormask & D_TRAPPED) {
393  | 	    lev->doormask = D_NODOOR;
394  | 	    b_trapped("door", 0);
395  | 	} else {
396  | 	    digtxt = "chew through the door.";
397  | 	    lev->doormask = D_BROKEN;
398  | 	}
399  | 
400  |     } else { /* STONE or SCORR */
401  | 	digtxt = "chew a passage through the rock.";
402  | 	lev->typ = CORR;
403  |     }
404  | 
405  |     unblock_point(x, y);	/* vision */
406  |     newsym(x, y);
407  |     if (digtxt) You(digtxt);	/* after newsym */
408  |     if (dmgtxt) pay_for_damage(dmgtxt);
409  |     (void) memset((genericptr_t)&digging, 0, sizeof digging);
410  |     return 0;
411  | }
412  | 
413  | #endif /* OVL2 */
414  | #ifdef OVLB
415  | 
416  | void
417  | movobj(obj, ox, oy)
418  | register struct obj *obj;
419  | register xchar ox, oy;
420  | {
421  | 	/* optimize by leaving on the fobj chain? */
422  | 	remove_object(obj);
423  | 	newsym(obj->ox, obj->oy);
424  | 	place_object(obj, ox, oy);
425  | 	newsym(ox, oy);
426  | }
427  | 
428  | #ifdef SINKS
429  | static NEARDATA const char fell_on_sink[] = "fell onto a sink";
430  | 
431  | STATIC_OVL void
432  | dosinkfall()
433  | {
434  | 	register struct obj *obj;
435  | 
436  | 	if (is_floater(youmonst.data) || (HLevitation & FROMOUTSIDE)) {
437  | 		You("wobble unsteadily for a moment.");
438  | 	} else {
439  | 		You("crash to the floor!");
440  | 		losehp((rn1(10, 20 - (int)ACURR(A_CON))),
441  | 			fell_on_sink, NO_KILLER_PREFIX);
442  | 		exercise(A_DEX, FALSE);
443  | 		for(obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere)
444  | 		    if(obj->oclass == WEAPON_CLASS) {
445  | 			You("fell on %s.",doname(obj));
446  | 			losehp(rnd(3), fell_on_sink, NO_KILLER_PREFIX);
447  | 			exercise(A_CON, FALSE);
448  | 		    }
449  | 	}
450  | 
451  | 	ELevitation &= ~W_ARTI;
452  | 	HLevitation &= ~(I_SPECIAL|TIMEOUT);
453  | 	HLevitation++;
454  | 	if(uleft && uleft->otyp == RIN_LEVITATION) {
455  | 	    obj = uleft;
456  | 	    Ring_off(obj);
457  | 	    off_msg(obj);
458  | 	}
459  | 	if(uright && uright->otyp == RIN_LEVITATION) {
460  | 	    obj = uright;
461  | 	    Ring_off(obj);
462  | 	    off_msg(obj);
463  | 	}
464  | 	if(uarmf && uarmf->otyp == LEVITATION_BOOTS) {
465  | 	    obj = uarmf;
466  | 	    (void)Boots_off();
467  | 	    off_msg(obj);
468  | 	}
469  | 	HLevitation--;
470  | }
471  | #endif
472  | 
473  | boolean
474  | may_dig(x,y)
475  | register xchar x,y;
476  | /* intended to be called only on ROCKs */
477  | {
478  |     return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
479  | 			(levl[x][y].wall_info & W_NONDIGGABLE)));
480  | }
481  | 
482  | boolean
483  | may_passwall(x,y)
484  | register xchar x,y;
485  | {
486  |    return (boolean)(!(IS_STWALL(levl[x][y].typ) &&
487  | 			(levl[x][y].wall_info & W_NONPASSWALL)));
488  | }
489  | 
490  | #endif /* OVLB */
491  | #ifdef OVL1
492  | 
493  | boolean
494  | bad_rock(mdat,x,y)
495  | struct permonst *mdat;
496  | register xchar x,y;
497  | {
498  | 	return((boolean) ((In_sokoban(&u.uz) && sobj_at(BOULDER,x,y)) ||
499  | 	       (IS_ROCK(levl[x][y].typ)
500  | 		    && (!tunnels(mdat) || needspick(mdat) || !may_dig(x,y))
501  | 		    && !(passes_walls(mdat) && may_passwall(x,y)))));
502  | }
503  | 
504  | boolean
505  | invocation_pos(x, y)
506  | xchar x, y;
507  | {
508  | 	return((boolean)(Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y));
509  | }
510  | 
511  | #endif /* OVL1 */
512  | #ifdef OVL3
513  | 
514  | void
515  | domove()
516  | {
517  | 	register struct monst *mtmp;
518  | 	register struct rm *tmpr,*ust;
519  | 	register xchar x,y;
520  | 	struct trap *trap;
521  | 	int wtcap;
522  | 	boolean on_ice;
523  | 	xchar chainx, chainy, ballx, bally;	/* ball&chain new positions */
524  | 	int bc_control;				/* control for ball&chain */
525  | 	boolean cause_delay = FALSE;	/* dragging ball will skip a move */
526  | 
527  | 	u_wipe_engr(rnd(5));
528  | 
529  | 	if(((wtcap = near_capacity()) >= OVERLOADED
530  | 	    || (wtcap > SLT_ENCUMBER &&
531  | 		(Upolyd ? (u.mh < 5 && u.mh != u.mhmax)
532  | 			: (u.uhp < 10 && u.uhp != u.uhpmax))))
533  | 	   && !Is_airlevel(&u.uz)) {
534  | 	    if(wtcap < OVERLOADED) {
535  | 		You("don't have enough stamina to move.");
536  | 		exercise(A_CON, FALSE);
537  | 	    } else
538  | 		You("collapse under your load.");
539  | 	    nomul(0);
540  | 	    return;
541  | 	}
542  | 	if(u.uswallow) {
543  | 		u.dx = u.dy = 0;
544  | 		u.ux = x = u.ustuck->mx;
545  | 		u.uy = y = u.ustuck->my;
546  | 		mtmp = u.ustuck;
547  | 	} else {
548  | 		if (Is_airlevel(&u.uz) && rn2(4) &&
549  | 			!Levitation && !Flying) {
550  | 		    switch(rn2(3)) {
551  | 		    case 0:
552  | 			You("tumble in place.");
553  | 			exercise(A_DEX, FALSE);
554  | 			break;
555  | 		    case 1:
556  | 			You_cant("control your movements very well."); break;
557  | 		    case 2:
558  | 			pline("It's hard to walk in thin air.");
559  | 			exercise(A_DEX, TRUE);
560  | 			break;
561  | 		    }
562  | 		    return;
563  | 		}
564  | 
565  | 		/* check slippery ice */
566  | 		on_ice = !Levitation && is_ice(u.ux, u.uy);
567  | 		if (on_ice) {
568  | 		    static int skates = 0;
569  | 		    if (!skates) skates = find_skates();
570  | 		    if ((uarmf && uarmf->otyp == skates)
571  | 			    || resists_cold(&youmonst) || Flying
572  | 			    || is_floater(youmonst.data) || is_clinger(youmonst.data)
573  | 			    || is_whirly(youmonst.data))
574  | 			on_ice = FALSE;
575  | 		    else if (!rn2(Cold_resistance ? 3 : 2)) {
576  | 			HFumbling |= FROMOUTSIDE;
577  | 			HFumbling &= ~TIMEOUT;
578  | 			HFumbling += 1;  /* slip on next move */
579  | 		    }
580  | 		}
581  | 		if (!on_ice && (HFumbling & FROMOUTSIDE))
582  | 		    HFumbling &= ~FROMOUTSIDE;
583  | 
584  | 		x = u.ux + u.dx;
585  | 		y = u.uy + u.dy;
586  | 		if(Stunned || (Confusion && !rn2(5))) {
587  | 			register int tries = 0;
588  | 
589  | 			do {
590  | 				if(tries++ > 50) {
591  | 					nomul(0);
592  | 					return;
593  | 				}
594  | 				confdir();
595  | 				x = u.ux + u.dx;
596  | 				y = u.uy + u.dy;
597  | 			} while(!isok(x, y) || bad_rock(youmonst.data, x, y));
598  | 		}
599  | 		/* turbulence might alter your actual destination */
600  | 		if (u.uinwater) {
601  | 			water_friction();
602  | 			if (!u.dx && !u.dy) {
603  | 				nomul(0);
604  | 				return;
605  | 			}
606  | 			x = u.ux + u.dx;
607  | 			y = u.uy + u.dy;
608  | 		}
609  | 		if(!isok(x, y)) {
610  | 			nomul(0);
611  | 			return;
612  | 		}
613  | 		if((trap = t_at(x, y)) && trap->tseen) {
614  | 			if(flags.run >= 2) {
615  | 				nomul(0);
616  | 				flags.move = 0;
617  | 				return;
618  | 			} else
619  | 				nomul(0);
620  | 		}
621  | 
622  | 		if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) {
623  | 		    if (distu(u.ustuck->mx, u.ustuck->my) > 2) {
624  | 			/* perhaps it fled (or was teleported or ... ) */
625  | 			u.ustuck = 0;
626  | 		    } else if (sticks(youmonst.data)) {
627  | 			/* When polymorphed into a sticking monster,
628  | 			 * u.ustuck means it's stuck to you, not you to it.
629  | 			 */
630  | 			You("release %s.", mon_nam(u.ustuck));
631  | 			u.ustuck = 0;
632  | 		    } else {
633  | 			/* If holder is asleep or paralyzed:
634  | 			 *	37.5% chance of getting away,
635  | 			 *	12.5% chance of waking/releasing it;
636  | 			 * otherwise:
637  | 			 *	 7.5% chance of getting away.
638  | 			 * [strength ought to be a factor]
639  | 			 */
640  | 			switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) {
641  | 			case 0: case 1: case 2:
642  | 			    You("pull free from %s.", mon_nam(u.ustuck));
643  | 			    u.ustuck = 0;
644  | 			    break;
645  | 			case 3:
646  | 			    if (!u.ustuck->mcanmove) {
647  | 				/* it's free to move on next turn */
648  | 				u.ustuck->mfrozen = 1;
649  | 				u.ustuck->msleeping = 0;
650  | 			    }
651  | 			    /*FALLTHRU*/
652  | 			default:
653  | 			    You("cannot escape from %s!", mon_nam(u.ustuck));
654  | 			    nomul(0);
655  | 			    return;
656  | 			}
657  | 		    }
658  | 		}
659  | 
660  | 		mtmp = m_at(x,y);
661  | 		if (mtmp) {
662  | 			/* Don't attack if you're running, and can see it */
663  | 			/* We should never get here if forcefight */
664  | 			if (flags.run &&
665  | 			    ((!Blind && mon_visible(mtmp) &&
666  | 			      ((mtmp->m_ap_type != M_AP_FURNITURE &&
667  | 				mtmp->m_ap_type != M_AP_OBJECT) ||
668  | 			       Protection_from_shape_changers)) ||
669  | 			     sensemon(mtmp))) {
670  | 				nomul(0);
671  | 				flags.move = 0;
672  | 				return;
673  | 			}
674  | 		}
675  | 	}
676  | 
677  | 	u.ux0 = u.ux;
678  | 	u.uy0 = u.uy;
679  | 	bhitpos.x = x;
680  | 	bhitpos.y = y;
681  | 	tmpr = &levl[x][y];
682  | 
683  | 	/* attack monster */
684  | 	if(mtmp) {
685  | 	    nomul(0);
686  | 	    /* only attack if we know it's there */
687  | 	    /* or if we used the 'F' command to fight blindly */
688  | 	    /* or if it hides_under, in which case we call attack() to print
689  | 	     * the Wait! message.
690  | 	     * This is different from ceiling hiders, who aren't handled in
691  | 	     * attack().
692  | 	     */
693  | 
694  | 	    /* If they used a 'm' command, trying to move onto a monster
695  | 	     * prints the below message and wastes a turn.  The exception is
696  | 	     * if the monster is unseen and the player doesn't remember an
697  | 	     * invisible monster--then, we fall through to attack() and
698  | 	     * attack_check(), which still wastes a turn, but prints a
699  | 	     * different message and makes the player remember the monster.		     */
700  | 	    if(flags.nopick &&
701  | 		  (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){
702  | 		if(mtmp->m_ap_type && !Protection_from_shape_changers
703  | 						    && !sensemon(mtmp))
704  | 		    stumble_onto_mimic(mtmp);
705  | 		else if (mtmp->mpeaceful)
706  | 		    pline("Pardon me, %s.", m_monnam(mtmp));
707  | 		else
708  | 		    You("move right into %s.", mon_nam(mtmp));
709  | 		return;
710  | 	    }
711  | 	    if(flags.forcefight || !mtmp->mundetected || sensemon(mtmp) ||
712  | 		    ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) &&
713  | 			!is_safepet(mtmp))){
714  | 		gethungry();
715  | 		if(wtcap >= HVY_ENCUMBER && moves%3) {
716  | 		    if (Upolyd && u.mh > 1) {
717  | 			u.mh--;
718  | 		    } else if (!Upolyd && u.uhp > 1) {
719  | 			u.uhp--;
720  | 		    } else {
721  | 			You("pass out from exertion!");
722  | 			exercise(A_CON, FALSE);
723  | 			fall_asleep(-10, FALSE);
724  | 		    }
725  | 		}
726  | 		if(multi < 0) return;	/* we just fainted */
727  | 
728  | 		/* try to attack; note that it might evade */
729  | 		/* also, we don't attack tame when _safepet_ */
730  | 		if(attack(mtmp)) return;
731  | 	    }
732  | 	}
733  | 
734  | 	/* specifying 'F' with no monster wastes a turn */
735  | 	if (flags.forcefight ||
736  | 	    /* remembered an 'I' && didn't use a move command */
737  | 	    (glyph_is_invisible(levl[x][y].glyph) && !flags.nopick)) {
738  | 		You("attack %s.", Underwater ? "empty water" : "thin air");
739  | 		unmap_object(x, y); /* known empty -- remove 'I' if present */
740  | 		newsym(x, y);
741  | 		nomul(0);
742  | 		return;
743  | 	}
744  | 	if (glyph_is_invisible(levl[x][y].glyph)) {
745  | 	    unmap_object(x, y);
746  | 	    newsym(x, y);
747  | 	}
748  | 	/* not attacking an animal, so we try to move */
749  | #ifdef STEED
750  | 	if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) {
751  | 		pline("%s won't move!", Monnam(u.usteed));
752  | 		nomul(0);
753  | 		return;
754  | 	} else
755  | #endif
756  | 	if(!youmonst.data->mmove) {
757  | 		You("are rooted %s.",
758  | 		    Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ?
759  | 		    "in place" : "to the ground");
760  | 		nomul(0);
761  | 		return;
762  | 	}
763  | 	if(u.utrap) {
764  | 		if(u.utraptype == TT_PIT) {
765  | 		    if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) {
766  | 			Your("%s gets stuck in a crevice.", body_part(LEG));
767  | 			display_nhwindow(WIN_MESSAGE, FALSE);
768  | 			clear_nhwindow(WIN_MESSAGE);
769  | 			You("free your %s.", body_part(LEG));
770  | 		    } else if (!(--u.utrap)) {
771  | 			You("%s to the edge of the pit.",
772  | 				(In_sokoban(&u.uz) && Levitation) ?
773  | 				"struggle against the air currents and float" : "crawl");
774  | 			fill_pit(u.ux, u.uy);
775  | 			vision_full_recalc = 1;	/* vision limits change */
776  | 		    } else if (flags.verbose)
777  | 			Norep( (Hallucination && !rn2(5)) ?
778  | 				"You've fallen, and you can't get up." :
779  | 				"You are still in a pit." );
780  | 		} else if (u.utraptype == TT_LAVA) {
781  | 		    if(flags.verbose)
782  | 			Norep("You are stuck in the lava.");
783  | 		    if(!is_lava(x,y)) {
784  | 			u.utrap--;
785  | 			if((u.utrap & 0xff) == 0) {
786  | 			    You("pull yourself to the edge of the lava.");
787  | 			    u.utrap = 0;
788  | 			}
789  | 		    }
790  | 		    u.umoved = TRUE;
791  | 		} else if (u.utraptype == TT_WEB) {
792  | 		    if(uwep && uwep->oartifact == ART_STING) {
793  | 			u.utrap = 0;
794  | 			pline("Sting cuts through the web!");
795  | 			return;
796  | 		    }
797  | 		    if(--u.utrap) {
798  | 			if(flags.verbose)
799  | 			    Norep("You are stuck to the web.");
800  | 		    } else You("disentangle yourself.");
801  | 		} else if (u.utraptype == TT_INFLOOR) {
802  | 		    if(--u.utrap) {
803  | 			if(flags.verbose)
804  | 			    Norep("You are stuck in the %s.",
805  | 					surface(u.ux, u.uy));
806  | 		    } else You("finally wiggle free.");
807  | 		} else {
808  | 		    if(flags.verbose)
809  | 			Norep("You are caught in a bear trap.");
810  | 		    if((u.dx && u.dy) || !rn2(5)) u.utrap--;
811  | 		}
812  | 		return;
813  | 	}
814  | 
815  | 
816  | 	/*
817  | 	 *  Check for physical obstacles.  First, the place we are going.
818  | 	 */
819  | 	if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) {
820  | 	    if (Blind) feel_location(x,y);
821  | 	    if (Passes_walls && may_passwall(x,y)) {
822  | 		;	/* do nothing */
823  | 	    } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
824  | 		/* Eat the rock. */
825  | 		if (still_chewing(x,y)) return;
826  | 	    } else {
827  | 		if (Is_stronghold(&u.uz) && is_db_wall(x,y))
828  | 		    pline_The("drawbridge is up!");
829  | 		flags.move = 0;
830  | 		nomul(0);
831  | 		return;
832  | 	    }
833  | 	} else if (IS_DOOR(tmpr->typ)) {
834  | 	    if (closed_door(x,y)) {
835  | 		if (Blind) feel_location(x,y);
836  | 		if (Passes_walls)
837  | 		    ;	/* do nothing */
838  | 		else if (can_ooze(&youmonst))
839  | 		    You("ooze under the door.");
840  | 		else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
841  | 		    /* Eat the door. */
842  | 		    if (still_chewing(x,y)) return;
843  | 		} else {
844  | 		    flags.move = 0;
845  | 		    if (amorphous(youmonst.data))
846  | 			You("try to ooze under the door, but can't squeeze your possessions through.");
847  | 		    else if (x == u.ux || y == u.uy) {
848  | 			if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) {
849  | 			    pline("Ouch!  You bump into a door.");
850  | 			    exercise(A_DEX, FALSE);
851  | 			} else pline("That door is closed.");
852  | 		    }
853  | 		    nomul(0);
854  | 		    return;
855  | 		}
856  | 	    } else if (u.dx && u.dy && !Passes_walls
857  | 			&& ((tmpr->doormask & ~D_BROKEN)
858  | #ifdef REINCARNATION
859  | 					|| Is_rogue_level(&u.uz)
860  | #endif
861  | 					|| block_door(x,y))) {
862  | 		/* Diagonal moves into a door are not allowed. */
863  | 		if (Blind) feel_location(x,y);	/* ?? */
864  | 		flags.move = 0;
865  | 		nomul(0);
866  | 		return;
867  | 	    }
868  | 	}
869  | 	if (u.dx && u.dy
870  | 		&& bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) {
871  | 	    /* Move at a diagonal. */
872  | 	    if (In_sokoban(&u.uz)) {
873  | 	    	You("cannot pass that way.");
874  | 	    	nomul(0);
875  | 	    	return;
876  | 	    }
877  | 	    if (bigmonst(youmonst.data)) {
878  | 		Your("body is too large to fit through.");
879  | 		nomul(0);
880  | 		return;
881  | 	    }
882  | 	    if (invent && (inv_weight() + weight_cap() > 600)) {
883  | 		You("are carrying too much to get through.");
884  | 		nomul(0);
885  | 		return;
886  | 	    }
887  | 	}
888  | 
889  | 	ust = &levl[u.ux][u.uy];
890  | 
891  | 	/* Now see if other things block our way . . */
892  | 	if (u.dx && u.dy && !Passes_walls
893  | 			 && (IS_DOOR(ust->typ) && ((ust->doormask & ~D_BROKEN)
894  | #ifdef REINCARNATION
895  | 				 || Is_rogue_level(&u.uz)
896  | #endif
897  | 				 || block_entry(x, y))
898  | 			     )) {
899  | 	    /* Can't move at a diagonal out of a doorway with door. */
900  | 	    flags.move = 0;
901  | 	    nomul(0);
902  | 	    return;
903  | 	}
904  | 
905  | 	if (sobj_at(BOULDER,x,y) && (In_sokoban(&u.uz) || !Passes_walls)) {
906  | 	    if (!(Blind || Hallucination) && (flags.run >= 2)) {
907  | 		nomul(0);
908  | 		flags.move = 0;
909  | 		return;
910  | 	    }
911  | 	    /* tunneling monsters will chew before pushing */
912  | 	    if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
913  | 		if (still_chewing(x,y)) return;
914  | 	    } else
915  | 		if (moverock() < 0) return;
916  | 	}
917  | 
918  | 	/* OK, it is a legal place to move. */
919  | 
920  | 	/* Move ball and chain.  */
921  | 	if (Punished)
922  | 	    if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
923  | 			&cause_delay))
924  | 		return;
925  | 
926  | 	/* Check regions entering/leaving */
927  | 	if (!in_out_region(x,y))
928  | 	    return;
929  | 
930  |  	/* now move the hero */
931  | 	mtmp = m_at(x, y);
932  | 	u.ux += u.dx;
933  | 	u.uy += u.dy;
934  | #ifdef STEED
935  | 	/* Move your steed, too */
936  | 	if (u.usteed) {
937  | 		u.usteed->mx = u.ux;
938  | 		u.usteed->my = u.uy;
939  | 		exercise_steed();
940  | 	}
941  | #endif
942  | 
943  | 	/*
944  | 	 * If safepet at destination then move the pet to the hero's
945  | 	 * previous location using the same conditions as in attack().
946  | 	 * there are special extenuating circumstances:
947  | 	 * (1) if the pet dies then your god angers,
948  | 	 * (2) if the pet gets trapped then your god may disapprove,
949  | 	 * (3) if the pet was already trapped and you attempt to free it
950  | 	 * not only do you encounter the trap but you may frighten your
951  | 	 * pet causing it to go wild!  moral: don't abuse this privilege.
952  | 	 *
953  | 	 * Ceiling-hiding pets are skipped by this section of code, to
954  | 	 * be caught by the normal falling-monster code.
955  | 	 */
956  | 	if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) {
957  | 	    /* if trapped, there's a chance the pet goes wild */
958  | 	    if (mtmp->mtrapped) {
959  | 		if (!rn2(mtmp->mtame)) {
960  | 		    mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0;
961  | 		    growl(mtmp);
962  | 		} else {
963  | 		    yelp(mtmp);
964  | 		}
965  | 	    }
966  | 	    mtmp->mundetected = 0;
967  | 	    if (mtmp->m_ap_type) seemimic(mtmp);
968  | 	    else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my);
969  | 
970  | 	    if (mtmp->mtrapped &&
971  | 		    (trap = t_at(mtmp->mx, mtmp->my)) != 0 &&
972  | 		    (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) &&
973  | 		    sobj_at(BOULDER, trap->tx, trap->ty)) {
974  | 		/* can't swap places with pet pinned in a pit by a boulder */
975  | 		u.ux = u.ux0,  u.uy = u.uy0;	/* didn't move after all */
976  | 	    } else {
977  | 		mtmp->mtrapped = 0;
978  | 		remove_monster(x, y);
979  | 		place_monster(mtmp, u.ux0, u.uy0);
980  | 
981  | 		/* check for displacing it into pools and traps */
982  | 		switch (minwater(mtmp) ? 2 : mintrap(mtmp)) {
983  | 		case 0:
984  | 		    You("%s %s.", mtmp->mtame ? "displaced" : "frightened",
985  | 			y_monnam(mtmp));
986  | 		    break;
987  | 		case 1:		/* trapped */
988  | 		case 3:		/* changed levels */
989  | 		    /* there's already been a trap message, reinforce it */
990  | 		    abuse_dog(mtmp);
991  | 		    adjalign(-3);
992  | 		    break;
993  | 		case 2:
994  | 		    /* it may have drowned or died.  that's no way to
995  | 		     * treat a pet!  your god gets angry.
996  | 		     */
997  | 		    if (rn2(4)) {
998  | 			You_feel("guilty about losing your pet like this.");
999  | 			u.ugangr++;
1000 | 			adjalign(-15);
1001 | 		    }
1002 | 		    break;
1003 | 		default:
1004 | 		    pline("that's strange, unknown mintrap result!");
1005 | 		    break;
1006 | 		}
1007 | 	    }
1008 | 	}
1009 | 
1010 | 	reset_occupations();
1011 | 	if (flags.run) {
1012 | 		if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) ||
1013 | 			IS_FURNITURE(tmpr->typ))
1014 | 		    nomul(0);
1015 | 	}
1016 | 
1017 | 	if (hides_under(youmonst.data))
1018 | 	    u.uundetected = OBJ_AT(u.ux, u.uy);
1019 | 	else if (youmonst.data->mlet == S_EEL)
1020 | 	    u.uundetected = is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz);
1021 | 	else if (u.dx || u.dy)
1022 | 	    u.uundetected = 0;
1023 | 
1024 | 	/*
1025 | 	 * Mimics (or whatever) become noticeable if they move and are
1026 | 	 * imitating something that doesn't move.  We could extend this
1027 | 	 * to non-moving monsters...
1028 | 	 */
1029 | 	if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT
1030 | 				|| youmonst.m_ap_type == M_AP_FURNITURE))
1031 | 	    youmonst.m_ap_type = M_AP_NOTHING;
1032 | 
1033 | 	check_leash(u.ux0,u.uy0);
1034 | 
1035 | 	if(u.ux0 != u.ux || u.uy0 != u.uy) {
1036 | 	    u.umoved = TRUE;
1037 | 	    /* Clean old position -- vision_recalc() will print our new one. */
1038 | 	    newsym(u.ux0,u.uy0);
1039 | 	    /* Since the hero has moved, adjust what can be seen/unseen. */
1040 | 	    vision_recalc(1);	/* Do the work now in the recover time. */
1041 | 	    invocation_message();
1042 | 	}
1043 | 
1044 | 	if (Punished)				/* put back ball and chain */
1045 | 	    move_bc(0,bc_control,ballx,bally,chainx,chainy);
1046 | 
1047 | 	spoteffects(TRUE);
1048 | 
1049 | 	/* delay next move because of ball dragging */
1050 | 	/* must come after we finished picking up, in spoteffects() */
1051 | 	if (cause_delay) {
1052 | 	    nomul(-2);
1053 | 	    nomovemsg = "";
1054 | 	}
1055 | }
1056 | 
1057 | void
1058 | invocation_message()
1059 | {
1060 | 	/* a special clue-msg when on the Invocation position */
1061 | 	if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) {
1062 | 	    struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION);
1063 | 
1064 | 	    You_feel("a strange vibration under your %s.",
1065 | 		    makeplural(body_part(FOOT)));
1066 | 	    if (otmp && otmp->spe == 7 && otmp->lamplit)
1067 | 		pline("%s %s!", The(xname(otmp)),
1068 | 		    Blind ? "throbs palpably" : "glows with a strange light");
1069 | 	}
1070 | }
1071 | 
1072 | #endif /* OVL3 */
1073 | #ifdef OVL2
1074 | 
1075 | void
1076 | spoteffects(pick)
1077 | boolean pick;
1078 | {
1079 | 	register struct trap *trap;
1080 | 	register struct monst *mtmp;
1081 | 
1082 | 	if(u.uinwater) {
1083 | 		int was_underwater;
1084 | 
1085 | 		if (!is_pool(u.ux,u.uy)) {
1086 | 			if (Is_waterlevel(&u.uz))
1087 | 				You("pop into an air bubble.");
1088 | 			else if (is_lava(u.ux, u.uy))
1089 | 				You("leave the water...");	/* oops! */
1090 | 			else
1091 | 				You("are on solid %s again.",
1092 | 				    is_ice(u.ux, u.uy) ? "ice" : "land");
1093 | 		}
1094 | 		else if (Is_waterlevel(&u.uz))
1095 | 			goto stillinwater;
1096 | 		else if (Levitation)
1097 | 			You("pop out of the water like a cork!");
1098 | 		else if (Flying)
1099 | 			You("fly out of the water.");
1100 | 		else if (Wwalking)
1101 | 			You("slowly rise above the surface.");
1102 | 		else
1103 | 			goto stillinwater;
1104 | 		was_underwater = Underwater && !Is_waterlevel(&u.uz);
1105 | 		u.uinwater = 0;		/* leave the water */
1106 | 		if (was_underwater) {	/* restore vision */
1107 | 			docrt();
1108 | 			vision_full_recalc = 1;
1109 | 		}
1110 | 	}
1111 | stillinwater:;
1112 | 	if (!Levitation && !u.ustuck && !Flying) {
1113 | 	    /* limit recursive calls through teleds() */
1114 | 	    if(is_lava(u.ux,u.uy) && lava_effects())
1115 | 		    return;
1116 | 	    if(is_pool(u.ux,u.uy) && !Wwalking && drown())
1117 | 		    return;
1118 | 	}
1119 | 	check_special_room(FALSE);
1120 | #ifdef SINKS
1121 | 	if(IS_SINK(levl[u.ux][u.uy].typ) && Levitation)
1122 | 		dosinkfall();
1123 | #endif
1124 | 	if (pick && !in_steed_dismounting)
1125 | 		(void) pickup(1);
1126 | 	if ((trap = t_at(u.ux,u.uy)) != 0)
1127 | 		dotrap(trap);	/* fall into pit, arrow trap, etc. */
1128 | 	if((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) {
1129 | 		mtmp->mundetected = mtmp->msleeping = 0;
1130 | 		switch(mtmp->data->mlet) {
1131 | 		    case S_PIERCER:
1132 | 			pline("%s suddenly drops from the %s!",
1133 | 			      Amonnam(mtmp), ceiling(u.ux,u.uy));
1134 | 			if(mtmp->mtame) /* jumps to greet you, not attack */
1135 | 			    ;
1136 | 			else if(uarmh)
1137 | 			    pline("Its blow glances off your helmet.");
1138 | 			else if (u.uac + 3 <= rnd(20))
1139 | 			    You("are almost hit by %s!",
1140 | 				x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
1141 | 			else {
1142 | 			    int dmg;
1143 | 			    You("are hit by %s!",
1144 | 				x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE));
1145 | 			    dmg = d(4,6);
1146 | 			    if(Half_physical_damage) dmg = (dmg+1) / 2;
1147 | 			    mdamageu(mtmp, dmg);
1148 | 			}
1149 | 			break;
1150 | 		    default:	/* monster surprises you. */
1151 | 			if(mtmp->mtame)
1152 | 			    pline("%s jumps near you from the %s.",
1153 | 					Amonnam(mtmp), ceiling(u.ux,u.uy));
1154 | 			else if(mtmp->mpeaceful) {
1155 | 				You("surprise %s!",
1156 | 				    Blind && !sensemon(mtmp) ?
1157 | 				    something : a_monnam(mtmp));
1158 | 				mtmp->mpeaceful = 0;
1159 | 			} else
1160 | 			    pline("%s attacks you by surprise!",
1161 | 					Amonnam(mtmp));
1162 | 			break;
1163 | 		}
1164 | 		mnexto(mtmp); /* have to move the monster */
1165 | 	}
1166 | }
1167 | 
1168 | STATIC_OVL boolean
1169 | monstinroom(mdat,roomno)
1170 | struct permonst *mdat;
1171 | int roomno;
1172 | {
1173 | 	register struct monst *mtmp;
1174 | 
1175 | 	for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1176 | 		if(!DEADMONSTER(mtmp) && mtmp->data == mdat &&
1177 | 		   index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET))
1178 | 			return(TRUE);
1179 | 	return(FALSE);
1180 | }
1181 | 
1182 | char *
1183 | in_rooms(x, y, typewanted)
1184 | register xchar x, y;
1185 | register int typewanted;
1186 | {
1187 | 	static char buf[5];
1188 | 	char rno, *ptr = &buf[4];
1189 | 	int typefound, min_x, min_y, max_x, max_y_offset, step;
1190 | 	register struct rm *lev;
1191 | 
1192 | #define goodtype(rno) (!typewanted || \
1193 | 	     ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) || \
1194 | 	     ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) \
1195 | 
1196 | 	switch (rno = levl[x][y].roomno) {
1197 | 		case NO_ROOM:
1198 | 			return(ptr);
1199 | 		case SHARED:
1200 | 			step = 2;
1201 | 			break;
1202 | 		case SHARED_PLUS:
1203 | 			step = 1;
1204 | 			break;
1205 | 		default:			/* i.e. a regular room # */
1206 | 			if (goodtype(rno))
1207 | 				*(--ptr) = rno;
1208 | 			return(ptr);
1209 | 	}
1210 | 
1211 | 	min_x = x - 1;
1212 | 	max_x = x + 1;
1213 | 	if (x < 1)
1214 | 		min_x += step;
1215 | 	else
1216 | 	if (x >= COLNO)
1217 | 		max_x -= step;
1218 | 
1219 | 	min_y = y - 1;
1220 | 	max_y_offset = 2;
1221 | 	if (min_y < 0) {
1222 | 		min_y += step;
1223 | 		max_y_offset -= step;
1224 | 	} else
1225 | 	if ((min_y + max_y_offset) >= ROWNO)
1226 | 		max_y_offset -= step;
1227 | 
1228 | 	for (x = min_x; x <= max_x; x += step) {
1229 | 		lev = &levl[x][min_y];
1230 | 		y = 0;
1231 | 		if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1232 | 		    !index(ptr, rno) && goodtype(rno))
1233 | 			*(--ptr) = rno;
1234 | 		y += step;
1235 | 		if (y > max_y_offset)
1236 | 			continue;
1237 | 		if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1238 | 		    !index(ptr, rno) && goodtype(rno))
1239 | 			*(--ptr) = rno;
1240 | 		y += step;
1241 | 		if (y > max_y_offset)
1242 | 			continue;
1243 | 		if (((rno = lev[y].roomno) >= ROOMOFFSET) &&
1244 | 		    !index(ptr, rno) && goodtype(rno))
1245 | 			*(--ptr) = rno;
1246 | 	}
1247 | 	return(ptr);
1248 | }
1249 | 
1250 | STATIC_OVL void
1251 | move_update(newlev)
1252 | register boolean newlev;
1253 | {
1254 | 	char *ptr1, *ptr2, *ptr3, *ptr4;
1255 | 
1256 | 	Strcpy(u.urooms0, u.urooms);
1257 | 	Strcpy(u.ushops0, u.ushops);
1258 | 	if (newlev) {
1259 | 		u.urooms[0] = '\0';
1260 | 		u.uentered[0] = '\0';
1261 | 		u.ushops[0] = '\0';
1262 | 		u.ushops_entered[0] = '\0';
1263 | 		Strcpy(u.ushops_left, u.ushops0);
1264 | 		return;
1265 | 	}
1266 | 	Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0));
1267 | 
1268 | 	for (ptr1 = &u.urooms[0],
1269 | 	     ptr2 = &u.uentered[0],
1270 | 	     ptr3 = &u.ushops[0],
1271 | 	     ptr4 = &u.ushops_entered[0];
1272 | 	     *ptr1; ptr1++) {
1273 | 		if (!index(u.urooms0, *ptr1))
1274 | 			*(ptr2++) = *ptr1;
1275 | 		if (IS_SHOP(*ptr1 - ROOMOFFSET)) {
1276 | 			*(ptr3++) = *ptr1;
1277 | 			if (!index(u.ushops0, *ptr1))
1278 | 				*(ptr4++) = *ptr1;
1279 | 		}
1280 | 	}
1281 | 	*ptr2 = '\0';
1282 | 	*ptr3 = '\0';
1283 | 	*ptr4 = '\0';
1284 | 
1285 | 	/* filter u.ushops0 -> u.ushops_left */
1286 | 	for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++)
1287 | 		if (!index(u.ushops, *ptr1))
1288 | 			*(ptr2++) = *ptr1;
1289 | 	*ptr2 = '\0';
1290 | }
1291 | 
1292 | void
1293 | check_special_room(newlev)
1294 | register boolean newlev;
1295 | {
1296 | 	register struct monst *mtmp;
1297 | 	char *ptr;
1298 | 
1299 | 	move_update(newlev);
1300 | 
1301 | 	if (*u.ushops0)
1302 | 	    u_left_shop(u.ushops_left, newlev);
1303 | 
1304 | 	if (!*u.uentered && !*u.ushops_entered)		/* implied by newlev */
1305 | 	    return;		/* no entrance messages necessary */
1306 | 
1307 | 	/* Did we just enter a shop? */
1308 | 	if (*u.ushops_entered)
1309 | 	    u_entered_shop(u.ushops_entered);
1310 | 
1311 | 	for (ptr = &u.uentered[0]; *ptr; ptr++) {
1312 | 	    register int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype;
1313 | 
1314 | 	    /* Did we just enter some other special room? */
1315 | 	    /* vault.c insists that a vault remain a VAULT,
1316 | 	     * and temples should remain TEMPLEs,
1317 | 	     * but everything else gives a message only the first time */
1318 | 	    switch (rt) {
1319 | 		case ZOO:
1320 | 		    pline("Welcome to David's treasure zoo!");
1321 | 		    break;
1322 | 		case SWAMP:
1323 | 		    pline("It %s rather %s down here.",
1324 | 			  Blind ? "feels" : "looks",
1325 | 			  Blind ? "humid" : "muddy");
1326 | 		    break;
1327 | 		case COURT:
1328 | 		    You("enter an opulent throne room!");
1329 | 		    break;
1330 | 		case LEPREHALL:
1331 | 		    You("enter a leprechaun hall!");
1332 | 		    break;
1333 | 		case MORGUE:
1334 | 		    if(midnight()) {
1335 | 			const char *run = locomotion(youmonst.data, "Run");
1336 | 			pline("%s away!  %s away!", run, run);
1337 | 		    } else
1338 | 			You("have an uncanny feeling...");
1339 | 		    break;
1340 | 		case BEEHIVE:
1341 | 		    You("enter a giant beehive!");
1342 | 		    break;
1343 | 		case COCKNEST:
1344 | 		    You("enter a disgusting nest!");
1345 | 		    break;
1346 | 		case ANTHOLE:
1347 | 		    You("enter an anthole!");
1348 | 		    break;
1349 | 		case BARRACKS:
1350 | 		    if(monstinroom(&mons[PM_SOLDIER], roomno) ||
1351 | 			monstinroom(&mons[PM_SERGEANT], roomno) ||
1352 | 			monstinroom(&mons[PM_LIEUTENANT], roomno) ||
1353 | 			monstinroom(&mons[PM_CAPTAIN], roomno))
1354 | 			You("enter a military barracks!");
1355 | 		    else
1356 | 			You("enter an abandoned barracks.");
1357 | 		    break;
1358 | 		case DELPHI:
1359 | 		    if(monstinroom(&mons[PM_ORACLE], roomno))
1360 | 			verbalize("%s, %s, welcome to Delphi!",
1361 | 					Hello((struct monst *) 0), plname);
1362 | 		    break;
1363 | 		case TEMPLE:
1364 | 		    intemple(roomno + ROOMOFFSET);
1365 | 		    /* fall through */
1366 | 		default:
1367 | 		    rt = 0;
1368 | 	    }
1369 | 
1370 | 	    if (rt != 0) {
1371 | 		rooms[roomno].rtype = OROOM;
1372 | 		if (!search_special(rt)) {
1373 | 			/* No more room of that type */
1374 | 			switch(rt) {
1375 | 			    case COURT:
1376 | 				level.flags.has_court = 0;
1377 | 				break;
1378 | 			    case SWAMP:
1379 | 				level.flags.has_swamp = 0;
1380 | 				break;
1381 | 			    case MORGUE:
1382 | 				level.flags.has_morgue = 0;
1383 | 				break;
1384 | 			    case ZOO:
1385 | 				level.flags.has_zoo = 0;
1386 | 				break;
1387 | 			    case BARRACKS:
1388 | 				level.flags.has_barracks = 0;
1389 | 				break;
1390 | 			    case TEMPLE:
1391 | 				level.flags.has_temple = 0;
1392 | 				break;
1393 | 			    case BEEHIVE:
1394 | 				level.flags.has_beehive = 0;
1395 | 				break;
1396 | 			}
1397 | 		}
1398 | 		if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO)
1399 | 		    for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1400 | 			if (!DEADMONSTER(mtmp) && !Stealth && !rn2(3)) mtmp->msleeping = 0;
1401 | 	    }
1402 | 	}
1403 | 
1404 | 	return;
1405 | }
1406 | 
1407 | #endif /* OVL2 */
1408 | #ifdef OVLB
1409 | 
1410 | int
1411 | dopickup()
1412 | {
1413 | 	int count;
1414 | 	/* awful kludge to work around parse()'s pre-decrement */
1415 | 	count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0;
1416 | 	multi = 0;	/* always reset */
1417 | 	/* uswallow case added by GAN 01/29/87 */
1418 | 	if(u.uswallow) {
1419 | 		if (is_animal(u.ustuck->data)) {
1420 | 		    You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck)));
1421 | 		    pline("But it's kind of slimy, so you drop it.");
1422 | 		} else
1423 | 		    You("don't %s anything in here to pick up.",
1424 | 			  Blind ? "feel" : "see");
1425 | 		return(1);
1426 | 	}
1427 | 	if(is_pool(u.ux, u.uy)) {
1428 | 	    if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
1429 | 			|| (Flying && !Breathless)) {
1430 | 		You("cannot dive into the water to pick things up.");
1431 | 		return(0);
1432 | 	    } else if (!Underwater) {
1433 | 		You_cant("even see the bottom, let alone pick up %s.",
1434 | 				something);
1435 | 		return(0);
1436 | 	    }
1437 | 	}
1438 | 	if (is_lava(u.ux, u.uy)) {
1439 | 	    if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
1440 | 			|| (Flying && !Breathless)) {
1441 | 		You_cant("reach the bottom to pick things up.");
1442 | 		return(0);
1443 | 	    } else if (!likes_lava(youmonst.data)) {
1444 | 		You("would burn to a crisp trying to pick things up.");
1445 | 		return(0);
1446 | 	    }
1447 | 	}
1448 | 	if(!OBJ_AT(u.ux, u.uy)) {
1449 | 		There("is nothing here to pick up.");
1450 | 		return(0);
1451 | 	}
1452 | 	if (!can_reach_floor()) {
1453 | #ifdef STEED
1454 | 		if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
1455 | 			You("aren't skilled enough to reach from %s.",
1456 | 					mon_nam(u.usteed));
1457 | 		else
1458 | #endif
1459 | 		You("cannot reach the %s.", surface(u.ux,u.uy));
1460 | 		return(0);
1461 | 	}
1462 | 	return (pickup(-count));
1463 | }
1464 | 
1465 | #endif /* OVLB */
1466 | #ifdef OVL2
1467 | 
1468 | /* stop running if we see something interesting */
1469 | /* turn around a corner if that is the only way we can proceed */
1470 | /* do not turn left or right twice */
1471 | void
1472 | lookaround()
1473 | {
1474 |     register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9;
1475 |     register int corrct = 0, noturn = 0;
1476 |     register struct monst *mtmp;
1477 |     register struct trap *trap;
1478 | 
1479 | 	/* Grid bugs stop if trying to move diagonal, even if blind.  Maybe */
1480 | 	/* they polymorphed while in the middle of a long move. */
1481 | 	if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) {
1482 | 		nomul(0);
1483 | 		return;
1484 | 	}
1485 | 
1486 | 	if(Blind || flags.run == 0) return;
1487 | 	for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++) {
1488 | 		if(!isok(x,y)) continue;
1489 | 
1490 | 	if(u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue;
1491 | 
1492 | 	if(x == u.ux && y == u.uy) continue;
1493 | 
1494 | 	if((mtmp = m_at(x,y)) &&
1495 | 		    mtmp->m_ap_type != M_AP_FURNITURE &&
1496 | 		    mtmp->m_ap_type != M_AP_OBJECT &&
1497 | 		    (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
1498 | 	    if((flags.run != 1 && !mtmp->mtame)
1499 | 					|| (x == u.ux+u.dx && y == u.uy+u.dy))
1500 | 		goto stop;
1501 | 	}
1502 | 
1503 | 	if (levl[x][y].typ == STONE) continue;
1504 | 	if (x == u.ux-u.dx && y == u.uy-u.dy) continue;
1505 | 
1506 | 	if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) ||
1507 | 	    IS_AIR(levl[x][y].typ))
1508 | 	    continue;
1509 | 	else if (closed_door(x,y)) {
1510 | 	    if(x != u.ux && y != u.uy) continue;
1511 | 	    if(flags.run != 1) goto stop;
1512 | 	    goto bcorr;
1513 | 	} else if (levl[x][y].typ == CORR) {
1514 | bcorr:
1515 | 	    if(levl[u.ux][u.uy].typ != ROOM) {
1516 | 		if(flags.run == 1 || flags.run == 3) {
1517 | 		    i = dist2(x,y,u.ux+u.dx,u.uy+u.dy);
1518 | 		    if(i > 2) continue;
1519 | 		    if(corrct == 1 && dist2(x,y,x0,y0) != 1)
1520 | 			noturn = 1;
1521 | 		    if(i < i0) {
1522 | 			i0 = i;
1523 | 			x0 = x;
1524 | 			y0 = y;
1525 | 			m0 = mtmp ? 1 : 0;
1526 | 		    }
1527 | 		}
1528 | 		corrct++;
1529 | 	    }
1530 | 	    continue;
1531 | 	} else if ((trap = t_at(x,y)) && trap->tseen) {
1532 | 	    if(flags.run == 1) goto bcorr;	/* if you must */
1533 | 	    if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop;
1534 | 	    continue;
1535 | 	} else if (is_pool(x,y) || is_lava(x,y)) {
1536 | 	    /* water and lava only stop you if directly in front, and stop
1537 | 	     * you even if you are running
1538 | 	     */
1539 | 	    if(!Levitation && !Flying && !is_clinger(youmonst.data) &&
1540 | 				x == u.ux+u.dx && y == u.uy+u.dy)
1541 | 			/* No Wwalking check; otherwise they'd be able
1542 | 			 * to test boots by trying to SHIFT-direction
1543 | 			 * into a pool and seeing if the game allowed it
1544 | 			 */
1545 | 			goto stop;
1546 | 	    continue;
1547 | 	} else {		/* e.g. objects or trap or stairs */
1548 | 	    if(flags.run == 1) goto bcorr;
1549 | 	    if(mtmp) continue;		/* d */
1550 | 	    if(((x == u.ux - u.dx) && (y != u.uy + u.dy)) ||
1551 | 	       ((y == u.uy - u.dy) && (x != u.ux + u.dx)))
1552 | 	       continue;
1553 | 	}
1554 | stop:
1555 | 	nomul(0);
1556 | 	return;
1557 |     } /* end for loops */
1558 | 
1559 |     if(corrct > 1 && flags.run == 2) goto stop;
1560 |     if((flags.run == 1 || flags.run == 3) && !noturn && !m0 && i0 &&
1561 | 				(corrct == 1 || (corrct == 2 && i0 == 1))) {
1562 | 	/* make sure that we do not turn too far */
1563 | 	if(i0 == 2) {
1564 | 	    if(u.dx == y0-u.uy && u.dy == u.ux-x0)
1565 | 		i = 2;		/* straight turn right */
1566 | 	    else
1567 | 		i = -2;		/* straight turn left */
1568 | 	} else if(u.dx && u.dy) {
1569 | 	    if((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy))
1570 | 		i = -1;		/* half turn left */
1571 | 	    else
1572 | 		i = 1;		/* half turn right */
1573 | 	} else {
1574 | 	    if((x0-u.ux == y0-u.uy && !u.dy) || (x0-u.ux != y0-u.uy && u.dy))
1575 | 		i = 1;		/* half turn right */
1576 | 	    else
1577 | 		i = -1;		/* half turn left */
1578 | 	}
1579 | 
1580 | 	i += u.last_str_turn;
1581 | 	if(i <= 2 && i >= -2) {
1582 | 	    u.last_str_turn = i;
1583 | 	    u.dx = x0-u.ux;
1584 | 	    u.dy = y0-u.uy;
1585 | 	}
1586 |     }
1587 | }
1588 | 
1589 | /* something like lookaround, but we are not running */
1590 | /* react only to monsters that might hit us */
1591 | int
1592 | monster_nearby()
1593 | {
1594 | 	register int x,y;
1595 | 	register struct monst *mtmp;
1596 | 
1597 | 	/* Also see the similar check in dochugw() in monmove.c */
1598 | 	for(x = u.ux-1; x <= u.ux+1; x++)
1599 | 	    for(y = u.uy-1; y <= u.uy+1; y++) {
1600 | 		if(!isok(x,y)) continue;
1601 | 		if(x == u.ux && y == u.uy) continue;
1602 | 		if((mtmp = m_at(x,y)) &&
1603 | 		   mtmp->m_ap_type != M_AP_FURNITURE &&
1604 | 		   mtmp->m_ap_type != M_AP_OBJECT &&
1605 | 		   (!mtmp->mpeaceful || Hallucination) &&
1606 | 		   (!is_hider(mtmp->data) || !mtmp->mundetected) &&
1607 | 		   !noattacks(mtmp->data) &&
1608 | 		   mtmp->mcanmove && !mtmp->msleeping &&  /* aplvax!jcn */
1609 | 		   !onscary(u.ux, u.uy, mtmp) &&
1610 | 		   canspotmon(mtmp))
1611 | 			return(1);
1612 | 	}
1613 | 	return(0);
1614 | }
1615 | 
1616 | void
1617 | nomul(nval)
1618 | 	register int nval;
1619 | {
1620 | 	if(multi < nval) return;	/* This is a bug fix by ab@unido */
1621 | 	u.uinvulnerable = FALSE;	/* Kludge to avoid ctrl-C bug -dlc */
1622 | 	u.usleep = 0;
1623 | 	multi = nval;
1624 | 	flags.mv = flags.run = 0;
1625 | }
1626 | 
1627 | /* called when a non-movement, multi-turn action has completed */
1628 | void unmul(msg_override)
1629 | const char *msg_override;
1630 | {
1631 | 	multi = 0;	/* caller will usually have done this already */
1632 | 	if (msg_override) nomovemsg = msg_override;
1633 | 	else if (!nomovemsg) nomovemsg = You_can_move_again;
1634 | 	if (*nomovemsg) pline(nomovemsg);
1635 | 	nomovemsg = 0;
1636 | 	u.usleep = 0;
1637 | 	if (afternmv) (*afternmv)();
1638 | 	afternmv = 0;
1639 | }
1640 | 
1641 | #endif /* OVL2 */
1642 | #ifdef OVL1
1643 | 
1644 | static void
1645 | maybe_wail()
1646 | {
1647 |     static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES,
1648 | 			      SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES,
1649 | 			      TELEPORT_CONTROL, STEALTH, FAST, INVIS };
1650 | 
1651 |     if (moves <= wailmsg + 50) return;
1652 | 
1653 |     wailmsg = moves;
1654 |     if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) {
1655 | 	const char *who;
1656 | 	int i, powercnt;
1657 | 
1658 | 	who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
1659 | 		urole.name.m : "Elf";
1660 | 	if (u.uhp == 1) {
1661 | 	    pline("%s is about to die.", who);
1662 | 	} else {
1663 | 	    for (i = 0, powercnt = 0; i < SIZE(powers); ++i)
1664 | 		if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt;
1665 | 
1666 | 	    pline(powercnt >= 4 ? "%s, all your powers will be lost..."
1667 | 				: "%s, your life force is running out.", who);
1668 | 	}
1669 |     } else {
1670 | 	You_hear(u.uhp == 1 ? "the wailing of the Banshee..."
1671 | 			    : "the howling of the CwnAnnwn...");
1672 |     }
1673 | }
1674 | 
1675 | void
1676 | losehp(n, knam, k_format)
1677 | register int n;
1678 | register const char *knam;
1679 | boolean k_format;
1680 | {
1681 | 	if (Upolyd) {
1682 | 		u.mh -= n;
1683 | 		if (u.mhmax < u.mh) u.mhmax = u.mh;
1684 | 		flags.botl = 1;
1685 | 		if (u.mh < 1)
1686 | 		    rehumanize();
1687 | 		else if (n > 0 && u.mh*10 < u.mhmax && Unchanging)
1688 | 		    maybe_wail();
1689 | 		return;
1690 | 	}
1691 | 
1692 | 	u.uhp -= n;
1693 | 	if(u.uhp > u.uhpmax)
1694 | 		u.uhpmax = u.uhp;	/* perhaps n was negative */
1695 | 	flags.botl = 1;
1696 | 	if(u.uhp < 1) {
1697 | 		killer_format = k_format;
1698 | 		killer = knam;		/* the thing that killed you */
1699 | 		You("die...");
1700 | 		done(DIED);
1701 | 	} else if (n > 0 && u.uhp*10 < u.uhpmax) {
1702 | 		maybe_wail();
1703 | 	}
1704 | }
1705 | 
1706 | int
1707 | weight_cap()
1708 | {
1709 | 	register long carrcap;
1710 | 
1711 | 	carrcap = (((ACURRSTR + ACURR(A_CON))/2)+1)*50;
1712 | 	if (Upolyd) {
1713 | 		/* consistent with can_carry() in mon.c */
1714 | 		if (youmonst.data->mlet == S_NYMPH)
1715 | 			carrcap = MAX_CARR_CAP;
1716 | 		else if (!youmonst.data->cwt)
1717 | 			carrcap = (carrcap * (long)youmonst.data->msize) / MZ_HUMAN;
1718 | 		else if (!strongmonst(youmonst.data)
1719 | 			|| (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN)))
1720 | 			carrcap = (carrcap * (long)youmonst.data->cwt / WT_HUMAN);
1721 | 	}
1722 | 
1723 | 	if (Levitation || Is_airlevel(&u.uz)    /* pugh@cornell */
1724 | #ifdef STEED
1725 | 			|| (u.usteed && strongmonst(u.usteed->data))
1726 | #endif
1727 | 	)
1728 | 		carrcap = MAX_CARR_CAP;
1729 | 	else {
1730 | 		if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP;
1731 | 		if (!Flying) {
1732 | 			if(EWounded_legs & LEFT_SIDE) carrcap -= 100;
1733 | 			if(EWounded_legs & RIGHT_SIDE) carrcap -= 100;
1734 | 		}
1735 | 		if (carrcap < 0) carrcap = 0;
1736 | 	}
1737 | 	return((int) carrcap);
1738 | }
1739 | 
1740 | static int wc;	/* current weight_cap(); valid after call to inv_weight() */
1741 | 
1742 | /* returns how far beyond the normal capacity the player is currently. */
1743 | /* inv_weight() is negative if the player is below normal capacity. */
1744 | int
1745 | inv_weight()
1746 | {
1747 | 	register struct obj *otmp = invent;
1748 | 	register int wt;
1749 | 
1750 | 	/* when putting stuff into containers, gold is inserted at the head
1751 | 	   of invent for easier manipulation by askchain & co, but it's also
1752 | 	   retained in u.ugold in order to keep the status line accurate; we
1753 | 	   mustn't add its weight in twice under that circumstance */
1754 | 	wt = (otmp && otmp->oclass == GOLD_CLASS) ? 0 :
1755 | 		(int)((u.ugold + 50L) / 100L);
1756 | 
1757 | 	while (otmp) {
1758 | 		if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data))
1759 | 			wt += otmp->owt;
1760 | 		otmp = otmp->nobj;
1761 | 	}
1762 | 	wc = weight_cap();
1763 | 	return (wt - wc);
1764 | }
1765 | 
1766 | /*
1767 |  * Returns 0 if below normal capacity, or the number of "capacity units"
1768 |  * over the normal capacity the player is loaded.  Max is 5.
1769 |  */
1770 | int
1771 | calc_capacity(xtra_wt)
1772 | int xtra_wt;
1773 | {
1774 |     int cap, wt = inv_weight() + xtra_wt;
1775 | 
1776 |     if (wt <= 0) return UNENCUMBERED;
1777 |     if (wc <= 1) return OVERLOADED;
1778 |     cap = (wt*2 / wc) + 1;
1779 |     return min(cap, OVERLOADED);
1780 | }
1781 | 
1782 | int
1783 | near_capacity()
1784 | {
1785 |     return calc_capacity(0);
1786 | }
1787 | 
1788 | int
1789 | max_capacity()
1790 | {
1791 |     int wt = inv_weight();
1792 | 
1793 |     return (wt - (2 * wc));
1794 | }
1795 | 
1796 | boolean
1797 | check_capacity(str)
1798 | const char *str;
1799 | {
1800 |     if(near_capacity() >= EXT_ENCUMBER) {
1801 | 	if(str)
1802 | 	    pline(str);
1803 | 	else
1804 | 	    You_cant("do that while carrying so much stuff.");
1805 | 	return 1;
1806 |     }
1807 |     return 0;
1808 | }
1809 | 
1810 | #endif /* OVL1 */
1811 | #ifdef OVLB
1812 | 
1813 | int
1814 | inv_cnt()
1815 | {
1816 | 	register struct obj *otmp = invent;
1817 | 	register int ct = 0;
1818 | 
1819 | 	while(otmp){
1820 | 		ct++;
1821 | 		otmp = otmp->nobj;
1822 | 	}
1823 | 	return(ct);
1824 | }
1825 | 
1826 | #endif /* OVLB */
1827 | 
1828 | /*hack.c*/