-/* NetHack 3.6 do.c $NHDT-Date: 1472809073 2016/09/02 09:37:53 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.158 $ */
+/* NetHack 3.6 do.c $NHDT-Date: 1548978604 2019/01/31 23:50:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.189 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */
levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
levl[rx][ry].drawbridgemask |= DB_FLOOR;
} else
- levl[rx][ry].typ = ROOM;
+ levl[rx][ry].typ = ROOM, levl[rx][ry].flags = 0;
if (ttmp)
(void) delfloortrap(ttmp);
struct trap *t;
struct monst *mtmp;
struct obj *otmp;
+ boolean tseen;
+ int ttyp = NO_TRAP;
if (obj->where != OBJ_FREE)
panic("flooreffects: obj not free");
if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) {
return TRUE;
} else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0
- && (t->ttyp == PIT || t->ttyp == SPIKED_PIT
- || t->ttyp == TRAPDOOR || t->ttyp == HOLE)) {
+ && (is_pit(t->ttyp) || is_hole(t->ttyp))) {
+ ttyp = t->ttyp;
+ tseen = t->tseen ? TRUE : FALSE;
if (((mtmp = m_at(x, y)) && mtmp->mtrapped)
|| (u.utrap && u.ux == x && u.uy == y)) {
- if (*verb)
+ if (*verb && (cansee(x, y) || distu(x, y) == 0))
#if 0 /*JP*/
- pline_The("boulder %s into the pit%s.",
- vtense((const char *) 0, verb),
- (mtmp) ? "" : " with you");
+ pline("%s boulder %s into the pit%s.",
+ Blind ? "A" : "The",
+ vtense((const char *) 0, verb),
+ mtmp ? "" : " with you");
#else
pline("\8aâ\82Í%s\97\8e\82µ\8c\8a\82Ö%s\81D",
- (mtmp) ? "" : "\82 \82È\82½\82Æ\82¢\82Á\82µ\82å\82É",
+ mtmp ? "" : "\82 \82È\82½\82Æ\82¢\82Á\82µ\82å\82É",
jpast(verb));
#endif
if (mtmp) {
if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data)) {
- int dieroll = rnd(20);
-
- if (hmon(mtmp, obj, HMON_THROWN, dieroll)
- && !is_whirly(mtmp->data))
+ /* dieroll was rnd(20); 1: maximum chance to hit
+ since trapped target is a sitting duck */
+ int damage, dieroll = 1;
+
+ /* 3.6.2: this was calling hmon() unconditionally
+ so always credited/blamed the hero but the boulder
+ might have been thrown by a giant or launched by
+ a rolling boulder trap triggered by a monster or
+ dropped by a scroll of earth read by a monster */
+ if (context.mon_moving) {
+ /* normally we'd use ohitmon() but it can call
+ drop_throw() which calls flooreffects() */
+ damage = dmgval(obj, mtmp);
+ mtmp->mhp -= damage;
+ if (DEADMONSTER(mtmp)) {
+ if (canspotmon(mtmp))
+ pline("%s is %s!", Monnam(mtmp),
+ (nonliving(mtmp->data)
+ || is_vampshifter(mtmp))
+ ? "destroyed" : "killed");
+ mondied(mtmp);
+ }
+ } else {
+ (void) hmon(mtmp, obj, HMON_THROWN, dieroll);
+ }
+ if (!DEADMONSTER(mtmp) && !is_whirly(mtmp->data))
return FALSE; /* still alive */
}
mtmp->mtrapped = 0;
#endif
return FALSE; /* player remains trapped */
} else
- u.utrap = 0;
+ reset_utrap(TRUE);
}
}
if (*verb) {
You_hear("\91«\8c³\82Å\89½\82©\82ª\8dÓ\82¯\82é\89¹\82ð\95·\82¢\82½\81D");
} else if (!Blind && cansee(x, y)) {
#if 0 /*JP*/
- pline_The("boulder %s%s.", t->tseen ? "" : "triggers and ",
- t->ttyp == TRAPDOOR
+ pline_The("boulder %s%s.",
+ (ttyp == TRAPDOOR && !tseen)
+ ? "triggers and " : "",
+ (ttyp == TRAPDOOR)
? "plugs a trap door"
- : t->ttyp == HOLE ? "plugs a hole"
- : "fills a pit");
+ : (ttyp == HOLE) ? "plugs a hole"
+ : "fills a pit");
#else
pline_The("\8aâ\82Í%s%s\81D", t->tseen ? "" : "ã©\82ð\8bN\93®\82µ\82Ä\81C",
t->ttyp == TRAPDOOR ? "\97\8e\82µ\94à\82ð\96\84\82ß\82½" :
You_hear("\8aâ\82ª%s\89¹\82ð\95·\82¢\82½\81D", verb);
}
}
- deltrap(t);
+ /*
+ * Note: trap might have gone away via ((hmon -> killed -> xkilled)
+ * || mondied) -> mondead -> m_detach -> fill_pit.
+ */
+ if ((t = t_at(x, y)) != 0)
+ deltrap(t);
useupf(obj, 1L);
bury_objs(x, y);
newsym(x, y);
polymorph_sink()
{
uchar sym = S_sink;
+ boolean sinklooted;
if (levl[u.ux][u.uy].typ != SINK)
return;
+ sinklooted = levl[u.ux][u.uy].looted != 0;
level.flags.nsinks--;
- levl[u.ux][u.uy].doormask = 0;
+ levl[u.ux][u.uy].doormask = 0; /* levl[][].flags */
switch (rn2(4)) {
default:
case 0:
sym = S_fountain;
levl[u.ux][u.uy].typ = FOUNTAIN;
+ levl[u.ux][u.uy].blessedftn = 0;
+ if (sinklooted)
+ SET_FOUNTAIN_LOOTED(u.ux, u.uy);
level.flags.nfountains++;
break;
case 1:
sym = S_throne;
levl[u.ux][u.uy].typ = THRONE;
+ if (sinklooted)
+ levl[u.ux][u.uy].looted = T_LOOTED;
break;
case 2:
sym = S_altar;
pline_The("ring is regurgitated!");
*/
pline("\8ew\97Ö\82Í\8bt\97¬\82µ\82½\81I");
- giveback:
+ giveback:
obj->in_use = FALSE;
dropx(obj);
trycall(obj);
if (u.uswallow) {
/* barrier between you and the floor */
if (flags.verbose) {
- char buf[BUFSZ];
+ char *onam_p, monbuf[BUFSZ];
/* doname can call s_suffix, reusing its buffer */
- Strcpy(buf, s_suffix(mon_nam(u.ustuck)));
+ Strcpy(monbuf, s_suffix(mon_nam(u.ustuck)));
+ onam_p = is_unpaid(obj) ? yobjnam(obj, (char *) 0) : doname(obj);
#if 0 /*JP*/
- You("drop %s into %s %s.", doname(obj), buf,
+ You("drop %s into %s %s.", onam_p, monbuf,
mbodypart(u.ustuck, STOMACH));
#else
- You("%s\82ð%s%s\82É\92u\82¢\82½\81D", doname(obj), buf,
+ You("%s\82ð%s%s\82É\92u\82¢\82½\81D", onam_p, monbuf,
mbodypart(u.ustuck, STOMACH));
#endif
}
if (obj->oclass == COIN_CLASS)
context.botl = 1;
freeinv(obj);
- hitfloor(obj);
+ hitfloor(obj, TRUE);
if (levhack)
float_down(I_SPECIAL | TIMEOUT, W_ARTI | W_ART);
return 1;
could_grow = (obj->corpsenm == PM_WRAITH);
could_heal = (obj->corpsenm == PM_NURSE);
}
+ if (is_unpaid(obj))
+ (void) stolen_value(obj, u.ux, u.uy, TRUE, FALSE);
(void) mpickobj(u.ustuck, obj);
if (is_animal(u.ustuck->data)) {
if (could_poly || could_slime) {
}
}
-drop_done:
+ drop_done:
return n_dropped;
}
if (trap && uteetering_at_seen_pit(trap)) {
dotrap(trap, TOOKPLUNGE);
return 1;
- } else if (!trap || (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE)
+ } else if (!trap || !is_hole(trap->ttyp)
|| !Can_fall_thru(&u.uz) || !trap->tseen) {
if (flags.autodig && !context.nopick && uwep && is_pick(uwep)) {
return use_pick_axe2(uwep);
return 0;
}
- if (trap)
+ if (trap) {
+ const char *down_or_thru = trap->ttyp == HOLE ? "down" : "through";
+ const char *actn = Flying ? "fly" : locomotion(youmonst.data, "jump");
+
+ if (youmonst.data->msize >= MZ_HUGE) {
+ char qbuf[QBUFSZ];
+
+ You("don't fit %s easily.", down_or_thru);
+ Sprintf(qbuf, "Try to squeeze %s?", down_or_thru);
+ if (yn(qbuf) == 'y') {
+ if (!rn2(3)) {
+ actn = "manage to squeeze";
+ losehp(Maybe_Half_Phys(rnd(4)),
+ "contusion from a small passage", KILLED_BY);
+ } else {
+ You("were unable to fit %s.", down_or_thru);
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
#if 0 /*JP*/
- You("%s %s.", Flying ? "fly" : locomotion(youmonst.data, "jump"),
- trap->ttyp == HOLE ? "down the hole" : "through the trap door");
+ You("%s %s the %s.", actn, down_or_thru,
+ trap->ttyp == HOLE ? "hole" : "trap door");
#else
You("%s\81D",
trap->ttyp == HOLE ? "\8c\8a\82ð\8d~\82è\82½" : "\97\8e\82µ\94à\82ð\92Ê\82è\94²\82¯\82½");
#endif
-
+ }
if (trap && Is_stronghold(&u.uz)) {
goto_hell(FALSE, TRUE);
} else {
return 1;
}
if (ledger_no(&u.uz) == 1) {
+ if (iflags.debug_fuzzer)
+ return 0;
/*JP
- if (yn("Beware, there will be no return! Still climb?") != 'y')
+ if (yn("Beware, there will be no return! Still climb?") != 'y')
*/
if (yn("\8bC\82ð\82Â\82¯\82ë\81C\96ß\82ê\82È\82¢\82¼\81I\82»\82ê\82Å\82à\8fã\82é\81H") != 'y')
return 0;
}
*/
+/* when arriving on a level, if hero and a monster are trying to share same
+ spot, move one; extracted from goto_level(); also used by wiz_makemap() */
+void
+u_collide_m(mtmp)
+struct monst *mtmp;
+{
+ coord cc;
+
+ if (!mtmp || mtmp == u.usteed || mtmp != m_at(u.ux, u.uy)) {
+ impossible("level arrival collision: %s?",
+ !mtmp ? "no monster"
+ : (mtmp == u.usteed) ? "steed is on map"
+ : "monster not co-located");
+ return;
+ }
+
+ /* There's a monster at your target destination; it might be one
+ which accompanied you--see mon_arrive(dogmove.c)--or perhaps
+ it was already here. Randomly move you to an adjacent spot
+ or else the monster to any nearby location. Prior to 3.3.0
+ the latter was done unconditionally. */
+ if (!rn2(2) && enexto(&cc, u.ux, u.uy, youmonst.data)
+ && distu(cc.x, cc.y) <= 2)
+ u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/
+ else
+ mnexto(mtmp);
+
+ if ((mtmp = m_at(u.ux, u.uy)) != 0) {
+ /* there was an unconditional impossible("mnexto failed")
+ here, but it's not impossible and we're prepared to cope
+ with the situation, so only say something when debugging */
+ if (wizard)
+ pline("(monster in hero's way)");
+ if (!rloc(mtmp, TRUE) || (mtmp = m_at(u.ux, u.uy)) != 0)
+ /* no room to move it; send it away, to return later */
+ m_into_limbo(mtmp);
+ }
+}
+
void
goto_level(newlevel, at_stairs, falling, portal)
d_level *newlevel;
if (fd < 0)
return;
+ /* discard context which applies to the level we're leaving;
+ for lock-picking, container may be carried, in which case we
+ keep context; if on the floor, it's about to be saved+freed and
+ maybe_reset_pick() needs to do its carried() check before that */
+ maybe_reset_pick((struct obj *) 0);
+ reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */
+ iflags.travelcc.x = iflags.travelcc.y = 0; /* travel destination cache */
+ context.polearm.hitmon = (struct monst *) 0; /* polearm target */
+ /* digging context is level-aware and can actually be resumed if
+ hero returns to the previous level without any intervening dig */
+
if (falling) /* assuming this is only trap door or hole */
impact_drop((struct obj *) 0, u.ux, u.uy, newlevel->dlevel);
check_special_room(TRUE); /* probably was a trap door */
if (Punished)
unplacebc();
- u.utrap = 0; /* needed in level_tele */
+ reset_utrap(FALSE); /* needed in level_tele */
fill_pit(u.ux, u.uy);
u.ustuck = 0; /* idem */
u.uinwater = 0;
/* we'll reach here if running in wizard mode */
error("Cannot continue this game.");
}
+ reseed_random(rn2);
+ reseed_random(rn2_on_display_rng);
minit(); /* ZEROCOMP */
getlev(fd, hackpid, new_ledger, FALSE);
(void) nhclose(fd);
*/
run_timers();
- initrack();
+ /* hero might be arriving at a spot containing a monster;
+ if so, move one or the other to another location */
+ if ((mtmp = m_at(u.ux, u.uy)) != 0)
+ u_collide_m(mtmp);
- if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) {
- /* There's a monster at your target destination; it might be one
- which accompanied you--see mon_arrive(dogmove.c)--or perhaps
- it was already here. Randomly move you to an adjacent spot
- or else the monster to any nearby location. Prior to 3.3.0
- the latter was done unconditionally. */
- coord cc;
-
- if (!rn2(2) && enexto(&cc, u.ux, u.uy, youmonst.data)
- && distu(cc.x, cc.y) <= 2)
- u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/
- else
- mnexto(mtmp);
-
- if ((mtmp = m_at(u.ux, u.uy)) != 0) {
- /* there was an unconditional impossible("mnearto failed")
- here, but it's not impossible and we're prepared to cope
- with the situation, so only say something when debugging */
- if (wizard)
- pline("(monster in hero's way)");
- if (!rloc(mtmp, TRUE))
- /* no room to move it; send it away, to return later */
- migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_RANDOM,
- (coord *) 0);
- }
- }
+ initrack();
/* initial movement of bubbles just before vision_recalc */
if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
/* assume this will always return TRUE when changing level */
(void) in_out_region(u.ux, u.uy);
(void) pickup(1);
-
- /* discard context which applied to previous level */
- maybe_reset_pick(); /* for door or for box not accompanying hero */
- reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */
- iflags.travelcc.x = iflags.travelcc.y = -1; /* travel destination cache */
- context.polearm.hitmon = (struct monst *) 0; /* polearm target */
- /* digging context is level-aware and can actually be resumed if
- hero returns to the previous level without any intervening dig */
}
STATIC_OVL void
where = corpse->where;
is_uwep = (corpse == uwep);
chewed = (corpse->oeaten != 0);
- Strcpy(cname,
-/*JP
- corpse_xname(corpse, chewed ? "bite-covered" : (const char *) 0,
-*/
- corpse_xname(corpse, chewed ? "\8e\95\8c^\82Ì\82Â\82¢\82½" : (const char *) 0,
- CXN_SINGULAR));
+#if 0 /*JP*/
+ Strcpy(cname, corpse_xname(corpse,
+ chewed ? "bite-covered" : (const char *) 0,
+ CXN_SINGULAR));
+#else
+ Strcpy(cname, corpse_xname(corpse,
+ chewed ? "\8e\95\8c^\82Ì\82Â\82¢\82½" : (const char *) 0,
+ CXN_SINGULAR));
+#endif
mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
if (where == OBJ_CONTAINED) {
struct monst *mtmp2;
container = corpse->ocontainer;
- mtmp2 =
- get_container_location(container, &container_where, (int *) 0);
+ mtmp2 = get_container_location(container, &container_where, (int *) 0);
/* container_where is the outermost container's location even if
* nested */
if (container_where == OBJ_MINVENT && mtmp2)
}
void
-heal_legs()
+heal_legs(how)
+int how; /* 0: ordinary, 1: dismounting steed, 2: limbs turn to stone */
{
if (Wounded_legs) {
if (ATEMP(A_DEX) < 0) {
context.botl = 1;
}
- if (!u.usteed) {
+ /* when mounted, wounded legs applies to the steed;
+ during petrification countdown, "your limbs turn to stone"
+ before the final stages and that calls us (how==2) to cure
+ wounded legs, but we want to suppress the feel better message */
+ if (!u.usteed && how != 2) {
#if 0 /*JP*/
const char *legs = body_part(LEG);
#endif
}
- HWounded_legs = EWounded_legs = 0;
+ HWounded_legs = EWounded_legs = 0L;
/* Wounded_legs reduces carrying capacity, so we want
an encumbrance check when they're healed. However,
it might be immediately contradicted [able to carry
more when steed becomes healthy, then possible floor
feedback, then able to carry less when back on foot]. */
- if (!in_steed_dismounting)
+ if (how == 0)
(void) encumber_msg();
}
}