diff --git a/include/extern.h b/include/extern.h index 28c8c8c8b..6887b02d0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1773,6 +1773,7 @@ extern boolean defended(struct monst *, int) NONNULLARG1; extern boolean resists_drli(struct monst *) NONNULLARG1; extern boolean resists_magm(struct monst *) NONNULLARG1; extern boolean resists_blnd(struct monst *) NONNULLARG1; +extern boolean resists_blnd_by_arti(struct monst *) NONNULLARG1; extern boolean can_blnd(struct monst *, struct monst *, uchar, struct obj *) NONNULLARG2; extern boolean ranged_attk(struct permonst *) NONNULLARG1; @@ -3829,7 +3830,7 @@ extern int dozap(void); extern int zapyourself(struct obj *, boolean) NONNULLARG1; extern void ubreatheu(struct attack *) NONNULLARG1; extern int lightdamage(struct obj *, boolean, int) NONNULLARG1; -extern boolean flashburn(long); +extern boolean flashburn(long, boolean); extern boolean cancel_monst(struct monst *, struct obj *, boolean, boolean, boolean) NONNULLARG12; extern void zapsetup(void); diff --git a/src/artifact.c b/src/artifact.c index 40b46a44d..6764d8762 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -1942,7 +1942,8 @@ arti_invoke(struct obj *obj) if (vulnerable) /* could be fatal if Unchanging */ (void) lightdamage(obj, TRUE, 2 * damg); - if (!flashburn((long) (damg + rnd(damg))) && !vulnerable) + if (!flashburn((long) (damg + rnd(damg)), FALSE) + && !vulnerable) pline("%s", nothing_seems_to_happen); } } else { diff --git a/src/mcastu.c b/src/mcastu.c index f9b315c65..d686ced9d 100644 --- a/src/mcastu.c +++ b/src/mcastu.c @@ -688,7 +688,7 @@ cast_cleric_spell(struct monst *mtmp, int dmg, int spellnum) do this before maybe blinding the hero via flashburn() */ mon_spell_hits_spot(mtmp, AD_ELEC, u.ux, u.uy); /* blind hero; no effect if already blind */ - (void) flashburn((long) rnd(100)); + (void) flashburn((long) rnd(100), TRUE); break; } case CLC_CURSE_ITEMS: diff --git a/src/mondata.c b/src/mondata.c index 0b8136dcd..07a3259a3 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -170,14 +170,13 @@ resists_magm(struct monst *mon) return FALSE; } -/* True iff monster is resistant to light-induced blindness */ +/* True iff monster is resistant to light-induced blindness due to some + mundane reason (already blinded) */ boolean resists_blnd(struct monst *mon) { struct permonst *ptr = mon->data; boolean is_you = (mon == &gy.youmonst); - long slotmask; - struct obj *o; if (is_you ? (Blind || Unaware) : (mon->mblinded || !mon->mcansee || !haseyes(ptr) @@ -189,21 +188,32 @@ resists_blnd(struct monst *mon) if (dmgtype_fromattack(ptr, AD_BLND, AT_EXPL) || dmgtype_fromattack(ptr, AD_BLND, AT_GAZE)) return TRUE; + return resists_blnd_by_arti(mon); +} + +/* True iff monster is resistant to light-induced blindness due to worn + or wielded magical equipment (used to decide whether to show sparkle + animation when resisting) */ +boolean +resists_blnd_by_arti(struct monst *mon) +{ + struct obj *o; + boolean is_you = (mon == &gy.youmonst); + o = is_you ? uwep : MON_WEP(mon); if (o && o->oartifact && defends(AD_BLND, o)) return TRUE; o = is_you ? gi.invent : mon->minvent; - slotmask = W_ARMOR | W_ACCESSORY; - if (!is_you /* assumes monsters don't wield non-weapons */ - || (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)))) - slotmask |= W_WEP; - if (is_you && u.twoweap) - slotmask |= W_SWAPWEP; for (; o; o = o->nobj) - if (((o->owornmask & slotmask) != 0L - && objects[o->otyp].oc_oprop == BLINDED) - || (o->oartifact && defends_when_carried(AD_BLND, o))) + if (defends_when_carried(AD_BLND, o)) return TRUE; +#if 0 /* omit this; the Eyes of the Overworld have no carry property and + * their worn property is magic resistance rather than blindness + * resistance; wearing them blocks blindness without actually + * preventing it, so don't classify them as providing resistance */ + if (is_you && is_art(uamul, ART_EYES_OF_THE_OVERWORLD)) + return TRUE; +#endif /* 0 */ return FALSE; } diff --git a/src/uhitm.c b/src/uhitm.c index adf0cd0eb..7f33c8777 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -6097,17 +6097,17 @@ flash_hits_mon( struct obj *otmp) /* source of flash */ { struct rm *lev; + coordxy mx = mtmp->mx, my = mtmp->my; int tmp, amt, useeit, res = 0; if (gn.notonhead) return 0; - lev = &levl[mtmp->mx][mtmp->my]; + lev = &levl[mx][my]; useeit = canseemon(mtmp); if (M_AP_TYPE(mtmp) != M_AP_NOTHING) { char whatbuf[BUFSZ]; - coordxy x = mtmp->mx, y = mtmp->my; - int oldglyph = glyph_at(x, y); + int oldglyph = glyph_at(mx, my); /* 'altmon' probably doesn't matter here because 'whatbuf' will only be shown if the glyph changes and wakeup() doesn't call @@ -6118,13 +6118,14 @@ flash_hits_mon( * finish_meating() to end quickmimic */ /* if glyph has changed then hero saw something happen */ - if (glyph_at(x, y) != oldglyph) + if (glyph_at(mx, my) != oldglyph) { pline("That %s is really %s%c", whatbuf, /* y_monnam()+a_monnam() */ x_monnam(mtmp, mtmp->mtame ? ARTICLE_YOUR : ARTICLE_A, (char *) 0, 0, FALSE), mtmp->mtame ? '.' : '!'); - res = 1; /* mtmp is affected whether hero sees it or not */ + res = 1; + } } if (mtmp->msleeping && haseyes(mtmp->data)) { @@ -6135,15 +6136,15 @@ flash_hits_mon( } } else if (mtmp->data->mlet != S_LIGHT) { if (!resists_blnd(mtmp)) { - tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my); + tmp = dist2(otmp->ox, otmp->oy, mx, my); if (useeit) { pline("%s is blinded by the flash!", Monnam(mtmp)); res = 1; } if (mtmp->data == &mons[PM_GREMLIN]) { /* Rule #1: Keep them out of the light. */ - amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4) - : rn2(min(mtmp->mhp, 4)); + amt = (otmp->otyp == WAN_LIGHT) ? d(1 + otmp->spe, 4) + : rnd(min(mtmp->mhp, 4)); light_hits_gremlin(mtmp, amt); } if (!DEADMONSTER(mtmp)) { @@ -6154,12 +6155,16 @@ flash_hits_mon( mtmp->mcansee = 0; mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50 / tmp); } - } else if (flags.verbose && useeit) { - if (lev->lit) - pline("The flash of light shines on %s.", mon_nam(mtmp)); - else - pline("%s is illuminated.", Monnam(mtmp)); - res = 2; /* 'message has been given' temporary value */ + } else if (useeit) { + if (resists_blnd_by_arti(mtmp)) + shieldeff(mx, my); + if (flags.verbose) { + if (lev->lit) + pline("The flash of light shines on %s.", mon_nam(mtmp)); + else + pline("%s is illuminated.", Monnam(mtmp)); + res = 2; /* 'message has been given' temporary value */ + } } } if (res) { diff --git a/src/zap.c b/src/zap.c index 7e341c630..759f32e6b 100644 --- a/src/zap.c +++ b/src/zap.c @@ -2657,7 +2657,7 @@ zapyourself(struct obj *obj, boolean ordinary) ugolemeffects(AD_ELEC, orig_dmg); } (void) destroy_items(&gy.youmonst, AD_ELEC, orig_dmg); - (void) flashburn((long) rnd(100)); + (void) flashburn((long) rnd(100), TRUE); break; case SPE_FIREBALL: @@ -2836,7 +2836,7 @@ zapyourself(struct obj *obj, boolean ordinary) damage = 5; damage = lightdamage(obj, ordinary, damage); damage += rnd(25); - if (flashburn((long) damage)) + if (flashburn((long) damage, FALSE)) learn_it = TRUE; damage = 0; /* reset */ break; @@ -2971,7 +2971,7 @@ lightdamage( /* light[ning] causes blindness */ boolean -flashburn(long duration) +flashburn(long duration, boolean via_lightning) { if (!resists_blnd(&gy.youmonst)) { You(are_blinded_by_the_flash); @@ -2980,6 +2980,16 @@ flashburn(long duration) Your1(vision_clears); return TRUE; } + /* if blinding is resisted due to magical equipment (Sunsword), give + a sparkle animation (even if also resisted due to being blind) + _unless_ this is lightning-induced; we don't want a double sparkle + if hero is both lightning resistant and blindness resistant, or + worse, have a single sparkle where the player confuses blindness + resistance for lightning resistance */ + if (!via_lightning && resists_blnd_by_arti(&gy.youmonst)) { + shieldeff(u.ux, u.uy); + return TRUE; + } return FALSE; } @@ -4817,7 +4827,7 @@ dobuzz( Your("%s tingles.", body_part(ARM)); } if (damgtype == ZT_LIGHTNING) - (void) flashburn((long) d(nd, 50)); + (void) flashburn((long) d(nd, 50), TRUE); stop_occupation(); nomul(0); }