From: PatR Date: Thu, 28 Apr 2022 00:16:23 +0000 (-0700) Subject: show trapped doors,chests as themselves \ X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4ab68767bfd3f45783acbfcda0d779f503137d3e;p=nethack show trapped doors,chests as themselves \ instead of as fake bear traps Use the new traps and their tiles when confused gold detection finds trapped doors and trapped chests. (Large boxes can be trapped too; they use the trapped chest trap and corresponding tile rather than have their own.) Usually these pseudo-traps go away when as soon as they are within line of sight. (While testing, I noticed that seeing a trapped door from outside its room rather than inside didn't behave that way. The door was created by wizard mode wishing; I don't know whether that was a factor.) I also discovered that secret doors weren't being handled correctly. They can't be trapped because of their use of both the doormask and wall_info overlays of levl[][].flags, but I had a secret door be falsely displayed as a trap. This fixes that. We should have obj->tknown and rm->D_TRAPKNOWN so that the hero won't forget about these traps after declining to attempt to untrap them. But that's more work than I care to tackle. --- diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index b708a4fb5..7bcbe1cac 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -894,6 +894,8 @@ inventory #adjust for !fixinv, after picking 'from' slot the prompt for 'to' where x is last letter used (despite that, y could still be picked) with two-weapon combat or Cleaver attacking multiple targets, hero kept going with next attack after being paralyzed by passive counter-attack +trap detection could falsely find trapped secret doors; those can't be trapped + due to details of how they use overlaid fields in the rm structure Fixes to 3.7.0-x Problems that Were Exposed Via git Repository @@ -1595,6 +1597,8 @@ pets are more likely to follow you closely if you are carrying something they really like to eat; behave as if you are carrying such whenever you are standing on stairs so that pets will try harder to come to you allow setting msgtype in SOUND line +display detected door traps and chest traps as trapped doors and trapped + chests rather than as fake bear traps Platform- and/or Interface-Specific New Features diff --git a/src/detect.c b/src/detect.c index 387729bca..e388930a2 100644 --- a/src/detect.c +++ b/src/detect.c @@ -28,6 +28,12 @@ static void openone(int, int, genericptr_t); static int mfind0(struct monst *, boolean); static int reveal_terrain_getglyph(int, int, int, unsigned, int, int); +/* dummytrap: used when detecting traps finds a door or chest trap; the + couple of fields that matter are always re-initialized during use so + this does not need to be part of 'struct instance_globals g'; fields + that aren't used are compile-/link-/load-time initialized to 0 */ +static struct trap dummytrap; + /* wildcard class for clear_stale_map - this used to be used as a getobj() input but it's no longer used for that function */ #define ALL_CLASSES (MAXOCLASSES + 1) @@ -111,7 +117,7 @@ trapped_chest_at(int ttyp, int x, int y) if (!glyph_is_trap(glyph_at(x, y))) return FALSE; - if (ttyp != BEAR_TRAP || (Hallucination && rn2(20))) + if (ttyp != TRAPPED_CHEST || (Hallucination && rn2(20))) return FALSE; /* @@ -153,7 +159,7 @@ trapped_door_at(int ttyp, int x, int y) if (!glyph_is_trap(glyph_at(x, y))) return FALSE; - if (ttyp != BEAR_TRAP || (Hallucination && rn2(20))) + if (ttyp != TRAPPED_DOOR || (Hallucination && rn2(20))) return FALSE; lev = &levl[x][y]; if (!IS_DOOR(lev->typ)) @@ -851,14 +857,16 @@ sense_trap(struct trap *trap, xchar x, xchar y, int src_cursed) } else if (trap) { map_trap(trap, 1); trap->tseen = 1; - } else { /* trapped door or trapped chest */ - struct trap temp_trap; /* fake trap */ - - (void) memset((genericptr_t) &temp_trap, 0, sizeof temp_trap); - temp_trap.tx = x; - temp_trap.ty = y; - temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */ - map_trap(&temp_trap, 1); + } else { + /* + * OBSOLETE; this was for trapped door or trapped chest + * but those are handled by 'if (trap) {map_trap()}' now + * and this block of code shouldn't be reachable anymore. + */ + dummytrap.tx = x; + dummytrap.ty = y; + dummytrap.ttyp = BEAR_TRAP; /* some kind of trap */ + map_trap(&dummytrap, 1); } } @@ -870,8 +878,10 @@ sense_trap(struct trap *trap, xchar x, xchar y, int src_cursed) 2 if found at some other spot, 3 if both, 0 otherwise; optionally update the map to show where such traps were found */ static int -detect_obj_traps(struct obj *objlist, boolean show_them, - int how) /* 1 for misleading map feedback */ +detect_obj_traps( + struct obj *objlist, + boolean show_them, + int how) /* 1 for misleading map feedback */ { struct obj *otmp; xchar x, y; @@ -882,12 +892,15 @@ detect_obj_traps(struct obj *objlist, boolean show_them, * If so, should they be displayed as objects or as traps? */ + dummytrap.ttyp = TRAPPED_CHEST; for (otmp = objlist; otmp; otmp = otmp->nobj) { if (Is_box(otmp) && otmp->otrapped && get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) { result |= u_at(x, y) ? OTRAP_HERE : OTRAP_THERE; - if (show_them) - sense_trap((struct trap *) 0, x, y, how); + if (show_them) { + dummytrap.tx = x, dummytrap.ty = y; + sense_trap(&dummytrap, x, y, how); + } } if (Has_contents(otmp)) result |= detect_obj_traps(otmp->cobj, show_them, how); @@ -950,6 +963,11 @@ trap_detect(struct obj *sobj) /* null if crystal ball, /* door traps */ for (door = 0; door < g.doorindex; door++) { cc = g.doors[door]; + /* levl[][].doormask and .wall_info both overlay levl[][].flags; + the bit in doormask for D_TRAPPED is also a bit in wall_info; + secret doors use wall_info so can't be marked as trapped */ + if (levl[cc.x][cc.y].typ == SDOOR) + continue; if (levl[cc.x][cc.y].doormask & D_TRAPPED) { if (cc.x != u.ux || cc.y != u.uy) goto outtrapmap; @@ -986,10 +1004,15 @@ trap_detect(struct obj *sobj) /* null if crystal ball, for (ttmp = g.ftrap; ttmp; ttmp = ttmp->ntrap) sense_trap(ttmp, 0, 0, cursed_src); + dummytrap.ttyp = TRAPPED_DOOR; for (door = 0; door < g.doorindex; door++) { cc = g.doors[door]; - if (levl[cc.x][cc.y].doormask & D_TRAPPED) - sense_trap((struct trap *) 0, cc.x, cc.y, cursed_src); + if (levl[cc.x][cc.y].typ == SDOOR) /* see above */ + continue; + if (levl[cc.x][cc.y].doormask & D_TRAPPED) { + dummytrap.tx = cc.x, dummytrap.ty = cc.y; + sense_trap(&dummytrap, cc.x, cc.y, cursed_src); + } } /* redisplay hero unless sense_trap() revealed something at */ @@ -1575,6 +1598,8 @@ openone(int zx, int zy, genericptr_t num) } /* let it fall to the next cases. could be on trap. */ } + /* note: secret doors can't be trapped; they use levl[][].wall_info; + see rm.h for the troublesome overlay of doormask and wall_info */ if (levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR && (levl[zx][zy].doormask & (D_CLOSED | D_LOCKED)))) { diff --git a/src/pager.c b/src/pager.c index 128d68c37..06ed6e6f3 100644 --- a/src/pager.c +++ b/src/pager.c @@ -145,11 +145,10 @@ monhealthdescr(struct monst *mon, boolean addspace, char *outbuf) static void trap_description(char *outbuf, int tnum, int x, int y) { - /* Trap detection displays a bear trap at locations having - * a trapped door or trapped container or both. - * - * TODO: we should create actual trap types for doors and - * chests so that they can have their own glyphs and tiles. + /* + * Trap detection used to display a bear trap at locations having + * a trapped door or trapped container or both. They're semi-real + * traps now (defined trap types but not part of ftrap chain). */ if (trapped_chest_at(tnum, x, y)) Strcpy(outbuf, "trapped chest"); /* might actually be a large box */ @@ -1908,9 +1907,14 @@ doidtrap(void) x = u.ux + u.dx; y = u.uy + u.dy; - /* check fake bear trap from confused gold detection */ + /* trapped doors and chests used to be shown as fake bear traps; + they have their own trap types now but aren't part of the ftrap + chain; usually they revert to normal door or chest when the hero + sees them but player might be using '^' while the hero is blind */ glyph = glyph_at(x, y); - if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) { + if (glyph_is_trap(glyph) + && ((tt = glyph_to_trap(glyph)) == BEAR_TRAP + || tt == TRAPPED_DOOR || tt == TRAPPED_CHEST)) { boolean chesttrap = trapped_chest_at(tt, x, y); if (chesttrap || trapped_door_at(tt, x, y)) {