1 /*	SCCS Id: @(#)steed.c	3.4	2003/01/10	*/
2 /* Copyright (c) Kevin Hugo, 1998-1999. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "hack.h"
6 
7 
8 #ifdef STEED
9 
10 /* Monsters that might be ridden */
11 static NEARDATA const char steeds[] = {
12 	S_QUADRUPED, S_UNICORN, S_ANGEL, S_CENTAUR, S_DRAGON, S_JABBERWOCK, '\0'
13 };
14 
15 STATIC_DCL boolean FDECL(landing_spot, (coord *, int, int));
16 
17 /* caller has decided that hero can't reach something while mounted */
18 void
rider_cant_reach()19 rider_cant_reach()
20 {
21      You("aren't skilled enough to reach from %s.", y_monnam(u.usteed));
22 }
23 
24 /*** Putting the saddle on ***/
25 
26 /* Can this monster wear a saddle? */
27 boolean
can_saddle(mtmp)28 can_saddle(mtmp)
29 	struct monst *mtmp;
30 {
31 	struct permonst *ptr = mtmp->data;
32 
33 	return (index(steeds, ptr->mlet) && (ptr->msize >= MZ_MEDIUM) &&
34 			(!humanoid(ptr) || ptr->mlet == S_CENTAUR) &&
35 			!amorphous(ptr) && !noncorporeal(ptr) &&
36 			!is_whirly(ptr) && !unsolid(ptr));
37 }
38 
39 
40 int
use_saddle(otmp)41 use_saddle(otmp)
42 	struct obj *otmp;
43 {
44 	struct monst *mtmp;
45 	struct permonst *ptr;
46 	int chance;
47 	const char *s;
48 
49 
50 	/* Can you use it? */
51 	if (nohands(youmonst.data)) {
52 		You("have no hands!");	/* not `body_part(HAND)' */
53 		return 0;
54 	} else if (!freehand()) {
55 		You("have no free %s.", body_part(HAND));
56 		return 0;
57 	}
58 
59 	/* Select an animal */
60 	if (u.uswallow || Underwater || !getdir((char *)0)) {
61 	    pline(Never_mind);
62 	    return 0;
63 	}
64 	if (!u.dx && !u.dy) {
65 	    pline("Saddle yourself?  Very funny...");
66 	    return 0;
67 	}
68 	if (!isok(u.ux+u.dx, u.uy+u.dy) ||
69 			!(mtmp = m_at(u.ux+u.dx, u.uy+u.dy)) ||
70 			!canspotmon(mtmp)) {
71 	    pline("I see nobody there.");
72 	    return 1;
73 	}
74 
75 	/* Is this a valid monster? */
76 	if (mtmp->misc_worn_check & W_SADDLE ||
77 			which_armor(mtmp, W_SADDLE)) {
78 	    pline("%s doesn't need another one.", Monnam(mtmp));
79 	    return 1;
80 	}
81 	ptr = mtmp->data;
82 	if (touch_petrifies(ptr) && !uarmg && !Stone_resistance) {
83 	    char kbuf[BUFSZ];
84 
85 	    You("touch %s.", mon_nam(mtmp));
86  	    if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
87 		Sprintf(kbuf, "attempting to saddle %s", an(mtmp->data->mname));
88 		instapetrify(kbuf);
89  	    }
90 	}
91 	if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) {
92 	    pline("Shame on you!");
93 	    exercise(A_WIS, FALSE);
94 	    return 1;
95 	}
96 	if (mtmp->isminion || mtmp->isshk || mtmp->ispriest ||
97 			mtmp->isgd || mtmp->iswiz) {
98 	    pline("I think %s would mind.", mon_nam(mtmp));
99 	    return 1;
100 	}
101 	if (!can_saddle(mtmp)) {
102 		You_cant("saddle such a creature.");
103 		return 1;
104 	}
105 
106 	/* Calculate your chance */
107 	chance = ACURR(A_DEX) + ACURR(A_CHA)/2 + 2*mtmp->mtame;
108 	chance += u.ulevel * (mtmp->mtame ? 20 : 5);
109 	if (!mtmp->mtame) chance -= 10*mtmp->m_lev;
110 	if (Role_if(PM_KNIGHT))
111 	    chance += 20;
112 	switch (P_SKILL(P_RIDING)) {
113 	case P_ISRESTRICTED:
114 	case P_UNSKILLED:
115 	default:
116 	    chance -= 20;	break;
117 	case P_BASIC:
118 	    break;
119 	case P_SKILLED:
120 	    chance += 15;	break;
121 	case P_EXPERT:
122 	    chance += 30;	break;
123 	}
124 	if (Confusion || Fumbling || Glib)
125 	    chance -= 20;
126 	else if (uarmg &&
127 		(s = OBJ_DESCR(objects[uarmg->otyp])) != (char *)0 &&
128 		!strncmp(s, "riding ", 7))
129 	    /* Bonus for wearing "riding" (but not fumbling) gloves */
130 	    chance += 10;
131 	else if (uarmf &&
132 		(s = OBJ_DESCR(objects[uarmf->otyp])) != (char *)0 &&
133 		!strncmp(s, "riding ", 7))
134 	    /* ... or for "riding boots" */
135 	    chance += 10;
136 	if (otmp->cursed)
137 	    chance -= 50;
138 
139 	/* Make the attempt */
140 	if (rn2(100) < chance) {
141 	    You("put the saddle on %s.", mon_nam(mtmp));
142 	    if (otmp->owornmask) remove_worn_item(otmp, FALSE);
143 	    freeinv(otmp);
144 	    /* mpickobj may free otmp it if merges, but we have already
145 	       checked for a saddle above, so no merger should happen */
146 	    (void) mpickobj(mtmp, otmp);
147 	    mtmp->misc_worn_check |= W_SADDLE;
148 	    otmp->owornmask = W_SADDLE;
149 	    otmp->leashmon = mtmp->m_id;
150 	    update_mon_intrinsics(mtmp, otmp, TRUE, FALSE);
151 	} else
152 	    pline("%s resists!", Monnam(mtmp));
153 	return 1;
154 }
155 
156 
157 /*** Riding the monster ***/
158 
159 /* Can we ride this monster?  Caller should also check can_saddle() */
160 boolean
can_ride(mtmp)161 can_ride(mtmp)
162 	struct monst *mtmp;
163 {
164 	return (mtmp->mtame && humanoid(youmonst.data) &&
165 			!verysmall(youmonst.data) && !bigmonst(youmonst.data) &&
166 			(!Underwater || is_swimmer(mtmp->data)));
167 }
168 
169 
170 int
doride()171 doride()
172 {
173 	boolean forcemount = FALSE;
174 
175 	if (u.usteed)
176 	    dismount_steed(DISMOUNT_BYCHOICE);
177 	else if (getdir((char *)0) && isok(u.ux+u.dx, u.uy+u.dy)) {
178 #ifdef WIZARD
179 	if (wizard && yn("Force the mount to succeed?") == 'y')
180 		forcemount = TRUE;
181 #endif
182 	    return (mount_steed(m_at(u.ux+u.dx, u.uy+u.dy), forcemount));
183 	} else
184 	    return 0;
185 	return 1;
186 }
187 
188 
189 /* Start riding, with the given monster */
190 boolean
mount_steed(mtmp,force)191 mount_steed(mtmp, force)
192 	struct monst *mtmp;	/* The animal */
193 	boolean force;		/* Quietly force this animal */
194 {
195 	struct obj *otmp;
196 	char buf[BUFSZ];
197 	struct permonst *ptr;
198 
199 	/* Sanity checks */
200 	if (u.usteed) {
201 	    You("are already riding %s.", mon_nam(u.usteed));
202 	    return (FALSE);
203 	}
204 
205 	/* Is the player in the right form? */
206 	if (Hallucination && !force) {
207 	    pline("Maybe you should find a designated driver.");
208 	    return (FALSE);
209 	}
210 	/* While riding Wounded_legs refers to the steed's,
211 	 * not the hero's legs.
212 	 * That opens up a potential abuse where the player
213 	 * can mount a steed, then dismount immediately to
214 	 * heal leg damage, because leg damage is always
215 	 * healed upon dismount (Wounded_legs context switch).
216 	 * By preventing a hero with Wounded_legs from
217 	 * mounting a steed, the potential for abuse is
218 	 * minimized, if not eliminated altogether.
219 	 */
220 	if (Wounded_legs) {
221 	    Your("%s are in no shape for riding.", makeplural(body_part(LEG)));
222 #ifdef WIZARD
223 	    if (force && wizard && yn("Heal your legs?") == 'y')
224 		HWounded_legs = EWounded_legs = 0;
225 	    else
226 #endif
227 	    return (FALSE);
228 	}
229 
230 	if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) ||
231 			bigmonst(youmonst.data) || slithy(youmonst.data))) {
232 	    You("won't fit on a saddle.");
233 	    return (FALSE);
234 	}
235 	if(!force && (near_capacity() > SLT_ENCUMBER)) {
236 	    You_cant("do that while carrying so much stuff.");
237 	    return (FALSE);
238 	}
239 
240 	/* Can the player reach and see the monster? */
241 	if (!mtmp || (!force && ((Blind && !Blind_telepat) ||
242 		mtmp->mundetected ||
243 		mtmp->m_ap_type == M_AP_FURNITURE ||
244 		mtmp->m_ap_type == M_AP_OBJECT))) {
245 	    pline("I see nobody there.");
246 	    return (FALSE);
247 	}
248 	if (u.uswallow || u.ustuck || u.utrap || Punished ||
249 	    !test_move(u.ux, u.uy, mtmp->mx-u.ux, mtmp->my-u.uy, TEST_MOVE)) {
250 	    if (Punished || !(u.uswallow || u.ustuck || u.utrap))
251 		You("are unable to swing your %s over.", body_part(LEG));
252 	    else
253 		You("are stuck here for now.");
254 	    return (FALSE);
255 	}
256 
257 	/* Is this a valid monster? */
258 	otmp = which_armor(mtmp, W_SADDLE);
259 	if (!otmp) {
260 	    pline("%s is not saddled.", Monnam(mtmp));
261 	    return (FALSE);
262 	}
263 	ptr = mtmp->data;
264 	if (touch_petrifies(ptr) && !Stone_resistance) {
265 	    char kbuf[BUFSZ];
266 
267 	    You("touch %s.", mon_nam(mtmp));
268 	    Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname));
269 	    instapetrify(kbuf);
270 	}
271 	if (!mtmp->mtame || mtmp->isminion) {
272 	    pline("I think %s would mind.", mon_nam(mtmp));
273 	    return (FALSE);
274 	}
275 	if (mtmp->mtrapped) {
276 	    struct trap *t = t_at(mtmp->mx, mtmp->my);
277 
278 	    You_cant("mount %s while %s's trapped in %s.",
279 		     mon_nam(mtmp), mhe(mtmp),
280 		     an(defsyms[trap_to_defsym(t->ttyp)].explanation));
281 	    return (FALSE);
282 	}
283 
284 	if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) {
285 	    /* no longer tame */
286 	    newsym(mtmp->mx, mtmp->my);
287 	    pline("%s resists%s!", Monnam(mtmp),
288 		  mtmp->mleashed ? " and its leash comes off" : "");
289 	    if (mtmp->mleashed) m_unleash(mtmp, FALSE);
290 	    return (FALSE);
291 	}
292 	if (!force && Underwater && !is_swimmer(ptr)) {
293 	    You_cant("ride that creature while under water.");
294 	    return (FALSE);
295 	}
296 	if (!can_saddle(mtmp) || !can_ride(mtmp)) {
297 	    You_cant("ride such a creature.");
298 	    return (0);
299 	}
300 
301 	/* Is the player impaired? */
302 	if (!force && !is_floater(ptr) && !is_flyer(ptr) &&
303 			Levitation && !Lev_at_will) {
304 	    You("cannot reach %s.", mon_nam(mtmp));
305 	    return (FALSE);
306 	}
307 	if (!force && uarm && is_metallic(uarm) &&
308 			greatest_erosion(uarm)) {
309 	    Your("%s armor is too stiff to be able to mount %s.",
310 			uarm->oeroded ? "rusty" : "corroded",
311 			mon_nam(mtmp));
312 	    return (FALSE);
313 	}
314 	if (!force && (Confusion || Fumbling || Glib || Wounded_legs ||
315 		otmp->cursed || (u.ulevel+mtmp->mtame < rnd(MAXULEV/2+5)))) {
316 	    if (Levitation) {
317 		pline("%s slips away from you.", Monnam(mtmp));
318 		return FALSE;
319 	    }
320 	    You("slip while trying to get on %s.", mon_nam(mtmp));
321 
322 	    Sprintf(buf, "slipped while mounting %s",
323 		    /* "a saddled mumak" or "a saddled pony called Dobbin" */
324 		    x_monnam(mtmp, ARTICLE_A, (char *)0,
325 			SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_HALLUCINATION,
326 			     TRUE));
327 	    losehp(rn1(5,10), buf, NO_KILLER_PREFIX);
328 	    return (FALSE);
329 	}
330 
331 	/* Success */
332 	if (!force) {
333 	    if (Levitation && !is_floater(ptr) && !is_flyer(ptr))
334 	    	/* Must have Lev_at_will at this point */
335 	    	pline("%s magically floats up!", Monnam(mtmp));
336 	    You("mount %s.", mon_nam(mtmp));
337 	}
338 	/* setuwep handles polearms differently when you're mounted */
339 	if (uwep && is_pole(uwep)) unweapon = FALSE;
340 	u.usteed = mtmp;
341 	remove_monster(mtmp->mx, mtmp->my);
342 	teleds(mtmp->mx, mtmp->my, TRUE);
343 	return (TRUE);
344 }
345 
346 
347 /* You and your steed have moved */
348 void
exercise_steed()349 exercise_steed()
350 {
351 	if (!u.usteed)
352 		return;
353 
354 	/* It takes many turns of riding to exercise skill */
355 	if (u.urideturns++ >= 100) {
356 	    u.urideturns = 0;
357 	    use_skill(P_RIDING, 1);
358 	}
359 	return;
360 }
361 
362 
363 /* The player kicks or whips the steed */
364 void
kick_steed()365 kick_steed()
366 {
367 	char He[4];
368 	if (!u.usteed)
369 	    return;
370 
371 	/* [ALI] Various effects of kicking sleeping/paralyzed steeds */
372 	if (u.usteed->msleeping || !u.usteed->mcanmove) {
373 	    /* We assume a message has just been output of the form
374 	     * "You kick <steed>."
375 	     */
376 	    Strcpy(He, mhe(u.usteed));
377 	    *He = highc(*He);
378 	    if ((u.usteed->mcanmove || u.usteed->mfrozen) && !rn2(2)) {
379 		if (u.usteed->mcanmove)
380 		    u.usteed->msleeping = 0;
381 		else if (u.usteed->mfrozen > 2)
382 		    u.usteed->mfrozen -= 2;
383 		else {
384 		    u.usteed->mfrozen = 0;
385 		    u.usteed->mcanmove = 1;
386 		}
387 		if (u.usteed->msleeping || !u.usteed->mcanmove)
388 		    pline("%s stirs.", He);
389 		else
390 		    pline("%s rouses %sself!", He, mhim(u.usteed));
391 	    } else
392 		pline("%s does not respond.", He);
393 	    return;
394 	}
395 
396 	/* Make the steed less tame and check if it resists */
397 	if (u.usteed->mtame) u.usteed->mtame--;
398 	if (!u.usteed->mtame && u.usteed->mleashed) m_unleash(u.usteed, TRUE);
399 	if (!u.usteed->mtame || (u.ulevel+u.usteed->mtame < rnd(MAXULEV/2+5))) {
400 	    newsym(u.usteed->mx, u.usteed->my);
401 	    dismount_steed(DISMOUNT_THROWN);
402 	    return;
403 	}
404 
405 	pline("%s gallops!", Monnam(u.usteed));
406 	u.ugallop += rn1(20, 30);
407 	return;
408 }
409 
410 /*
411  * Try to find a dismount point adjacent to the steed's location.
412  * If all else fails, try enexto().  Use enexto() as a last resort because
413  * enexto() chooses its point randomly, possibly even outside the
414  * room's walls, which is not what we want.
415  * Adapted from mail daemon code.
416  */
417 STATIC_OVL boolean
landing_spot(spot,reason,forceit)418 landing_spot(spot, reason, forceit)
419 coord *spot;	/* landing position (we fill it in) */
420 int reason;
421 int forceit;
422 {
423     int i = 0, x, y, distance, min_distance = -1;
424     boolean found = FALSE;
425     struct trap *t;
426 
427     /* avoid known traps (i == 0) and boulders, but allow them as a backup */
428     if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling) i = 1;
429     for (; !found && i < 2; ++i) {
430 	for (x = u.ux-1; x <= u.ux+1; x++)
431 	    for (y = u.uy-1; y <= u.uy+1; y++) {
432 		if (!isok(x, y) || (x == u.ux && y == u.uy)) continue;
433 
434 		if (ACCESSIBLE(levl[x][y].typ) &&
435 			    !MON_AT(x,y) && !closed_door(x,y)) {
436 		    distance = distu(x,y);
437 		    if (min_distance < 0 || distance < min_distance ||
438 			    (distance == min_distance && rn2(2))) {
439 			if (i > 0 || (((t = t_at(x, y)) == 0 || !t->tseen) &&
440 				      (!sobj_at(BOULDER, x, y) ||
441 				       throws_rocks(youmonst.data)))) {
442 			    spot->x = x;
443 			    spot->y = y;
444 			    min_distance = distance;
445 			    found = TRUE;
446 			}
447 		    }
448 		}
449 	    }
450     }
451 
452     /* If we didn't find a good spot and forceit is on, try enexto(). */
453     if (forceit && min_distance < 0 &&
454 		!enexto(spot, u.ux, u.uy, youmonst.data))
455 	return FALSE;
456 
457     return found;
458 }
459 
460 /* Stop riding the current steed */
461 void
dismount_steed(reason)462 dismount_steed(reason)
463 	int reason;		/* Player was thrown off etc. */
464 {
465 	struct monst *mtmp;
466 	struct obj *otmp;
467 	coord cc;
468 	const char *verb = "fall";
469 	boolean repair_leg_damage = TRUE;
470 	unsigned save_utrap = u.utrap;
471 	boolean have_spot = landing_spot(&cc,reason,0);
472 
473 	mtmp = u.usteed;		/* make a copy of steed pointer */
474 	/* Sanity check */
475 	if (!mtmp)		/* Just return silently */
476 	    return;
477 
478 	/* Check the reason for dismounting */
479 	otmp = which_armor(mtmp, W_SADDLE);
480 	switch (reason) {
481 	    case DISMOUNT_THROWN:
482 		verb = "are thrown";
483 	    case DISMOUNT_FELL:
484 		You("%s off of %s!", verb, mon_nam(mtmp));
485 		if (!have_spot) have_spot = landing_spot(&cc,reason,1);
486 		losehp(rn1(10,10), "riding accident", KILLED_BY_AN);
487 		set_wounded_legs(BOTH_SIDES, (int)HWounded_legs + rn1(5,5));
488 		repair_leg_damage = FALSE;
489 		break;
490 	    case DISMOUNT_POLY:
491 		You("can no longer ride %s.", mon_nam(u.usteed));
492 		if (!have_spot) have_spot = landing_spot(&cc,reason,1);
493 		break;
494 	    case DISMOUNT_ENGULFED:
495 		/* caller displays message */
496 		break;
497 	    case DISMOUNT_BONES:
498 		/* hero has just died... */
499 		break;
500 	    case DISMOUNT_GENERIC:
501 		/* no messages, just make it so */
502 		break;
503 	    case DISMOUNT_BYCHOICE:
504 	    default:
505 		if (otmp && otmp->cursed) {
506 		    You("can't.  The saddle %s cursed.",
507 			otmp->bknown ? "is" : "seems to be");
508 		    otmp->bknown = TRUE;
509 		    return;
510 		}
511 		if (!have_spot) {
512 		    You("can't. There isn't anywhere for you to stand.");
513 		    return;
514 		}
515 		if (!mtmp->mnamelth) {
516 			pline("You've been through the dungeon on %s with no name.",
517 				an(mtmp->data->mname));
518 			if (Hallucination)
519 				pline("It felt good to get out of the rain.");
520 		} else
521 			You("dismount %s.", mon_nam(mtmp));
522 	}
523 	/* While riding these refer to the steed's legs
524 	 * so after dismounting they refer to the player's
525 	 * legs once again.
526 	 */
527 	if (repair_leg_damage) HWounded_legs = EWounded_legs = 0;
528 
529 	/* Release the steed and saddle */
530 	u.usteed = 0;
531 	u.ugallop = 0L;
532 
533 	/* Set player and steed's position.  Try moving the player first
534 	   unless we're in the midst of creating a bones file. */
535 	if (reason == DISMOUNT_BONES) {
536 	    /* move the steed to an adjacent square */
537 	    if (enexto(&cc, u.ux, u.uy, mtmp->data))
538 		rloc_to(mtmp, cc.x, cc.y);
539 	    else	/* evidently no room nearby; move steed elsewhere */
540 		(void) rloc(mtmp, FALSE);
541 	    return;
542 	}
543 	if (!DEADMONSTER(mtmp)) {
544 	    place_monster(mtmp, u.ux, u.uy);
545 	    if (!u.uswallow && !u.ustuck && have_spot) {
546 		struct permonst *mdat = mtmp->data;
547 
548 		/* The steed may drop into water/lava */
549 		if (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) {
550 		    if (is_pool(u.ux, u.uy)) {
551 			if (!Underwater)
552 			    pline("%s falls into the %s!", Monnam(mtmp),
553 							surface(u.ux, u.uy));
554 			if (!is_swimmer(mdat) && !amphibious(mdat)) {
555 			    killed(mtmp);
556 			    adjalign(-1);
557 			}
558 		    } else if (is_lava(u.ux, u.uy)) {
559 			pline("%s is pulled into the lava!", Monnam(mtmp));
560 			if (!likes_lava(mdat)) {
561 			    killed(mtmp);
562 			    adjalign(-1);
563 			}
564 		    }
565 		}
566 	    /* Steed dismounting consists of two steps: being moved to another
567 	     * square, and descending to the floor.  We have functions to do
568 	     * each of these activities, but they're normally called
569 	     * individually and include an attempt to look at or pick up the
570 	     * objects on the floor:
571 	     * teleds() --> spoteffects() --> pickup()
572 	     * float_down() --> pickup()
573 	     * We use this kludge to make sure there is only one such attempt.
574 	     *
575 	     * Clearly this is not the best way to do it.  A full fix would
576 	     * involve having these functions not call pickup() at all, instead
577 	     * calling them first and calling pickup() afterwards.  But it
578 	     * would take a lot of work to keep this change from having any
579 	     * unforseen side effects (for instance, you would no longer be
580 	     * able to walk onto a square with a hole, and autopickup before
581 	     * falling into the hole).
582 	     */
583 		/* [ALI] No need to move the player if the steed died. */
584 		if (!DEADMONSTER(mtmp)) {
585 		    /* Keep steed here, move the player to cc;
586 		     * teleds() clears u.utrap
587 		     */
588 		    in_steed_dismounting = TRUE;
589 		    teleds(cc.x, cc.y, TRUE);
590 		    in_steed_dismounting = FALSE;
591 
592 		    /* Put your steed in your trap */
593 		    if (save_utrap)
594 			(void) mintrap(mtmp);
595 		}
596 	    /* Couldn't... try placing the steed */
597 	    } else if (enexto(&cc, u.ux, u.uy, mtmp->data)) {
598 		/* Keep player here, move the steed to cc */
599 		rloc_to(mtmp, cc.x, cc.y);
600 		/* Player stays put */
601 	    /* Otherwise, kill the steed */
602 	    } else {
603 		killed(mtmp);
604 		adjalign(-1);
605 	    }
606 	}
607 
608 	/* Return the player to the floor */
609 	if (reason != DISMOUNT_ENGULFED) {
610 	    in_steed_dismounting = TRUE;
611 	    (void) float_down(0L, W_SADDLE);
612 	    in_steed_dismounting = FALSE;
613 	    flags.botl = 1;
614 	    (void)encumber_msg();
615 	    vision_full_recalc = 1;
616 	} else
617 	    flags.botl = 1;
618 	/* polearms behave differently when not mounted */
619 	if (uwep && is_pole(uwep)) unweapon = TRUE;
620 	return;
621 }
622 
623 void
place_monster(mon,x,y)624 place_monster(mon, x, y)
625 struct monst *mon;
626 int x, y;
627 {
628     if (mon == u.usteed ||
629 	    /* special case is for convoluted vault guard handling */
630 	    (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) {
631 	impossible("placing %s onto map?",
632 		   (mon == u.usteed) ? "steed" : "defunct monster");
633 	return;
634     }
635     mon->mx = x, mon->my = y;
636     level.monsters[x][y] = mon;
637 }
638 
639 #endif /* STEED */
640 
641 /*steed.c*/
642