Skip to content

Commit

Permalink
mirror fixes (trunk only)
Browse files Browse the repository at this point in the history
     From some notes I made prior to release of 3.4.3, about applying a
carried mirror in the direction of a monster:

 invisible player applying mirror toward monster which can't see invisible
   should have no effect (monster can't see hero's equipment);
 similarly when inside engulfer regardless of whether it can see invisible;
 applying mirror at worm tail shouldn't work but does;
 applying mirror toward unseen monster that can see invisible (so should be
   able to see its own image) doesn't work because bhit() won't target it;
 mirror shouldn't work when target is only visible via infravision.

The fourth one is iffy since it assumes that invisible monsters produce
invisible reflections rather than no reflections.  The reverse of that is
probably more reasonable but isn't as interesting.  The fifth one may be
contradictory; it fails to extend that logic to "infravisible monsters
produce infravisible reflections."
  • Loading branch information
nethack.rankin committed May 12, 2007
1 parent 24f3e00 commit 5ca566f
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 57 deletions.
1 change: 1 addition & 0 deletions doc/fixes35.0
Expand Up @@ -228,6 +228,7 @@ eliminate case-sensitivity when converting words from singular to plural and
vice versa, so some failing wishes like "Gauntlets of Power" now work
breath attack directed at self by poly'd hero always hits
override non-silver vs shades for artifacts which deal extra damage to undead
assorted mirror fixes--mainly visibility issues


Platform- and/or Interface-Specific Fixes
Expand Down
85 changes: 53 additions & 32 deletions src/apply.c
Expand Up @@ -4,6 +4,8 @@

#include "hack.h"

extern boolean notonhead; /* for long worms */

static const char tools[] = { TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 };
static const char tools_too[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS,
WEAPON_CLASS, WAND_CLASS, GEM_CLASS, 0 };
Expand Down Expand Up @@ -717,20 +719,30 @@ STATIC_OVL int
use_mirror(obj)
struct obj *obj;
{
const char *mirror;
const char *mirror, *uvisage;
struct monst *mtmp;
unsigned how_seen;
char mlet;
boolean vis;
boolean vis, invis_mirror, useeit, monable;

if(!getdir((char *)0)) return 0;
invis_mirror = Invis;
#ifdef INVISIBLE_OBJECTS
if (obj->oinvis) invis_mirror = TRUE;
#endif
useeit = !Blind && (!invis_mirror || See_invisible);
uvisage = (ACURR(A_CHA) > 14) ?
(poly_gender() == 1 ? "beautiful" : "handsome") : "ugly";
mirror = simpleonames(obj); /* "mirror" or "looking glass" */
if(obj->cursed && !rn2(2)) {
if (!Blind)
pline_The("%s fogs up and doesn't reflect!", mirror);
return 1;
}
if(!u.dx && !u.dy && !u.dz) {
if(!Blind && !Invisible) {
if (!useeit) {
You_cant("see your %s %s.", uvisage, body_part(FACE));
} else {
if (u.umonnum == PM_FLOATING_EYE) {
if (Free_action) {
You("stiffen momentarily under your gaze.");
Expand All @@ -753,32 +765,26 @@ struct obj *obj;
You(look_str, "peaked");
else if (u.uhs >= WEAK)
You(look_str, "undernourished");
else You("look as %s as ever.",
ACURR(A_CHA) > 14 ?
(poly_gender()==1 ? "beautiful" : "handsome") :
"ugly");
} else {
You_cant("see your %s %s.",
ACURR(A_CHA) > 14 ?
(poly_gender()==1 ? "beautiful" : "handsome") :
"ugly",
body_part(FACE));
else
You("look as %s as ever.", uvisage);
}
return 1;
}
if(u.uswallow) {
if (!Blind) You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)),
mbodypart(u.ustuck, STOMACH));
if (useeit)
You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)),
mbodypart(u.ustuck, STOMACH));
return 1;
}
if(Underwater) {
You(Hallucination ?
"give the fish a chance to fix their makeup." :
"reflect the murky water.");
if (useeit)
You(Hallucination ?
"give the fish a chance to fix their makeup." :
"reflect the murky water.");
return 1;
}
if(u.dz) {
if (!Blind)
if (useeit)
You("reflect the %s.",
(u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy));
return 1;
Expand All @@ -787,10 +793,18 @@ struct obj *obj;
(int FDECL((*),(MONST_P,OBJ_P)))0,
(int FDECL((*),(OBJ_P,OBJ_P)))0,
&obj);
if (!mtmp || !haseyes(mtmp->data))
if (!mtmp || !haseyes(mtmp->data) || notonhead)
return 1;

/* couldsee(mtmp->mx, mtmp->my) is implied by the fact that bhit()
targetted it, so we can ignore possibility of X-ray vision */
vis = canseemon(mtmp);
/* ways to directly see monster (excludes X-ray vision, telepathy,
extended detection, type-specific warning) */
#define SEENMON (MONSEEN_NORMAL | MONSEEN_SEEINVIS | MONSEEN_INFRAVIS)
how_seen = vis ? howmonseen(mtmp) : 0;
/* whether monster is able to use its vision-based capabilities */
monable = !mtmp->mcan && (!mtmp->minvis || perceives(mtmp->data));
mlet = mtmp->data->mlet;
if (mtmp->msleeping) {
if (vis)
Expand All @@ -799,33 +813,39 @@ struct obj *obj;
} else if (!mtmp->mcansee) {
if (vis)
pline("%s can't see anything right now.", Monnam(mtmp));
} else if (invis_mirror && !perceives(mtmp->data)) {
if (vis)
pline("%s fails to notice your %s.", Monnam(mtmp), mirror);
/* infravision doesn't produce an image in the mirror */
} else if ((how_seen & SEENMON) == MONSEEN_INFRAVIS) {
if (vis) /* (redundant) */
pline("%s is too far away to see %sself in the dark.",
Monnam(mtmp), mhim(mtmp));
/* some monsters do special things */
} else if (mlet == S_VAMPIRE || mlet == S_GHOST || is_vampshifter(mtmp)) {
} else if (mlet == S_VAMPIRE || mlet == S_GHOST ||
is_vampshifter(mtmp)) {
if (vis)
pline("%s doesn't have a reflection.", Monnam(mtmp));
} else if(!mtmp->mcan && !mtmp->minvis &&
mtmp->data == &mons[PM_MEDUSA]) {
} else if (monable && mtmp->data == &mons[PM_MEDUSA]) {
if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!"))
return 1;
if (vis)
pline("%s is turned to stone!", Monnam(mtmp));
stoned = TRUE;
killed(mtmp);
} else if(!mtmp->mcan && !mtmp->minvis &&
mtmp->data == &mons[PM_FLOATING_EYE]) {
} else if (monable && mtmp->data == &mons[PM_FLOATING_EYE]) {
int tmp = d((int)mtmp->m_lev, (int)mtmp->data->mattk[0].damd);
if (!rn2(4)) tmp = 120;
if (vis)
pline("%s is frozen by its reflection.", Monnam(mtmp));
else
You_hear("%s stop moving.", something);
paralyze_monst(mtmp, (int)mtmp->mfrozen + tmp);
} else if(!mtmp->mcan && !mtmp->minvis &&
mtmp->data == &mons[PM_UMBER_HULK]) {
} else if (monable && mtmp->data == &mons[PM_UMBER_HULK]) {
if (vis)
pline("%s confuses itself!", Monnam(mtmp));
mtmp->mconf = 1;
} else if (!mtmp->mcan && !mtmp->minvis &&
} else if (monable &&
(mlet == S_NYMPH ||
mtmp->data == &mons[PM_SUCCUBUS] ||
mtmp->data == &mons[PM_INCUBUS])) {
Expand All @@ -849,10 +869,11 @@ struct obj *obj;
} else if (!Blind) {
if (mtmp->minvis && !See_invisible)
;
else if ((mtmp->minvis && !perceives(mtmp->data))
|| !haseyes(mtmp->data))
pline("%s doesn't seem to notice its reflection.",
Monnam(mtmp));
else if ((mtmp->minvis && !perceives(mtmp->data)) ||
/* redundant: can't get here if these are true */
!haseyes(mtmp->data) || notonhead || !mtmp->mcansee)
pline("%s doesn't seem to notice %s reflection.",
Monnam(mtmp), mhis(mtmp));
else
pline("%s ignores %s reflection.",
Monnam(mtmp), mhis(mtmp));
Expand Down
52 changes: 27 additions & 25 deletions src/zap.c
Expand Up @@ -2994,37 +2994,39 @@ struct obj **pobj; /* object tossed/used, set to NULL
if (mtmp && !(in_skip && M_IN_WATER(mtmp->data))) {
notonhead = (bhitpos.x != mtmp->mx ||
bhitpos.y != mtmp->my);
if (weapon != FLASHED_LIGHT) {
if(weapon != ZAPPED_WAND) {
if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) {
if (weapon != INVIS_BEAM) {
map_invisible(bhitpos.x, bhitpos.y);
return(mtmp);
}
} else
return(mtmp);
}
if (weapon != INVIS_BEAM) {
(*fhitm)(mtmp, obj);
range -= 3;
}
} else {
/* FLASHED_LIGHT hitting invisible monster
should pass through instead of stop so
we call flash_hits_mon() directly rather
than returning mtmp back to caller. That
allows the flash to keep on going. Note
that we use mtmp->minvis not canspotmon()
because it makes no difference whether
the hero can see the monster or not.*/
if (weapon == FLASHED_LIGHT) {
/* FLASHED_LIGHT hitting invisible monster should
pass through instead of stop so we call
flash_hits_mon() directly rather than returning
mtmp back to caller. That allows the flash to
keep on going. Note that we use mtmp->minvis
not canspotmon() because it makes no difference
whether the hero can see the monster or not. */
if (mtmp->minvis) {
obj->ox = u.ux, obj->oy = u.uy;
(void) flash_hits_mon(mtmp, obj);
} else {
tmp_at(DISP_END, 0);
return(mtmp); /* caller will call flash_hits_mon */
return mtmp; /* caller will call flash_hits_mon */
}
} else if (weapon == INVIS_BEAM) {
/* Like FLASHED_LIGHT, INVIS_BEAM should continue
through invisible targets; unlike it, we aren't
prepared for multiple hits so just get first one
that's either visible or could see its invisible
self. [No tmp_at() cleanup is needed here.] */
if (!mtmp->minvis || perceives(mtmp->data))
return mtmp;
} else if (weapon != ZAPPED_WAND) {
/* THROWN_WEAPON, KICKED_WEAPON */
tmp_at(DISP_END, 0);
if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp))
map_invisible(bhitpos.x, bhitpos.y);
return mtmp;
} else {
/* ZAPPED_WAND */
(*fhitm)(mtmp, obj);
range -= 3;
}
} else {
if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING &&
Expand Down

0 comments on commit 5ca566f

Please sign in to comment.