1 /* NetHack 3.7 steed.c $NHDT-Date: 1720128167 2024/07/04 21:22:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.121 $ */
2 /* Copyright (c) Kevin Hugo, 1998-1999. */
3 /* NetHack may be freely redistributed. See license for details. */
7 /* Monsters that might be ridden */
8 static NEARDATA
const char steeds
[] = { S_QUADRUPED
, S_UNICORN
, S_ANGEL
,
9 S_CENTAUR
, S_DRAGON
, S_JABBERWOCK
,
12 staticfn boolean
landing_spot(coord
*, int, int);
13 staticfn
void maybewakesteed(struct monst
*);
15 /* caller has decided that hero can't reach something while mounted */
17 rider_cant_reach(void)
19 You("aren't skilled enough to reach from %s.", y_monnam(u
.usteed
));
22 /*** Putting the saddle on ***/
24 /* Can this monster wear a saddle? */
26 can_saddle(struct monst
*mtmp
)
28 struct permonst
*ptr
= mtmp
->data
;
30 return (strchr(steeds
, ptr
->mlet
) && (ptr
->msize
>= MZ_MEDIUM
)
31 && (!humanoid(ptr
) || ptr
->mlet
== S_CENTAUR
) && !amorphous(ptr
)
32 && !noncorporeal(ptr
) && !is_whirly(ptr
) && !unsolid(ptr
));
36 use_saddle(struct obj
*otmp
)
45 /* Select an animal */
46 if (u
.uswallow
|| Underwater
|| !getdir((char *) 0)) {
51 pline("Saddle yourself? Very funny...");
54 if (!isok(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
)
55 || !(mtmp
= m_at(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
)) || !canspotmon(mtmp
)) {
56 pline("I see nobody there.");
60 /* Is this a valid monster? */
61 if ((mtmp
->misc_worn_check
& W_SADDLE
) != 0L
62 || which_armor(mtmp
, W_SADDLE
)) {
63 pline("%s doesn't need another one.", Monnam(mtmp
));
67 if (touch_petrifies(ptr
) && !uarmg
&& !Stone_resistance
) {
70 You("touch %s.", mon_nam(mtmp
));
71 if (!(poly_when_stoned(gy
.youmonst
.data
) && polymon(PM_STONE_GOLEM
))) {
72 Sprintf(kbuf
, "attempting to saddle %s",
73 an(pmname(mtmp
->data
, Mgender(mtmp
))));
77 if (ptr
== &mons
[PM_AMOROUS_DEMON
]) {
78 pline("Shame on you!");
79 exercise(A_WIS
, FALSE
);
82 if (mtmp
->isminion
|| mtmp
->isshk
|| mtmp
->ispriest
|| mtmp
->isgd
84 pline("I think %s would mind.", mon_nam(mtmp
));
87 if (!can_saddle(mtmp
)) {
88 You_cant("saddle such a creature.");
92 /* Calculate your chance */
93 chance
= ACURR(A_DEX
) + ACURR(A_CHA
) / 2 + 2 * mtmp
->mtame
;
94 chance
+= u
.ulevel
* (mtmp
->mtame
? 20 : 5);
96 chance
-= 10 * mtmp
->m_lev
;
97 if (Role_if(PM_KNIGHT
))
99 switch (P_SKILL(P_RIDING
)) {
114 if (Confusion
|| Fumbling
|| Glib
)
116 else if (uarmg
&& objdescr_is(uarmg
, "riding gloves"))
117 /* Bonus for wearing "riding" (but not fumbling) gloves */
119 else if (uarmf
&& objdescr_is(uarmf
, "riding boots"))
120 /* ... or for "riding boots" */
125 /* [intended] steed becomes alert if possible */
126 maybewakesteed(mtmp
);
128 /* Make the attempt */
129 if (rn2(100) < chance
) {
130 You("put the saddle on %s.", mon_nam(mtmp
));
132 remove_worn_item(otmp
, FALSE
);
134 /* !can_saddle(mtmp) already eliminated above */
135 put_saddle_on_mon(otmp
, mtmp
);
137 pline("%s resists!", Monnam(mtmp
));
142 put_saddle_on_mon(struct obj
*saddle
, struct monst
*mtmp
)
144 if (!can_saddle(mtmp
) || which_armor(mtmp
, W_SADDLE
)) {
146 impossible("put_saddle_on_mon: saddle obj could get orphaned");
150 if ((saddle
= mksobj(SADDLE
, TRUE
, FALSE
)) != 0) {
151 fully_identify_obj(saddle
);
152 /* mpickobj can later override identification if out-of-view */
157 if (mpickobj(mtmp
, saddle
))
158 panic("merged saddle?");
159 mtmp
->misc_worn_check
|= W_SADDLE
;
160 saddle
->owornmask
= W_SADDLE
;
161 saddle
->leashmon
= mtmp
->m_id
;
162 update_mon_extrinsics(mtmp
, saddle
, TRUE
, FALSE
);
165 /*** Riding the monster ***/
167 /* Can we ride this monster? Caller should also check can_saddle() */
169 can_ride(struct monst
*mtmp
)
171 return (mtmp
->mtame
&& humanoid(gy
.youmonst
.data
)
172 && !verysmall(gy
.youmonst
.data
) && !bigmonst(gy
.youmonst
.data
)
173 && (!Underwater
|| is_swimmer(mtmp
->data
)));
176 /* the #ride command */
180 boolean forcemount
= FALSE
;
183 dismount_steed(DISMOUNT_BYCHOICE
);
184 } else if (getdir((char *) 0) && isok(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
)) {
185 if (wizard
&& y_n("Force the mount to succeed?") == 'y')
187 return (mount_steed(m_at(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
), forcemount
)
188 ? ECMD_TIME
: ECMD_OK
);
195 /* Start riding, with the given monster */
198 struct monst
*mtmp
, /* The animal */
199 boolean force
) /* Quietly force this animal */
203 struct permonst
*ptr
;
207 You("are already riding %s.", mon_nam(u
.usteed
));
211 /* Is the player in the right form? */
212 if (Hallucination
&& !force
) {
213 pline("Maybe you should find a designated driver.");
216 /* While riding Wounded_legs refers to the steed's,
217 * not the hero's legs.
218 * That opens up a potential abuse where the player
219 * can mount a steed, then dismount immediately to
220 * heal leg damage, because leg damage is always
221 * healed upon dismount (Wounded_legs context switch).
222 * By preventing a hero with Wounded_legs from
223 * mounting a steed, the potential for abuse is
224 * reduced. However, dismounting still immediately
225 * heals the steed's wounded legs. [In 3.4.3 and
226 * earlier, that unintentionally made the hero's
227 * temporary 1 point Dex loss become permanent.]
232 legs_in_no_shape("riding", FALSE
);
233 Sprintf(qbuf
, "Heal your leg%s?",
234 ((HWounded_legs
& BOTH_SIDES
) == BOTH_SIDES
) ? "s" : "");
235 if (force
&& wizard
&& y_n(qbuf
) == 'y')
241 if (Upolyd
&& (!humanoid(gy
.youmonst
.data
)
242 || verysmall(gy
.youmonst
.data
)
243 || bigmonst(gy
.youmonst
.data
)
244 || slithy(gy
.youmonst
.data
))) {
245 You("won't fit on a saddle.");
248 if (!force
&& (near_capacity() > SLT_ENCUMBER
)) {
249 You_cant("do that while carrying so much stuff.");
253 /* Can the player reach and see the monster? */
254 if (!mtmp
|| (!force
&& ((Blind
&& !Blind_telepat
) || mtmp
->mundetected
255 || M_AP_TYPE(mtmp
) == M_AP_FURNITURE
256 || M_AP_TYPE(mtmp
) == M_AP_OBJECT
))) {
257 pline("I see nobody there.");
260 if (mtmp
->data
== &mons
[PM_LONG_WORM
]
261 && (u
.ux
+ u
.dx
!= mtmp
->mx
|| u
.uy
+ u
.dy
!= mtmp
->my
)) {
262 /* As of 3.6.2: test_move(below) is used to check for trying to mount
263 diagonally into or out of a doorway or through a tight squeeze;
264 attempting to mount a tail segment when hero was not adjacent
265 to worm's head could trigger an impossible() in worm_cross()
266 called from test_move(), so handle not-on-head before that */
267 You("couldn't ride %s, let alone its tail.", a_monnam(mtmp
));
270 if (u
.uswallow
|| u
.ustuck
|| u
.utrap
|| Punished
271 || !test_move(u
.ux
, u
.uy
, mtmp
->mx
- u
.ux
, mtmp
->my
- u
.uy
,
273 if (Punished
|| !(u
.uswallow
|| u
.ustuck
|| u
.utrap
))
274 You("are unable to swing your %s over.", body_part(LEG
));
276 You("are stuck here for now.");
280 /* Is this a valid monster? */
281 otmp
= which_armor(mtmp
, W_SADDLE
);
283 pline("%s is not saddled.", Monnam(mtmp
));
288 if (touch_petrifies(ptr
) && !Stone_resistance
) {
291 You("touch %s.", mon_nam(mtmp
));
292 Sprintf(kbuf
, "attempting to ride %s",
293 an(pmname(mtmp
->data
, Mgender(mtmp
))));
296 if (!mtmp
->mtame
|| mtmp
->isminion
) {
297 pline("I think %s would mind.", mon_nam(mtmp
));
300 if (mtmp
->mtrapped
) {
301 struct trap
*t
= t_at(mtmp
->mx
, mtmp
->my
);
303 You_cant("mount %s while %s's trapped in %s.", mon_nam(mtmp
),
304 mhe(mtmp
), an(trapname(t
->ttyp
, FALSE
)));
308 if (!force
&& !Role_if(PM_KNIGHT
) && !(--mtmp
->mtame
)) {
310 newsym(mtmp
->mx
, mtmp
->my
);
311 pline("%s resists%s!", Monnam(mtmp
),
312 mtmp
->mleashed
? " and its leash comes off" : "");
314 m_unleash(mtmp
, FALSE
);
317 if (!force
&& Underwater
&& !is_swimmer(ptr
)) {
318 You_cant("ride that creature while under %s.",
322 if (!can_saddle(mtmp
) || !can_ride(mtmp
)) {
323 You_cant("ride such a creature.");
327 /* Is the player impaired? */
328 if (!force
&& !is_floater(ptr
) && !is_flyer(ptr
) && Levitation
330 You("cannot reach %s.", mon_nam(mtmp
));
333 if (!force
&& uarm
&& is_metallic(uarm
) && greatest_erosion(uarm
)) {
334 Your("%s armor is too stiff to be able to mount %s.",
335 uarm
->oeroded
? "rusty" : "corroded", mon_nam(mtmp
));
339 && (Confusion
|| Fumbling
|| Glib
|| Wounded_legs
|| otmp
->cursed
341 || (u
.ulevel
+ mtmp
->mtame
< rnd(MAXULEV
/ 2 + 5)))) {
343 pline("%s slips away from you.", Monnam(mtmp
));
346 You("slip while trying to get on %s.", mon_nam(mtmp
));
348 Sprintf(buf
, "slipped while mounting %s",
349 /* "a saddled mumak" or "a saddled pony called Dobbin" */
350 x_monnam(mtmp
, ARTICLE_A
, (char *) 0,
351 SUPPRESS_IT
| SUPPRESS_INVISIBLE
352 | SUPPRESS_HALLUCINATION
,
354 losehp(Maybe_Half_Phys(rn1(5, 10)), buf
, NO_KILLER_PREFIX
);
359 maybewakesteed(mtmp
);
361 if (Levitation
&& !is_floater(ptr
) && !is_flyer(ptr
))
362 /* Must have Lev_at_will at this point */
363 pline("%s magically floats up!", Monnam(mtmp
));
364 You("mount %s.", mon_nam(mtmp
));
366 You("and %s take flight together.", mon_nam(mtmp
));
368 /* setuwep handles polearms differently when you're mounted */
369 if (uwep
&& is_pole(uwep
))
373 boolean was_stealthy
= Stealth
!= 0;
376 if (was_stealthy
&& !Stealth
)
377 You("aren't stealthy anymore.");
379 remove_monster(mtmp
->mx
, mtmp
->my
);
380 teleds(mtmp
->mx
, mtmp
->my
, TELEDS_ALLOW_DRAG
);
385 /* You and your steed have moved */
392 /* It takes many turns of riding to exercise skill */
393 if (++u
.urideturns
>= 100) {
395 use_skill(P_RIDING
, 1);
400 /* The player kicks or whips the steed */
404 char He
[BUFSZ
]; /* monverbself() appends to the "He"/"She"/"It" value */
408 /* [ALI] Various effects of kicking sleeping/paralyzed steeds */
409 if (helpless(u
.usteed
)) {
410 /* We assume a message has just been output of the form
411 * "You kick <steed>."
413 Strcpy(He
, mhe(u
.usteed
));
415 if ((u
.usteed
->mcanmove
|| u
.usteed
->mfrozen
) && !rn2(2)) {
416 if (u
.usteed
->mcanmove
)
417 u
.usteed
->msleeping
= 0;
418 else if (u
.usteed
->mfrozen
> 2)
419 u
.usteed
->mfrozen
-= 2;
421 u
.usteed
->mfrozen
= 0;
422 u
.usteed
->mcanmove
= 1;
424 if (helpless(u
.usteed
))
425 pline("%s stirs.", He
);
427 /* if hallucinating, might yield "He rouses herself" or
428 "She rouses himself" */
429 pline("%s!", monverbself(u
.usteed
, He
, "rouse", (char *) 0));
431 pline("%s does not respond.", He
);
435 /* Make the steed less tame and check if it resists */
438 if (!u
.usteed
->mtame
&& u
.usteed
->mleashed
)
439 m_unleash(u
.usteed
, TRUE
);
441 || (u
.ulevel
+ u
.usteed
->mtame
< rnd(MAXULEV
/ 2 + 5))) {
442 newsym(u
.usteed
->mx
, u
.usteed
->my
);
443 dismount_steed(DISMOUNT_THROWN
);
447 pline("%s gallops!", Monnam(u
.usteed
));
448 u
.ugallop
+= rn1(20, 30);
453 * Try to find a dismount point adjacent to the steed's location.
454 * If all else fails, try enexto(). Use enexto() as a last resort because
455 * enexto() chooses its point randomly, possibly even outside the
456 * room's walls, which is not what we want.
457 * Adapted from mail daemon code.
461 coord
*spot
, /* landing position (we fill it in) */
465 coord cc
, try[8]; /* 8: the 8 spots adjacent to the hero's spot */
466 int i
, j
, best_j
, clockwise_j
, counterclk_j
,
467 n
, viable
, distance
, min_distance
= -1;
469 boolean found
, impaird
, kn_trap
, boulder
;
472 (void) memset((genericptr_t
) try, 0, sizeof try);
474 j
= xytod(u
.dx
, u
.dy
);
475 if (reason
== DISMOUNT_KNOCKED
&& j
!= DIR_ERR
) {
476 /* we'll check preferred location first; if viable it'll be picked */
478 try[0].x
= u
.dx
, try[0].y
= u
.dy
;
479 /* the two next best locations are checked second and third */
481 clockwise_j
= DIR_RIGHT(j
); /* (j + 1) % 8 */
482 dtoxy(&cc
, clockwise_j
);
483 try[1 + i
].x
= cc
.x
, try[1 + i
].y
= cc
.y
; /* [1] or [2] */
484 counterclk_j
= DIR_LEFT(j
); /* (j + 8 - 1) % 8 */
485 dtoxy(&cc
, counterclk_j
);
486 try[2 - i
].x
= cc
.x
, try[2 - i
].y
= cc
.y
; /* [2] or [1] */
488 debugpline3("knock from saddle: best %s, next %s or %s",
489 directionname(best_j
),
490 directionname(clockwise_j
), directionname(counterclk_j
));
492 best_j
= clockwise_j
= counterclk_j
= -1;
494 for (j
= 0; j
< N_DIRS
; ++j
) {
495 /* fortunately NODIAG() handling isn't needed for DISMOUNT_KNOCKED
496 because hero can only ride when humanoid */
497 if (j
== best_j
|| j
== clockwise_j
|| j
== counterclk_j
)
499 /* j==0 is W, j==1 NW, j==2 N, j==3 NE, ..., around to j==7 SW;
500 so odd j values are diagonal directions here */
501 if (reason
== DISMOUNT_POLY
&& NODIAG(u
.umonnum
) && (j
% 1) != 0)
508 * Up to three passes;
509 * i==0: voluntary dismount without impairment avoids known traps and
511 * i==1: voluntary dismount with impairment or knocked out of saddle
512 * avoids boulders but allows known traps;
513 * i==2: other, allow traps and boulders.
515 * Fallback to i==1 if nothing appropriate was found for i==0 and
516 * to i==2 as last resort.
518 impaird
= (Stunned
|| Confusion
|| Fumbling
);
521 for (i
= (reason
== DISMOUNT_BYCHOICE
&& !impaird
) ? 0
522 : ((reason
== DISMOUNT_BYCHOICE
&& impaird
)
523 || reason
== DISMOUNT_KNOCKED
) ? 1
525 i
<= 2 && !found
; ++i
) {
526 for (j
= 0; j
< n
; ++j
) {
529 if (!isok(x
, y
) || u_at(x
, y
)) /* [note: u_at() can't happen] */
532 if (accessible(x
, y
) && !MON_AT(x
, y
)
533 && test_move(u
.ux
, u
.uy
, x
- u
.ux
, y
- u
.uy
, TEST_MOVE
)) {
535 distance
= distu(x
, y
);
536 if (min_distance
< 0 /* no viable candidate yet */
537 /* or better than pending candidate (note: orthogonal
538 spots are distance 1 and diagonal ones distance 2;
539 treating one as better than the other is arbitrary
540 and not wanted for DISMOUNT_KNOCKED) */
541 || ((best_j
== -1) ? (distance
< min_distance
) : (j
< 3))
542 /* or equally good, maybe substitute this one */
543 || (distance
== min_distance
&& !rn2(viable
))) {
544 /* traps avoided on pass 0; boulders avoided on 0 and 1 */
545 kn_trap
= i
== 0 && ((t
= t_at(x
, y
)) != 0 && t
->tseen
546 && t
->ttyp
!= VIBRATING_SQUARE
);
547 boulder
= i
<= 1 && (sobj_at(BOULDER
, x
, y
)
548 && !throws_rocks(gy
.youmonst
.data
));
549 if (!kn_trap
&& !boulder
) {
552 min_distance
= distance
;
554 if (best_j
!= -1 && j
< 3)
555 /* since best_j is first candidate (j==0), j==1
556 and j==2 can only get here when best_j was
557 not viable; 50:50 chance for clockwise_j to
558 come before counterclk_j so each has same
559 chance to be next after best_j */
567 /* If we didn't find a good spot and forceit is on, try enexto(). */
568 if (forceit
&& !found
)
569 found
= enexto(spot
, u
.ux
, u
.uy
, gy
.youmonst
.data
);
574 /* Stop riding the current steed */
577 int reason
) /* Player was thrown off etc. */
583 unsigned save_utrap
= u
.utrap
;
585 repair_leg_damage
= (Wounded_legs
!= 0L),
586 have_spot
= landing_spot(&cc
, reason
, 0);
588 mtmp
= u
.usteed
; /* make a copy of steed pointer */
590 if (!mtmp
) /* Just return silently */
592 u
.usteed
= 0; /* affects Fly test; could hypothetically affect Lev;
593 * also affects u_locomotion() */
594 ufly
= Flying
? TRUE
: FALSE
;
595 ulev
= Levitation
? TRUE
: FALSE
;
596 verb
= u_locomotion("fall"); /* only used for _FELL and _KNOCKED */
599 /* Check the reason for dismounting */
600 otmp
= which_armor(mtmp
, W_SADDLE
);
602 case DISMOUNT_THROWN
:
606 case DISMOUNT_KNOCKED
:
608 You("%s off of %s!", verb
, mon_nam(mtmp
));
610 have_spot
= landing_spot(&cc
, reason
, 1);
611 if (!ulev
&& !ufly
) {
612 losehp(Maybe_Half_Phys(rn1(10, 10)), "riding accident",
614 set_wounded_legs(BOTH_SIDES
, (int) HWounded_legs
+ rn1(5, 5));
615 repair_leg_damage
= FALSE
;
619 You("can no longer ride %s.", mon_nam(u
.usteed
));
621 have_spot
= landing_spot(&cc
, reason
, 1);
623 case DISMOUNT_ENGULFED
:
624 /* caller displays message */
627 /* hero has just died... */
629 case DISMOUNT_GENERIC
:
630 /* no messages, just make it so */
632 case DISMOUNT_BYCHOICE
:
634 if (otmp
&& otmp
->cursed
) {
635 You("can't. The saddle %s cursed.",
636 otmp
->bknown
? "is" : "seems to be");
637 otmp
->bknown
= 1; /* ok to skip set_bknown() here */
641 You("can't. There isn't anywhere for you to stand.");
644 if (!has_mgivenname(mtmp
)) {
645 pline("You've been through the dungeon on %s with no name.",
646 an(pmname(mtmp
->data
, Mgender(mtmp
))));
648 pline("It felt good to get out of the rain.");
650 You("dismount %s.", mon_nam(mtmp
));
652 /* While riding, Wounded_legs refers to the steed's legs;
653 after dismounting, it reverts to the hero's legs. */
654 if (repair_leg_damage
)
657 /* Release the steed */
658 u
.usteed
= (struct monst
*) NULL
;
661 boolean was_stealthy
= Stealth
!= 0;
664 if (Stealth
&& !was_stealthy
)
665 You("seem less noisy now.");
668 if (u
.utraptype
== TT_BEARTRAP
669 || u
.utraptype
== TT_PIT
670 || u
.utraptype
== TT_WEB
) {
675 * rloc(), rloc_to(), and monkilled()->mondead()->m_detach() all
676 * expect mtmp to be on the map or else have mtmp->mx be 0, but
677 * setting the latter to 0 here would interfere with dropping
678 * the saddle. Prior to 3.6.2, being off the map didn't matter.
680 * place_monster() expects mtmp to be alive and not be u.usteed.
682 * Unfortunately, <u.ux,u.uy> (former steed's implicit location)
683 * might now be occupied by an engulfer, so we can't just put mtmp
684 * at that spot. An engulfer's previous spot will be unoccupied
685 * but we don't know where that was and even if we did, it might
686 * be hostile terrain.
688 steedcc
.x
= u
.ux
, steedcc
.y
= u
.uy
;
689 if (m_at(u
.ux
, u
.uy
)) {
690 /* hero's spot has a monster in it; hero must have been plucked
691 from saddle as engulfer moved into his spot--other dismounts
692 shouldn't run into this situation; find nearest viable spot */
693 if (!enexto(&steedcc
, u
.ux
, u
.uy
, mtmp
->data
)
694 /* no spot? must have been engulfed by a lurker-above over
695 water or lava; try requesting a location for a flyer */
696 && !enexto(&steedcc
, u
.ux
, u
.uy
, &mons
[PM_BAT
]))
697 /* still no spot; last resort is any spot within bounds */
698 (void) enexto(&steedcc
, u
.ux
, u
.uy
, &mons
[PM_GHOST
]);
701 if (!DEADMONSTER(mtmp
)) {
702 gi
.in_steed_dismounting
++;
703 place_monster(mtmp
, steedcc
.x
, steedcc
.y
);
704 gi
.in_steed_dismounting
--;
706 /* if for bones, there's no reason to place the hero;
707 we want to make room for potential ghost, so move steed */
708 if (reason
== DISMOUNT_BONES
) {
709 /* move the steed to an adjacent square */
710 if (enexto(&cc
, u
.ux
, u
.uy
, mtmp
->data
))
711 rloc_to(mtmp
, cc
.x
, cc
.y
);
712 else /* evidently no room nearby; move steed elsewhere */
713 (void) rloc(mtmp
, RLOC_ERR
| RLOC_NOMSG
);
717 /* Set hero's and/or steed's positions. Usually try moving the
718 hero first. Note: for DISMOUNT_ENGULFED, caller hasn't set
719 u.uswallow yet but has set u.ustuck. */
720 if (!u
.uswallow
&& !u
.ustuck
&& have_spot
) {
721 struct permonst
*mdat
= mtmp
->data
;
723 /* The steed may drop into water/lava */
724 if (grounded(mdat
)) {
725 if (is_pool(u
.ux
, u
.uy
)) {
727 pline("%s falls into the %s!", Monnam(mtmp
),
728 surface(u
.ux
, u
.uy
));
729 if (!cant_drown(mdat
)) {
733 } else if (is_lava(u
.ux
, u
.uy
)) {
734 pline("%s is pulled into the %s!", Monnam(mtmp
),
736 if (!likes_lava(mdat
)) {
742 /* Steed dismounting consists of two steps: being moved to another
743 * square, and descending to the floor. We have functions to do
744 * each of these activities, but they're normally called
745 * individually and include an attempt to look at or pick up the
746 * objects on the floor:
747 * teleds() --> spoteffects() --> pickup()
748 * float_down() --> pickup()
749 * We use this kludge to make sure there is only one such attempt.
751 * Clearly this is not the best way to do it. A full fix would
752 * involve having these functions not call pickup() at all,
753 * instead calling them first and calling pickup() afterwards.
754 * But it would take a lot of work to keep this change from
755 * having any unforeseen side effects (for instance, you would
756 * no longer be able to walk onto a square with a hole, and
757 * autopickup before falling into the hole).
759 /* [ALI] No need to move the player if the steed died. */
760 if (!DEADMONSTER(mtmp
)) {
761 /* Keep steed here, move the player to cc;
762 * teleds() clears u.utrap
764 gi
.in_steed_dismounting
= TRUE
;
765 teleds(cc
.x
, cc
.y
, TELEDS_ALLOW_DRAG
);
766 if (sobj_at(BOULDER
, cc
.x
, cc
.y
))
768 gi
.in_steed_dismounting
= FALSE
;
770 /* Put your steed in your trap */
772 (void) mintrap(mtmp
, NO_TRAP_FLAGS
);
775 /* Couldn't move hero... try moving the steed. */
776 } else if (enexto(&cc
, u
.ux
, u
.uy
, mtmp
->data
)) {
777 /* Keep player here, move the steed to cc */
778 rloc_to(mtmp
, cc
.x
, cc
.y
);
779 /* Player stays put */
781 /* Otherwise, steed goes bye-bye. */
783 #if 1 /* original there's-no-room handling */
784 if (reason
== DISMOUNT_BYCHOICE
) {
785 /* [un]#ride: hero gets credit/blame for killing steed */
789 /* other dismount: kill former steed with no penalty;
790 damage type is just "neither AD_DGST nor -AD_RBRE" */
791 monkilled(mtmp
, "", -AD_PHYS
);
794 /* Can't use this [yet?] because it violates monmove()'s
795 * assumption that a moving monster (engulfer) can't cause
796 * another monster (steed) to be removed from the fmon list.
797 * That other monster (steed) might be cached as the next one
800 /* migrate back to this level if hero leaves and returns
801 or to next level if it is happening in the endgame */
802 mdrop_special_objs(mtmp
);
803 deal_with_overcrowding(mtmp
);
806 } /* !DEADMONST(mtmp) */
808 /* usually return the hero to the surface */
809 if (reason
!= DISMOUNT_ENGULFED
&& reason
!= DISMOUNT_BONES
) {
810 gi
.in_steed_dismounting
= TRUE
;
811 (void) float_down(0L, W_SADDLE
);
812 gi
.in_steed_dismounting
= FALSE
;
814 (void) encumber_msg();
815 gv
.vision_full_recalc
= 1;
818 /* polearms behave differently when not mounted */
819 if (uwep
&& is_pole(uwep
))
824 /* when attempting to saddle or mount a sleeping steed, try to wake it up
825 (for the saddling case, it won't be u.usteed yet) */
827 maybewakesteed(struct monst
*steed
)
829 int frozen
= (int) steed
->mfrozen
;
830 boolean wasimmobile
= helpless(steed
);
832 steed
->msleeping
= 0;
834 frozen
= (frozen
+ 1) / 2; /* half */
835 /* might break out of timed sleep or paralysis */
840 /* didn't awake, but remaining duration is halved */
841 steed
->mfrozen
= frozen
;
844 if (wasimmobile
&& !helpless(steed
))
845 pline("%s wakes up.", Monnam(steed
));
846 /* regardless of waking, terminate any meal in progress */
847 finish_meating(steed
);
850 /* steed has taken on a new shape */
854 struct permonst
*oldshape
)
856 if (!can_saddle(steed
) || !can_ride(steed
)) {
857 /* can't get here; newcham() -> mon_break_armor() -> m_lose_armor()
858 removes saddle and/or forces hero to dismount, if applicable,
859 before newcham() calls us */
860 dismount_steed(DISMOUNT_FELL
);
864 Strcpy(buf
, x_monnam(steed
, ARTICLE_YOUR
, (char *) 0,
865 SUPPRESS_SADDLE
, FALSE
));
866 if (oldshape
!= steed
->data
)
867 (void) strsubst(buf
, "your ", "your new ");
868 You("adjust yourself in the saddle on %s.", buf
);
870 /* riding blocks stealth unless hero+steed fly */
875 /* decide whether hero's steed is able to move;
876 doesn't check for holding traps--those affect the hero directly */
878 stucksteed(boolean checkfeeding
)
880 struct monst
*steed
= u
.usteed
;
883 /* check whether steed can move */
884 if (helpless(steed
)) {
885 pline("%s won't move!", YMonnam(steed
));
888 /* optionally check whether steed is in the midst of a meal */
889 if (checkfeeding
&& steed
->meating
) {
890 pline("%s is still eating.", YMonnam(steed
));
898 place_monster(struct monst
*mon
, coordxy x
, coordxy y
)
900 struct monst
*othermon
;
901 const char *monnm
, *othnm
;
905 /* normal map bounds are <1..COLNO-1,0..ROWNO-1> but sometimes
906 vault guards (either living or dead) are parked at <0,0> */
907 if (!isok(x
, y
) && (x
!= 0 || y
!= 0 || !mon
->isgd
)) {
908 describe_level(buf
, 0);
909 impossible("trying to place %s at <%d,%d> mstate:%lx on %s",
910 minimal_monnam(mon
, TRUE
), x
, y
, mon
->mstate
, buf
);
913 if ((mon
== u
.usteed
&& !gi
.in_steed_dismounting
)
914 /* special case is for convoluted vault guard handling */
915 || (DEADMONSTER(mon
) && !(mon
->isgd
&& x
== 0 && y
== 0))) {
916 describe_level(buf
, 0);
917 impossible("placing %s onto map, mstate:%lx, on %s?",
918 (mon
== u
.usteed
) ? "steed" : "defunct monster",
922 if ((othermon
= svl
.level
.monsters
[x
][y
]) != 0) {
923 describe_level(buf
, 0);
924 monnm
= minimal_monnam(mon
, FALSE
);
925 othnm
= (mon
!= othermon
) ? minimal_monnam(othermon
, TRUE
) : "itself";
926 impossible("placing %s over %s at <%d,%d>, mstates:%lx %lx on %s?",
927 monnm
, othnm
, x
, y
, othermon
->mstate
, mon
->mstate
, buf
);
929 mon
->mx
= x
, mon
->my
= y
;
930 svl
.level
.monsters
[x
][y
] = mon
;
931 mon
->mstate
= MON_FLOOR
;