diff --git a/include/extern.h b/include/extern.h index d8e794276..462bbb821 100644 --- a/include/extern.h +++ b/include/extern.h @@ -652,7 +652,7 @@ E void FDECL(cant_reach_floor, (int,int,BOOLEAN_P,BOOLEAN_P)); E const char *FDECL(surface, (int,int)); E const char *FDECL(ceiling, (int,int)); E struct engr *FDECL(engr_at, (XCHAR_P,XCHAR_P)); -E int FDECL(sengr_at, (const char *,XCHAR_P,XCHAR_P)); +E int FDECL(sengr_at, (const char *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E void FDECL(u_wipe_engr, (int)); E void FDECL(wipe_engr_at, (XCHAR_P,XCHAR_P,XCHAR_P)); E void FDECL(read_engr_at, (int,int)); diff --git a/src/engrave.c b/src/engrave.c index 5a8aa38f3..47e2b5af0 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -220,16 +220,24 @@ xchar x, y; /* Decide whether a particular string is engraved at a specified * location; a case-insensitive substring match used. * Ignore headstones, in case the player names herself "Elbereth". + * + * If strict checking is requested, the word is only considered to be + * present if it is intact and is the first word in the engraving. + * ("Elbereth burrito" matches; "o Elbereth" does not.) */ int -sengr_at(s, x, y) +sengr_at(s, x, y, strict) const char *s; xchar x, y; + boolean strict; { register struct engr *ep = engr_at(x,y); - return (ep && ep->engr_type != HEADSTONE && - ep->engr_time <= moves && strstri(ep->engr_txt, s) != 0); + if (ep && ep->engr_type != HEADSTONE && ep->engr_time <= moves) { + return strict ? (strncmpi(ep->engr_txt, s, strlen(s)) == 0) : + (strstri(ep->engr_txt, s) != 0); + } + return FALSE; } void diff --git a/src/monmove.c b/src/monmove.c index a7a3ca46f..82679886f 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -113,17 +113,42 @@ onscary(x, y, mtmp) int x, y; struct monst *mtmp; { - if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee || - mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN || - is_lminion(mtmp) || mtmp->data == &mons[PM_ANGEL] || - is_rider(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR]) - return(FALSE); + boolean epresent = sengr_at("Elbereth", x, y, TRUE); + + /* creatures who are directly resistant to magical scaring: + * Rodney, lawful minions, angels, the Riders + */ + if (mtmp->iswiz || is_lminion(mtmp) + || mtmp->data == &mons[PM_ANGEL] + || is_rider(mtmp->data)) + return(FALSE); - return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y) || - sengr_at("Elbereth", x, y) || - (IS_ALTAR(levl[x][y].typ) && - (mtmp->data->mlet == S_VAMPIRE || - is_vampshifter(mtmp)))); + /* creatures who don't (or can't) fear a written Elbereth: + * all the above plus shopkeepers, guards, blind or + * peaceful monsters, humans, and minotaurs. + * + * Elbereth doesn't work in Gehennom, the Elemental Planes, or the + * Astral Plane; the influence of the Valar only reaches so far. + */ + if (epresent && (mtmp->isshk || mtmp->isgd || !mtmp->mcansee + || mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN + || mtmp->data == &mons[PM_MINOTAUR] + || Inhell || In_endgame(&u.uz))) + return(FALSE); + + /* should this still be true for defiled/molochian altars? */ + if (IS_ALTAR(levl[x][y].typ) && (mtmp->data->mlet == S_VAMPIRE + || is_vampshifter(mtmp))) + return(TRUE); + + /* if the player isn't actually on the square OR the player's image + * isn't displaced to the square, no protection is being granted + * + * the scare monster scroll, though, is quite powerful. + */ + return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y) + || (epresent && ((u.ux == x && u.uy == y) + || (Displaced && mtmp->mux == x && mtmp->muy == y)))); } /* regenerate lost hit points */