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;
+ g.bhitpos.x = mon->mx;
+ g.bhitpos.y = mon->my;
if (tethered_weapon)
tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng));
} else if (u.dz) {
goto throwit_return; /* alert shk caught it */
}
(void) snuff_candle(obj);
- notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my);
+ g.notonhead = (g.bhitpos.x != mon->mx || g.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);
+ mon = m_at(g.bhitpos.x, g.bhitpos.y);
/* [perhaps this should be moved into thitmonst or hmon] */
if (mon && mon->isshk
{
const char *fmt;
char buf[BUFSZ];
- showit |= vis;
+ boolean showit = FALSE;
+
+ /* unhiding or unmimicking happens even if hero can't see it
+ because the formerly concealed monster is now in action */
+ if (M_AP_TYPE(mdef)) {
+ seemimic(mdef);
- showit |= vis;
++ showit |= g.vis;
+ } else if (mdef->mundetected) {
+ mdef->mundetected = 0;
- showit |= vis;
++ showit |= g.vis;
+ }
+ if (M_AP_TYPE(magr)) {
+ seemimic(magr);
- showit |= vis;
++ showit |= g.vis;
+ } else if (magr->mundetected) {
+ magr->mundetected = 0;
++ showit |= g.vis;
+ }
- if (vis) {
+ if (g.vis) {
if (!canspotmon(magr))
map_invisible(magr->mx, magr->my);
+ else if (showit)
+ newsym(magr->mx, magr->my);
if (!canspotmon(mdef))
map_invisible(mdef->mx, mdef->my);
- if (M_AP_TYPE(mdef))
- seemimic(mdef);
- if (M_AP_TYPE(magr))
- seemimic(magr);
+ else if (showit)
+ newsym(mdef->mx, mdef->my);
+
fmt = (could_seduce(magr, mdef, mattk) && !magr->mcan)
? "%s pretends to be friendly to"
: "%s misses";
res[i] = hitmm(magr, mdef, mattk);
if ((mdef->data == &mons[PM_BLACK_PUDDING]
|| mdef->data == &mons[PM_BROWN_PUDDING])
- && (otmp && (objects[otmp->otyp].oc_material == IRON
- || objects[otmp->otyp].oc_material == METAL))
+ && (g.otmp && (objects[g.otmp->otyp].oc_material == IRON
+ || objects[g.otmp->otyp].oc_material == METAL))
- && mdef->mhp > 1
- && !mdef->mcan) {
+ && mdef->mhp > 1 && !mdef->mcan) {
struct monst *mclone;
+
if ((mclone = clone_mon(mdef, 0, 0)) != 0) {
- if (vis && canspotmon(mdef)) {
+ if (g.vis && canspotmon(mdef)) {
char buf[BUFSZ];
Strcpy(buf, Monnam(mdef));
break;
case AT_ENGL:
- if (vis)
+ if (mdef->data == &mons[PM_SHADE]) { /* no silver teeth... */
++ if (g.vis)
+ pline("%s attempt to engulf %s is futile.",
+ s_suffix(Monnam(magr)), mon_nam(mdef));
+ strike = 0;
+ break;
+ }
if (u.usteed && mdef == u.usteed) {
strike = 0;
break;
register struct monst *magr, *mdef;
struct attack *mattk;
{
- || (mattk->aatyp == AT_CLAW && otmp))),
- silverhit = (weaponhit && otmp
- && objects[otmp->otyp].oc_material == SILVER),
+ boolean weaponhit = ((mattk->aatyp == AT_WEAP
- showit |= vis;
++ || (mattk->aatyp == AT_CLAW && g.otmp))),
++ silverhit = (weaponhit && g.otmp
++ && objects[g.otmp->otyp].oc_material == SILVER),
+ showit = FALSE;
+
+ /* unhiding or unmimicking happens even if hero can't see it
+ because the formerly concealed monster is now in action */
+ if (M_AP_TYPE(mdef)) {
+ seemimic(mdef);
- showit |= vis;
++ showit |= g.vis;
+ } else if (mdef->mundetected) {
+ mdef->mundetected = 0;
- showit |= vis;
++ showit |= g.vis;
+ }
+ if (M_AP_TYPE(magr)) {
+ seemimic(magr);
- showit |= vis;
++ showit |= g.vis;
+ } else if (magr->mundetected) {
+ magr->mundetected = 0;
- if (vis) {
++ showit |= g.vis;
+ }
+
+ if (g.vis) {
int compat;
char buf[BUFSZ];
mdef->mcansee ? "smiles at" : "talks to");
pline("%s %s %s.", buf, mon_nam(mdef),
compat == 2 ? "engagingly" : "seductively");
- } else if (shade_miss(magr, mdef, otmp, FALSE, TRUE)) {
++ } else if (shade_miss(magr, mdef, g.otmp, FALSE, TRUE)) {
+ return MM_MISS; /* bypass mdamagem() */
} else {
char magr_name[BUFSZ];
Sprintf(buf, "%s hits", magr_name);
}
pline("%s %s.", buf, mon_nam_too(mdef, magr));
- simpleonames(otmp), mdef_name);
+
+ if (mon_hates_silver(mdef) && silverhit) {
+ char *mdef_name = mon_nam_too(mdef, magr);
+
+ /* note: mon_nam_too returns a modifiable buffer; so
+ does s_suffix, but it returns a single static buffer
+ and we might be calling it twice for this message */
+ Strcpy(magr_name, s_suffix(magr_name));
+ if (!noncorporeal(mdef->data) && !amorphous(mdef->data)) {
+ if (mdef != magr) {
+ mdef_name = s_suffix(mdef_name);
+ } else {
+ (void) strsubst(mdef_name, "himself", "his own");
+ (void) strsubst(mdef_name, "herself", "her own");
+ (void) strsubst(mdef_name, "itself", "its own");
+ }
+ Strcat(mdef_name, " flesh");
+ }
+
+ pline("%s %s sears %s!", magr_name, /*s_suffix(magr_name), */
++ simpleonames(g.otmp), mdef_name);
+ }
}
} else
noises(magr, mattk);
case AD_HEAL:
case AD_PHYS:
physical:
- if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
+ /* this shade check is necessary in case any attacks which
+ dish out physical damage bypass hitmm() to get here */
- if ((mattk->aatyp == AT_WEAP || mattk->aatyp == AT_CLAW) && otmp)
- dmgwep = *otmp;
++ if ((mattk->aatyp == AT_WEAP || mattk->aatyp == AT_CLAW) && g.otmp)
++ dmgwep = *g.otmp;
+ else
- dmgwep = zeroobj;
++ dmgwep = cg.zeroobj;
+
+ if (shade_miss(magr, mdef, &dmgwep, FALSE, TRUE)) {
+ tmp = 0;
+ } else if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
tmp = 0;
- } else if (mattk->aatyp == AT_WEAP) {
+ } else if (mattk->aatyp == AT_WEAP
- || (mattk->aatyp == AT_CLAW && otmp)) {
- if (otmp) {
++ || (mattk->aatyp == AT_CLAW && g.otmp)) {
+ if (g.otmp) {
struct obj *marmg;
- if (otmp->otyp == CORPSE
- && touch_petrifies(&mons[otmp->corpsenm]))
+ if (g.otmp->otyp == CORPSE
+ && touch_petrifies(&mons[g.otmp->corpsenm]))
goto do_stone;
- tmp += dmgval(otmp, mdef);
+
+ tmp += dmgval(g.otmp, mdef);
if ((marmg = which_armor(magr, W_ARMG)) != 0
&& marmg->otyp == GAUNTLETS_OF_POWER)
tmp += rn1(4, 3); /* 3..6 */
if (!u.uswallow) { /* swallows you */
int omx = mtmp->mx, omy = mtmp->my;
- if (!engulf_target(mtmp, &youmonst))
+ if (!engulf_target(mtmp, &g.youmonst))
return 0;
- if ((t && is_pit(t->ttyp))
- && sobj_at(BOULDER, u.ux, u.uy))
+ if ((t && is_pit(t->ttyp)) && sobj_at(BOULDER, u.ux, u.uy))
return 0;
if (Punished)
}
if (objects[otmp->otyp].oc_material == SILVER
&& mon_hates_silver(mtmp)) {
- if (vis)
- pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
- else if (verbose && !g.mtarget)
- pline("Its flesh is seared!");
+ boolean flesh = (!noncorporeal(mtmp->data)
+ && !amorphous(mtmp->data));
+
+ /* note: extra silver damage is handled by dmgval() */
+ if (vis) {
+ char *m_name = mon_nam(mtmp);
+
+ if (flesh) /* s_suffix returns a modifiable buffer */
+ m_name = strcat(s_suffix(m_name), " flesh");
+ pline_The("silver sears %s!", m_name);
- } else if (verbose && !target) {
++ } else if (verbose && !g.mtarget) {
+ pline("%s is seared!", flesh ? "Its flesh" : "It");
+ }
}
if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
if (resists_acid(mtmp)) {
if (sym)
tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng));
while (range-- > 0) { /* Actually the loop is always exited by break */
- bhitpos.x += dx;
- bhitpos.y += dy;
- mtmp = m_at(bhitpos.x, bhitpos.y);
+ g.bhitpos.x += dx;
+ g.bhitpos.y += dy;
- if ((mtmp = m_at(g.bhitpos.x, g.bhitpos.y)) != 0) {
++ mtmp = m_at(g.bhitpos.x, g.bhitpos.y);
+ if (mtmp && shade_miss(mon, mtmp, singleobj, TRUE, TRUE)) {
+ /* if mtmp is a shade and missile passes harmlessly through it,
+ give message and skip it in order to keep going */
+ mtmp = (struct monst *) 0;
+ } else if (mtmp) {
if (ohitmon(mtmp, singleobj, range, TRUE))
break;
- } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
- if (multi)
+ } else if (g.bhitpos.x == u.ux && g.bhitpos.y == u.uy) {
+ if (g.multi)
nomul(0);
if (singleobj->oclass == GEM_CLASS
poiskilled = TRUE;
}
if (tmp < 1) {
+ boolean mon_is_shade = (mon->data == &mons[PM_SHADE]);
+
/* make sure that negative damage adjustment can't result
in inadvertently boosting the victim's hit points */
- tmp = 0;
- if (mdat == &mons[PM_SHADE]) {
- if (!hittxt) {
- const char *what = *unconventional ? unconventional : "attack";
-
- Your("%s %s harmlessly through %s.", what,
- vtense(what, "pass"), mon_nam(mon));
- hittxt = TRUE;
- }
- } else {
- if (get_dmg_bonus)
- tmp = 1;
- }
+ tmp = (get_dmg_bonus && !mon_is_shade) ? 1 : 0;
+ if (mon_is_shade && !hittxt
+ && thrown != HMON_THROWN && thrown != HMON_KICKED)
- hittxt = shade_miss(&youmonst, mon, obj, FALSE, TRUE);
++ hittxt = shade_miss(&g.youmonst, mon, obj, FALSE, TRUE);
}
if (jousting) {
return FALSE;
}
- boolean youagr = (magr == &youmonst), youdef = (mdef == &youmonst);
+ /* used for hero vs monster and monster vs monster; also handles
+ monster vs hero but that won't happen because hero can't be a shade */
+ boolean
+ shade_miss(magr, mdef, obj, thrown, verbose)
+ struct monst *magr, *mdef;
+ struct obj *obj;
+ boolean thrown, verbose;
+ {
+ const char *what, *whose, *target;
- || (magr == &youmonst && distu(mdef->mx, mdef->my) <= 2))) {
++ boolean youagr = (magr == &g.youmonst), youdef = (mdef == &g.youmonst);
+
+ /* we're using dmgval() for zero/not-zero, not for actual damage amount */
+ if (mdef->data != &mons[PM_SHADE] || (obj && dmgval(obj, mdef)))
+ return FALSE;
+
+ if (verbose
+ && ((youdef || cansee(mdef->mx, mdef->my) || sensemon(mdef))
++ || (magr == &g.youmonst && distu(mdef->mx, mdef->my) <= 2))) {
+ static const char harmlessly_thru[] = " harmlessly through ";
+
+ what = (!obj || shade_aware(obj)) ? "attack" : cxname(obj);
+ target = youdef ? "you" : mon_nam(mdef);
+ if (!thrown) {
+ whose = youagr ? "Your" : s_suffix(Monnam(magr));
+ pline("%s %s %s%s%s.", whose, what,
+ vtense(what, "pass"), harmlessly_thru, target);
+ } else {
+ pline("%s %s%s%s.", The(what), /* note: not pline_The() */
+ vtense(what, "pass"), harmlessly_thru, target);
+ }
+ if (!youdef && !canspotmon(mdef))
+ map_invisible(mdef->mx, mdef->my);
+ }
+ if (!youdef)
+ mdef->msleeping = 0;
+ return TRUE;
+ }
+
/* check whether slippery clothing protects from hug or wrap attack */
/* [currently assumes that you are the attacker] */
-STATIC_OVL boolean
+static boolean
m_slips_free(mdef, mattk)
struct monst *mdef;
struct attack *mattk;
}
}
- if (mtmp && !(in_skip && M_IN_WATER(mtmp->data))) {
+ /* if mtmp is a shade and missile passes harmlessly through it,
+ give message and skip it in order to keep going */
+ if (mtmp && (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
- && shade_miss(&youmonst, mtmp, obj, TRUE, TRUE))
++ && shade_miss(&g.youmonst, mtmp, obj, TRUE, TRUE))
+ mtmp = (struct monst *) 0;
+
+ if (mtmp) {
- notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
+ g.notonhead = (g.bhitpos.x != mtmp->mx || g.bhitpos.y != mtmp->my);
if (weapon == FLASHED_LIGHT) {
/* FLASHED_LIGHT hitting invisible monster should
pass through instead of stop so we call