-/* NetHack 3.6 dothrow.c $NHDT-Date: 1522967321 2018/04/05 22:28:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.135 $ */
+/* NetHack 3.6 dothrow.c $NHDT-Date: 1573688688 2019/11/13 23:44:48 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.164 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2018 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2021 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
u_wipe_engr(2);
if (!uarmg && obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])
&& !Stone_resistance) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("throw %s with your bare %s.",
corpse_xname(obj, (const char *) 0, CXN_PFX_THE),
/* throwing with one hand, but pluralize since the
attempted to specify a count */
if (multishot > 1 || shotlimit > 0) {
/* "You shoot N arrows." or "You throw N daggers." */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%s %d %s.", m_shot.s ? "shoot" : "throw",
multishot, /* (might be 1 if player gave shotlimit) */
(multishot == 1) ? singular(obj, xname) : xname(obj));
You("\89½\82©\82ð\93\8a\82°\82é\82Ì\82Í\95¨\97\9d\93I\82É\96³\97\9d\82¾\81D");
return FALSE;
} else if (nohands(youmonst.data)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You_cant("throw or shoot without hands."); /* not body_part(HAND) */
#else
You("\8eè\82ª\82È\82¢\81D"); /* not body_part(HAND) */
You("\94\8eË\82·\82é\82à\82Ì\82ª\82È\82¢\81D");
}
/* if autoquiver is disabled or has failed, prompt for missile;
- fill quiver with it if it's not wielded */
+ fill quiver with it if it's not wielded or worn */
if (!obj) {
+ /* in case we're using ^A to repeat prior 'f' command, don't
+ use direction of previous throw as getobj()'s choice here */
+ in_doagain = 0;
+ /* choose something from inventory, then usually quiver it */
obj = getobj(uslinging() ? bullets : toss_objs, "throw");
/* Q command doesn't allow gold in quiver */
if (obj && !obj->owornmask && obj->oclass != COIN_CLASS)
{
if (m_shot.i < m_shot.n) {
if (verbose && !context.mon_moving) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("stop %s after the %d%s %s.",
m_shot.s ? "firing" : "throwing", m_shot.i, ordin(m_shot.i),
m_shot.s ? "shot" : "toss");
}
}
-/*
- * Object hits floor at hero's feet. Called from drop() and throwit().
- */
+/* Object hits floor at hero's feet.
+ Called from drop(), throwit(), hold_another_object(). */
void
-hitfloor(obj)
-register struct obj *obj;
+hitfloor(obj, verbosely)
+struct obj *obj;
+boolean verbosely; /* usually True; False if caller has given drop message */
{
- if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) {
+ if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater || u.uswallow) {
dropy(obj);
return;
}
if (IS_ALTAR(levl[u.ux][u.uy].typ))
doaltarobj(obj);
- else
-#if 0 /*JP*/
- pline("%s hit%s the %s.", Doname2(obj), (obj->quan == 1L) ? "s" : "",
+ else if (verbosely)
+#if 0 /*JP:T*/
+ pline("%s %s the %s.", Doname2(obj), otense(obj, "hit"),
surface(u.ux, u.uy));
#else
pline("%s\82Í%s\82É\96½\92\86\82µ\82½\81D", Doname2(obj),
- surface(u.ux,u.uy));
+ surface(u.ux, u.uy));
#endif
if (hero_breaks(obj, u.ux, u.uy, TRUE))
int ox, oy, *range = (int *) arg;
struct obj *obj;
struct monst *mon;
- boolean may_pass = TRUE;
+ boolean may_pass = TRUE, via_jumping, stopping_short;
struct trap *ttmp;
int dmg = 0;
} else if (*range == 0) {
return FALSE; /* previous step wants to stop now */
}
+ via_jumping = (EWwalking & I_SPECIAL) != 0L;
+ stopping_short = (via_jumping && *range < 2);
if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
boolean odoor_diag = (IS_DOOR(levl[x][y].typ)
*/
You("\93S\82Ì\96_\82É\82Ô\82¿\82 \82½\82Á\82½\81D\82¢\82Ä\82Á\81I");
dmg = rnd(2 + *range);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
losehp(Maybe_Half_Phys(dmg), "crashing into iron bars",
KILLED_BY);
#else
*/
You("\89½\82©\82É\82Ô\82¿\82 \82½\82Á\82½\81I");
dmg = rnd(2 + *range);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
losehp(Maybe_Half_Phys(dmg), "touching the edge of the universe",
KILLED_BY);
#else
/* Move at a diagonal. */
if (bigmonst(youmonst.data) || too_much) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("%sget forcefully wedged into a crevice.",
too_much ? "and all your belongings " : "");
#else
too_much ? "\82Æ\91S\95\94\82Ì\89×\95¨" : "");
#endif
dmg = rnd(2 + *range);
-#if 0 /*JP*/
+#if 0 /*JP:T*/
losehp(Maybe_Half_Phys(dmg), "wedging into a narrow crevice",
KILLED_BY);
#else
mon->mundetected = 0; /* wakeup() will handle mimic */
mnam = a_monnam(mon); /* after unhiding */
- pronoun = mhim(mon);
+ pronoun = noit_mhim(mon);
#if 0 /*JP*/
if (!strcmp(mnam, "it")) {
#else
if (!strcmp(mnam, "\89½\8eÒ\82©")) {
#endif
- /* mhim() uses pronoun_gender() which forces neuter if monster
- can't be seen; we want him/her for humanoid sensed by touch */
-#if 0 /*JP*/
- if (!strcmp(pronoun, "it") && humanoid(mon->data))
-#else
- if (!strcmp(pronoun, "\89½\8eÒ\82©") && humanoid(mon->data))
-#endif
- pronoun = genders[mon->female].him;
#if 0 /*JP*/
mnam = !strcmp(pronoun, "it") ? "something" : "someone";
#else
#endif
}
if (!glyph_is_monster(glyph) && !glyph_is_invisible(glyph))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("find %s by bumping into %s.", mnam, pronoun);
#else
You("\82Ô\82¿\82 \82½\82Á\82½\82±\82Æ\82Å%s\82ð\8c©\82Â\82¯\82½\81D", mnam);
newsym(ox, oy); /* update old position */
vision_recalc(1); /* update for new position */
flush_screen(1);
-
- if (is_pool(x, y) && !u.uinwater
- && ((Is_waterlevel(&u.uz) && levl[x][y].typ == WATER)
- || !(Levitation || Flying || Wwalking))) {
- multi = 0; /* can move, so drown() allows crawling out of water */
- (void) drown();
- return FALSE;
+ /* if terrain type changes, levitation or flying might become blocked
+ or unblocked; might issue message, so do this after map+vision has
+ been updated for new location instead of right after u_on_newpos() */
+ if (levl[u.ux][u.uy].typ != levl[ox][oy].typ)
+ switch_terrain();
+
+ if (is_pool(x, y) && !u.uinwater) {
+ if ((Is_waterlevel(&u.uz) && levl[x][y].typ == WATER)
+ || !(Levitation || Flying || Wwalking)) {
+ multi = 0; /* can move, so drown() allows crawling out of water */
+ (void) drown();
+ return FALSE;
+ } else if (!Is_waterlevel(&u.uz) && !stopping_short) {
+/*JP
+ Norep("You move over %s.", an(is_moat(x, y) ? "moat" : "pool"));
+*/
+ Norep("\82 \82È\82½\82Í%s\82Ì\8fã\82ð\88Ú\93®\82µ\82½\81D", is_moat(x, y) ? "\96x" : "\90\85\82½\82Ü\82è");
+ }
+ } else if (is_lava(x, y) && !stopping_short) {
+/*JP
+ Norep("You move over some lava.");
+*/
+ Norep("\82 \82È\82½\82Í\97n\8aâ\82Ì\8fã\82ð\88Ú\93®\82µ\82½\81D");
}
/* FIXME:
- * Each trap should really trigger on the recoil if
- * it would trigger during normal movement. However,
- * not all the possible side-effects of this are
- * tested [as of 3.4.0] so we trigger those that
- * we have tested, and offer a message for the
- * ones that we have not yet tested.
+ * Each trap should really trigger on the recoil if it would
+ * trigger during normal movement. However, not all the possible
+ * side-effects of this are tested [as of 3.4.0] so we trigger
+ * those that we have tested, and offer a message for the ones
+ * that we have not yet tested.
*/
if ((ttmp = t_at(x, y)) != 0) {
- if (ttmp->ttyp == MAGIC_PORTAL) {
+ if (stopping_short) {
+ ; /* see the comment above hurtle_jump() */
+ } else if (ttmp->ttyp == MAGIC_PORTAL) {
dotrap(ttmp, 0);
return FALSE;
} else if (ttmp->ttyp == VIBRATING_SQUARE) {
dotrap(ttmp, 0); /* doesn't print messages */
} else if (ttmp->ttyp == FIRE_TRAP) {
dotrap(ttmp, 0);
- } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT
- || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR)
+ } else if ((is_pit(ttmp->ttyp) || is_hole(ttmp->ttyp))
&& Sokoban) {
- /* Air currents overcome the recoil */
- dotrap(ttmp, 0);
+ /* air currents overcome the recoil in Sokoban;
+ when jumping, caller performs last step and enters trap */
+ if (!via_jumping)
+ dotrap(ttmp, 0);
*range = 0;
return TRUE;
} else {
if (ttmp->tseen)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("pass right over %s.",
an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation));
#else
nomul(0);
return;
} else if (u.utrap) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
You("are anchored by the %s.",
u.utraptype == TT_WEB
? "web"
xchar x, y;
boolean broken;
{
+ boolean costly_xy;
struct monst *shkp = shop_keeper(*u.ushops);
if (!shkp)
return;
- if (broken || !costly_spot(x, y)
- || *in_rooms(x, y, SHOPBASE) != *u.ushops) {
+ costly_xy = costly_spot(x, y);
+ if (broken || !costly_xy || *in_rooms(x, y, SHOPBASE) != *u.ushops) {
/* thrown out of a shop or into a different shop */
if (is_unpaid(obj))
(void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
FALSE);
if (broken)
obj->no_charge = 1;
- } else {
- if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) {
+ } else if (costly_xy) {
+ char *oshops = in_rooms(x, y, SHOPBASE);
+
+ /* ushops0: in case we threw while levitating and recoiled
+ out of shop (most likely to the shk's spot in front of door) */
+ if (*oshops == *u.ushops || *oshops == *u.ushops0) {
if (is_unpaid(obj))
subfrombill(obj, shkp);
else if (x != shkp->mx || y != shkp->my)
} else if (petrifier && !Stone_resistance
&& !(poly_when_stoned(youmonst.data)
&& polymon(PM_STONE_GOLEM))) {
- petrify:
+ petrify:
killer.format = KILLED_BY;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Strcpy(killer.name, "elementary physics"); /* "what goes up..." */
#else
Strcpy(killer.name, "\8f\89\93\99\95¨\97\9d\82É\82æ\82è"); /* "what goes up..." */
done(STONING);
return obj ? TRUE : FALSE;
}
- hitfloor(obj);
+ hitfloor(obj, TRUE);
thrownobj = 0;
-#if 0 /*JP*/
+#if 0 /*JP:T*/
losehp(Maybe_Half_Phys(dmg), "falling object", KILLED_BY_AN);
#else
losehp(Maybe_Half_Phys(dmg), "\97\8e\89º\95¨\82Å", KILLED_BY_AN);
if ((u.dx || u.dy) && (bhitpos.x != u.ux || bhitpos.y != u.uy)) {
int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy;
- tmp_at(DISP_FLASH, obj_to_glyph(obj));
+ tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng));
while (isok(x,y) && (x != u.ux || y != u.uy)) {
tmp_at(x, y);
delay_output();
boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */
{
register struct monst *mon;
- register int range, urange;
- boolean crossbowing, impaired = (Confusion || Stunned || Blind
- || Hallucination || Fumbling);
+ int range, urange;
+ boolean crossbowing, clear_thrownobj = FALSE,
+ impaired = (Confusion || Stunned || Blind
+ || Hallucination || Fumbling),
+ tethered_weapon = (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0);
notonhead = FALSE; /* reset potentially stale value */
if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) {
boolean slipok = TRUE;
- if (ammo_and_launcher(obj, uwep))
+ if (ammo_and_launcher(obj, uwep)) {
/*JP
pline("%s!", Tobjnam(obj, "misfire"));
*/
pline("%s\82Í\82Í\82¸\82ê\82½\81I", xname(obj));
- else {
+ } else {
/* only slip if it's greased or meant to be thrown */
if (obj->greased || throwing_weapon(obj))
/* BUG: this message is grammatically incorrect if obj has
thrownobj = obj;
thrownobj->was_thrown = 1;
+ iflags.returning_missile = ((obj->oartifact == ART_MJOLLNIR
+ && Role_if(PM_VALKYRIE))
+ || tethered_weapon) ? (genericptr_t) obj
+ : (genericptr_t) 0;
+ /* NOTE: No early returns after this point or returning_missile
+ will be left with a stale pointer. */
if (u.uswallow) {
+ if (obj == uball) {
+ uball->ox = uchain->ox = u.ux;
+ uball->oy = uchain->oy = u.uy;
+ }
mon = u.ustuck;
bhitpos.x = mon->mx;
bhitpos.y = mon->my;
+ if (tethered_weapon)
+ tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng));
} else if (u.dz) {
if (u.dz < 0
/* Mjollnir must we wielded to be thrown--caller verifies this;
aklys must we wielded as primary to return when thrown */
- && ((Role_if(PM_VALKYRIE) && obj->oartifact == ART_MJOLLNIR)
- || (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0))
+ && iflags.returning_missile
&& !impaired) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s the %s and returns to your hand!", Tobjnam(obj, "hit"),
ceiling(u.ux, u.uy));
#else
for dealing with cursed saddle: throw holy water > */
potionhit(u.usteed, obj, POTHIT_HERO_THROW);
} else {
- hitfloor(obj);
+ hitfloor(obj, TRUE);
}
- thrownobj = (struct obj *) 0;
- return;
+ clear_thrownobj = TRUE;
+ goto throwit_return;
} else if (obj->otyp == BOOMERANG && !Underwater) {
if (Is_airlevel(&u.uz) || Levitation)
setworn(obj, wep_mask);
u.twoweap = twoweap;
}
- thrownobj = (struct obj *) 0;
- return;
+ clear_thrownobj = TRUE;
+ goto throwit_return;
}
} else {
/* crossbow range is independent of strength */
- crossbowing =
- (ammo_and_launcher(obj, uwep) && weapon_type(uwep) == P_CROSSBOW);
+ crossbowing = (ammo_and_launcher(obj, uwep)
+ && weapon_type(uwep) == P_CROSSBOW);
urange = (crossbowing ? 18 : (int) ACURRSTR) / 2;
/* balls are easy to throw or at least roll;
* also, this insures the maximum range of a ball is greater
range = 20; /* you must be giant */
else if (obj->oartifact == ART_MJOLLNIR)
range = (range + 1) / 2; /* it's heavy */
- else if (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0)
+ else if (tethered_weapon) /* primary weapon is aklys */
/* if an aklys is going to return, range is limited by the
length of the attached cord [implicit aspect of item] */
range = min(range, BOLT_LIM / 2);
if (Underwater)
range = 1;
- mon = bhit(u.dx, u.dy, range, THROWN_WEAPON,
+ mon = bhit(u.dx, u.dy, range,
+ tethered_weapon ? THROWN_TETHERED_WEAPON : THROWN_WEAPON,
(int FDECL((*), (MONST_P, OBJ_P))) 0,
(int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
thrownobj = obj; /* obj may be null now */
if (Is_airlevel(&u.uz) || Levitation)
hurtle(-u.dx, -u.dy, urange, TRUE);
- if (!obj)
- return;
+ if (!obj) {
+ /* bhit display cleanup was left with this caller
+ for tethered_weapon, but clean it up now since
+ we're about to return */
+ if (tethered_weapon)
+ tmp_at(DISP_END, 0);
+ goto throwit_return;
+ }
}
if (mon) {
boolean obj_gone;
if (mon->isshk && obj->where == OBJ_MINVENT && obj->ocarry == mon) {
- thrownobj = (struct obj *) 0;
- return; /* alert shk caught it */
+ clear_thrownobj = TRUE;
+ goto throwit_return; /* alert shk caught it */
}
(void) snuff_candle(obj);
notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
obj_gone = thitmonst(mon, obj);
- /* Monster may have been tamed; this frees old mon */
+ /* Monster may have been tamed; this frees old mon [obsolete] */
mon = m_at(bhitpos.x, bhitpos.y);
/* [perhaps this should be moved into thitmonst or hmon] */
hot_pursuit(mon);
if (obj_gone)
- thrownobj = 0;
+ thrownobj = (struct obj *) 0;
}
if (!thrownobj) {
- ; /* missile has already been handled */
- } else if (u.uswallow) {
- /* ball is not picked up by monster */
+ /* missile has already been handled */
+ if (tethered_weapon)
+ tmp_at(DISP_END, 0);
+ } else if (u.uswallow && !iflags.returning_missile) {
+ swallowit:
if (obj != uball)
- (void) mpickobj(u.ustuck, obj);
- thrownobj = (struct obj *) 0;
+ (void) mpickobj(u.ustuck, obj); /* clears 'thrownobj' */
+ else
+ clear_thrownobj = TRUE;
+ goto throwit_return;
} else {
- /* Mjollnir must we wielded to be thrown--caller verifies this;
- aklys must we wielded as primary to return when thrown */
- if ((obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE))
- || (obj->otyp == AKLYS && (wep_mask & W_WEP) != 0)) {
+ /* Mjollnir must be wielded to be thrown--caller verifies this;
+ aklys must be wielded as primary to return when thrown */
+ if (iflags.returning_missile) { /* Mjollnir or aklys */
if (rn2(100)) {
- sho_obj_return_to_u(obj); /* display its flight */
+ if (tethered_weapon)
+ tmp_at(DISP_END, BACKTRACK);
+ else
+ sho_obj_return_to_u(obj); /* display its flight */
if (!impaired && rn2(100)) {
/*JP
- pline("%s to your hand!", Tobjnam(obj, "return"));
+ pline("%s to your hand!", Tobjnam(obj, "return"));
*/
- pline("%s\82Í\82 \82È\82½\82Ì\8eè\82É\96ß\82Á\82Ä\82«\82½\81I", xname(obj));
+ pline("%s\82Í\82 \82È\82½\82Ì\8eè\82É\96ß\82Á\82Ä\82«\82½\81I", xname(obj));
obj = addinv(obj);
(void) encumber_msg();
/* addinv autoquivers an aklys if quiver is empty;
}
#endif
}
- if (ship_object(obj, u.ux, u.uy, FALSE)) {
- thrownobj = (struct obj *) 0;
- return;
- }
- dropy(obj);
+
+ if (u.uswallow)
+ goto swallowit;
+ if (!ship_object(obj, u.ux, u.uy, FALSE))
+ dropy(obj);
}
- thrownobj = (struct obj *) 0;
- return;
+ clear_thrownobj = TRUE;
+ goto throwit_return;
} else {
+ if (tethered_weapon)
+ tmp_at(DISP_END, 0);
/* when this location is stepped on, the weapon will be
auto-picked up due to 'obj->was_thrown' of 1;
addinv() prevents thrown Mjollnir from being placed
pline("%s to return!", Tobjnam(obj, "fail"));
*/
pline("%s\82Í\96ß\82é\82Ì\82É\8e¸\94s\82µ\82½\81I", xname(obj));
+
+ if (u.uswallow)
+ goto swallowit;
/* continue below with placing 'obj' at target location */
}
}
- if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) && breaktest(obj)) {
- tmp_at(DISP_FLASH, obj_to_glyph(obj));
+ if ((!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) && breaktest(obj))
+ /* venom [via #monster to spit while poly'd] fails breaktest()
+ but we want to force breakage even when location IS_SOFT() */
+ || obj->oclass == VENOM_CLASS) {
+ tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng));
tmp_at(bhitpos.x, bhitpos.y);
delay_output();
tmp_at(DISP_END, 0);
breakmsg(obj, cansee(bhitpos.x, bhitpos.y));
breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE);
- thrownobj = (struct obj *) 0;
- return;
+ clear_thrownobj = TRUE;
+ goto throwit_return;
}
/*JP
if (flooreffects(obj, bhitpos.x, bhitpos.y, "fall")) {
*/
if (flooreffects(obj,bhitpos.x, bhitpos.y, "\97\8e\82¿\82é")) {
- thrownobj = (struct obj *) 0;
- return;
+ clear_thrownobj = TRUE;
+ goto throwit_return;
}
obj_no_longer_held(obj);
if (mon && mon->isshk && is_pick(obj)) {
if (*u.ushops || obj->unpaid)
check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE);
(void) mpickobj(mon, obj); /* may merge and free obj */
- thrownobj = (struct obj *) 0;
- return;
+ clear_thrownobj = TRUE;
+ goto throwit_return;
}
(void) snuff_candle(obj);
if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) {
- thrownobj = (struct obj *) 0;
- return;
+ clear_thrownobj = TRUE;
+ goto throwit_return;
}
thrownobj = (struct obj *) 0;
place_object(obj, bhitpos.x, bhitpos.y);
if (obj_sheds_light(obj))
vision_full_recalc = 1;
}
+
+ throwit_return:
+ iflags.returning_missile = (genericptr_t) 0;
+ if (clear_thrownobj)
+ thrownobj = (struct obj *) 0;
+ return;
}
-/* an object may hit a monster; various factors adjust the chance of hitting
- */
+/* an object may hit a monster; various factors adjust chance of hitting */
int
omon_adj(mon, obj, mon_notices)
struct monst *mon;
An attentive player will still notice that this is different from
an arrow just landing short of any target (no message in that case),
so will realize that there is a valid target here anyway. */
- if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER))
+ if (!canseemon(mon) || (M_AP_TYPE(mon) && M_AP_TYPE(mon) != M_AP_MONSTER))
/*JP
pline("%s %s.", The(missile), otense(obj, "miss"));
*/
* No bonuses for fleeing or stunned targets (they don't dodge
* melee blows as readily, but dodging arrows is hard anyway).
* Not affected by traps, etc.
- * Certain items which don't in themselves do damage ignore tmp.
+ * Certain items which don't in themselves do damage ignore 'tmp'.
* Distance and monster size affect chance to hit.
*/
tmp = -1 + Luck + find_mac(mon) + u.uhitinc
boolean next2u = monnear(mon, u.ux, u.uy);
finish_quest(obj); /* acknowledge quest completion */
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s %s %s back to you.", Monnam(mon),
(next2u ? "hands" : "tosses"), the(xname(obj)));
#else
}
if (tmp >= dieroll) {
- boolean wasthrown = (thrownobj != 0);
+ boolean wasthrown = (thrownobj != 0),
+ /* remember weapon attribute; hmon() might destroy obj */
+ chopper = is_axe(obj);
/* attack hits mon */
if (hmode == HMON_APPLIED)
u.uconduct.weaphit++;
if (hmon(mon, obj, hmode, dieroll)) { /* mon still alive */
- cutworm(mon, bhitpos.x, bhitpos.y, obj);
+ if (mon->wormno)
+ cutworm(mon, bhitpos.x, bhitpos.y, chopper);
}
exercise(A_DEX, TRUE);
/* if hero was swallowed and projectile killed the engulfer,
if (wasthrown && !thrownobj)
return 1;
- /* projectiles other than magic stones
- sometimes disappear when thrown */
+ /* projectiles other than magic stones sometimes disappear
+ when thrown; projectiles aren't among the types of weapon
+ that hmon() might have destroyed so obj is intact */
if (objects[otyp].oc_skill < P_NONE
&& objects[otyp].oc_skill > -P_BOOMERANG
&& !objects[otyp].oc_magic) {
}
}
}
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s into %s %s.", Tobjnam(obj, "vanish"),
s_suffix(mon_nam(mon)),
is_animal(u.ustuck->data) ? "entrails" : "currents");
(void) mpickobj(mon, obj); /* may merge and free obj */
ret = 1;
-nopick:
+ nopick:
if (!Blind)
pline1(buf);
if (!tele_restrict(mon))
boolean from_invent; /* thrown or dropped by player; maybe on shop bill */
{
boolean in_view = Blind ? FALSE : (from_invent || cansee(x, y));
+
if (!breaktest(obj))
return 0;
breakmsg(obj, in_view);
&& (mtmp = makemon(&mons[rn2(3) ? PM_HOMUNCULUS : PM_IMP], x, y,
NO_MM_FLAGS)) != 0) {
if (canspotmon(mtmp))
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline("%s is released!", Hallucination
? An(rndmonnam(NULL))
: "The picture-painting demon");
*/
You("\96ò\82Á\82Û\82¢\93õ\82¢\82ª\82µ\82½\81D\81D\81D");
} else {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
const char *eyes = body_part(EYE);
if (eyecount(youmonst.data) != 1)
}
freeinv(obj);
if (u.uswallow) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline(is_animal(u.ustuck->data) ? "%s in the %s's entrails."
: "%s into %s.",
"The money disappears", mon_nam(u.ustuck));
if (u.dz) {
if (u.dz < 0 && !Is_airlevel(&u.uz) && !Underwater
&& !Is_waterlevel(&u.uz)) {
-#if 0 /*JP*/
+#if 0 /*JP:T*/
pline_The("gold hits the %s, then falls back on top of your %s.",
ceiling(u.ux, u.uy), body_part(HEAD));
#else