diff --git a/doc/fixes3-7-0.txt b/doc/fixes3-7-0.txt index a9dae38aa..518770914 100644 --- a/doc/fixes3-7-0.txt +++ b/doc/fixes3-7-0.txt @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1268 $ $NHDT-Date: 1698090922 2023/10/23 19:55:22 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1271 $ $NHDT-Date: 1698264796 2023/10/25 20:13:16 $ General Fixes and Modified Features ----------------------------------- @@ -2284,6 +2284,7 @@ applying gold pieces will flip one and report "heads" or "tails"; with a stack of more than one, normally the flipped coin will rejoin the stack during enlightenment and end-of-game disclosure, use contraction "n't" for " not" +give feedback about the thaw status of ice terrain Platform- and/or Interface-Specific New Features diff --git a/include/decl.h b/include/decl.h index 128b7d93d..98110f3d7 100644 --- a/include/decl.h +++ b/include/decl.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 decl.h $NHDT-Date: 1686726249 2023/06/14 07:04:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.333 $ */ +/* NetHack 3.7 decl.h $NHDT-Date: 1698264758 2023/10/25 20:12:38 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.339 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2007. */ /* NetHack may be freely redistributed. See license for details. */ @@ -322,6 +322,10 @@ struct instance_globals_d { but that would require all xname() and doname() calls to be modified */ int distantname; + /* pickup.c */ + boolean decor_fumble_override; + boolean decor_levitate_override; + boolean havestate; unsigned long magic; /* validate that structure layout is preserved */ }; diff --git a/include/extern.h b/include/extern.h index df688821b..f092d2b0d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 extern.h $NHDT-Date: 1695159584 2023/09/19 21:39:44 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1287 $ */ +/* NetHack 3.7 extern.h $NHDT-Date: 1698264776 2023/10/25 20:12:56 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1296 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2099,6 +2099,7 @@ extern char *monhealthdescr(struct monst *mon, boolean, char *); extern void mhidden_description(struct monst *, boolean, char *); extern boolean object_from_map(int, coordxy, coordxy, struct obj **); extern const char *waterbody_name(coordxy, coordxy); +extern const char *ice_descr(coordxy, coordxy, char *); extern boolean ia_checkfile(struct obj *); extern int do_screen_description(coord, boolean, int, char *, const char **, struct permonst **); @@ -2162,6 +2163,7 @@ extern void getlock(void); extern int collect_obj_classes(char *, struct obj *, boolean, boolean(*)(struct obj *), int *); extern boolean rider_corpse_revival(struct obj *, boolean); +extern void force_decor(boolean); extern void deferred_decor(boolean); extern boolean menu_class_present(int); extern void add_valid_menu_class(int); diff --git a/include/flag.h b/include/flag.h index 61d855bbb..3da48464f 100644 --- a/include/flag.h +++ b/include/flag.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 flag.h $NHDT-Date: 1684791761 2023/05/22 21:42:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.217 $ */ +/* NetHack 3.7 flag.h $NHDT-Date: 1698264779 2023/10/25 20:12:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.224 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -290,6 +290,7 @@ struct instance_flags { boolean zerocomp; /* write zero-compressed save files */ boolean rlecomp; /* alternative to zerocomp; run-length encoding * compression of levels when writing savefile */ + schar ice_rating; /* ice_descr()'s classification of ice terrain */ schar prev_decor; /* 'mention_decor' just mentioned this */ uchar num_pad_mode; uchar bouldersym; /* symbol for boulder display */ diff --git a/src/decl.c b/src/decl.c index 3191180d5..1518fa780 100644 --- a/src/decl.c +++ b/src/decl.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 decl.c $NHDT-Date: 1686726255 2023/06/14 07:04:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.286 $ */ +/* NetHack 3.7 decl.c $NHDT-Date: 1698264780 2023/10/25 20:13:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.293 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -328,6 +328,9 @@ const struct instance_globals_d g_init_d = { DUMMY, /* disco */ /* objname.c */ 0, /* distantname */ + /* pickup.c */ + FALSE, /* decor_fumble_override */ + FALSE, /* decor_levitate_override */ TRUE, /* havestate*/ IVMAGIC /* d_magic to validate that structure layout has been preserved */ }; diff --git a/src/invent.c b/src/invent.c index 17e4809ec..3c7d175f0 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 invent.c $NHDT-Date: 1698090922 2023/10/23 19:55:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.456 $ */ +/* NetHack 3.7 invent.c $NHDT-Date: 1698264784 2023/10/25 20:13:04 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.457 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4224,7 +4224,7 @@ dfeature_at(coordxy x, coordxy y, char *buf) else if (is_lava(x, y)) cmap = S_lava; /* "molten lava" */ else if (is_ice(x, y)) - cmap = S_ice; /* "ice" */ + dfeature = ice_descr(x, y, altbuf), cmap = -1; /* "ice" */ else if (is_pool(x, y)) dfeature = "pool of water"; else if (IS_SINK(ltyp)) @@ -4330,19 +4330,28 @@ look_here( if (dfeature && !strncmp(dfeature, "altar ", 6)) { /* don't say "altar" twice, dfeature has more info */ You("try to feel what is here."); + } else if (SURFACE_AT(u.ux, u.uy) == ICE) { + /* using describe_decor() to handle ice is simpler than + replicating it in the conditional message construction */ + if (!flags.mention_decor || iflags.prev_decor == ICE) + force_decor(FALSE); + /* plain "ice" if blind and levitating, otherwise "solid ice" &c; + "There is [thin ]ice here. You try to feel what is on it." */ + You("try to feel what is on it."); + skip_dfeature = TRUE; /* ice already described */ } else { - const char *where = (Blind && !can_reach_floor(TRUE)) - ? "lying beneath you" - : "lying here on the ", - *onwhat = (Blind && !can_reach_floor(TRUE)) - ? "" - : surface(u.ux, u.uy); + boolean cant_reach = !can_reach_floor(TRUE); + const char *surf = surface(u.ux, u.uy), + *where = cant_reach ? "lying beneath you" + : "lying here on the ", + *onwhat = cant_reach ? "" : surf; You("try to feel what is %s%s.", drift ? "floating here" : where, drift ? "" : onwhat); + + if (dfeature && !drift && !strcmp(dfeature, surf)) + skip_dfeature = TRUE; /* terrain feature already identified */ } - if (dfeature && !drift && !strcmp(dfeature, surface(u.ux, u.uy))) - dfeature = 0; /* ice already identified */ trap = t_at(u.ux, u.uy); if (!can_reach_floor(trap && is_pit(trap->ttyp))) { pline("But you can't reach it!"); diff --git a/src/objnam.c b/src/objnam.c index f63f0ee1c..c7621e8b6 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 objnam.c $NHDT-Date: 1686386790 2023/06/10 08:46:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.392 $ */ +/* NetHack 3.7 objnam.c $NHDT-Date: 1698264786 2023/10/25 20:13:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.398 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1858,7 +1858,7 @@ singular(struct obj* otmp, char* (*func)(OBJ_P)) char * just_an(char *outbuf, const char *str) { - char c0; + char c0, *p; *outbuf = '\0'; c0 = lowc(*str); @@ -1866,7 +1866,10 @@ just_an(char *outbuf, const char *str) /* single letter; might be used for named fruit or a musical note */ Strcpy(outbuf, strchr("aefhilmnosx", c0) ? "an " : "a "); } else if (!strncmpi(str, "the ", 4) || !strcmpi(str, "molten lava") - || !strcmpi(str, "iron bars") || !strcmpi(str, "ice")) { + || !strcmpi(str, "iron bars") || !strcmpi(str, "ice") + || !strncmpi(str, "frozen ", 7) /* ice while hallucinating */ + /* thawing ice ("solid ice", "thin ice", &c) */ + || ((p = strchr(str, ' ')) != 0 && !strcmpi(p, " ice"))) { ; /* no article */ } else { /* normal case is "an " or "a " */ diff --git a/src/pager.c b/src/pager.c index 23216e0e3..c883daaf9 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pager.c $NHDT-Date: 1655120486 2022/06/13 11:41:26 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.225 $ */ +/* NetHack 3.7 pager.c $NHDT-Date: 1698264788 2023/10/25 20:13:08 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.252 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -482,16 +482,12 @@ const char * waterbody_name(coordxy x, coordxy y) { static char pooltype[40]; - struct rm *lev; schar ltyp; boolean hallucinate = Hallucination && !gp.program_state.gameover; if (!isok(x, y)) return "drink"; /* should never happen */ - lev = &levl[x][y]; - ltyp = lev->typ; - if (ltyp == DRAWBRIDGE_UP) - ltyp = db_under_typ(lev->drawbridgemask); + ltyp = SURFACE_AT(x, y); if (ltyp == LAVAPOOL) { Snprintf(pooltype, sizeof pooltype, "molten %s", hliquid("lava")); @@ -535,6 +531,43 @@ waterbody_name(coordxy x, coordxy y) return "water"; /* don't hallucinate this as some other liquid */ } +const char * +ice_descr(coordxy x, coordxy y, char *outbuf) +{ + static const char *const icetyp[] = { + "solid", /* 0: not melting */ + "sturdy", /* 1: more than 1000 turns left */ + "steady", /* 2: 101..1000 turns left */ + "unsteady", /* 3: 51..100 turns left */ + "thin", /* 4: 15..50 turns left */ + "slushy", /* 5: 1..14 turns left; matches Warning on ice */ + }; + /* same formula as is used in distant_name() for objects */ + int r = (u.xray_range > 2) ? u.xray_range : 2, + neardist = (r * r) * 2 - r; /* same as r*r + r*(r-1) */ + + iflags.ice_rating = -1; /* secondary output, for ' mention_decor' */ + if (levl[x][y].typ != ICE) { + Sprintf(outbuf, "[ice:%d?]", (int) levl[x][y].typ); + } else if ((distu(x, y) > neardist + || (!cansee(x, y) && (!u_at(x, y) || Levitation))) + && !gd.decor_levitate_override) { /* probe_decor(pickup.c) */ + Strcpy(outbuf, waterbody_name(x, y)); /* "ice" or "frozen " */ + } else { + long time_left = spot_time_left(x, y, MELT_ICE_AWAY); + + iflags.ice_rating = !time_left ? 0 /* solid */ + : (time_left > 1000L) ? 1 /* sturdy */ + : (time_left > 100L) ? 2 /* steady */ + : (time_left > 50L) ? 3 /* unsteady */ + : (time_left > 14L) ? 4 /* thin */ + : 5; /* slushy */ + Sprintf(outbuf, "%s %s", icetyp[(int) iflags.ice_rating], + waterbody_name(x, y)); + } + return outbuf; +} + /* * Return the name of the glyph found at (x,y). * If not hallucinating and the glyph is a monster, also monster data. @@ -1442,6 +1475,8 @@ do_screen_description( pm = lookat(cc.x, cc.y, look_buf, monbuf); if (pm && for_supplement) *for_supplement = pm; + if (!strcmp(look_buf, "ice")) + (void) ice_descr(cc.x, cc.y, look_buf); if (look_buf[0] != '\0') *firstmatch = look_buf; diff --git a/src/pickup.c b/src/pickup.c index 08b8afa72..fd0b976ae 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 pickup.c $NHDT-Date: 1654760203 2022/06/09 07:36:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.310 $ */ +/* NetHack 3.7 pickup.c $NHDT-Date: 1698264789 2023/10/25 20:13:09 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.339 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -291,6 +291,25 @@ rider_corpse_revival(struct obj *obj, boolean remotely) return TRUE; } +/* wand of probing zapped down; perhaps hero is levitating while blind */ +void +force_decor(boolean via_probing) +{ + /* we don't want describe_decor() to defer feedback if hero is fumbling + with 1 turn left, or for ice_descr() to skip thawing details if hero + is probing when levitating while blind (those will be skipped for + look_here() and farlook() or autodescribe); we can't control that by + temporarily tweaking properties because that could become noticeable + if status gets updated while decor feedback is being delivered */ + gd.decor_fumble_override = TRUE; + gd.decor_levitate_override = via_probing; + /* force current terrain to be different from previous location */ + iflags.prev_decor = STONE; + (void) describe_decor(); + gd.decor_fumble_override = gd.decor_levitate_override = FALSE; + gl.lastseentyp[u.ux][u.uy] = levl[u.ux][u.uy].typ; +} + void deferred_decor(boolean setup) /* True: deferring, False: catching up */ { @@ -312,7 +331,8 @@ describe_decor(void) const char *dfeature; int ltyp; - if ((HFumbling & TIMEOUT) == 1L && !iflags.defer_decor) { + if ((HFumbling & TIMEOUT) == 1L && !iflags.defer_decor + && !gd.decor_fumble_override) { /* probe_decor() */ /* * Work around a message sequencing issue: avoid * |You are back on floor. @@ -324,9 +344,7 @@ describe_decor(void) return FALSE; } - ltyp = levl[u.ux][u.uy].typ; - if (ltyp == DRAWBRIDGE_UP) /* surface for spot in front of closed db */ - ltyp = db_under_typ(levl[u.ux][u.uy].drawbridgemask); + ltyp = SURFACE_AT(u.ux, u.uy); dfeature = dfeature_at(u.ux, u.uy, fbuf); /* we don't mention "ordinary" doors but do mention broken ones (and @@ -337,6 +355,10 @@ describe_decor(void) if (doorhere || Underwater || (ltyp == ICE && IS_POOL(iflags.prev_decor))) /* pooleffects() */ dfeature = 0; + /* + * TODO: if on ice, report moving between thicker and thinner ice (based + * on ice_descr()'s classification) as if moving onto different terrain. + */ if (ltyp == iflags.prev_decor && !IS_FURNITURE(ltyp)) { res = FALSE; @@ -353,18 +375,26 @@ describe_decor(void) Strcpy(fbuf, dfeature); Sprintf(outbuf, "%s.", upstart(fbuf)); } - pline("%s", outbuf); + if (ltyp == ICE) + Norep("%s", outbuf); + else + pline("%s", outbuf); } else if (!Underwater) { if (IS_POOL(iflags.prev_decor) - || iflags.prev_decor == LAVAPOOL + || IS_LAVA(iflags.prev_decor) || iflags.prev_decor == ICE) { - const char *ground = surface(u.ux, u.uy); + if (iflags.last_msg != PLNMSG_BACK_ON_GROUND) { + const char *surf = is_ice(u.ux, u.uy) + ? ice_descr(u.ux, u.uy, fbuf) + : surface(u.ux, u.uy); - if (iflags.last_msg != PLNMSG_BACK_ON_GROUND) + if (!strcmpi(surf, "floor") || !strcmpi(surf, "ground")) + surf = "solid ground"; pline("%s %s %s.", Verbose(2, describe_decor2) ? "You are back" : "Back", - (Levitation || Flying) ? "over" : "on", - ground); + (Levitation || Flying) ? "over" : "on", surf); + } + } } iflags.prev_decor = ltyp; diff --git a/src/zap.c b/src/zap.c index ee75d857c..0af692c5e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 zap.c $NHDT-Date: 1686178723 2023/06/07 22:58:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.472 $ */ +/* NetHack 3.7 zap.c $NHDT-Date: 1698264791 2023/10/25 20:13:11 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.481 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3094,7 +3094,7 @@ cancel_monst(struct monst *mdef, struct obj *obj, boolean youattack, static boolean zap_updown(struct obj *obj) /* wand or spell */ { - boolean striking = FALSE, disclose = FALSE; + boolean striking = FALSE, disclose = FALSE, map_zapped = FALSE; coordxy x, y, xx, yy; int ptmp; struct obj *otmp; @@ -3113,9 +3113,24 @@ zap_updown(struct obj *obj) /* wand or spell */ ptmp = 0; if (u.dz < 0) { You("probe towards the %s.", ceiling(x, y)); - } else { + } else { /* down */ + const char *surf; + schar ltyp, rememberedltyp = gl.lastseentyp[x][y]; + ptmp += bhitpile(obj, bhito, x, y, u.dz); - You("probe beneath the %s.", surface(x, y)); + /* sequencing: zap_map() calls force_decor() for ice or furniture; + we need to call it before probing for buried objects */ + ltyp = SURFACE_AT(x, y); + zap_map(x, y, obj); + map_zapped = TRUE; + if (ltyp == ICE || IS_FURNITURE(ltyp)) { + surf = "it"; + if (gl.lastseentyp[x][y] != rememberedltyp) + ptmp += 1; + } else { + surf = the(surface(x, y)); + } + You("probe beneath %s.", surf); ptmp += display_binventory(x, y, TRUE); } if (!ptmp) @@ -3245,7 +3260,8 @@ zap_updown(struct obj *obj) /* wand or spell */ /* note: engraving handling that used to be here has been moved to zap_map() */ - zap_map(x, y, obj); + if (!map_zapped) + zap_map(x, y, obj); } else if (u.dz < 0) { /* zapping upward */ @@ -3582,10 +3598,9 @@ zap_map( } /* !u.uz */ if (obj->otyp == WAN_PROBING) { + schar ltyp; /* * Probing, either up/down or lateral. - * - * TODO: if terrain is ice, report on its thaw timer. */ /* map unseen terrain */ @@ -3598,8 +3613,9 @@ zap_map( learn_it = TRUE; } } + ltyp = SURFACE_AT(x, y); /* secret door gets revealed, converted into regular door */ - if (levl[x][y].typ == SDOOR) { + if (ltyp == SDOOR) { cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ newsym(x, y); if (cansee(x, y)) { @@ -3612,12 +3628,20 @@ zap_map( /* secret corridor likewise, although only ones within view will still be secret; for the !cansee(x,y) case, show_map_spot() above has already converted the spot to regular corridor */ - } else if (levl[x][y].typ == SCORR) { + } else if (ltyp == SCORR) { levl[x][y].typ = CORR; unblock_point(x, y); newsym(x, y); pline("Probing exposes a secret corridor."); learn_it = TRUE; + + /* if on or over ice, describe it ("solid ice", "thin ice", &c); + likewise for furniture in case hero is levitating while blind */ + } else if (ltyp == ICE || IS_FURNITURE(ltyp)) { + if (u.dz > 0) { /* down, which also means x,y == u.ux,u.uy */ + force_decor(TRUE); + learn_it = TRUE; + } } /* * Probing reveals undiscovered traps.