fix issue #339 - duplicate feature messages

while 'mention_decor' is enabled.  When stepping onto different
terrain and one or more objects remained on the new spot after
autopickup, describe_decor() was issuing its new-terrain message
right before look_here()'s similar under-the-objects message.  If
autopickup grabbed everything or there weren't any objects to begin
with, look_here() doesn't issue any dfeature (terrain) message.
describe_decor() isn't smart enought to know whether that is going
to happen.  Give look_here() a new flag argument so that its caller
can ask for the dfeature message to be skipped for the case where a
similar message has already been given.
This commit is contained in:
PatR
2020-04-27 04:25:26 -07:00
parent 42ffce0e5d
commit 09f9b3598f
6 changed files with 48 additions and 57 deletions
+2
View File
@@ -211,6 +211,8 @@ fix crash in water_damage_chain
teleport feedback "you materialize at another location" was given too soon teleport feedback "you materialize at another location" was given too soon
'mention_decore' was repeatedly reporting "you are back on bottom" when 'mention_decore' was repeatedly reporting "you are back on bottom" when
moving around underwater moving around underwater
revised 'mention_decor' was describing furniture or ice right before look-here
described the same thing when stepping onto object(s)
poison gas clouds located over known but unlit pools were visible as known poison gas clouds located over known but unlit pools were visible as known
clouds but steam clouds in that situation were not clouds but steam clouds in that situation were not
after the wish parsing change, wishing for "<something of monster>" or for after the wish parsing change, wishing for "<something of monster>" or for
+1 -1
View File
@@ -1075,7 +1075,7 @@ E struct obj *FDECL(display_cinventory, (struct obj *));
E struct obj *FDECL(display_minventory, (struct monst *, int, char *)); E struct obj *FDECL(display_minventory, (struct monst *, int, char *));
E int NDECL(dotypeinv); E int NDECL(dotypeinv);
E const char *FDECL(dfeature_at, (int, int, char *)); E const char *FDECL(dfeature_at, (int, int, char *));
E int FDECL(look_here, (int, BOOLEAN_P)); E int FDECL(look_here, (int, unsigned));
E int NDECL(dolook); E int NDECL(dolook);
E boolean FDECL(will_feel_cockatrice, (struct obj *, BOOLEAN_P)); E boolean FDECL(will_feel_cockatrice, (struct obj *, BOOLEAN_P));
E void FDECL(feel_cockatrice, (struct obj *, BOOLEAN_P)); E void FDECL(feel_cockatrice, (struct obj *, BOOLEAN_P));
+10 -7
View File
@@ -134,6 +134,10 @@ enum cost_alteration_types {
#define CXN_ARTICLE 8 /* include a/an/the prefix */ #define CXN_ARTICLE 8 /* include a/an/the prefix */
#define CXN_NOCORPSE 16 /* suppress " corpse" suffix */ #define CXN_NOCORPSE 16 /* suppress " corpse" suffix */
/* flags for look_here() */
#define LOOKHERE_PICKED_SOME 1
#define LOOKHERE_SKIP_DFEATURE 2
/* getpos() return values */ /* getpos() return values */
enum getpos_retval { enum getpos_retval {
LOOK_TRADITIONAL = 0, /* '.' -- ask about "more info?" */ LOOK_TRADITIONAL = 0, /* '.' -- ask about "more info?" */
@@ -255,13 +259,12 @@ struct sortloot_item {
}; };
typedef struct sortloot_item Loot; typedef struct sortloot_item Loot;
#define MATCH_WARN_OF_MON(mon) \ #define MATCH_WARN_OF_MON(mon) \
(Warn_of_mon && ((g.context.warntype.obj \ (Warn_of_mon \
&& (g.context.warntype.obj & (mon)->data->mflags2)) \ && ((g.context.warntype.obj & (mon)->data->mflags2) != 0 \
|| (g.context.warntype.polyd \ || (g.context.warntype.polyd & (mon)->data->mflags2) != 0 \
&& (g.context.warntype.polyd & (mon)->data->mflags2)) \ || (g.context.warntype.species \
|| (g.context.warntype.species \ && (g.context.warntype.species == (mon)->data))))
&& (g.context.warntype.species == (mon)->data))))
#include "trap.h" #include "trap.h"
#include "flag.h" #include "flag.h"
+12 -9
View File
@@ -3414,9 +3414,9 @@ char *buf;
/* look at what is here; if there are many objects (pile_limit or more), /* look at what is here; if there are many objects (pile_limit or more),
don't show them unless obj_cnt is 0 */ don't show them unless obj_cnt is 0 */
int int
look_here(obj_cnt, picked_some) look_here(obj_cnt, lookhere_flags)
int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */ int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progress */
boolean picked_some; unsigned lookhere_flags;
{ {
struct obj *otmp; struct obj *otmp;
struct trap *trap; struct trap *trap;
@@ -3424,12 +3424,15 @@ boolean picked_some;
const char *dfeature = (char *) 0; const char *dfeature = (char *) 0;
char fbuf[BUFSZ], fbuf2[BUFSZ]; char fbuf[BUFSZ], fbuf2[BUFSZ];
winid tmpwin; winid tmpwin;
boolean skip_objects, felt_cockatrice = FALSE; boolean skip_objects, felt_cockatrice = FALSE,
picked_some = (lookhere_flags & LOOKHERE_PICKED_SOME) != 0,
/* skip 'dfeature' if caller used describe_decor() to show it */
skip_dfeature = (lookhere_flags & LOOKHERE_SKIP_DFEATURE) != 0;
/* default pile_limit is 5; a value of 0 means "never skip" /* default pile_limit is 5; a value of 0 means "never skip"
(and 1 effectively forces "always skip") */ (and 1 effectively forces "always skip") */
skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit); skip_objects = (flags.pile_limit > 0 && obj_cnt >= flags.pile_limit);
if (u.uswallow && u.ustuck) { if (u.uswallow) {
struct monst *mtmp = u.ustuck; struct monst *mtmp = u.ustuck;
/* /*
@@ -3502,12 +3505,12 @@ boolean picked_some;
} }
} }
if (dfeature) if (dfeature && !skip_dfeature)
Sprintf(fbuf, "There is %s here.", an(dfeature)); Sprintf(fbuf, "There is %s here.", an(dfeature));
if (!otmp || is_lava(u.ux, u.uy) if (!otmp || is_lava(u.ux, u.uy)
|| (is_pool(u.ux, u.uy) && !Underwater)) { || (is_pool(u.ux, u.uy) && !Underwater)) {
if (dfeature) if (dfeature && !skip_dfeature)
pline1(fbuf); pline1(fbuf);
read_engr_at(u.ux, u.uy); /* Eric Backus */ read_engr_at(u.ux, u.uy); /* Eric Backus */
if (!skip_objects && (Blind || !dfeature)) if (!skip_objects && (Blind || !dfeature))
@@ -3517,7 +3520,7 @@ boolean picked_some;
/* we know there is something here */ /* we know there is something here */
if (skip_objects) { if (skip_objects) {
if (dfeature) if (dfeature && !skip_dfeature)
pline1(fbuf); pline1(fbuf);
read_engr_at(u.ux, u.uy); /* Eric Backus */ read_engr_at(u.ux, u.uy); /* Eric Backus */
if (obj_cnt == 1 && otmp->quan == 1L) if (obj_cnt == 1 && otmp->quan == 1L)
@@ -3547,7 +3550,7 @@ boolean picked_some;
} }
} else if (!otmp->nexthere) { } else if (!otmp->nexthere) {
/* only one object */ /* only one object */
if (dfeature) if (dfeature && !skip_dfeature)
pline1(fbuf); pline1(fbuf);
read_engr_at(u.ux, u.uy); /* Eric Backus */ read_engr_at(u.ux, u.uy); /* Eric Backus */
You("%s here %s.", verb, doname_with_price(otmp)); You("%s here %s.", verb, doname_with_price(otmp));
@@ -3559,7 +3562,7 @@ boolean picked_some;
display_nhwindow(WIN_MESSAGE, FALSE); display_nhwindow(WIN_MESSAGE, FALSE);
tmpwin = create_nhwindow(NHW_MENU); tmpwin = create_nhwindow(NHW_MENU);
if (dfeature) { if (dfeature && !skip_dfeature) {
putstr(tmpwin, 0, fbuf); putstr(tmpwin, 0, fbuf);
putstr(tmpwin, 0, ""); putstr(tmpwin, 0, "");
} }
+21 -28
View File
@@ -16,7 +16,7 @@ static boolean FDECL(query_classes, (char *, boolean *, boolean *,
const char *, struct obj *, const char *, struct obj *,
BOOLEAN_P, int *)); BOOLEAN_P, int *));
static boolean FDECL(fatal_corpse_mistake, (struct obj *, BOOLEAN_P)); static boolean FDECL(fatal_corpse_mistake, (struct obj *, BOOLEAN_P));
static void NDECL(describe_decor); static boolean NDECL(describe_decor);
static void FDECL(check_here, (BOOLEAN_P)); static void FDECL(check_here, (BOOLEAN_P));
static boolean FDECL(n_or_more, (struct obj *)); static boolean FDECL(n_or_more, (struct obj *));
static boolean FDECL(all_but_uchain, (struct obj *)); static boolean FDECL(all_but_uchain, (struct obj *));
@@ -295,32 +295,31 @@ boolean setup; /* True: deferring, False: catching up */
if (setup) { if (setup) {
iflags.defer_decor = TRUE; iflags.defer_decor = TRUE;
} else { } else {
describe_decor(); (void) describe_decor();
iflags.defer_decor = FALSE; iflags.defer_decor = FALSE;
} }
} }
/* handle 'mention_decor' (when walking onto a dungeon feature such as /* handle 'mention_decor' (when walking onto a dungeon feature such as
stairs or altar, describe it even if it isn't covered up by an object) */ stairs or altar, describe it even if it isn't covered up by an object) */
static void static boolean
describe_decor() describe_decor()
{ {
char outbuf[BUFSZ], fbuf[QBUFSZ]; char outbuf[BUFSZ], fbuf[QBUFSZ];
boolean doorhere, waterhere, do_norep; boolean doorhere, waterhere, res = TRUE;
const char *dfeature; const char *dfeature;
int ltyp; int ltyp;
if (Fumbling && !iflags.defer_decor) { if ((HFumbling & TIMEOUT) == 1L && !iflags.defer_decor) {
/* /*
* In case Fumbling is due to walking on ice.
* Work around a message sequencing issue: avoid * Work around a message sequencing issue: avoid
* |You are back on floor. * |You are back on floor.
* |You trip over <object>. * |You trip over <object>. or You flounder.
* when the trip is being caused by moving on ice as hero * when the trip is being caused by moving on ice as hero
* steps off ice onto non-ice. * steps off ice onto non-ice.
*/ */
deferred_decor(TRUE); deferred_decor(TRUE);
return; return FALSE;
} }
ltyp = levl[u.ux][u.uy].typ; ltyp = levl[u.ux][u.uy].typ;
@@ -328,7 +327,8 @@ describe_decor()
ltyp = db_under_typ(levl[u.ux][u.uy].drawbridgemask); ltyp = db_under_typ(levl[u.ux][u.uy].drawbridgemask);
dfeature = dfeature_at(u.ux, u.uy, fbuf); dfeature = dfeature_at(u.ux, u.uy, fbuf);
/* we don't mention "ordinary" doors but do mention broken ones */ /* we don't mention "ordinary" doors but do mention broken ones (and
closed ones, which will only happen for Passes_walls) */
doorhere = dfeature && (!strcmp(dfeature, "open door") doorhere = dfeature && (!strcmp(dfeature, "open door")
|| !strcmp(dfeature, "doorway")); || !strcmp(dfeature, "doorway"));
waterhere = dfeature && !strcmp(dfeature, "pool of water"); waterhere = dfeature && !strcmp(dfeature, "pool of water");
@@ -337,7 +337,7 @@ describe_decor()
dfeature = 0; dfeature = 0;
if (ltyp == iflags.prev_decor && !IS_FURNITURE(ltyp)) { if (ltyp == iflags.prev_decor && !IS_FURNITURE(ltyp)) {
; res = FALSE;
} else if (dfeature) { } else if (dfeature) {
if (waterhere) if (waterhere)
dfeature = strcpy(fbuf, waterbody_name(u.ux, u.uy)); dfeature = strcpy(fbuf, waterbody_name(u.ux, u.uy));
@@ -351,14 +351,7 @@ describe_decor()
Strcpy(fbuf, dfeature); Strcpy(fbuf, dfeature);
Sprintf(outbuf, "%s.", upstart(fbuf)); Sprintf(outbuf, "%s.", upstart(fbuf));
} }
do_norep = (ltyp == iflags.prev_decor pline("%s", outbuf);
&& (waterhere
|| !strcmp(dfeature, "molten lava")
|| !strcmp(dfeature, "ice")));
if (!do_norep)
pline("%s", outbuf);
else
Norep("%s", outbuf);
} else if (!Underwater) { } else if (!Underwater) {
if (IS_POOL(iflags.prev_decor) if (IS_POOL(iflags.prev_decor)
|| iflags.prev_decor == LAVAPOOL || iflags.prev_decor == LAVAPOOL
@@ -373,6 +366,7 @@ describe_decor()
} }
} }
iflags.prev_decor = ltyp; iflags.prev_decor = ltyp;
return res;
} }
/* look at the objects at our location, unless there are too many of them */ /* look at the objects at our location, unless there are too many of them */
@@ -382,9 +376,12 @@ boolean picked_some;
{ {
register struct obj *obj; register struct obj *obj;
register int ct = 0; register int ct = 0;
unsigned lhflags = picked_some ? LOOKHERE_PICKED_SOME : 0;
if (flags.mention_decor) if (flags.mention_decor) {
describe_decor(); if (describe_decor())
lhflags |= LOOKHERE_SKIP_DFEATURE;
}
/* count the objects here */ /* count the objects here */
for (obj = g.level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) { for (obj = g.level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) {
@@ -397,9 +394,7 @@ boolean picked_some;
if (g.context.run) if (g.context.run)
nomul(0); nomul(0);
flush_screen(1); flush_screen(1);
(void) look_here(ct, picked_some); (void) look_here(ct, lhflags);
iflags.prev_decor = STONE;
} else { } else {
read_engr_at(u.ux, u.uy); read_engr_at(u.ux, u.uy);
} }
@@ -599,13 +594,13 @@ int what; /* should be a long */
|| (is_pool(u.ux, u.uy) && !Underwater) || (is_pool(u.ux, u.uy) && !Underwater)
|| is_lava(u.ux, u.uy))) { || is_lava(u.ux, u.uy))) {
if (flags.mention_decor) if (flags.mention_decor)
describe_decor(); (void) describe_decor();
read_engr_at(u.ux, u.uy); read_engr_at(u.ux, u.uy);
return 0; return 0;
} }
/* no pickup if levitating & not on air or water level */ /* no pickup if levitating & not on air or water level */
if (!can_reach_floor(TRUE)) { if (!can_reach_floor(TRUE)) {
describe_decor(); /* even when !flags.mention_decor */ (void) describe_decor(); /* even when !flags.mention_decor */
if ((g.multi && !g.context.run) || (autopickup && !flags.pickup) if ((g.multi && !g.context.run) || (autopickup && !flags.pickup)
|| ((t = t_at(u.ux, u.uy)) != 0 || ((t = t_at(u.ux, u.uy)) != 0
&& (uteetering_at_seen_pit(t) || uescaped_shaft(t)))) && (uteetering_at_seen_pit(t) || uescaped_shaft(t))))
@@ -631,8 +626,6 @@ int what; /* should be a long */
&& !g.context.nopick) && !g.context.nopick)
nomul(0); nomul(0);
} }
/* for describe_decor()'s Norep handling */
iflags.prev_decor = STONE;
add_valid_menu_class(0); /* reset */ add_valid_menu_class(0); /* reset */
if (!u.uswallow) { if (!u.uswallow) {
@@ -988,7 +981,7 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */
if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE
&& will_feel_cockatrice(curr, FALSE)) { && will_feel_cockatrice(curr, FALSE)) {
destroy_nhwindow(win); /* stop the menu and revert */ destroy_nhwindow(win); /* stop the menu and revert */
(void) look_here(0, FALSE); (void) look_here(0, 0);
unsortloot(&sortedolist); unsortloot(&sortedolist);
return 0; return 0;
} }
+2 -12
View File
@@ -737,18 +737,8 @@ nh_timeout()
incr_itimeout(&HFumbling, rnd(20)); incr_itimeout(&HFumbling, rnd(20));
if (iflags.defer_decor) { if (iflags.defer_decor) {
/* /* 'mention_decor' was deferred for message sequencing
* describe_decor() is attempting to work around a reasons; catch up now */
* message sequencing issue: avoid
* |You are back on floor.
* |You trip over <object>.
* if the trip is being caused by moving on ice
* that the hero just left. A trip message has
* just been given, now give change-in-terrain one.
* Operate this way even for non-ice Fumbling so
* that describe_decor() doesn't need to know any
* details about that.
*/
deferred_decor(FALSE); deferred_decor(FALSE);
} }
break; break;