diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 80e792766..d33e86598 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -490,6 +490,19 @@ if a fiery monster, wand of fire, or fiery explosion burned up a paper golem, it could still leave blank scrolls hero poly'd into paper or straw golem reverts to human if burned up even when Unchanging without any explanation given +hero polymorphed into form which can't wear armor via 'W' (eliciting "don't + even bother") could wear it via 'P' +make multi-shot missiles fired by monsters be less verbose when they miss +can no longer play controlled notes on musical instrument if impaired +if a special level specified the appearance of a mimic and mimics had been + genocided prior to creating the level, whatever random monster took + the mimic's place got its intended appearance +redundant "hit by gush of water" message if poly'd into iron golem or gremlin +a shop object stolen from outside the shop (via grappling hook) would be left + marked as 'unpaid' after the shop robbery took place, resulting in + "unpaid_cost: object wasn't on any bill" when looking at inventory +a shop object stolen from outside the shop could trigger a crash if that shop + had never been entered by the hero Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository @@ -735,11 +748,14 @@ Master Key of Thievery always finds door and chest traps if used to lock or blessed (for non-rogues); player is offered the opportunity to disarm "Elbereth" must now be the only engraved text on a square to function "Elbereth" now erodes based on attacks by the player, not monsters scared -option herecmd_menu to make a mouse click on your character pop up +add option herecmd_menu to make a mouse click on your character pop up a context menu, and extended command #herecmdmenu to do the same change #adjust's behavior when collecting compatible stacks; that used to occur for any #adjust which lacked a split count, now it only happens when 'adjusting' into a stack's own inventory slot +a prayer result which results in uncursing some or all of the hero's items + won't uncurse a worn helm of opposite alignment since that would + facilitate the hero switching to another god by taking it off Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 6fd1df12f..6f355fa07 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1513130012 2017/12/13 01:53:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.621 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1514769568 2018/01/01 01:19:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.622 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1397,6 +1397,7 @@ E void FDECL(restore_cham, (struct monst *)); E boolean FDECL(hideunder, (struct monst *)); E void FDECL(hide_monst, (struct monst *)); E void FDECL(mon_animal_list, (BOOLEAN_P)); +E boolean FDECL(validvamp, (struct monst *, int *, int)); E int FDECL(select_newcham_form, (struct monst *)); E void FDECL(mgender_from_permonst, (struct monst *, struct permonst *)); E int FDECL(newcham, diff --git a/include/flag.h b/include/flag.h index a8f9172f7..d3938adca 100644 --- a/include/flag.h +++ b/include/flag.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 flag.h $NHDT-Date: 1508827590 2017/10/24 06:46:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.129 $ */ +/* NetHack 3.6 flag.h $NHDT-Date: 1514071158 2017/12/23 23:19:18 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.132 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -48,7 +48,42 @@ struct flag { boolean showexp; /* show experience points */ boolean showscore; /* show score */ boolean silent; /* whether the bell rings or not */ + /* The story so far: + * 'sortloot' originally took a True/False value but was changed + * to use a letter instead. 3.6.0 was released without changing its + * type from 'boolean' to 'char'. A compiler was smart enough to + * complain that assigning any of the relevant letters was not 0 or 1 + * so not appropriate for boolean (by a configuration which used + * SKIP_BOOLEAN to bypass nethack's 'boolean' and use a C++-compatible + * one). So the type was changed to 'xchar', which is guaranteed to + * match the size of 'boolean' (this guarantee only applies for the + * !SKIP_BOOLEAN config, unfortunately). Since xchar does not match + * actual use, the type was later changed to 'char'. But that would + * break 3.6.0 savefile compatibility for configurations which typedef + * 'schar' to 'short int' instead of to 'char'. (Needed by pre-ANSI + * systems that use unsigned characters without a way to force them + * to be signed.) So, the type has been changed back to 'xchar' for + * 3.6.1. + * + * TODO: change to 'char' (and move out of this block of booleans, + * and get rid of these comments...) once 3.6.0 savefile compatibility + * eventually ends. + */ +#ifndef SKIP_BOOLEAN + /* this is the normal configuration; assigning a character constant + for a normal letter to an 'xchar' variable should always work even + if 'char' is unsigned since character constants are actually 'int' + and letters are within the range where signedness shouldn't matter */ + xchar sortloot; /* 'n'=none, 'l'=loot (pickup), 'f'=full ('l'+invent) */ +#else + /* with SKIP_BOOLEAN, we have no idea what underlying type is being + used, other than it isn't 'xchar' (although its size might match + that) or a bitfield (because it must be directly addressable); + it's probably either 'char' for compactness or 'int' for access, + but we don't know which and it might be something else anyway; + flip a coin here and guess 'char' for compactness */ char sortloot; /* 'n'=none, 'l'=loot (pickup), 'f'=full ('l'+invent) */ +#endif boolean sortpack; /* sorted inventory */ boolean sparkle; /* show "resisting" special FX (Scott Bigham) */ boolean standout; /* use standout for --More-- */ diff --git a/src/do_wear.c b/src/do_wear.c index 2adcb6816..f8f94e342 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_wear.c $NHDT-Date: 1496959478 2017/06/08 22:04:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */ +/* NetHack 3.6 do_wear.c $NHDT-Date: 1514072526 2017/12/23 23:42:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.100 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1617,6 +1617,14 @@ boolean noisy; int err = 0; const char *which; + /* this is the same check as for 'W' (dowear), but different message, + in case we get here via 'P' (doputon) */ + if (verysmall(youmonst.data) || nohands(youmonst.data)) { + if (noisy) + You("can't wear any armor in your current form."); + return 0; + } + which = is_cloak(otmp) ? c_cloak : is_shirt(otmp) @@ -1964,7 +1972,7 @@ dowear() /* cantweararm() checks for suits of armor, not what we want here; verysmall() or nohands() checks for shields, gloves, etc... */ - if ((verysmall(youmonst.data) || nohands(youmonst.data))) { + if (verysmall(youmonst.data) || nohands(youmonst.data)) { pline("Don't even bother."); return 0; } diff --git a/src/mon.c b/src/mon.c index a872b93a9..62fb34a8f 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1505266804 2017/09/13 01:40:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.244 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1514769571 2018/01/01 01:19:31 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.246 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -23,7 +23,6 @@ STATIC_DCL void FDECL(kill_eggs, (struct obj *)); STATIC_DCL int FDECL(pickvampshape, (struct monst *)); STATIC_DCL boolean FDECL(isspecmon, (struct monst *)); STATIC_DCL boolean FDECL(validspecmon, (struct monst *, int)); -STATIC_DCL boolean FDECL(validvamp, (struct monst *, int *, int)); STATIC_DCL struct permonst *FDECL(accept_newcham_form, (int)); STATIC_DCL struct obj *FDECL(make_corpse, (struct monst *, unsigned)); STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *)); @@ -3162,7 +3161,7 @@ int mndx; } /* prevent wizard mode user from specifying invalid vampshifter shape */ -STATIC_OVL boolean +boolean validvamp(mon, mndx_p, monclass) struct monst *mon; int *mndx_p, monclass; diff --git a/src/mthrowu.c b/src/mthrowu.c index 3d2830b96..6806feef4 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mthrowu.c $NHDT-Date: 1446887531 2015/11/07 09:12:11 $ $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */ +/* NetHack 3.6 mthrowu.c $NHDT-Date: 1514152830 2017/12/24 22:00:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.73 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -26,6 +26,7 @@ STATIC_OVL NEARDATA const char *breathwep[] = { }; extern boolean notonhead; /* for long worms */ +STATIC_VAR int mesg_given; /* for m_throw()/thitu() 'miss' message */ /* hero is hit by something other than a monster */ int @@ -37,7 +38,7 @@ const char *name; /* if null, then format `*objp' */ struct obj *obj = objp ? *objp : 0; const char *onm, *knm; boolean is_acid; - int kprefix = KILLED_BY_AN; + int kprefix = KILLED_BY_AN, dieroll; char onmbuf[BUFSZ], knmbuf[BUFSZ]; if (!name) { @@ -59,10 +60,15 @@ const char *name; /* if null, then format `*objp' */ : an(name); is_acid = (obj && obj->otyp == ACID_VENOM); - if (u.uac + tlev <= rnd(20)) { - if (Blind || !flags.verbose) + if (u.uac + tlev <= (dieroll = rnd(20))) { + ++mesg_given; + if (Blind || !flags.verbose) { pline("It misses."); - else + } else if (u.uac + tlev <= dieroll - 2) { + if (onm != onmbuf) + Strcpy(onmbuf, onm); /* [modifiable buffer for upstart()] */ + pline("%s %s you.", upstart(onmbuf), vtense(onmbuf, "miss")); + } else You("are almost hit by %s.", onm); return 0; } else { @@ -518,6 +524,7 @@ struct obj *obj; /* missile (or stack providing it) */ (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } + mesg_given = 0; /* a 'missile misses' message has not yet been shown */ /* Note: drop_throw may destroy singleobj. Since obj must be destroyed * early to avoid the dagger bug, anyone who modifies this code should @@ -646,8 +653,10 @@ struct obj *obj; /* missile (or stack providing it) */ if (!range /* reached end of path */ || MT_FLIGHTCHECK(FALSE)) { if (singleobj) { /* hits_bars might have destroyed it */ - if (m_shot.n > 1 && (cansee(bhitpos.x, bhitpos.y) - || (archer && canseemon(archer)))) + if (m_shot.n > 1 + && (!mesg_given || bhitpos.x != u.ux || bhitpos.y != u.uy) + && (cansee(bhitpos.x, bhitpos.y) + || (archer && canseemon(archer)))) pline("%s misses.", The(mshot_xname(singleobj))); (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); } @@ -659,6 +668,7 @@ struct obj *obj; /* missile (or stack providing it) */ tmp_at(bhitpos.x, bhitpos.y); delay_output(); tmp_at(DISP_END, 0); + mesg_given = 0; /* reset */ if (blindinc) { u.ucreamed += blindinc; diff --git a/src/music.c b/src/music.c index 75ab39d4d..68c9e97d5 100644 --- a/src/music.c +++ b/src/music.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 music.c $NHDT-Date: 1452660194 2016/01/13 04:43:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.42 $ */ +/* NetHack 3.6 music.c $NHDT-Date: 1514504228 2017/12/28 23:37:08 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.46 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,7 +6,7 @@ * This file contains the different functions designed to manipulate the * musical instruments and their various effects. * - * Actually the list of instruments / effects is : + * The list of instruments / effects is : * * (wooden) flute may calm snakes if player has enough dexterity * magic flute may put monsters to sleep: area of effect depends @@ -450,8 +450,7 @@ STATIC_OVL int do_improvisation(instr) struct obj *instr; { - int damage, do_spec = !Confusion; -#if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined(PCMUSIC) + int damage, mode, do_spec = !(Stunned || Confusion); struct obj itmp; itmp = *instr; @@ -476,23 +475,55 @@ struct obj *instr; #ifdef PCMUSIC pc_speaker(&itmp, "C"); #endif -#endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */ - if (!do_spec) +#define PLAY_NORMAL 0 +#define PLAY_STUNNED 1 +#define PLAY_CONFUSED 2 +#define PLAY_HALLU 4 + mode = PLAY_NORMAL; + if (Stunned) + mode |= PLAY_STUNNED; + if (Confusion) + mode |= PLAY_CONFUSED; + if (Hallucination) + mode |= PLAY_HALLU; + + switch (mode) { + case PLAY_NORMAL: + You("start playing %s.", yname(instr)); + break; + case PLAY_STUNNED: + You("produce an obnoxious droning sound."); + break; + case PLAY_CONFUSED: + You("produce a raucous noise."); + break; + case PLAY_HALLU: + You("produce a kaleidoscopic display of floating butterfiles."); + break; + /* TODO? give some or all of these combinations their own feedback; + hallucination ones should reference senses other than hearing... */ + case PLAY_STUNNED | PLAY_CONFUSED: + case PLAY_STUNNED | PLAY_HALLU: + case PLAY_CONFUSED | PLAY_HALLU: + case PLAY_STUNNED | PLAY_CONFUSED | PLAY_HALLU: + default: pline("What you produce is quite far from music..."); - else - You("start playing %s.", the(xname(instr))); + break; + } +#undef PLAY_NORMAL +#undef PLAY_STUNNED +#undef PLAY_CONFUSED +#undef PLAY_HALLU - switch (instr->otyp) { + switch (itmp.otyp) { /* note: itmp.otyp might differ from instr->otyp */ case MAGIC_FLUTE: /* Make monster fall asleep */ - if (do_spec && instr->spe > 0) { - consume_obj_charge(instr, TRUE); + consume_obj_charge(instr, TRUE); - You("produce %s music.", Hallucination ? "piped" : "soft"); - put_monsters_to_sleep(u.ulevel * 5); - exercise(A_DEX, TRUE); - break; - } /* else FALLTHRU */ + You("produce %s music.", Hallucination ? "piped" : "soft"); + put_monsters_to_sleep(u.ulevel * 5); + exercise(A_DEX, TRUE); + break; case WOODEN_FLUTE: /* May charm snakes */ do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25); pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot")); @@ -502,66 +533,59 @@ struct obj *instr; break; case FIRE_HORN: /* Idem wand of fire */ case FROST_HORN: /* Idem wand of cold */ - if (do_spec && instr->spe > 0) { - consume_obj_charge(instr, TRUE); + consume_obj_charge(instr, TRUE); - if (!getdir((char *) 0)) { - pline("%s.", Tobjnam(instr, "vibrate")); - break; - } else if (!u.dx && !u.dy && !u.dz) { - if ((damage = zapyourself(instr, TRUE)) != 0) { - char buf[BUFSZ]; - - Sprintf(buf, "using a magical horn on %sself", uhim()); - losehp(damage, buf, KILLED_BY); /* fire or frost damage */ - } - } else { - buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1, - rn1(6, 6), u.ux, u.uy, u.dx, u.dy); - } - makeknown(instr->otyp); + if (!getdir((char *) 0)) { + pline("%s.", Tobjnam(instr, "vibrate")); break; - } /* else FALLTHRU */ + } else if (!u.dx && !u.dy && !u.dz) { + if ((damage = zapyourself(instr, TRUE)) != 0) { + char buf[BUFSZ]; + + Sprintf(buf, "using a magical horn on %sself", uhim()); + losehp(damage, buf, KILLED_BY); /* fire or frost damage */ + } + } else { + buzz((instr->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1, + rn1(6, 6), u.ux, u.uy, u.dx, u.dy); + } + makeknown(instr->otyp); + break; case TOOLED_HORN: /* Awaken or scare monsters */ You("produce a frightful, grave sound."); awaken_monsters(u.ulevel * 30); exercise(A_WIS, FALSE); break; case BUGLE: /* Awaken & attract soldiers */ - You("extract a loud noise from %s.", the(xname(instr))); + You("extract a loud noise from %s.", yname(instr)); awaken_soldiers(&youmonst); exercise(A_WIS, FALSE); break; case MAGIC_HARP: /* Charm monsters */ - if (do_spec && instr->spe > 0) { - consume_obj_charge(instr, TRUE); + consume_obj_charge(instr, TRUE); - pline("%s very attractive music.", Tobjnam(instr, "produce")); - charm_monsters((u.ulevel - 1) / 3 + 1); - exercise(A_DEX, TRUE); - break; - } /* else FALLTHRU */ + pline("%s very attractive music.", Tobjnam(instr, "produce")); + charm_monsters((u.ulevel - 1) / 3 + 1); + exercise(A_DEX, TRUE); + break; case WOODEN_HARP: /* May calm Nymph */ do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25); - pline("%s %s.", The(xname(instr)), + pline("%s %s.", Yname2(instr), do_spec ? "produces a lilting melody" : "twangs"); if (do_spec) calm_nymphs(u.ulevel * 3); exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ - if (do_spec && instr->spe > 0) { - consume_obj_charge(instr, TRUE); + consume_obj_charge(instr, TRUE); - You("produce a heavy, thunderous rolling!"); - pline_The("entire %s is shaking around you!", - generic_lvl_desc()); - do_earthquake((u.ulevel - 1) / 3 + 1); - /* shake up monsters in a much larger radius... */ - awaken_monsters(ROWNO * COLNO); - makeknown(DRUM_OF_EARTHQUAKE); - break; - } /* else FALLTHRU */ + You("produce a heavy, thunderous rolling!"); + pline_The("entire %s is shaking around you!", generic_lvl_desc()); + do_earthquake((u.ulevel - 1) / 3 + 1); + /* shake up monsters in a much larger radius... */ + awaken_monsters(ROWNO * COLNO); + makeknown(DRUM_OF_EARTHQUAKE); + break; case LEATHER_DRUM: /* Awaken monsters */ You("beat a deafening row!"); awaken_monsters(u.ulevel * 40); @@ -571,7 +595,7 @@ struct obj *instr; break; default: impossible("What a weird instrument (%d)!", instr->otyp); - break; + return 0; } return 2; /* That takes time */ } @@ -598,11 +622,13 @@ struct obj *instr; You("are incapable of playing %s.", the(distant_name(instr, xname))); return 0; } - if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) { + if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE + && !(Stunned || Confusion || Hallucination)) { c = ynq("Improvise?"); if (c == 'q') goto nevermind; } + if (c == 'n') { if (u.uevent.uheard_tune == 2) c = ynq("Play the passtune?"); diff --git a/src/pickup.c b/src/pickup.c index aa147080b..d09bbbfdb 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pickup.c $NHDT-Date: 1508549438 2017/10/21 01:30:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.192 $ */ +/* NetHack 3.6 pickup.c $NHDT-Date: 1515144225 2018/01/05 09:23:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.193 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1495,15 +1495,30 @@ struct obj * pick_obj(otmp) struct obj *otmp; { + struct obj *result; + int ox = otmp->ox, oy = otmp->oy; + boolean robshop = (!u.uswallow && otmp != uball && costly_spot(ox, oy)); + obj_extract_self(otmp); - if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) { + otmp->nomerge = 1; + result = addinv(otmp); + otmp->nomerge = 0; + newsym(ox, oy); + + /* this used to be done before addinv(), but remote_burglary() + calls rob_shop() which calls setpaid() after moving costs of + unpaid items to shop debt; setpaid() calls clear_unpaid() for + lots of object chains, but 'otmp' wasn't on any of those so + remained flagged as an unpaid item in inventory, triggering + impossible() every time inventory was examined... */ + if (robshop) { char saveushops[5], fakeshop[2]; /* addtobill cares about your location rather than the object's; usually they'll be the same, but not when using telekinesis (if ever implemented) or a grappling hook */ Strcpy(saveushops, u.ushops); - fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE); + fakeshop[0] = *in_rooms(ox, oy, SHOPBASE); fakeshop[1] = '\0'; Strcpy(u.ushops, fakeshop); /* sets obj->unpaid if necessary */ @@ -1511,10 +1526,9 @@ struct obj *otmp; Strcpy(u.ushops, saveushops); /* if you're outside the shop, make shk notice */ if (!index(u.ushops, *fakeshop)) - remote_burglary(otmp->ox, otmp->oy); + remote_burglary(ox, oy); } - newsym(otmp->ox, otmp->oy); - return addinv(otmp); /* might merge it with other objects */ + return result; } /* diff --git a/src/pray.c b/src/pray.c index 51dfbb5bb..0e74bb98a 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pray.c $NHDT-Date: 1450577672 2015/12/20 02:14:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.89 $ */ +/* NetHack 3.6 pray.c $NHDT-Date: 1514593198 2017/12/30 00:19:58 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.95 $ */ /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -265,18 +265,21 @@ worst_cursed_item() with taking off a ring or putting on a shield */ if (welded(uwep) && (uright || bimanual(uwep))) { /* weapon */ otmp = uwep; - /* gloves come next, due to rings */ + /* gloves come next, due to rings */ } else if (uarmg && uarmg->cursed) { /* gloves */ otmp = uarmg; - /* then shield due to two handed weapons and spells */ + /* then shield due to two handed weapons and spells */ } else if (uarms && uarms->cursed) { /* shield */ otmp = uarms; - /* then cloak due to body armor */ + /* then cloak due to body armor */ } else if (uarmc && uarmc->cursed) { /* cloak */ otmp = uarmc; } else if (uarm && uarm->cursed) { /* suit */ otmp = uarm; - } else if (uarmh && uarmh->cursed) { /* helmet */ + /* if worn helmet of opposite alignment is making you an adherent + of the current god, he/she/it won't uncurse that for you */ + } else if (uarmh && uarmh->cursed /* helmet */ + && uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT) { otmp = uarmh; } else if (uarmf && uarmf->cursed) { /* boots */ otmp = uarmf; @@ -290,13 +293,13 @@ worst_cursed_item() otmp = uright; } else if (ublindf && ublindf->cursed) { /* eyewear */ otmp = ublindf; /* must be non-blinding lenses */ - /* if weapon wasn't handled above, do it now */ + /* if weapon wasn't handled above, do it now */ } else if (welded(uwep)) { /* weapon */ otmp = uwep; - /* active secondary weapon even though it isn't welded */ + /* active secondary weapon even though it isn't welded */ } else if (uswapwep && uswapwep->cursed && u.twoweap) { otmp = uswapwep; - /* all worn items ought to be handled by now */ + /* all worn items ought to be handled by now */ } else { for (otmp = invent; otmp; otmp = otmp->nobj) { if (!otmp->cursed) @@ -336,9 +339,7 @@ int trouble; break; case TROUBLE_LAVA: You("are back on solid ground."); - /* teleport should always succeed, but if not, - * just untrap them. - */ + /* teleport should always succeed, but if not, just untrap them */ if (!safe_teleds(FALSE)) u.utrap = 0; break; @@ -386,8 +387,7 @@ int trouble; if ((otmp = stuck_ring(uleft, RIN_SUSTAIN_ABILITY)) != 0) { if (otmp == uleft) what = leftglow; - } else if ((otmp = stuck_ring(uright, RIN_SUSTAIN_ABILITY)) - != 0) { + } else if ((otmp = stuck_ring(uright, RIN_SUSTAIN_ABILITY)) != 0) { if (otmp == uright) what = rightglow; } @@ -1070,7 +1070,9 @@ aligntyp g_align; else You("are surrounded by %s aura.", an(hcolor(NH_LIGHT_BLUE))); for (otmp = invent; otmp; otmp = otmp->nobj) { - if (otmp->cursed) { + if (otmp->cursed + && (otmp != uarmh /* [see worst_cursed_item()] */ + || uarmh->otyp != HELM_OF_OPPOSITE_ALIGNMENT)) { if (!Blind) { pline("%s %s.", Yobjnam2(otmp, "softly glow"), hcolor(NH_AMBER)); diff --git a/src/shk.c b/src/shk.c index 62052fbe7..c81c788b2 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shk.c $NHDT-Date: 1464138042 2016/05/25 01:00:42 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.132 $ */ +/* NetHack 3.6 shk.c $NHDT-Date: 1515144230 2018/01/05 09:23:50 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.136 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2354,6 +2354,12 @@ struct monst *shkp; return; } + /* normally bill_p gets set up whenever you enter the shop, but obj + might be going onto the bill because hero just snagged it with + a grappling hook from outside without ever having been inside */ + if (!eshkp->bill_p) + eshkp->bill_p = &(eshkp->bill[0]); + bct = eshkp->billct; bp = &(eshkp->bill_p[bct]); bp->bo_id = obj->o_id; diff --git a/src/sp_lev.c b/src/sp_lev.c index 5981a1b5e..e2d362c6c 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sp_lev.c $NHDT-Date: 1513879435 2017/12/21 18:03:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.93 $ */ +/* NetHack 3.6 sp_lev.c $NHDT-Date: 1514769572 2018/01/01 01:19:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.95 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -1589,11 +1589,14 @@ struct mkroom *croom; mtmp = christen_monst(mtmp, m->name.str); /* - * This is currently hardwired for mimics only. It should - * eventually be expanded. + * This doesn't complain if an attempt is made to give a + * non-mimic/non-shapechanger an appearance or to give a + * shapechanger a non-monster shape, it just refuses to comply. */ if (m->appear_as.str - && ((mtmp->data->mlet == S_MIMIC) || mtmp->cham) + && ((mtmp->data->mlet == S_MIMIC) + /* shapechanger (chameleons, et al, and vampires) */ + || (mtmp->cham >= LOW_PM && m->appear == M_AP_MONSTER)) && !Protection_from_shape_changers) { int i; @@ -1658,7 +1661,29 @@ struct mkroom *croom; mndx = select_newcham_form(mtmp); else mndx = name_to_mon(m->appear_as.str); - if ((mndx != NON_PM) && (&mons[mndx] != mtmp->data)) { + + if (mndx == NON_PM || (is_vampshifter(mtmp) + && !validvamp(mtmp, &mndx, S_HUMAN))) { + impossible("create_monster: invalid %s (\"%s\")", + (mtmp->data->mlet == S_MIMIC) + ? "mimic appearance" + : (mtmp->data == &mons[PM_WIZARD_OF_YENDOR]) + ? "Wizard appearance" + : is_vampshifter(mtmp) + ? "vampire shape" + : "chameleon shape", + m->appear_as.str); + } else if (&mons[mndx] == mtmp->data) { + /* explicitly forcing a mimic to appear as itself */ + mtmp->m_ap_type = M_AP_NOTHING; + mtmp->mappearance = 0; + } else if (mtmp->data->mlet == S_MIMIC + || mtmp->data == &mons[PM_WIZARD_OF_YENDOR]) { + /* this is ordinarily only used for Wizard clones + and hasn't been exhaustively tested for mimics */ + mtmp->m_ap_type = M_AP_MONSTER; + mtmp->mappearance = mndx; + } else { /* chameleon or vampire */ struct permonst *mdat = &mons[mndx]; struct permonst *olddata = mtmp->data; diff --git a/src/trap.c b/src/trap.c index 66ab163f8..1855a722a 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1494107206 2017/05/06 21:46:46 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.278 $ */ +/* NetHack 3.6 trap.c $NHDT-Date: 1514855666 2018/01/02 01:14:26 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.284 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1103,7 +1103,7 @@ unsigned trflags; if (uarmc) (void) water_damage(uarmc, cloak_simple_name(uarmc), TRUE); else if (uarm) - (void) water_damage(uarm, "armor", TRUE); + (void) water_damage(uarm, suit_simple_name(uarm), TRUE); else if (uarmu) (void) water_damage(uarmu, "shirt", TRUE); } @@ -1112,11 +1112,9 @@ unsigned trflags; if (u.umonnum == PM_IRON_GOLEM) { int dam = u.mhmax; - pline("%s you!", A_gush_of_water_hits); You("are covered with rust!"); losehp(Maybe_Half_Phys(dam), "rusting away", KILLED_BY); } else if (u.umonnum == PM_GREMLIN && rn2(3)) { - pline("%s you!", A_gush_of_water_hits); (void) split_mon(&youmonst, (struct monst *) 0); } @@ -2292,7 +2290,8 @@ register struct monst *mtmp; (void) water_damage(target, cloak_simple_name(target), TRUE); else if ((target = which_armor(mtmp, W_ARM)) != 0) - (void) water_damage(target, "armor", TRUE); + (void) water_damage(target, suit_simple_name(target), + TRUE); else if ((target = which_armor(mtmp, W_ARMU)) != 0) (void) water_damage(target, "shirt", TRUE); }