diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index cf8810c37..54bc83b0d 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -2601,7 +2601,8 @@ exclude that alignment from being picked randomly. Cannot be set with the `O' command. Persistent. .lp autodescribe Automatically describe the terrain under cursor when asked to get a location -on the map. The +on the map (default true). +The .op whatis_coord option controls whether the description includes map coordinates. .lp autodig diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 29bf17f69..d62403d6c 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -3038,8 +3038,8 @@ Cannot be set with the `{\tt O}' command. Persistent. %.lp \item[\ib{autodescribe}] Automatically describe the terrain under cursor when asked to get a location -on the map. The -{\it whatis\verb+_+coord\/} +on the map (default true). +The {\it whatis\verb+_+coord\/} option controls whether the description includes map coordinates. %.lp \item[\ib{autodig}] diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 25fd65dc4..d458496a1 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -152,6 +152,12 @@ fix missing space in "would flyif you weren't levitating" a wand of polymorph lost its magical ability for the turn just because the player using it to engrave happened to be blind, which didn't make a much sense +floating eye is classified as a flyer but flying is blocked while levitating, + so don't set intrinsic flying if hero is polymorphed into one +being trapped (bear trap, web, molten or solidified lava, chained to buried + iron ball) blocks both levitation and flight (note: being stuck in a + pit ends when either of those starts so doesn't apply) +change default value for the 'autodescribe' option to 'on' Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -163,6 +169,7 @@ sortloot segfaulted when filtering a subset of items (seen with 'A' command) orctown: prevent Bad fruit #0 and some minor tuning make long extended commands list be more navigable simplify #wizidentify; don't rely on having bold menu entries +ensure tmp_at() structures are initialized for all code paths when swallowed tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes tty: ensure that current status fields are always copied to prior status diff --git a/include/extern.h b/include/extern.h index 70ff25c4f..6d6089fa2 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2441,6 +2441,8 @@ E struct monst *FDECL(animate_statue, (struct obj *, XCHAR_P, XCHAR_P, int, int *)); E struct monst *FDECL(activate_statue_trap, (struct trap *, XCHAR_P, XCHAR_P, BOOLEAN_P)); +E void FDECL(set_utrap, (unsigned, unsigned)); +E void FDECL(reset_utrap, (BOOLEAN_P)); E void FDECL(dotrap, (struct trap *, unsigned)); E void FDECL(seetrap, (struct trap *)); E void FDECL(feeltrap, (struct trap *)); diff --git a/include/hack.h b/include/hack.h index 555a08818..5785b8590 100644 --- a/include/hack.h +++ b/include/hack.h @@ -333,6 +333,7 @@ typedef struct sortloot_item Loot; #define RECURSIVETRAP 0x08 /* trap changed into another type this same turn */ #define TOOKPLUNGE 0x10 /* used '>' to enter pit below you */ #define VIASITTING 0x20 /* #sit while at trap location (affects message) */ +#define FAILEDUNTRAP 0x40 /* trap activated by failed untrap attempt */ /* Flags to control test_move in hack.c */ #define DO_MOVE 0 /* really doing the move */ diff --git a/include/youprop.h b/include/youprop.h index d71ec8b5c..c0eb10eef 100644 --- a/include/youprop.h +++ b/include/youprop.h @@ -209,8 +209,12 @@ #define ETeleport_control u.uprops[TELEPORT_CONTROL].extrinsic #define Teleport_control (HTeleport_control || ETeleport_control) +/* HLevitation has I_SPECIAL set if levitating due to blessed potion + which allows player to use the '>' command to end levitation early */ #define HLevitation u.uprops[LEVITATION].intrinsic #define ELevitation u.uprops[LEVITATION].extrinsic +/* BLevitation has I_SPECIAL set if trapped in the floor, + FROMOUTSIDE set if inside solid rock (or in water on Plane of Water) */ #define BLevitation u.uprops[LEVITATION].blocked #define Levitation ((HLevitation || ELevitation) && !BLevitation) /* Can't touch surface, can't go under water; overrides all others */ @@ -219,8 +223,11 @@ && (HLevitation & ~(I_SPECIAL | TIMEOUT)) == 0L \ && (ELevitation & ~W_ARTI) == 0L) +/* Flying is overridden by Levitation */ #define HFlying u.uprops[FLYING].intrinsic #define EFlying u.uprops[FLYING].extrinsic +/* BFlying has I_SPECIAL set if levitating or trapped in the floor or both, + FROMOUTSIDE set if inside solid rock (or in water on Plane of Water) */ #define BFlying u.uprops[FLYING].blocked #define Flying \ ((HFlying || EFlying || (u.usteed && is_flyer(u.usteed->data))) \ diff --git a/src/allmain.c b/src/allmain.c index 1fbd5cdf9..6fef09bf1 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -801,44 +801,42 @@ enum earlyarg e_arg; userea = &argv[i][1]; } match = match_optname(userea, earlyopts[idx].name, - earlyopts[idx].minlength, earlyopts[idx].valallowed); + earlyopts[idx].minlength, + earlyopts[idx].valallowed); if (match) break; } if (match) { - const char *extended_opt = index(userea,':'); + const char *extended_opt = index(userea, ':'); if (!extended_opt) extended_opt = index(userea, '='); switch(e_arg) { - case ARG_DEBUG: - if (extended_opt) { - extended_opt++; - debug_fields(extended_opt); - } - return 1; - break; - case ARG_VERSION: { - boolean insert_into_pastebuf = FALSE; - - if (extended_opt) { - extended_opt++; - if (match_optname(extended_opt, "paste", - 5, FALSE)) { - insert_into_pastebuf = TRUE; - } else { - raw_printf( - "-%sversion can only be extended with -%sversion:paste.\n", - dashdash, dashdash); - return TRUE; - } - } - early_version_info(insert_into_pastebuf); - return 2; - break; + case ARG_DEBUG: + if (extended_opt) { + extended_opt++; + debug_fields(extended_opt); } - default: - break; + return 1; + case ARG_VERSION: { + boolean insert_into_pastebuf = FALSE; + + if (extended_opt) { + extended_opt++; + if (match_optname(extended_opt, "paste", 5, FALSE)) { + insert_into_pastebuf = TRUE; + } else { + raw_printf( + "-%sversion can only be extended with -%sversion:paste.\n", + dashdash, dashdash); + return TRUE; + } + } + early_version_info(insert_into_pastebuf); + return 2; + } + default: + break; } }; return FALSE; @@ -851,7 +849,7 @@ enum earlyarg e_arg; * are documented is right here. No gameplay is altered. * * test - test whether this parser is working - * ttystatus - TTY: + * ttystatus - TTY: * immediateflips - WIN32: turn off display performance * optimization so that display output * can be debugged without buffering. diff --git a/src/apply.c b/src/apply.c index 0fa842636..5a7ba6d19 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1752,7 +1752,7 @@ int magic; /* 0=Physical, otherwise skill level */ break; case TT_LAVA: You("pull yourself above the %s!", hliquid("lava")); - u.utrap = 0; + reset_utrap(TRUE); return 1; case TT_BURIEDBALL: case TT_INFLOOR: @@ -2738,7 +2738,7 @@ struct obj *obj; if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) { You("yank yourself out of the pit!"); teleds(cc.x, cc.y, TRUE); - u.utrap = 0; + reset_utrap(TRUE); vision_full_recalc = 1; } } else { diff --git a/src/ball.c b/src/ball.c index 762de85f8..3ac723866 100644 --- a/src/ball.c +++ b/src/ball.c @@ -703,11 +703,12 @@ xchar x, y; } if (x != u.ux || y != u.uy) { + static const char *pullmsg = "The ball pulls you out of the %s!"; struct trap *t; - const char *pullmsg = "The ball pulls you out of the %s!"; + long side; - if (u.utrap && u.utraptype != TT_INFLOOR - && u.utraptype != TT_BURIEDBALL) { + if (u.utrap + && u.utraptype != TT_INFLOOR && u.utraptype != TT_BURIEDBALL) { switch (u.utraptype) { case TT_PIT: pline(pullmsg, "pit"); @@ -720,8 +721,8 @@ xchar x, y; case TT_LAVA: pline(pullmsg, hliquid("lava")); break; - case TT_BEARTRAP: { - register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; + case TT_BEARTRAP: + side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; pline(pullmsg, "bear trap"); set_wounded_legs(side, rn1(1000, 500)); if (!u.usteed) { @@ -734,8 +735,7 @@ xchar x, y; } break; } - } - u.utrap = 0; + reset_utrap(TRUE); fill_pit(u.ux, u.uy); } diff --git a/src/botl.c b/src/botl.c index 721ad2316..fde46e2fb 100644 --- a/src/botl.c +++ b/src/botl.c @@ -799,7 +799,7 @@ boolean *valsetlist; * all of the fields when context.botlx is set. The tty port in * particular has a problem if that isn't done, since the core sets * context.botlx when a menu or text display obliterates the status - * line. + * line. * * For those situations, to trigger the full update of every field * whether changed or not, call status_update() with BL_RESET. @@ -817,7 +817,7 @@ boolean *valsetlist; else if ((windowprocs.wincap2 & WC2_FLUSH_STATUS) != 0L) status_update(BL_FLUSH, (genericptr_t) 0, 0, 0, NO_COLOR, &cond_hilites[0]); - + context.botl = context.botlx = 0; update_all = FALSE; } diff --git a/src/cmd.c b/src/cmd.c index 54054f3c3..34d3ee19a 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -803,6 +803,7 @@ wiz_makemap(VOID_ARGS) ballrelease(FALSE); unplacebc(); } + reset_utrap(FALSE); /* also done by safe_teleds() for new level */ check_special_room(TRUE); dmonsfree(); savelev(-1, ledger_no(&u.uz), FREE_SAVE); @@ -2458,9 +2459,19 @@ int final; long save_BLev = BLevitation; BLevitation = 0L; - if (Levitation) - enl_msg(You_, "would levitate", "would have levitated", - if_surroundings_permitted, ""); + if (Levitation) { + /* either trapped in the floor or inside solid rock + (or both if chained to buried iron ball and have + moved one step into solid rock somehow) */ + boolean trapped = (save_BLev & I_SPECIAL) != 0L, + terrain = (save_BLev & FROMOUTSIDE) != 0L; + + Sprintf(buf, "%s%s%s", + trapped ? " if not trapped" : "", + (trapped && terrain) ? " and" : "", + terrain ? if_surroundings_permitted : ""); + enl_msg(You_, "would levitate", "would have levitated", buf, ""); + } BLevitation = save_BLev; } /* actively flying handled earlier as a status condition */ @@ -2468,15 +2479,27 @@ int final; long save_BFly = BFlying; BFlying = 0L; - if (Flying) + if (Flying) { enl_msg(You_, "would fly", "would have flown", + /* wording quibble: for past tense, "hadn't been" + would sound better than "weren't" (and + "had permitted" better than "permitted"), but + "weren't" and "permitted" are adequate so the + extra complexity to handle that isn't worth it */ Levitation ? " if you weren't levitating" - : (save_BFly == FROMOUTSIDE) - ? if_surroundings_permitted - /* both surroundings and [latent] levitation */ - : " if circumstances permitted", + : (save_BFly == I_SPECIAL) + /* this is an oversimpliction; being trapped + might also be blocking levitation so flight + would still be blocked after escaping trap */ + ? " if you weren't trapped" + : (save_BFly == FROMOUTSIDE) + ? if_surroundings_permitted + /* two or more of levitation, surroundings, + and being trapped in the floor */ + : " if circumstances permitted", ""); + } BFlying = save_BFly; } /* actively walking on water handled earlier as a status condition */ diff --git a/src/dig.c b/src/dig.c index a89b354be..1cdaee380 100644 --- a/src/dig.c +++ b/src/dig.c @@ -339,8 +339,8 @@ dig(VOID_ARGS) } else { You("destroy the bear trap with %s.", yobjnam(uwep, (const char *) 0)); - u.utrap = 0; /* release from trap */ deltrap(ttmp); + reset_utrap(TRUE); /* release from trap, maybe Lev or Fly */ } /* we haven't made any progress toward a pit yet */ context.digging.effort = 0; @@ -557,7 +557,7 @@ int ttyp; if (u.utraptype == TT_BURIEDBALL) buried_ball_to_punishment(); else if (u.utraptype == TT_INFLOOR) - u.utrap = 0; + reset_utrap(FALSE); } /* these furniture checks were in dighole(), but wand @@ -619,11 +619,10 @@ int ttyp; if (at_u) { if (!wont_fall) { - u.utrap = rn1(4, 2); - u.utraptype = TT_PIT; + set_utrap(rn1(4, 2), TT_PIT); vision_full_recalc = 1; /* vision limits change */ } else - u.utrap = 0; + reset_utrap(TRUE); if (oldobjs != newobjs) /* something unearthed */ (void) pickup(1); /* detects pit */ } else if (mtmp) { @@ -1103,7 +1102,7 @@ struct obj *obj; pline("You clear some debris from between the pits."); } } else if (u.utrap && u.utraptype == TT_PIT - && (trap_with_u = t_at(u.ux, u.uy))) { + && (trap_with_u = t_at(u.ux, u.uy)) != 0) { You("swing %s, but the rubble has no place to go.", yobjnam(obj, (char *) 0)); } else { @@ -1775,8 +1774,7 @@ buried_ball_to_punishment() (void) stop_timer(RUST_METAL, obj_to_any(ball)); #endif punish(ball); /* use ball as flag for unearthed buried ball */ - u.utrap = 0; - u.utraptype = 0; + reset_utrap(FALSE); del_engr_at(cc.x, cc.y); newsym(cc.x, cc.y); } @@ -1800,8 +1798,7 @@ buried_ball_to_freedom() #endif place_object(ball, cc.x, cc.y); stackobj(ball); - u.utrap = 0; - u.utraptype = 0; + reset_utrap(TRUE); del_engr_at(cc.x, cc.y); newsym(cc.x, cc.y); } diff --git a/src/do.c b/src/do.c index 9ce7b7adc..614b4cd17 100644 --- a/src/do.c +++ b/src/do.c @@ -171,7 +171,7 @@ const char *verb; "squished under a boulder", NO_KILLER_PREFIX); return FALSE; /* player remains trapped */ } else - u.utrap = 0; + reset_utrap(TRUE); } } if (*verb) { @@ -1246,7 +1246,7 @@ boolean at_stairs, falling, portal; check_special_room(TRUE); /* probably was a trap door */ if (Punished) unplacebc(); - u.utrap = 0; /* needed in level_tele */ + reset_utrap(FALSE); /* needed in level_tele */ fill_pit(u.ux, u.uy); u.ustuck = 0; /* idem */ u.uinwater = 0; diff --git a/src/do_name.c b/src/do_name.c index b6decaa86..aa688765a 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -175,7 +175,7 @@ const char *goal; } /* disgusting hack; the alternate selection characters work for any getpos call, but only matter for dowhatis (and doquickwhatis) */ - doing_what_is = (goal == what_is_an_unknown_object); + doing_what_is = (goal == what_is_an_unknown_object); if (doing_what_is) { Sprintf(kbuf, "'%s' or '%s' or '%s' or '%s'", visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]), @@ -2071,20 +2071,17 @@ char * rndorcname(s) char *s; { - int i; - const char *v[] = {"a", "ai", "og", "u"}; - const char *snd[] = {"gor", "gris", "un", "bane", "ruk", - "oth","ul", "z", "thos","akh","hai"}; - int vstart = rn2(2); - + static const char *v[] = { "a", "ai", "og", "u" }; + static const char *snd[] = { "gor", "gris", "un", "bane", "ruk", + "oth","ul", "z", "thos","akh","hai" }; + int i, iend = rn1(2, 3), vstart = rn2(2); + if (s) { *s = '\0'; - for (i = 0; i < rn2(2) + 3; ++i) { + for (i = 0; i < iend; ++i) { vstart = 1 - vstart; /* 0 -> 1, 1 -> 0 */ - if (!rn2(30) && i > 0) - (void) strcat(s, "-"); - (void) sprintf(eos(s), "%s", vstart ? v[rn2(SIZE(v))] : - snd[rn2(SIZE(snd))]); + Sprintf(eos(s), "%s%s", (i > 0 && !rn2(30)) ? "-" : "", + vstart ? v[rn2(SIZE(v))] : snd[rn2(SIZE(snd))]); } } return s; diff --git a/src/do_wear.c b/src/do_wear.c index 269370e81..7ab53a79e 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -185,10 +185,11 @@ Boots_on(VOID_ARGS) incr_itimeout(&HFumbling, rnd(20)); break; case LEVITATION_BOOTS: - if (!oldprop && !HLevitation && !BLevitation) { + if (!oldprop && !HLevitation && !(BLevitation & FROMOUTSIDE)) { makeknown(uarmf->otyp); float_up(); - spoteffects(FALSE); + if (Levitation) + spoteffects(FALSE); /* for sink effect */ } else { float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ } @@ -238,7 +239,7 @@ Boots_off(VOID_ARGS) HFumbling = EFumbling = 0; break; case LEVITATION_BOOTS: - if (!oldprop && !HLevitation && !BLevitation + if (!oldprop && !HLevitation && !(BLevitation & FROMOUTSIDE) && !context.takeoff.cancelled_don) { (void) float_down(0L, 0L); makeknown(otyp); @@ -902,10 +903,11 @@ register struct obj *obj; } break; case RIN_LEVITATION: - if (!oldprop && !HLevitation && !BLevitation) { + if (!oldprop && !HLevitation && !(BLevitation & FROMOUTSIDE)) { float_up(); learnring(obj, TRUE); - spoteffects(FALSE); /* for sinks */ + if (Levitation) + spoteffects(FALSE); /* for sinks */ } else { float_vs_flight(); /* maybe toggle (BFlying & I_SPECIAL) */ } @@ -1016,7 +1018,7 @@ boolean gone; } break; case RIN_LEVITATION: - if (!BLevitation) { + if (!(BLevitation & FROMOUTSIDE)) { (void) float_down(0L, 0L); if (!Levitation) learnring(obj, TRUE); diff --git a/src/dog.c b/src/dog.c index 1dc4018b9..e5767103a 100644 --- a/src/dog.c +++ b/src/dog.c @@ -412,7 +412,7 @@ boolean with_you; if (migrating_objs) deliver_obj_to_mon(mtmp, 0, DF_ALL); } - + if (xlocale && wander) { /* monster moved a bit; pick a nearby location */ /* mnearto() deals w/stone, et al */ diff --git a/src/dokick.c b/src/dokick.c index 99858a62f..1bea20ab6 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1694,7 +1694,7 @@ unsigned long deliverflags; where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ if ((where & MIGR_TO_SPECIES) == 0) continue; - + if ((mtmp->data->mflags2 & otmp->corpsenm) != 0) { obj_extract_self(otmp); otmp->owornmask = 0L; diff --git a/src/dothrow.c b/src/dothrow.c index 5a559ae4e..877740193 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1134,6 +1134,8 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ mon = u.ustuck; bhitpos.x = mon->mx; bhitpos.y = mon->my; + if (tethered_weapon) + tmp_at(DISP_TETHER, obj_to_glyph(obj)); } else if (u.dz) { if (u.dz < 0 /* Mjollnir must we wielded to be thrown--caller verifies this; @@ -1280,19 +1282,27 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ /* missile has already been handled */ if (tethered_weapon) tmp_at(DISP_END, 0); } else if (u.uswallow) { - if (tethered_weapon) + if (tethered_weapon) { tmp_at(DISP_END, 0); - /* ball is not picked up by monster */ - if (obj != uball) - (void) mpickobj(u.ustuck, obj); - thrownobj = (struct obj *) 0; + pline("%s returns to your hand!", The(xname(thrownobj))); + thrownobj = addinv(thrownobj); + (void) encumber_msg(); + if (thrownobj->owornmask & W_QUIVER) /* in case addinv() autoquivered */ + setuqwep((struct obj *) 0); + setuwep(thrownobj); + } else { + /* ball is not picked up by monster */ + if (obj != uball) + (void) mpickobj(u.ustuck, obj); + thrownobj = (struct obj *) 0; + } } else { /* Mjollnir must we wielded to be thrown--caller verifies this; aklys must we wielded as primary to return when thrown */ if ((obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE)) || tethered_weapon) { if (rn2(100)) { - if (tethered_weapon) + if (tethered_weapon) tmp_at(DISP_END, BACKTRACK); else sho_obj_return_to_u(obj); /* display its flight */ diff --git a/src/eat.c b/src/eat.c index 895cdf2a6..3e74d435f 100644 --- a/src/eat.c +++ b/src/eat.c @@ -3088,15 +3088,17 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ struct trap *ttmp = t_at(u.ux, u.uy); if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) { + boolean u_in_beartrap = (u.utrap && u.utraptype == TT_BEARTRAP); + /* If not already stuck in the trap, perhaps there should be a chance to becoming trapped? Probably not, because then the trap would just get eaten on the _next_ turn... */ Sprintf(qbuf, "There is a bear trap here (%s); eat it?", - (u.utrap && u.utraptype == TT_BEARTRAP) ? "holding you" - : "armed"); + u_in_beartrap ? "holding you" : "armed"); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { - u.utrap = u.utraptype = 0; deltrap(ttmp); + if (u_in_beartrap) + reset_utrap(TRUE); return mksobj(BEARTRAP, TRUE, FALSE); } else if (c == 'q') { return (struct obj *) 0; diff --git a/src/end.c b/src/end.c index fd5d73db9..7b10d2c0e 100644 --- a/src/end.c +++ b/src/end.c @@ -870,7 +870,7 @@ int how; else multi = -1; if (u.utrap && u.utraptype == TT_LAVA) - u.utrap = 0; + reset_utrap(FALSE); context.botl = 1; u.ugrave_arise = NON_PM; HUnchanging = 0L; diff --git a/src/engrave.c b/src/engrave.c index abd531abf..39c4005be 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -690,7 +690,7 @@ doengrave() xcrypt(blengr(), buf); } dengr = TRUE; - } + } break; case WAN_NOTHING: case WAN_UNDEAD_TURNING: diff --git a/src/files.c b/src/files.c index c122c3794..77ff211c8 100644 --- a/src/files.c +++ b/src/files.c @@ -666,7 +666,7 @@ void really_close() { int fd; - + if (lftrack.init) { fd = lftrack.fd; @@ -2156,24 +2156,27 @@ char sep; return (char *) 0; while (*str) { - if (*str == sep) nsep++; - str++; + if (*str == sep) + nsep++; + str++; } csep = rn2(nsep); str = begin; while ((csep > 0) && *str) { - str++; - if (*str == sep) csep--; + str++; + if (*str == sep) + csep--; } if (*str) { - if (*str == sep) str++; - begin = str; - while (*str && *str != sep) { - str++; - len++; - } - *str = '\0'; - if (len) + if (*str == sep) + str++; + begin = str; + while (*str && *str != sep) { + str++; + len++; + } + *str = '\0'; + if (len) return begin; } return (char *) 0; @@ -3582,7 +3585,7 @@ const char *reason; /* explanation */ void testinglog(filenm, type, reason) const char *filenm; /* ad hoc file name */ -const char *type; +const char *type; const char *reason; /* explanation */ { FILE *lfile; diff --git a/src/hack.c b/src/hack.c index 1a83ae3d9..29261a968 100644 --- a/src/hack.c +++ b/src/hack.c @@ -539,11 +539,17 @@ dosinkfall() int dmg; boolean lev_boots = (uarmf && uarmf->otyp == LEVITATION_BOOTS), innate_lev = ((HLevitation & (FROMOUTSIDE | FROMFORM)) != 0L), - ufall = (!innate_lev && !(HFlying || EFlying)); /* BFlying */ + /* to handle being chained to buried iron ball, trying to + levitate but being blocked, then moving onto adjacent sink; + no need to worry about being blocked by terrain because we + couldn't be over a sink at the same time */ + blockd_lev = (BLevitation == I_SPECIAL), + ufall = (!innate_lev && !blockd_lev + && !(HFlying || EFlying)); /* BFlying */ if (!ufall) { - You(innate_lev ? "wobble unsteadily for a moment." - : "gain control of your flight."); + You((innate_lev || blockd_lev) ? "wobble unsteadily for a moment." + : "gain control of your flight."); } else { long save_ELev = ELevitation, save_HLev = HLevitation; @@ -1179,6 +1185,10 @@ struct trap *desttrap; /* nonnull if another trap at */ if (!u.utrap) return TRUE; /* sanity check */ + /* + * Note: caller should call reset_utrap() when we set u.utrap to 0. + */ + switch (u.utraptype) { case TT_BEARTRAP: if (flags.verbose) { @@ -1203,7 +1213,6 @@ struct trap *desttrap; /* nonnull if another trap at */ break; case TT_WEB: if (uwep && uwep->oartifact == ART_STING) { - u.utrap = 0; pline("Sting cuts through the web!"); break; /* escape trap but don't move */ } @@ -1656,7 +1665,12 @@ domove() return; if (u.utrap) { - if (!trapmove(x, y, trap)) + boolean moved = trapmove(x, y, trap); + + if (!u.utrap) + reset_utrap(TRUE); /* might resume levitation or flight */ + /* might not have escaped, or did escape but remain in same spot */ + if (!moved) return; } @@ -1927,13 +1941,15 @@ switch_terrain() || (Is_waterlevel(&u.uz) && lev->typ == WATER)); if (blocklev) { - /* called from spoteffects(), skip float_down() */ + /* called from spoteffects(), stop levitating but skip float_down() */ if (Levitation) You_cant("levitate in here."); BLevitation |= FROMOUTSIDE; } else if (BLevitation) { BLevitation &= ~FROMOUTSIDE; - if (Levitation) + /* we're probably levitating now; if not, we must be chained + to a buried iron ball so get float_up() feedback for that */ + if (Levitation || BLevitation) float_up(); } /* the same terrain that blocks levitation also blocks flight */ @@ -2042,7 +2058,7 @@ boolean pick; struct monst *mtmp; struct trap *trap = t_at(u.ux, u.uy); - int trapflag = iflags.failing_untrap ? FORCETRAP : 0; + int trapflag = iflags.failing_untrap ? FAILEDUNTRAP : 0; /* prevent recursion from affecting the hero all over again [hero poly'd to iron golem enters water here, drown() inflicts @@ -2058,7 +2074,7 @@ boolean pick; spotterrain = levl[u.ux][u.uy].typ; spotloc.x = u.ux, spotloc.y = u.uy; - /* moving onto different terrain might cause Levitation to toggle */ + /* moving onto different terrain might cause Lev or Fly to toggle */ if (spotterrain != levl[u.ux0][u.uy0].typ || !on_level(&u.uz, &u.uz0)) switch_terrain(); @@ -2890,7 +2906,7 @@ boolean k_format; int weight_cap() { - long carrcap, save_ELev = ELevitation; + long carrcap, save_ELev = ELevitation, save_BLev = BLevitation; /* boots take multiple turns to wear but any properties they confer are enabled at the start rather than the end; that @@ -2900,6 +2916,9 @@ weight_cap() ELevitation &= ~W_ARMF; float_vs_flight(); /* in case Levitation is blocking Flying */ } + /* levitation is blocked by being trapped in the floor, but it still + functions enough in that situation to enhance carrying capacity */ + BLevitation &= ~I_SPECIAL; carrcap = 25 * (ACURRSTR + ACURR(A_CON)) + 50; if (Upolyd) { @@ -2930,8 +2949,9 @@ weight_cap() carrcap = 0; } - if (ELevitation != save_ELev) { + if (ELevitation != save_ELev || BLevitation != save_BLev) { ELevitation = save_ELev; + BLevitation = save_BLev; float_vs_flight(); } diff --git a/src/invent.c b/src/invent.c index 84e6367df..34b784475 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2592,7 +2592,7 @@ long *out_cnt; int unid_cnt; char prompt[QBUFSZ]; - unid_cnt = count_unidentified(invent); + unid_cnt = count_unidentified(invent); Sprintf(prompt, "Debug Identify"); /* 'title' rather than 'prompt' */ if (unid_cnt) Sprintf(eos(prompt), diff --git a/src/makemon.c b/src/makemon.c index ae73ae309..cbc57a0e0 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1391,8 +1391,8 @@ int mmflags; } if (allow_minvent && migrating_objs) - deliver_obj_to_mon(mtmp, 1, DF_NONE); /* in case there's waiting items */ - + deliver_obj_to_mon(mtmp, 1, DF_NONE); /* in case of waiting items */ + if (!in_mklev) newsym(mtmp->mx, mtmp->my); /* make sure the mon shows up */ diff --git a/src/mhitm.c b/src/mhitm.c index 7426a135a..5244d919d 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -780,13 +780,13 @@ struct attack *mattk; /* Kill off aggressor if it didn't die. */ if (!(result & MM_AGR_DIED)) { - boolean was_leashed = (magr->mleashed); + boolean was_leashed = (magr->mleashed != 0); mondead(magr); if (!DEADMONSTER(magr)) return result; /* life saved */ result |= MM_AGR_DIED; - + /* mondead() -> m_detach() -> m_unleash() always suppresses the m_unleash() slack message, so deliver it here instead */ if (was_leashed) diff --git a/src/mhitu.c b/src/mhitu.c index 7ae3ff103..f3fecbd92 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1774,7 +1774,7 @@ struct attack *mattk; if (u.utrap) { You("are released from the %s!", u.utraptype == TT_WEB ? "web" : "trap"); - u.utrap = 0; + reset_utrap(FALSE); } i = number_leashed(); diff --git a/src/mklev.c b/src/mklev.c index 3a488597d..baf1608d9 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1686,9 +1686,9 @@ mkinvokearea() /* any trap hero is stuck in will be going away now */ if (u.utrap) { - u.utrap = 0; if (u.utraptype == TT_BURIEDBALL) buried_ball_to_punishment(); + reset_utrap(FALSE); } mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */ diff --git a/src/mkmaze.c b/src/mkmaze.c index 85b34d337..1d13685d1 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -815,11 +815,10 @@ stolen_booty(VOID_ARGS) mtyp = rn2((PM_ORC_SHAMAN - PM_ORC) + 1) + PM_ORC; mtmp = makemon(&mons[mtyp], 0, 0, MM_NONAME); if (mtmp) { - shiny_orc_stuff(mtmp); + shiny_orc_stuff(mtmp); migrate_orc(mtmp, 0UL); } } - ransacked = 0; } diff --git a/src/mon.c b/src/mon.c index 72f3df1a6..49ab5ac6a 100644 --- a/src/mon.c +++ b/src/mon.c @@ -462,7 +462,7 @@ unsigned corpseflags; * underneath it, you could be told the corpse type of a * monster that you never knew was there without this. * The code in hitmu() substitutes the word "something" - * if the corpses obj->dknown is 0. + * if the corpse's obj->dknown is 0. */ if (Blind && !sensemon(mtmp)) obj->dknown = 0; diff --git a/src/monmove.c b/src/monmove.c index fc32ebfb8..5694a31b8 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -255,14 +255,12 @@ struct monst *mon; } } -#define flees_light(mon) ((mon)->data == &mons[PM_GREMLIN] && \ - (uwep && artifact_light(uwep) && uwep->lamplit)) - +#define flees_light(mon) ((mon)->data == &mons[PM_GREMLIN] \ + && (uwep && artifact_light(uwep) && uwep->lamplit)) /* we could include this in the above macro, but probably overkill/overhead */ -/* (!((which_armor((mon), W_ARMC) != 0) && ((which_armor((mon), W_ARMH) != 0))) && */ +/* && (!(which_armor((mon), W_ARMC) != 0 */ +/* && which_armor((mon), W_ARMH) != 0)) */ - - /* monster begins fleeing for the specified time, 0 means untimed flee * if first, only adds fleetime if monster isn't already fleeing * if fleemsg, prints a message about new flight, otherwise, caller should */ diff --git a/src/music.c b/src/music.c index cb63bde90..b9e159e75 100644 --- a/src/music.c +++ b/src/music.c @@ -254,14 +254,10 @@ int force; start_y = u.uy - (force * 2); end_x = u.ux + (force * 2); end_y = u.uy + (force * 2); - if (start_x < 1) - start_x = 1; - if (start_y < 1) - start_y = 1; - if (end_x >= COLNO) - end_x = COLNO - 1; - if (end_y >= ROWNO) - end_y = ROWNO - 1; + start_x = max(start_x, 1); + start_y = max(start_y, 0); + end_x = min(end_x, COLNO - 1); + end_y = min(end_y, ROWNO - 1); for (x = start_x; x <= end_x; x++) for (y = start_y; y <= end_y; y++) { if ((mtmp = m_at(x, y)) != 0) { @@ -311,6 +307,11 @@ int force; break; /* no pit if portal at that location */ chasm->tseen = 1; + /* TODO: + * This ought to be split into a separate routine to + * reduce indentation and the consequent line-wraps. + */ + levl[x][y].doormask = 0; /* * Let liquid flow into the newly created chasm. @@ -328,8 +329,8 @@ int force; if ((otmp = sobj_at(BOULDER, x, y)) != 0) { if (cansee(x, y)) pline("KADOOM! The boulder falls into a chasm%s!", - ((x == u.ux) && (y == u.uy)) ? " below you" - : ""); + (x == u.ux && y == u.uy) ? " below you" + : ""); if (mtmp) mtmp->mtrapped = 0; obj_extract_self(otmp); @@ -343,6 +344,7 @@ int force; if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) { boolean m_already_trapped = mtmp->mtrapped; + mtmp->mtrapped = 1; if (!m_already_trapped) { /* suppress messages */ if (cansee(x, y)) @@ -375,6 +377,16 @@ int force; } } } else if (x == u.ux && y == u.uy) { + if (u.utrap && u.utraptype == TT_BURIEDBALL) { + /* Note: the chain should break if a pit gets + created at the buried ball's location, which + is not necessarily here. But if we don't do + things this way, entering the new pit below + will override current trap anyway, but too + late to get Lev and Fly handling. */ + Your("chain breaks!"); + reset_utrap(TRUE); + } if (Levitation || Flying || is_clinger(youmonst.data)) { if (!tu_pit) { /* no pit here previously */ @@ -384,10 +396,9 @@ int force; } else if (!tu_pit || !u.utrap || (u.utrap && u.utraptype != TT_PIT)) { /* no pit here previously, or you were - not in it even it there was */ + not in it even if there was */ You("fall into a chasm!"); - u.utrap = rn1(6, 2); - u.utraptype = TT_PIT; + set_utrap(rn1(6, 2), TT_PIT); losehp(Maybe_Half_Phys(rnd(6)), "fell into a chasm", NO_KILLER_PREFIX); selftouch("Falling, you"); @@ -396,9 +407,9 @@ int force; ((Fumbling && !rn2(5)) || (!rnl(Role_if(PM_ARCHEOLOGIST) ? 3 : 9)) || ((ACURR(A_DEX) > 7) && rn2(5))); + You("are jostled around violently!"); - u.utrap = rn1(6, 2); - u.utraptype = TT_PIT; /* superfluous */ + set_utrap(rn1(6, 2), TT_PIT); losehp(Maybe_Half_Phys(rnd(keepfooting ? 2 : 4)), "hurt in a chasm", NO_KILLER_PREFIX); if (keepfooting) @@ -587,7 +598,7 @@ struct obj *instr; exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ - /* a drum of earthquake does cause not cause deafness + /* a drum of earthquake does not cause deafness while still magically functional, nor afterwards when it invokes the LEATHER_DRUM case instead and mundane is flagged */ @@ -605,8 +616,8 @@ struct obj *instr; You("beat a deafening row!"); incr_itimeout(&HDeaf, rn1(20, 30)); exercise(A_WIS, FALSE); - } else - You("%s %s.", + } else + You("%s %s.", rn2(2) ? "butcher" : rn2(2) ? "manage" : "pull off", an(beats[rn2(SIZE(beats))])); awaken_monsters(u.ulevel * (mundane ? 5 : 40)); diff --git a/src/options.c b/src/options.c index 9829874e8..e337b4c36 100644 --- a/src/options.c +++ b/src/options.c @@ -78,7 +78,7 @@ static struct Bool_Opt { #else { "asksavedisk", (boolean *) 0, FALSE, SET_IN_FILE }, #endif - { "autodescribe", &iflags.autodescribe, FALSE, SET_IN_GAME }, + { "autodescribe", &iflags.autodescribe, TRUE, SET_IN_GAME }, { "autodig", &flags.autodig, FALSE, SET_IN_GAME }, { "autoopen", &flags.autoopen, TRUE, SET_IN_GAME }, { "autopickup", &flags.pickup, TRUE, SET_IN_GAME }, diff --git a/src/pager.c b/src/pager.c index 4515ea8e8..c1824d2f8 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1390,7 +1390,7 @@ boolean without_asking; } display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin), datawin = WIN_ERR; - } + } } } @@ -1470,7 +1470,7 @@ doidtrap() commands: basic letters vs digits, 'g' vs 'G' for '5', phone keypad vs normal layout of digits, and QWERTZ keyboard swap between y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.) - + The interpretor understands '&#' for comment, '&? option' for 'if' (also '&? !option' @@ -1481,7 +1481,7 @@ doidtrap() '&:' for 'else' (also '&: #comment'; 0 or 1 instance for a given 'if'), and '&.' for 'endif' (also '&. #comment'; required for each 'if'). - + The option handling is a bit of a mess, with no generality for which options to deal with and only a comma separated list of integer values for the '=value' part. number_pad is the only diff --git a/src/polyself.c b/src/polyself.c index c7f9c538d..e136d1898 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -86,7 +86,10 @@ set_uasmon() PROPSET(TELEPORT, can_teleport(mdat)); PROPSET(TELEPORT_CONTROL, control_teleport(mdat)); PROPSET(LEVITATION, is_floater(mdat)); - PROPSET(FLYING, is_flyer(mdat)); + /* floating eye is the only 'floater'; it is also flagged as a 'flyer'; + suppress flying for it so that enlightenment doesn't confusingly + show latent flight capability always blocked by levitation */ + PROPSET(FLYING, (is_flyer(mdat) && !is_floater(mdat))); PROPSET(SWIMMING, is_swimmer(mdat)); /* [don't touch MAGICAL_BREATHING here; both Amphibious and Breathless key off of it but include different monster forms...] */ @@ -116,12 +119,21 @@ set_uasmon() void float_vs_flight() { - /* floating overrides flight; normally float_up() and float_down() - handle this, but sometimes they're skipped */ - if (HLevitation || ELevitation) + boolean stuck_in_floor = (u.utrap && u.utraptype != TT_PIT); + + /* floating overrides flight; so does being trapped in the floor */ + if ((HLevitation || ELevitation) + || ((HFlying || EFlying) && stuck_in_floor)) BFlying |= I_SPECIAL; else BFlying &= ~I_SPECIAL; + /* being trapped on the ground (bear trap, web, molten lava survived + with fire resistance, former lava solidified via cold, tethered + to a buried iron ball) overrides floating--the floor is reachable */ + if ((HLevitation || ELevitation) && stuck_in_floor) + BLevitation |= I_SPECIAL; + else + BLevitation &= ~I_SPECIAL; context.botl = TRUE; } @@ -207,8 +219,8 @@ const char *fmt, *arg; if (u.twoweap && !could_twoweap(youmonst.data)) untwoweapon(); - if (u.utraptype == TT_PIT && u.utrap) { - u.utrap = rn1(6, 2); /* time to escape resets */ + if (u.utrap && u.utraptype == TT_PIT) { + set_utrap(rn1(6, 2), TT_PIT); /* time to escape resets */ } if (was_blind && !Blind) { /* reverting from eyeless */ Blinded = 1L; @@ -725,8 +737,8 @@ int mntmp; drop_weapon(1); (void) hideunder(&youmonst); - if (u.utraptype == TT_PIT && u.utrap) { - u.utrap = rn1(6, 2); /* time to escape resets */ + if (u.utrap && u.utraptype == TT_PIT) { + set_utrap(rn1(6, 2), TT_PIT); /* time to escape resets */ } if (was_blind && !Blind) { /* previous form was eyeless */ Blinded = 1L; @@ -794,17 +806,17 @@ int mntmp; spoteffects(TRUE); if (Passes_walls && u.utrap && (u.utraptype == TT_INFLOOR || u.utraptype == TT_BURIEDBALL)) { - u.utrap = 0; - if (u.utraptype == TT_INFLOOR) + if (u.utraptype == TT_INFLOOR) { pline_The("rock seems to no longer trap you."); - else { + } else { pline_The("buried ball is no longer bound to you."); buried_ball_to_freedom(); } + reset_utrap(TRUE); } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) { - u.utrap = 0; pline_The("%s now feels soothing.", hliquid("lava")); + reset_utrap(TRUE); } if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { @@ -823,11 +835,11 @@ int mntmp; You("are no longer stuck in the %s.", u.utraptype == TT_WEB ? "web" : "bear trap"); /* probably should burn webs too if PM_FIRE_ELEMENTAL */ - u.utrap = 0; + reset_utrap(TRUE); } if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) { You("orient yourself on the web."); - u.utrap = 0; + reset_utrap(TRUE); } check_strangling(TRUE); /* maybe start strangling */ @@ -1018,6 +1030,8 @@ int alone; void rehumanize() { + boolean was_flying = (Flying != 0); + /* You can't revert back while unchanging */ if (Unchanging) { if (u.mh < 1) { @@ -1048,7 +1062,9 @@ rehumanize() context.botl = 1; vision_full_recalc = 1; (void) encumber_msg(); - + if (was_flying && !Flying && u.usteed) + You("and %s return gently to the %s.", + mon_nam(u.usteed), surface(u.ux, u.uy)); retouch_equipment(2); if (!uarmg) selftouch(no_longer_petrify_resistant); diff --git a/src/pray.c b/src/pray.c index 5d0d456fc..bd8a3604e 100644 --- a/src/pray.c +++ b/src/pray.c @@ -355,7 +355,7 @@ int trouble; You("are back on solid ground."); /* teleport should always succeed, but if not, just untrap them */ if (!safe_teleds(FALSE)) - u.utrap = 0; + reset_utrap(TRUE); break; case TROUBLE_STARVING: /* temporarily lost strength recovery now handled by init_uhunger() */ diff --git a/src/steed.c b/src/steed.c index aa2beb300..1abdb867c 100644 --- a/src/steed.c +++ b/src/steed.c @@ -335,6 +335,8 @@ boolean force; /* Quietly force this animal */ /* Must have Lev_at_will at this point */ pline("%s magically floats up!", Monnam(mtmp)); You("mount %s.", mon_nam(mtmp)); + if (Flying) + You("and %s take flight together.", mon_nam(mtmp)); } /* setuwep handles polearms differently when you're mounted */ if (uwep && is_pole(uwep)) diff --git a/src/teleport.c b/src/teleport.c index 615292d5d..a1adfd95d 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -289,7 +289,7 @@ boolean allow_drag; } } } - u.utrap = 0; + reset_utrap(FALSE); u.ustuck = 0; u.ux0 = u.ux; u.uy0 = u.uy; diff --git a/src/trap.c b/src/trap.c index 056570906..957e0f63c 100644 --- a/src/trap.c +++ b/src/trap.c @@ -805,10 +805,12 @@ struct trap *trap; { boolean isyou = (mtmp == &youmonst); struct permonst *mptr = mtmp->data; + if (amorphous(mptr) || is_whirly(mptr) || flaming(mptr) || unsolid(mptr) || mptr == &mons[PM_GELATINOUS_CUBE]) { xchar x = trap->tx; xchar y = trap->ty; + if (flaming(mptr) || acidic(mptr)) { if (domsg) { if (isyou) @@ -825,9 +827,9 @@ struct trap *trap; return TRUE; } if (domsg) { - if (isyou) + if (isyou) { You("flow through %s spider web.", a_your[trap->madeby_u]); - else { + } else { pline("%s flows through %s spider web.", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); @@ -853,6 +855,37 @@ struct trap *trap; return otmp; } +void +set_utrap(tim, typ) +unsigned tim, typ; +{ + u.utrap = tim; + /* FIXME: + * utraptype==0 is bear trap rather than 'none'; we probably ought + * to change that but can't do so until save file compatability is + * able to be broken. + */ + u.utraptype = tim ? typ : 0; + + float_vs_flight(); /* maybe block Lev and/or Fly */ +} + +void +reset_utrap(msg) +boolean msg; +{ + boolean was_Lev = (Levitation != 0), was_Fly = (Flying != 0); + + set_utrap(0, 0); + + if (msg) { + if (!was_Lev && Levitation) + float_up(); + if (!was_Fly && Flying) + You("can fly."); + } +} + void dotrap(trap, trflags) register struct trap *trap; @@ -861,7 +894,8 @@ unsigned trflags; register int ttype = trap->ttyp; struct obj *otmp; boolean already_seen = trap->tseen, - forcetrap = (trflags & FORCETRAP) != 0, + forcetrap = ((trflags & FORCETRAP) != 0 + || (trflags & FAILEDUNTRAP) != 0), webmsgok = (trflags & NOWEBMSG) == 0, forcebungle = (trflags & FORCEBUNGLE) != 0, plunged = (trflags & TOOKPLUNGE) != 0, @@ -1042,13 +1076,12 @@ unsigned trflags; A_Your[trap->madeby_u]); break; } - u.utrap = rn1(4, 4); - u.utraptype = TT_BEARTRAP; + set_utrap((unsigned) rn1(4, 4), TT_BEARTRAP); if (u.usteed) { pline("%s bear trap closes on %s %s!", A_Your[trap->madeby_u], s_suffix(mon_nam(u.usteed)), mbodypart(u.usteed, FOOT)); if (thitm(0, u.usteed, (struct obj *) 0, dmg, FALSE)) - u.utrap = 0; /* steed died, hero not trapped */ + reset_utrap(TRUE); /* steed died, hero not trapped */ } else { pline("%s bear trap closes on your %s!", A_Your[trap->madeby_u], body_part(FOOT)); @@ -1191,8 +1224,12 @@ unsigned trflags; } else You("%s %s!", conj_pit ? "step" : "land", predicament); } - u.utrap = rn1(6, 2); - u.utraptype = TT_PIT; + /* FIXME: + * if hero gets killed here, setting u.utrap in advance will + * show "you were trapped in a pit" during disclosure's display + * of enlightenment, but hero is dying *before* becoming trapped. + */ + set_utrap((unsigned) rn1(6, 2), TT_PIT); if (!steedintrap(trap, (struct obj *) 0)) { if (ttype == SPIKED_PIT) { oldumort = u.umortality; @@ -1286,11 +1323,13 @@ unsigned trflags; } You("%s %s spider web!", verbbuf, a_your[trap->madeby_u]); } - u.utraptype = TT_WEB; + + /* time will be adjusted below */ + set_utrap(1, TT_WEB); /* Time stuck in the web depends on your/steed strength. */ { - register int str = ACURR(A_STR); + int tim, str = ACURR(A_STR); /* If mounted, the steed gets trapped. Use mintrap * to do all the work. If mtrapped is set as a result, @@ -1312,32 +1351,34 @@ unsigned trflags; if (strongmonst(u.usteed->data)) str = 17; } else { + reset_utrap(FALSE); break; } webmsgok = FALSE; /* mintrap printed the messages */ } if (str <= 3) - u.utrap = rn1(6, 6); + tim = rn1(6, 6); else if (str < 6) - u.utrap = rn1(6, 4); + tim = rn1(6, 4); else if (str < 9) - u.utrap = rn1(4, 4); + tim = rn1(4, 4); else if (str < 12) - u.utrap = rn1(4, 2); + tim = rn1(4, 2); else if (str < 15) - u.utrap = rn1(2, 2); + tim = rn1(2, 2); else if (str < 18) - u.utrap = rnd(2); + tim = rnd(2); else if (str < 69) - u.utrap = 1; + tim = 1; else { - u.utrap = 0; + tim = 0; if (webmsgok) You("tear through %s web!", a_your[trap->madeby_u]); deltrap(trap); newsym(u.ux, u.uy); /* get rid of trap symbol */ } + set_utrap((unsigned) tim, TT_WEB); } break; @@ -2767,16 +2808,34 @@ float_up() context.botl = TRUE; if (u.utrap) { if (u.utraptype == TT_PIT) { - u.utrap = 0; + reset_utrap(FALSE); You("float up, out of the pit!"); vision_full_recalc = 1; /* vision limits change */ fill_pit(u.ux, u.uy); - } else if (u.utraptype == TT_INFLOOR) { + } else if (u.utraptype == TT_LAVA /* molten lava */ + || u.utraptype == TT_INFLOOR) { /* solidified lava */ Your("body pulls upward, but your %s are still stuck.", makeplural(body_part(LEG))); - } else { - You("float up, only your %s is still stuck.", body_part(LEG)); + } else if (u.utraptype == TT_BURIEDBALL) { /* tethered */ + coord cc; + + cc.x = u.ux, cc.y = u.uy; + /* caveat: this finds the first buried iron ball within + one step of the specified location, not necessarily the + buried [former] uball at the original anchor point */ + (void) buried_ball(&cc); + /* being chained to the floor blocks levitation from floating + above that floor but not from enhancing carrying capacity */ + You("feel lighter, but your %s is still chained to the %s.", + body_part(LEG), + IS_ROOM(levl[cc.x][cc.y].typ) ? "floor" : "ground"); + } else if (u.utraptype == WEB) { + You("float up slightly, but you are still stuck in the web."); + } else { /* bear trap */ + You("float up slightly, but your %s is still stuck.", + body_part(LEG)); } + /* when still trapped, float_vs_flight() below will block levitation */ #if 0 } else if (Is_waterlevel(&u.uz)) { pline("It feels as though you've lost some weight."); @@ -2795,8 +2854,7 @@ float_up() } else { You("start to float in the air!"); } - if (u.usteed && !is_floater(u.usteed->data) - && !is_flyer(u.usteed->data)) { + if (u.usteed && !is_floater(u.usteed->data) && !is_flyer(u.usteed->data)) { if (Lev_at_will) { pline("%s magically floats up!", Monnam(u.usteed)); } else { @@ -2806,7 +2864,7 @@ float_up() } if (Flying) You("are no longer able to control your flight."); - BFlying |= I_SPECIAL; + float_vs_flight(); /* set BFlying, also BLevitation if still trapped */ /* levitation gives maximum carrying capacity, so encumbrance state might be reduced */ (void) encumber_msg(); @@ -2841,16 +2899,29 @@ long hmask, emask; /* might cancel timeout */ if (Levitation) return 0; /* maybe another ring/potion/boots */ if (BLevitation) { - /* Levitation is blocked, so hero is not actually floating - hence shouldn't have float_down effects and feedback */ - float_vs_flight(); /* before nomul() rather than after */ + /* if blocked by terrain, we haven't actually been levitating so + we don't give any end-of-levitation feedback or side-effects, + but if blocking is solely due to being trapped in/on floor, + do give some feedback but skip other float_down() effects */ + boolean trapped = (BLevitation == I_SPECIAL); + + float_vs_flight(); + if (trapped && u.utrap) /* u.utrap => paranoia */ + You("are no longer trying to float up from the %s.", + (u.utraptype == TT_BEARTRAP) ? "trap's jaws" + : (u.utraptype == TT_WEB) ? "web" + : (u.utraptype == TT_BURIEDBALL) ? "chain" + : (u.utraptype == TT_LAVA) ? "lava" + : "ground"); /* TT_INFLOOR */ + (void) encumber_msg(); /* carrying capacity might have changed */ return 0; } context.botl = TRUE; nomul(0); /* stop running or resting */ if (BFlying) { /* controlled flight no longer overridden by levitation */ - BFlying &= ~I_SPECIAL; + float_vs_flight(); /* clears BFlying & I_SPECIAL + * unless hero is stuck in floor */ if (Flying) { You("have stopped levitating and are now flying."); (void) encumber_msg(); /* carrying capacity might have changed */ @@ -2981,7 +3052,7 @@ climb_pit() if (Passes_walls) { /* marked as trapped so they can pick things up */ You("ascend from the pit."); - u.utrap = 0; + reset_utrap(FALSE); fill_pit(u.ux, u.uy); vision_full_recalc = 1; /* vision limits change */ } else if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) { @@ -2993,10 +3064,11 @@ climb_pit() /* eg fell in pit, then poly'd to a flying monster; or used '>' to deliberately enter it */ You("%s from the pit.", Flying ? "fly" : "climb"); - u.utrap = 0; + reset_utrap(FALSE); fill_pit(u.ux, u.uy); vision_full_recalc = 1; /* vision limits change */ } else if (!(--u.utrap)) { + reset_utrap(FALSE); You("%s to the edge of the pit.", (Sokoban && Levitation) ? "struggle against the air currents and float" @@ -3887,7 +3959,7 @@ boolean bury_it; } newsym(ttmp->tx, ttmp->ty); if (u.utrap && ttmp->tx == u.ux && ttmp->ty == u.uy) - u.utrap = 0; + reset_utrap(TRUE); deltrap(ttmp); } @@ -3918,7 +3990,7 @@ struct trap *ttmp; there are objects covering this trap */ ttmp->tseen = 0; /* hack for check_here() */ /* trigger the trap */ - iflags.failing_untrap++; /* spoteffects() -> dotrap(,FORCETRAP) */ + iflags.failing_untrap++; /* spoteffects() -> dotrap(,FAILEDUNTRAP) */ spoteffects(TRUE); /* pickup() + dotrap() */ iflags.failing_untrap--; /* this should no longer be necessary; before the failing_untrap @@ -4003,7 +4075,8 @@ boolean force_failure; pline("%s remains entangled.", Monnam(mtmp)); } } else if (under_u) { - dotrap(ttmp, 0); + /* [don't need the iflags.failing_untrap hack here] */ + dotrap(ttmp, FAILEDUNTRAP); } else { move_into_trap(ttmp); } @@ -4506,51 +4579,80 @@ struct monst *mon; boolean *noticed; /* set to true iff hero notices the effect; */ { /* otherwise left with its previous value intact */ struct trap *t; - char buf[BUFSZ]; - const char *trapdescr, *which; + char buf[BUFSZ], whichbuf[20]; + const char *trapdescr = 0, *which = 0; boolean ishero = (mon == &youmonst); if (!mon) return FALSE; if (mon == u.usteed) ishero = TRUE; - t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); - /* if no trap here or it's not a holding trap, we're done */ - if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) - return FALSE; - trapdescr = defsyms[trap_to_defsym(t->ttyp)].explanation; - which = t->tseen ? the_your[t->madeby_u] - : index(vowels, *trapdescr) ? "an" : "a"; + t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); + + if (ishero && u.utrap) { /* all u.utraptype values are holding traps */ + which = ""; + switch (u.utraptype) { + case TT_LAVA: + trapdescr = "molten lava"; + break; + case TT_INFLOOR: + /* solidified lava, so not "floor" even if within a room */ + trapdescr = "ground"; + break; + case TT_BURIEDBALL: + trapdescr = "your anchor"; + break; + case TT_BEARTRAP: + case TT_PIT: + case TT_WEB: + trapdescr = 0; /* use defsyms[].explanation */ + break; + default: + /* lint suppression in case 't' is unexpectedly Null + or u.utraptype has new value we don't know about yet */ + trapdescr = "trap"; + break; + } + } else { + /* if no trap here or it's not a holding trap, we're done */ + if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) + return FALSE; + } + + if (!trapdescr) + trapdescr = defsyms[trap_to_defsym(t->ttyp)].explanation; + if (!which) + which = t->tseen ? the_your[t->madeby_u] + : index(vowels, *trapdescr) ? "an" : "a"; + if (*which) + which = strcat(strcpy(whichbuf, which), " "); if (ishero) { if (!u.utrap) return FALSE; - u.utrap = 0; /* released regardless of type */ *noticed = TRUE; - /* give message only if trap was the expected type */ - if (u.utraptype == TT_BEARTRAP || u.utraptype == TT_WEB) { - if (u.usteed) - Sprintf(buf, "%s is", noit_Monnam(u.usteed)); - else - Strcpy(buf, "You are"); - pline("%s released from %s %s.", buf, which, trapdescr); - } + if (u.usteed) + Sprintf(buf, "%s is", noit_Monnam(u.usteed)); + else + Strcpy(buf, "You are"); + pline("%s released from %s%s.", buf, which, trapdescr); + reset_utrap(TRUE); } else { if (!mon->mtrapped) return FALSE; mon->mtrapped = 0; if (canspotmon(mon)) { *noticed = TRUE; - pline("%s is released from %s %s.", Monnam(mon), which, + pline("%s is released from %s%s.", Monnam(mon), which, trapdescr); } else if (cansee(t->tx, t->ty) && t->tseen) { *noticed = TRUE; if (t->ttyp == WEB) - pline("%s is released from %s %s.", Something, which, + pline("%s is released from %s%s.", Something, which, trapdescr); else /* BEAR_TRAP */ - pline("%s %s opens.", upstart(strcpy(buf, which)), trapdescr); + pline("%s%s opens.", upstart(strcpy(buf, which)), trapdescr); } /* might pacify monster if adjacent */ if (rn2(2) && distu(mon->mx, mon->my) <= 2) @@ -5002,8 +5104,8 @@ register struct trap *ttmp; register struct monst *mtmp; if (ttmp->tx == u.ux && ttmp->ty == u.uy) { - u.utrap = 0; - u.utraptype = 0; + if (u.utraptype != TT_BURIEDBALL) + reset_utrap(TRUE); } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { mtmp->mtrapped = 0; } @@ -5211,12 +5313,11 @@ lava_effects() boil_away = !Fire_resistance; /* if not fire resistant, sink_into_lava() will quickly be fatal; hero needs to escape immediately */ - u.utrap = rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8); - u.utraptype = TT_LAVA; + set_utrap((unsigned) (rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8)), + TT_LAVA); You("sink into the %s%s!", hliquid("lava"), - !boil_away - ? ", but it only burns slightly" - : " and are about to be immolated"); + !boil_away ? ", but it only burns slightly" + : " and are about to be immolated"); if (u.uhp > 1) losehp(!boil_away ? 1 : (u.uhp / 2), lava_killer, KILLED_BY); /* lava damage */ @@ -5238,7 +5339,7 @@ sink_into_lava() if (!u.utrap || u.utraptype != TT_LAVA) { ; /* do nothing; this shouldn't happen */ } else if (!is_lava(u.ux, u.uy)) { - u.utrap = 0; /* this shouldn't happen either */ + reset_utrap(FALSE); /* this shouldn't happen either */ } else if (!u.uinvulnerable) { /* ordinarily we'd have to be fire resistant to survive long enough to become stuck in lava, but it can happen without @@ -5255,8 +5356,10 @@ sink_into_lava() burn_away_slime(); /* add insult to injury? */ done(DISSOLVED); /* can only get here via life-saving; try to get away from lava */ - u.utrap = 0; - (void) safe_teleds(TRUE); + reset_utrap(TRUE); + /* levitation or flight have become unblocked, otherwise Tport */ + if (!Levitation && !Flying) + (void) safe_teleds(TRUE); } else if (!u.umoved) { /* can't fully turn into slime while in lava, but might not have it be burned away until you've come awfully close */ diff --git a/src/version.c b/src/version.c index 5055e8df6..9b3763841 100644 --- a/src/version.c +++ b/src/version.c @@ -57,7 +57,7 @@ char *buf; Sprintf(eos(buf), " ("); #if defined(RUNTIME_PORT_ID) - tmp = get_port_id(tmpbuf); + tmp = get_port_id(tmpbuf); if (tmp) Sprintf(eos(buf), "%s%s", c++ ? "," : "", tmp); #endif diff --git a/src/zap.c b/src/zap.c index 7a5ab3416..5781d8789 100644 --- a/src/zap.c +++ b/src/zap.c @@ -4431,11 +4431,10 @@ short exploding_wand_typ; vision_full_recalc = 1; } else if (u.utrap && u.utraptype == TT_LAVA) { if (Passes_walls) { - u.utrap = 0; You("pass through the now-solid rock."); + reset_utrap(TRUE); } else { - u.utrap = rn1(50, 20); - u.utraptype = TT_INFLOOR; + set_utrap(rn1(50, 20), TT_INFLOOR); You("are firmly stuck in the cooling rock."); } } diff --git a/win/share/tilemap.c b/win/share/tilemap.c index 46b1056e2..e2ec90e40 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -3,13 +3,15 @@ /* NetHack may be freely redistributed. See license for details. */ /* - * This source file is compiled twice: - * once without TILETEXT defined to make tilemap.{o,obj}, - * then again with it defined to produce tiletxt.{o,obj}. + * This source file is compiled twice: + * once without TILETEXT defined to make tilemap.{o,obj}, + * then again with it defined to produce tiletxt.{o,obj}. */ #include "hack.h" +#define Fprintf (void) fprintf + const char *FDECL(tilename, (int, int)); void NDECL(init_tilemap); void FDECL(process_substitutions, (FILE *)); @@ -40,7 +42,7 @@ struct conditionals { int sequence, predecessor; const char *name; } conditionals[] = { -#ifndef CHARON /* not supported yet */ +#ifndef CHARON /* not supported */ { MON_GLYPH, PM_HELL_HOUND, "Cerberus" }, #endif /* commented out in monst.c at present */ @@ -68,7 +70,8 @@ struct conditionals { * don't know what a slime mold should look like when renamed anyway */ #ifndef MAIL - { OBJ_GLYPH, SCR_STINKING_CLOUD + EXTRA_SCROLL_DESCR_COUNT, "stamped / mail" }, + { OBJ_GLYPH, SCR_STINKING_CLOUD + EXTRA_SCROLL_DESCR_COUNT, + "stamped / mail" }, #endif { 0, 0, 0 } }; @@ -394,19 +397,20 @@ init_tilemap() #endif } -const char *prolog[] = { "", "", "void", "substitute_tiles(plev)", - "d_level *plev;", "{", "\tint i;", "" }; +const char *prolog[] = { "", "void", "substitute_tiles(plev)", + "d_level *plev;", "{", " int i;", "" }; -const char *epilog[] = { "}" }; +const char *epilog[] = { " return;", "}" }; /* write out the substitutions in an easily-used form. */ void process_substitutions(ofp) FILE *ofp; { + static const char Dent[] = " "; /* 4 space indentation */ int i, j, k, span, start; - fprintf(ofp, "\n\n"); + Fprintf(ofp, "\n"); j = 0; /* unnecessary */ span = -1; @@ -415,16 +419,16 @@ FILE *ofp; || substitutes[i].last_glyph != substitutes[j].last_glyph) { j = i; span++; - fprintf(ofp, "short std_tiles%d[] = { ", span); + Fprintf(ofp, "short std_tiles%d[] = { ", span); for (k = substitutes[i].first_glyph; k < substitutes[i].last_glyph; k++) - fprintf(ofp, "%d, ", tilemap[k]); - fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph]); + Fprintf(ofp, "%d, ", tilemap[k]); + Fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph]); } } for (i = 0; i < SIZE(prolog); i++) { - fprintf(ofp, "%s\n", prolog[i]); + Fprintf(ofp, "%s\n", prolog[i]); } j = -1; span = -1; @@ -433,43 +437,41 @@ FILE *ofp; if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph || substitutes[i].last_glyph != substitutes[j].last_glyph) { if (i != 0) { /* finish previous span */ - fprintf(ofp, "\t} else {\n"); - fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", - substitutes[j].first_glyph, - substitutes[j].last_glyph); - fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", - span, substitutes[j].first_glyph); - fprintf(ofp, "\t}\n\n"); + Fprintf(ofp, "%s} else {\n", Dent); + Fprintf(ofp, "%s%sfor (i = %d; i <= %d; i++)\n", Dent, Dent, + substitutes[j].first_glyph, substitutes[j].last_glyph); + Fprintf(ofp, "%s%s%sglyph2tile[i] = std_tiles%d[i - %d];\n", + Dent, Dent, Dent, span, substitutes[j].first_glyph); + Fprintf(ofp, "%s}\n\n", Dent); } j = i; span++; } - if (i != j) - fprintf(ofp, "\t} else "); - fprintf(ofp, "\tif (%s) {\n", substitutes[i].level_test); - fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", + Fprintf(ofp, "%s%sif (%s) {\n", Dent, (i == j) ? "" : "} else ", + substitutes[i].level_test); + Fprintf(ofp, "%s%sfor (i = %d; i <= %d; i++)\n", Dent, Dent, substitutes[i].first_glyph, substitutes[i].last_glyph); - fprintf(ofp, "\t\t\tglyph2tile[i] = %d + i - %d;\n", start, - substitutes[i].first_glyph); + Fprintf(ofp, "%s%s%sglyph2tile[i] = %d + i - %d;\n", + Dent, Dent, Dent, start, substitutes[i].first_glyph); start += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } /* finish last span */ - fprintf(ofp, "\t} else {\n"); - fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", + Fprintf(ofp, "%s} else {\n", Dent); + Fprintf(ofp, "%s%sfor (i = %d; i <= %d; i++)\n", Dent, Dent, substitutes[j].first_glyph, substitutes[j].last_glyph); - fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span, - substitutes[j].first_glyph); - fprintf(ofp, "\t}\n\n"); + Fprintf(ofp, "%s%s%sglyph2tile[i] = std_tiles%d[i - %d];\n", + Dent, Dent, Dent, span, substitutes[j].first_glyph); + Fprintf(ofp, "%s}\n", Dent); for (i = 0; i < SIZE(epilog); i++) { - fprintf(ofp, "%s\n", epilog[i]); + Fprintf(ofp, "%s\n", epilog[i]); } lastothtile = start - 1; #ifdef STATUES_LOOK_LIKE_MONSTERS start = laststatuetile + 1; #endif - fprintf(ofp, "\nint total_tiles_used = %d;\n", start); + Fprintf(ofp, "\nint total_tiles_used = %d;\n", start); } int @@ -489,27 +491,27 @@ main() perror(filename); exit(EXIT_FAILURE); } - fprintf(ofp, + Fprintf(ofp, "/* This file is automatically generated. Do not edit. */\n"); - fprintf(ofp, "\n#include \"hack.h\"\n\n"); - fprintf(ofp, "short glyph2tile[MAX_GLYPH] = {\n"); + Fprintf(ofp, "\n#include \"hack.h\"\n"); + Fprintf(ofp, "\nshort glyph2tile[MAX_GLYPH] = {\n"); for (i = 0; i < MAX_GLYPH; i++) { - fprintf(ofp, "%2d,%c", tilemap[i], (i % 12) ? ' ' : '\n'); + Fprintf(ofp, "%2d,%c", tilemap[i], (i % 12) ? ' ' : '\n'); } - fprintf(ofp, "%s};\n", (i % 12) ? "\n" : ""); + Fprintf(ofp, "\n};\n"); process_substitutions(ofp); - fprintf(ofp, "\n#define MAXMONTILE %d\n", lastmontile); - fprintf(ofp, "#define MAXOBJTILE %d\n", lastobjtile); - fprintf(ofp, "#define MAXOTHTILE %d\n", lastothtile); + Fprintf(ofp, "\n#define MAXMONTILE %d\n", lastmontile); + Fprintf(ofp, "#define MAXOBJTILE %d\n", lastobjtile); + Fprintf(ofp, "#define MAXOTHTILE %d\n", lastothtile); #ifdef STATUES_LOOK_LIKE_MONSTERS - fprintf(ofp, "/* #define MAXSTATUETILE %d */\n", laststatuetile); + Fprintf(ofp, "/* #define MAXSTATUETILE %d */\n", laststatuetile); #endif - fprintf(ofp, "\n/*tile.c*/\n"); + Fprintf(ofp, "\n/*tile.c*/\n"); - fclose(ofp); + (void) fclose(ofp); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; @@ -634,3 +636,4 @@ const char *encountered, *expected; return FALSE; } +/*tilemap.c*/