Accessibility: Show a message when monster is spotted

Adds a new boolean option, spot_monsters.  If on, every time
the hero notices a monster which was out of sight before,
a message is given.  Combine with accessiblemsg to get the
monster location:

(3north): You see a newt.

Breaks saves and bones.
This commit is contained in:
Pasi Kallinen
2024-01-14 13:28:52 +02:00
parent 627b40fb57
commit 3160112ece
13 changed files with 119 additions and 1 deletions

View File

@@ -4650,6 +4650,8 @@ Allow sounds to be emitted from an integrated sound library (default on).
Display a sparkly effect when a monster (including yourself) is hit by an
attack to which it is resistant (default on).
Persistent.
.lp spot_monsters
Show a message when hero notices a monster (default is off).
.lp standout
Boldface monsters and \(lq\fB\-\-More\-\-\fP\(rq (default off).
Persistent.
@@ -5938,6 +5940,8 @@ Rogue-like commands.
Prevent walking into water or lava.
.lp accessiblemsg
Adds direction or location information to messages.
.lp spot_monsters
Shows a message when hero notices a monster; combine with accessiblemsg.
.lp autodescribe
Automatically describe the terrain under the cursor when targeting.
.lp mention_walls

View File

@@ -5092,6 +5092,9 @@ Allow sounds to be emitted from an integrated sound library (default on).
Display a sparkly effect when a monster (including yourself) is hit by an
attack to which it is resistant (default on). Persistent.
%.lp
\item[\ib{spot\verb+_+monsters}]
Show a message when hero notices a monster (default is off).
%.lp
\item[\ib{standout}]
Boldface monsters and ``{\tt --More--}'' (default off). Persistent.
%.lp
@@ -6535,6 +6538,9 @@ Prevent walking into water or lava.
\item[\ib{accessiblemsg}]
Adds direction or location information to messages.
%.lp
\item[\ib{spot\verb+_+monsters}]
Shows a message when hero notices a monster; combine with accessiblemsg.
%.lp
\item[\ib{autodescribe}]
Automatically describe the terrain under the cursor when targeting.
%.lp

View File

@@ -1074,6 +1074,8 @@ extern boolean test_move(coordxy, coordxy, coordxy, coordxy, int);
extern int wiz_debug_cmd_traveldisplay(void);
#endif
extern boolean u_rooted(void);
extern void notice_mon(struct monst *) NONNULLARG1;
extern void notice_all_mons(boolean);
extern void impact_disturbs_zombies(struct obj *, boolean) NONNULLARG1;
extern void disturb_buried_zombies(coordxy, coordxy);
extern boolean u_maybe_impaired(void);

View File

@@ -191,8 +191,20 @@ struct debug_flags {
struct accessibility_data {
boolean accessiblemsg; /* use msg_loc for plined messages */
coord msg_loc; /* accessiblemsg: location */
boolean mon_notices; /* msg when hero notices a monster */
int mon_notices_blocked; /* temp disable mon_notices */
};
/* Use notice_mon_off() / notice_mon_on() to temporarily disable
noticing the monsters in the vision code - perhaps the game
needs to output some other messages in between.
Call notice_all_mons() afterwards to catch up. */
#define notice_mon_off() do { a11y.mon_notices_blocked++; } while(0)
#define notice_mon_on() do { if (--a11y.mon_notices_blocked < 0) { \
impossible("mon_notices_blocked<0"); \
a11y.mon_notices_blocked = 0; \
} } while(0)
/*
* Stuff that really isn't option or platform related and does not
* get saved and restored. They are set and cleared during the game

View File

@@ -160,6 +160,8 @@ struct monst {
Bitfield(mtemplit, 1); /* temporarily seen; only valid during bhit() */
Bitfield(meverseen, 1); /* mon has been seen at some point */
Bitfield(mspotted, 1); /* mon is currently seen by hero */
#define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */
unsigned long mstrategy; /* for monsters with mflag3: current strategy */

View File

@@ -654,6 +654,9 @@ static int optfn_##a(int, int, boolean, char *, char *);
NHOPTB(sparkle, Map, 0, opt_out, set_in_game,
On, Yes, No, No, NoAlias, &flags.sparkle, Term_False,
"display sparkly effect when resisting magic")
NHOPTB(spot_monsters, Advanced, 0, opt_in, set_in_game,
Off, Yes, No, No, NoAlias, &a11y.mon_notices, Term_False,
"message when hero spots a monster")
NHOPTB(splash_screen, Advanced, 0, opt_out, set_in_config,
On, Yes, No, No, NoAlias, &iflags.wc_splash_screen, Term_False,
(char *)0)

View File

@@ -17,7 +17,7 @@
* Incrementing EDITLEVEL can be used to force invalidation of old bones
* and save files.
*/
#define EDITLEVEL 96
#define EDITLEVEL 97
/*
* Development status possibilities.

View File

@@ -705,6 +705,8 @@ newgame(void)
{
int i;
/* make sure welcome messages are given before noticing monsters */
notice_mon_off();
disp.botlx = TRUE;
gc.context.ident = 1;
gc.context.warnlevel = 1;
@@ -765,6 +767,8 @@ newgame(void)
/* Success! */
welcome(TRUE);
notice_mon_on(); /* now we can notice monsters */
notice_all_mons(TRUE);
return;
}

View File

@@ -1807,6 +1807,7 @@ goto_level(
/* Reset the screen. */
vision_reset(); /* reset the blockages */
reset_glyphmap(gm_levelchange);
notice_mon_off(); /* not noticing monsters yet! */
docrt(); /* does a full vision recalc */
flush_screen(-1);
@@ -1923,6 +1924,8 @@ goto_level(
#ifdef INSURANCE
save_currentstate();
#endif
notice_mon_on();
notice_all_mons(TRUE);
print_level_annotation();
/* give room entrance message, if any */

View File

@@ -12,6 +12,7 @@ static int moverock(void);
static void dosinkfall(void);
static boolean findtravelpath(int);
static boolean trapmove(coordxy, coordxy, struct trap *);
static int QSORTCALLBACK notice_mons_cmp(const genericptr, const genericptr);
static schar u_simple_floortyp(coordxy, coordxy);
static boolean swim_move_danger(coordxy, coordxy);
static boolean domove_bump_mon(struct monst *, int) NONNULLARG1;
@@ -1601,6 +1602,80 @@ u_rooted(void)
return FALSE;
}
void
notice_mon(struct monst *mtmp)
{
if (a11y.mon_notices && !a11y.mon_notices_blocked) {
boolean spot = canspotmon(mtmp)
&& !(is_hider(mtmp->data)
&& (mtmp->mundetected
|| M_AP_TYPE(mtmp) == M_AP_FURNITURE
|| M_AP_TYPE(mtmp) == M_AP_OBJECT));
if (spot && !mtmp->mspotted && !DEADMONSTER(mtmp)) {
mtmp->mspotted = TRUE;
set_msg_xy(mtmp->mx, mtmp->my);
You("%s %s.", canseemon(mtmp) ? "see" : "notice",
x_monnam(mtmp,
mtmp->mtame ? ARTICLE_YOUR
: (!has_mgivenname(mtmp)
&& !type_is_pname(mtmp->data)) ? ARTICLE_A
: ARTICLE_NONE,
(mtmp->mpeaceful && !mtmp->mtame) ? "peaceful" : 0,
has_mgivenname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE));
} else if (!spot) {
mtmp->mspotted = FALSE;
}
}
}
static int QSORTCALLBACK
notice_mons_cmp(const genericptr ptr1, const genericptr ptr2)
{
const struct monst *m1 = *(const struct monst **) ptr1,
*m2 = *(const struct monst **) ptr2;
return (distu(m1->mx, m1->my) - distu(m2->mx, m2->my));
}
void
notice_all_mons(boolean reset)
{
if (a11y.mon_notices && !a11y.mon_notices_blocked) {
struct monst *mtmp;
struct monst **arr = NULL;
int i = 0, cnt = 0;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if (canspotmon(mtmp))
cnt++;
else if (reset)
mtmp->mspotted = FALSE;
if (!cnt)
return;
arr = (struct monst **) alloc(cnt * sizeof(struct monst *));
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (!canspotmon(mtmp))
mtmp->mspotted = FALSE;
else if (!DEADMONSTER(mtmp) && i < cnt)
arr[i++] = mtmp;
}
if (i) {
qsort((genericptr_t) arr, (size_t) i, sizeof *arr, notice_mons_cmp);
for (i = 0; i < cnt; i++)
notice_mon(arr[i]);
}
free(arr);
}
}
/* maybe disturb buried zombies when an object is dropped or thrown nearby */
void
impact_disturbs_zombies(struct obj *obj, boolean violent)

View File

@@ -1307,6 +1307,8 @@ postmov(
boolean canseeit = cansee(mtmp->mx, mtmp->my),
didseeit = canseeit;
notice_mon(mtmp);
if (mmoved == MMOVE_MOVED) {
nix = mtmp->mx, niy = mtmp->my;
/* sequencing issue: when monster movement decides that a

View File

@@ -513,6 +513,7 @@ teleds(coordxy nux, coordxy nuy, int teleds_flags)
see_monsters();
gv.vision_full_recalc = 1;
nomul(0);
notice_mon_off();
vision_recalc(0); /* vision before effects */
/* this used to take place sooner, but if a --More-- prompt was issued
@@ -542,6 +543,8 @@ teleds(coordxy nux, coordxy nuy, int teleds_flags)
/* possible shop entry message comes after guard's shrill whistle */
spoteffects(TRUE);
invocation_message();
notice_mon_on();
notice_all_mons(TRUE);
return;
}

View File

@@ -837,6 +837,8 @@ vision_recalc(int control)
/* Set the new min and max pointers. */
gv.viz_rmin = next_rmin;
gv.viz_rmax = next_rmax;
notice_all_mons(TRUE);
}
/*