-/* NetHack 3.6 steed.c $NHDT-Date: 1445906867 2015/10/27 00:47:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.47 $ */
+/* NetHack 3.6 steed.c $NHDT-Date: 1545441042 2018/12/22 01:10:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.62 $ */
/* Copyright (c) Kevin Hugo, 1998-1999. */
/* NetHack may be freely redistributed. See license for details. */
*/
pline("%s\82ð\89ö\89ä\82µ\82Ä\82¢\82é\82Ì\82Å\8fæ\82ê\82È\82¢\81D", makeplural(body_part(LEG)));
if (force && wizard && yn("Heal your legs?") == 'y')
- HWounded_legs = EWounded_legs = 0;
+ HWounded_legs = EWounded_legs = 0L;
else
return (FALSE);
}
/* Can the player reach and see the monster? */
if (!mtmp || (!force && ((Blind && !Blind_telepat) || mtmp->mundetected
- || mtmp->m_ap_type == M_AP_FURNITURE
- || mtmp->m_ap_type == M_AP_OBJECT))) {
+ || M_AP_TYPE(mtmp) == M_AP_FURNITURE
+ || M_AP_TYPE(mtmp) == M_AP_OBJECT))) {
/*JP
pline("I see nobody there.");
*/
pline("\82»\82±\82É\82Í\89½\82à\8c©\82¦\82È\82¢\81D");
return (FALSE);
}
+ if (mtmp->data == &mons[PM_LONG_WORM]
+ && (u.ux + u.dx != mtmp->mx || u.uy + u.dy != mtmp->my)) {
+ /* 3.6.2: test_move(below) is used to check for trying to mount
+ diagonally into or out of a doorway or through a tight squeeze;
+ attempting to mount a tail segment when hero was not adjacent
+ to worm's head could trigger an impossible() in worm_cross()
+ called from test_move(), so handle not-on-head before that */
+/*JP
+ You("couldn't ride %s, let alone its tail.", a_monnam(mtmp));
+*/
+ You("%s\82É\82Í\8fæ\82ê\82È\82¢\81C\82à\82¿\82ë\82ñ\90K\94ö\82É\82à\8fæ\82ê\82È\82¢\81D", a_monnam(mtmp));
+ return FALSE;
+ }
if (u.uswallow || u.ustuck || u.utrap || Punished
|| !test_move(u.ux, u.uy, mtmp->mx - u.ux, mtmp->my - u.uy,
TEST_MOVE)) {
You("mount %s.", mon_nam(mtmp));
*/
You("%s\82É\8fæ\82Á\82½\81D", mon_nam(mtmp));
+ if (Flying)
+/*JP
+ You("and %s take flight together.", mon_nam(mtmp));
+*/
+ You("\82Æ%s\82Í\88ê\8f\8f\82É\8bó\82ð\94ò\82ñ\82¾\81D", mon_nam(mtmp));
}
/* setuwep handles polearms differently when you're mounted */
if (uwep && is_pole(uwep))
return;
/* It takes many turns of riding to exercise skill */
- if (u.urideturns++ >= 100) {
+ if (++u.urideturns >= 100) {
u.urideturns = 0;
use_skill(P_RIDING, 1);
}
{
struct monst *mtmp;
struct obj *otmp;
- coord cc;
+ coord cc, steedcc;
/*JP
const char *verb = "fall";
*/
}
if (!have_spot) {
/*JP
- You("can't. There isn't anywhere for you to stand.");
+ You("can't. There isn't anywhere for you to stand.");
*/
pline("\82 \82È\82½\82Ì\97§\82Â\8fê\8f\8a\82ª\82È\82¢\82Ì\82Å\8d~\82è\82ç\82ê\82È\82¢\81D");
return;
}
/* While riding, Wounded_legs refers to the steed's legs;
after dismounting, it reverts to the hero's legs. */
- if (repair_leg_damage) {
- /* [TODO: make heal_legs() take a parameter to handle this] */
- in_steed_dismounting = TRUE;
- heal_legs();
- in_steed_dismounting = FALSE;
- }
+ if (repair_leg_damage)
+ heal_legs(1);
/* Release the steed and saddle */
u.usteed = 0;
u.ugallop = 0L;
+ /*
+ * rloc(), rloc_to(), and monkilled()->mondead()->m_detach() all
+ * expect mtmp to be on the map or else have mtmp->mx be 0, but
+ * setting the latter to 0 here would interfere with dropping
+ * the saddle. Prior to 3.6.2, being off the map didn't matter.
+ *
+ * place_monster() expects mtmp to be alive and not be u.usteed.
+ *
+ * Unfortunately, <u.ux,u.uy> (former steed's implicit location)
+ * might now be occupied by an engulfer, so we can't just put mtmp
+ * at that spot. An engulfer's previous spot will be unoccupied
+ * but we don't know where that was and even if we did, it might
+ * be hostile terrain.
+ */
+ steedcc.x = u.ux, steedcc.y = u.uy;
+ if (m_at(u.ux, u.uy)) {
+ /* hero's spot has a monster in it; hero must have been plucked
+ from saddle as engulfer moved into his spot--other dismounts
+ shouldn't run into this situation; find nearest viable spot */
+ if (!enexto(&steedcc, u.ux, u.uy, mtmp->data)
+ /* no spot? must have been engulfed by a lurker-above over
+ water or lava; try requesting a location for a flyer */
+ && !enexto(&steedcc, u.ux, u.uy, &mons[PM_BAT]))
+ /* still no spot; last resort is any spot within bounds */
+ (void) enexto(&steedcc, u.ux, u.uy, &mons[PM_GHOST]);
+ }
+ if (!m_at(steedcc.x, steedcc.y)) {
+ if (mtmp->mhp < 1)
+ mtmp->mhp = 0; /* make sure it isn't negative */
+ mtmp->mhp++; /* force at least one hit point, possibly resurrecting */
+ place_monster(mtmp, steedcc.x, steedcc.y);
+ mtmp->mhp--; /* take the extra hit point away: cancel resurrection */
+ } else {
+ impossible("Dismounting: can't place former steed on map.");
+ }
+
+ if (!DEADMONSTER(mtmp)) {
+ /* if for bones, there's no reason to place the hero;
+ we want to make room for potential ghost, so move steed */
+ if (reason == DISMOUNT_BONES) {
+ /* move the steed to an adjacent square */
+ if (enexto(&cc, u.ux, u.uy, mtmp->data))
+ rloc_to(mtmp, cc.x, cc.y);
+ else /* evidently no room nearby; move steed elsewhere */
+ (void) rloc(mtmp, FALSE);
+ return;
+ }
- /* Set player and steed's position. Try moving the player first
- unless we're in the midst of creating a bones file. */
- if (reason == DISMOUNT_BONES) {
- /* move the steed to an adjacent square */
- if (enexto(&cc, u.ux, u.uy, mtmp->data))
- rloc_to(mtmp, cc.x, cc.y);
- else /* evidently no room nearby; move steed elsewhere */
- (void) rloc(mtmp, FALSE);
- return;
- }
- if (mtmp->mhp > 0) {
- place_monster(mtmp, u.ux, u.uy);
+ /* Set hero's and/or steed's positions. Try moving the hero first. */
if (!u.uswallow && !u.ustuck && have_spot) {
struct permonst *mdat = mtmp->data;
* falling into the hole).
*/
/* [ALI] No need to move the player if the steed died. */
- if (mtmp->mhp > 0) {
+ if (!DEADMONSTER(mtmp)) {
/* Keep steed here, move the player to cc;
* teleds() clears u.utrap
*/
if (save_utrap)
(void) mintrap(mtmp);
}
- /* Couldn't... try placing the steed */
+
+ /* Couldn't move hero... try moving the steed. */
} else if (enexto(&cc, u.ux, u.uy, mtmp->data)) {
/* Keep player here, move the steed to cc */
rloc_to(mtmp, cc.x, cc.y);
/* Player stays put */
- /* Otherwise, kill the steed */
+
+ /* Otherwise, kill the steed. */
} else {
- killed(mtmp);
- adjalign(-1);
+ if (reason == DISMOUNT_BYCHOICE) {
+ /* [un]#ride: hero gets credit/blame for killing steed */
+ killed(mtmp);
+ adjalign(-1);
+ } else {
+ /* other dismount: kill former steed with no penalty;
+ damage type is just "neither AD_DGST nor -AD_RBRE" */
+ monkilled(mtmp, "", -AD_PHYS);
+ }
}
- }
+ } /* !DEADMONST(mtmp) */
- /* Return the player to the floor */
- if (reason != DISMOUNT_ENGULFED) {
+ /* usually return the hero to the surface */
+ if (reason != DISMOUNT_ENGULFED && reason != DISMOUNT_BONES) {
in_steed_dismounting = TRUE;
(void) float_down(0L, W_SADDLE);
in_steed_dismounting = FALSE;
struct monst *mon;
int x, y;
{
+ /* normal map bounds are <1..COLNO-1,0..ROWNO-1> but sometimes
+ vault guards (either living or dead) are parked at <0,0> */
+ if (!isok(x, y) && (x != 0 || y != 0 || !mon->isgd)) {
+ impossible("trying to place monster at <%d,%d>", x, y);
+ x = y = 0;
+ }
if (mon == u.usteed
/* special case is for convoluted vault guard handling */
|| (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) {
(mon == u.usteed) ? "steed" : "defunct monster");
return;
}
+ if (level.monsters[x][y])
+ impossible("placing monster over another at <%d,%d>?", x, y);
mon->mx = x, mon->my = y;
level.monsters[x][y] = mon;
}