diff --git a/dat/data.base b/dat/data.base index ebb781af7..410912710 100644 --- a/dat/data.base +++ b/dat/data.base @@ -1,5 +1,5 @@ # NetHack 3.6 data.base -# $NHDT-Date: 1524683801 2018/04/25 19:16:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.84 $ +# $NHDT-Date: 1545359287 2018/12/21 02:28:07 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.87 $ # Copyright (c) 1994, 1995, 1996 by the NetHack Development Team # Copyright (c) 1994 by Boudewijn Wayers # NetHack may be freely redistributed. See license for details. @@ -1629,9 +1629,19 @@ eye of the aethiopica the power to instantly open a portal to any other area of the dungeon, allowing its invoker to travel quickly between areas. +# note: The Eyes of the Overworld is the title of Jack Vance's sequel +# to The Dying Earth and in it the 'Eyes' were separate "cusps" that +# needed to be worn like contact lenses, one on each eyeball. Wearing +# just one and attempting to look with both eyes caused instant stun. +# And when wearing two you couldn't see normal world, only a projection +# of it that had similar topology but where everything was "better". +# NetHack simplifies things: a pair of lenses is a single item like +# spectacles (eyeglasses), and the effect of wearing these lenses has +# been changed to be useful to game play (Xray vision). [The quote is +# not derived from the book.] eyes of the overworld - ... and finally there is "the Eyes of the Overworld". This - obscure artifact pushes the wearer's view sense into the + The Eyes of the Overworld is a rather obscure artifact. + These magical lenses push the wearer's view sense into the "overworld" -- another name for a segment of the Astral Plane. Usually, there is nothing to be seen. However, the wearer is also able to look back and see the area around herself, diff --git a/doc/fixes36.2 b/doc/fixes36.2 index d7348a2ee..d891d6e63 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -289,6 +289,17 @@ diluted potion of oil is less effective when filling lamps (adds less fuel) apply fix from grunthack to prevent panic "fakecorr overflow" when vault guard couldn't figure out how to lead the hero from vault to civilization; fixes longstanding bug C343-23 +vibrating square is not really a trap so monsters don't need to avoid it +if hero kicks some embedded gold out of a wall while following vault gaurd + away from vault, don't report "the guard _calms_down_and_ picks up + the gold" unless he's on brink of going ballistic +for '/?' information lookup, "item named The Artifact" failed to find info + about "Artifact" due to presence of "The" +identifying or forgetting gem types now adjusts prices for gems already on + shopping bill +when fire converts an ice location into a water location, dunk any monster on + that spot immediately instead of waiting until its next move +training riding skill had an off-by-one bug when counting turns riding Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/doc/fixes37.0 b/doc/fixes37.0 index c83af6c37..465eef81d 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -14,6 +14,8 @@ Platform- and/or Interface-Specific Fixes General New Features -------------------- +if a killer bee encounters a lump of royal jelly and there is no queen bee on + the level, the bee will eat the jelly and become a new queen Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 80ee2a1ff..1f801d6df 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1545182146 2018/12/19 01:15:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.674 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1545439142 2018/12/22 00:39:02 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.676 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1488,6 +1488,7 @@ E boolean FDECL(monhaskey, (struct monst *, BOOLEAN_P)); E void FDECL(mon_regen, (struct monst *, BOOLEAN_P)); E int FDECL(dochugw, (struct monst *)); E boolean FDECL(onscary, (int, int, struct monst *)); +E int FDECL(bee_eat_jelly, (struct monst *, struct obj *)); E void FDECL(monflee, (struct monst *, int, BOOLEAN_P, BOOLEAN_P)); E void FDECL(mon_yells, (struct monst *, const char *)); E int FDECL(dochug, (struct monst *)); @@ -2219,6 +2220,7 @@ E long FDECL(contained_cost, (struct obj *, struct monst *, long, BOOLEAN_P, BOOLEAN_P)); E long FDECL(contained_gold, (struct obj *)); E void FDECL(picked_container, (struct obj *)); +E void FDECL(gem_learned, (int)); E void FDECL(alter_cost, (struct obj *, long)); E long FDECL(unpaid_cost, (struct obj *, BOOLEAN_P)); E boolean FDECL(billable, (struct monst **, struct obj *, CHAR_P, BOOLEAN_P)); diff --git a/include/tradstdc.h b/include/tradstdc.h index e6a8f3e8f..468ebdea8 100644 --- a/include/tradstdc.h +++ b/include/tradstdc.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tradstdc.h $NHDT-Date: 1543371689 2018/11/28 02:21:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.32 $ */ +/* NetHack 3.6 tradstdc.h $NHDT-Date: 1545270756 2018/12/20 01:52:36 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.34 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -390,8 +390,10 @@ typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif #ifdef __clang__ -#define UNUSED __attribute__((unused)) -#define NORETURN __attribute__((noreturn)) +/* clang's gcc emulation is sufficient for nethack's usage */ +#ifndef __GNUC__ +#define __GNUC__ 4 +#endif #endif /* diff --git a/src/dog.c b/src/dog.c index be4ab472c..903a80a4a 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dog.c $NHDT-Date: 1543052701 2018/11/24 09:45:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.84 $ */ +/* NetHack 3.6 dog.c $NHDT-Date: 1545439150 2018/12/22 00:39:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.85 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -756,6 +756,21 @@ register struct obj *obj; if ((obj->otyp == CORPSE || obj->otyp == EGG) && touch_petrifies(fptr) && !resists_ston(mon)) return POISON; + if (obj->otyp == LUMP_OF_ROYAL_JELLY + && mon->data == &mons[PM_KILLER_BEE]) { + struct monst *mtmp = 0; + + /* if there's a queen bee on the level, don't eat royal jelly; + if there isn't, do eat it and grow into a queen */ + if ((mvitals[PM_QUEEN_BEE].mvflags & G_GENOD) == 0) + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + if (mtmp->data == &mons[PM_QUEEN_BEE]) + break; + } + return !mtmp ? DOGFOOD : TABU; + } if (!carni && !herbi) return obj->cursed ? UNDEF : APPORT; diff --git a/src/dogmove.c b/src/dogmove.c index 3fe8737e6..549c56e82 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dogmove.c $NHDT-Date: 1502753407 2017/08/14 23:30:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.63 $ */ +/* NetHack 3.6 dogmove.c $NHDT-Date: 1545439152 2018/12/22 00:39:12 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.72 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -208,7 +208,7 @@ boolean devour; { register struct edog *edog = EDOG(mtmp); boolean poly, grow, heal, eyes, slimer, deadmimic; - int nutrit; + int nutrit, res; long oprice; char objnambuf[BUFSZ]; @@ -247,6 +247,11 @@ boolean devour; newsym(x, y); newsym(mtmp->mx, mtmp->my); } + if (mtmp->data == &mons[PM_KILLER_BEE] + && obj->otyp == LUMP_OF_ROYAL_JELLY + && (res = bee_eat_jelly(mtmp, obj)) >= 0) + /* bypass most of dog_eat(), including apport update */ + return (res + 1); /* 1 -> 2, 0 -> 1; -1, keep going */ /* food items are eaten one at a time; entire stack for other stuff */ if (obj->quan > 1L && obj->oclass == FOOD_CLASS) @@ -376,8 +381,9 @@ struct edog *edog; else You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); - } else if (monstermoves > edog->hungrytime + 750 || DEADMONSTER(mtmp)) { - dog_died: + } else if (monstermoves > edog->hungrytime + 750 + || DEADMONSTER(mtmp)) { + dog_died: if (mtmp->mleashed && mtmp != u.usteed) Your("leash goes slack."); else if (cansee(mtmp->mx, mtmp->my)) @@ -1181,7 +1187,7 @@ int after; /* this is extra fast monster movement */ } } -newdogpos: + newdogpos: if (nix != omx || niy != omy) { boolean wasseen; @@ -1253,7 +1259,7 @@ newdogpos: } cc.x = mtmp->mx; cc.y = mtmp->my; - dognext: + dognext: if (!m_in_out_region(mtmp, nix, niy)) return 1; remove_monster(mtmp->mx, mtmp->my); diff --git a/src/makemon.c b/src/makemon.c index e4d40e887..02c0e36a3 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makemon.c $NHDT-Date: 1544998885 2018/12/16 22:21:25 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.131 $ */ +/* NetHack 3.6 makemon.c $NHDT-Date: 1545439153 2018/12/22 00:39:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.132 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1796,9 +1796,11 @@ struct monst *mtmp, *victim; return (struct permonst *) 0; /* note: none of the monsters with special hit point calculations - have both little and big forms */ + have both little and big forms (killer bee can't grow into queen + bee by just killing things, so isn't in the little_to_big list) */ oldtype = monsndx(ptr); - newtype = little_to_big(oldtype); + newtype = (oldtype == PM_KILLER_BEE && !victim) ? PM_QUEEN_BEE + : little_to_big(oldtype); if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS; diff --git a/src/mon.c b/src/mon.c index 10803e874..ad000602e 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1544658160 2018/12/12 23:42:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.274 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1545430257 2018/12/21 22:10:57 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.276 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -539,6 +539,12 @@ register struct monst *mtmp; * themselves --ALI */ if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) { + /* not fair...? hero doesn't automatically teleport away + from lava, just from water */ + if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) { + if (rloc(mtmp, TRUE)) + return 0; + } if (!resists_fire(mtmp)) { if (cansee(mtmp->mx, mtmp->my)) { struct attack *dummy = &mtmp->data->mattk[0]; @@ -549,7 +555,14 @@ register struct monst *mtmp; : !strcmp(how, "melting") ? "melts away" : "burns to a crisp"); } - mondead(mtmp); + /* unlike fire -> melt ice -> pool, there's no way for the + hero to create lava beneath a monster, so the !mon_moving + case is not expected to happen (and we haven't made a + player-against-monster variation of the message above) */ + if (context.mon_moving) + mondead(mtmp); + else + xkilled(mtmp, XKILL_NOMSG); } else { mtmp->mhp -= 1; if (DEADMONSTER(mtmp)) { @@ -574,16 +587,29 @@ register struct monst *mtmp; */ if (!is_clinger(mtmp->data) && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { + /* like hero with teleport intrinsic or spell, teleport away + if possible */ + if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) { + if (rloc(mtmp, TRUE)) + return 0; + } if (cansee(mtmp->mx, mtmp->my)) { - pline("%s drowns.", Monnam(mtmp)); + if (context.mon_moving) + pline("%s drowns.", Monnam(mtmp)); + else + /* hero used fire to melt ice that monster was on */ + You("drown %s.", mon_nam(mtmp)); } if (u.ustuck && u.uswallow && u.ustuck == mtmp) { /* This can happen after a purple worm plucks you off a - flying steed while you are over water. */ + flying steed while you are over water. */ pline("%s sinks as %s rushes in and flushes you out.", Monnam(mtmp), hliquid("water")); } - mondead(mtmp); + if (context.mon_moving) + mondead(mtmp); + else + xkilled(mtmp, XKILL_NOMSG); if (!DEADMONSTER(mtmp)) { water_damage_chain(mtmp->minvent, FALSE); (void) rloc(mtmp, FALSE); @@ -1474,6 +1500,7 @@ nexttry: /* eels prefer the water, but if there is no water nearby, if ((ttmp->ttyp != RUST_TRAP || mdat == &mons[PM_IRON_GOLEM]) && ttmp->ttyp != STATUE_TRAP + && ttmp->ttyp != VIBRATING_SQUARE && ((!is_pit(ttmp->ttyp) && !is_hole(ttmp->ttyp)) || (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) || Sokoban) diff --git a/src/monmove.c b/src/monmove.c index 78faf3cda..d7ead926c 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 monmove.c $NHDT-Date: 1544442712 2018/12/10 11:51:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.109 $ */ +/* NetHack 3.6 monmove.c $NHDT-Date: 1545439153 2018/12/22 00:39:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.110 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -252,6 +252,48 @@ struct monst *mon; } } +/* killer bee 'mon' is on a spot containing lump of royal jelly 'obj' and + will eat it if there is no queen bee on the level; return 1: mon died, + 0: mon ate jelly and lived; -1: mon didn't eat jelly to use its move */ +int +bee_eat_jelly(mon, obj) +struct monst *mon; +struct obj *obj; +{ + int m_delay; + struct monst *mtmp = 0; + + /* find a queen bee */ + if ((mvitals[PM_QUEEN_BEE].mvflags & G_GENOD) == 0) + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + if (mtmp->data == &mons[PM_QUEEN_BEE]) + break; + } + /* if there's no queen on the level, eat the royal jelly and become one */ + if (!mtmp) { + m_delay = obj->blessed ? 3 : !obj->cursed ? 5 : 7; + if (obj->quan > 1L) + obj = splitobj(obj, 1L); + if (canseemon(mon)) + pline("%s eats %s.", Monnam(mon), an(xname(obj))); + delobj(obj); + + if ((int) mon->m_lev < mons[PM_QUEEN_BEE].mlevel - 1) + mon->m_lev = (uchar) (mons[PM_QUEEN_BEE].mlevel - 1); + /* there should be delay after eating, but that's too much + hassle; transform immediately, then have a short delay */ + (void) grow_up(mon, (struct monst *) 0); + + if (DEADMONSTER(mon)) + return 1; /* dead; apparently queen bees have been genocided */ + mon->mfrozen = m_delay, mon->mcanmove = 0; + return 0; /* bee used its move */ + } + return -1; /* a queen is already present; ordinary bee hasn't moved yet */ +} + #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 */ @@ -369,7 +411,8 @@ register struct monst *mtmp; { register struct permonst *mdat; register int tmp = 0; - int inrange, nearby, scared; + int inrange, nearby, scared, res; + struct obj *otmp; /* Pre-movement adjustments */ @@ -377,11 +420,10 @@ register struct monst *mtmp; mdat = mtmp->data; if (mtmp->mstrategy & STRAT_ARRIVE) { - int res = m_arrival(mtmp); + res = m_arrival(mtmp); if (res >= 0) return res; } - /* check for waitmask status change */ if ((mtmp->mstrategy & STRAT_WAITFORU) && (m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax)) @@ -539,9 +581,9 @@ register struct monst *mtmp; } } } -toofar: + toofar: - /* If monster is nearby you, and has to wield a weapon, do so. This + /* If monster is nearby you, and has to wield a weapon, do so. This * costs the monster a move, of course. */ if ((!mtmp->mpeaceful || Conflict) && inrange @@ -569,6 +611,14 @@ toofar: /* Now the actual movement phase */ + if (mdat == &mons[PM_KILLER_BEE] + /* could be smarter and deliberately move to royal jelly, but + then we'd need to scan the level for queen bee in advance; + avoid that overhead and rely on serendipity... */ + && (otmp = sobj_at(LUMP_OF_ROYAL_JELLY, mtmp->mx, mtmp->my)) != 0 + && (res = bee_eat_jelly(mtmp, otmp)) >= 0) + return res; + if (!nearby || mtmp->mflee || scared || mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) || (mdat->mlet == S_LEPRECHAUN && !findgold(invent) diff --git a/src/o_init.c b/src/o_init.c index 2724b7b54..c5de7c58e 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 o_init.c $NHDT-Date: 1528332336 2018/06/07 00:45:36 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.24 $ */ +/* NetHack 3.6 o_init.c $NHDT-Date: 1545383615 2018/12/21 09:13:35 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.25 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -360,8 +360,11 @@ boolean credit_hero; exercise(A_WIS, TRUE); } /* moves==1L => initial inventory, gameover => final disclosure */ - if (moves > 1L && !program_state.gameover) + if (moves > 1L && !program_state.gameover) { + if (objects[oindx].oc_class == GEM_CLASS) + gem_learned(oindx); /* could affect price of unpaid gems */ update_inventory(); + } } } @@ -387,7 +390,10 @@ register int oindx; if (found) g.disco[dindx - 1] = 0; else - impossible("named object not in g.disco"); + impossible("named object not in disco"); + + if (objects[oindx].oc_class == GEM_CLASS) + gem_learned(oindx); /* ok, it's actually been unlearned */ update_inventory(); } } diff --git a/src/pager.c b/src/pager.c index 119f06516..f7fdb7087 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pager.c $NHDT-Date: 1545129848 2018/12/18 10:44:08 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.142 $ */ +/* NetHack 3.6 pager.c $NHDT-Date: 1545361111 2018/12/21 02:58:31 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.143 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -576,6 +576,8 @@ char *supplemental_name; if (*dbase_str == ' ') ++dbase_str; } + if (!strncmp(dbase_str, "pair of ", 8)) + dbase_str += 8; if (!strncmp(dbase_str, "tame ", 5)) dbase_str += 5; else if (!strncmp(dbase_str, "peaceful ", 9)) @@ -640,6 +642,14 @@ char *supplemental_name; ep = strstri(dbase_str, ", "); if (ep && ep > dbase_str) *ep = '\0'; + /* remove article from 'alt' name ("a pair of lenses named + The Eyes of the Overworld" simplified above to "lenses named + The Eyes of the Overworld", now reduced to "The Eyes of the + Overworld", skip "The" as with base name processing) */ + if (!strncmpi(alt, "a ", 2) + || !strncmpi(alt, "an ", 3) + || !strncmpi(alt, "the ", 4)) + alt = index(alt, ' ') + 1; /* remove charges or "(lit)" or wizmode "(N aum)" */ if ((ep = strstri(dbase_str, " (")) != 0 && ep > dbase_str) *ep = '\0'; diff --git a/src/shk.c b/src/shk.c index ce84b5b7d..f3d85199c 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shk.c $NHDT-Date: 1545036290 2018/12/17 08:44:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.143 $ */ +/* NetHack 3.6 shk.c $NHDT-Date: 1545383616 2018/12/21 09:13:36 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.144 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2273,6 +2273,45 @@ register struct monst *shkp; return tmp; } +/* unlike alter_cost() which operates on a specific item, identifying or + forgetting a gem causes all unpaid gems of its type to change value */ +void +gem_learned(oindx) +int oindx; +{ + struct obj *obj; + struct monst *shkp; + struct bill_x *bp; + int ct; + + /* + * Unfortunately, shop bill doesn't have object type included, + * just obj->oid for each unpaid stack, so we have to go through + * every bill and every item on that bill and match up against + * every unpaid stack on the level.... + * + * Fortunately, there's no need to catch up when changing dungeon + * levels even if we ID'd or forget some gems while gone from a + * level. There won't be any shop bills when arriving; they were + * either paid before leaving or got treated as robbery and it's + * too late to adjust pricing. + */ + for (shkp = next_shkp(fmon, TRUE); shkp; + shkp = next_shkp(shkp->nmon, TRUE)) { + ct = ESHK(shkp)->billct; + bp = ESHK(shkp)->bill; + while (--ct >= 0) { + obj = find_oid(bp->bo_id); + if (!obj) /* shouldn't happen */ + continue; + if ((oindx != STRANGE_OBJECT) ? (obj->otyp == oindx) + : (obj->oclass == GEM_CLASS)) + bp->price = get_cost(obj, shkp); + ++bp; + } + } +} + /* called when an item's value has been enhanced; if it happens to be on any shop bill, update that bill to reflect the new higher price [if the new price drops for some reason, keep the old one in place] */ diff --git a/src/steed.c b/src/steed.c index a90a0ce86..feede89c5 100644 --- a/src/steed.c +++ b/src/steed.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 steed.c $NHDT-Date: 1544666049 2018/12/13 01:54:09 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.61 $ */ +/* NetHack 3.6 steed.c $NHDT-Date: 1545441042 2018/12/22 01:10:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.62 $ */ /* Copyright (c) Kevin Hugo, 1998-1999. */ /* NetHack may be freely redistributed. See license for details. */ @@ -366,7 +366,7 @@ exercise_steed() return; /* It takes many turns of riding to exercise skill */ - if (u.urideturns++ >= 100) { + if (++u.urideturns >= 100) { u.urideturns = 0; use_skill(P_RIDING, 1); } diff --git a/src/trap.c b/src/trap.c index 5995d5324..9a31439ba 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1543515862 2018/11/29 18:24:22 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.312 $ */ +/* NetHack 3.6 trap.c $NHDT-Date: 1545259936 2018/12/19 22:52:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.313 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2678,13 +2678,29 @@ register struct monst *mtmp; break; case VIBRATING_SQUARE: if (see_it && !Blind) { - if (in_sight) - pline("You see a strange vibration beneath %s %s.", - s_suffix(mon_nam(mtmp)), - makeplural(mbodypart(mtmp, FOOT))); - else - pline("You see the ground vibrate in the distance."); - seetrap(trap); + seetrap(trap); /* before messages */ + if (in_sight) { + char buf[BUFSZ], *p, *monnm = mon_nam(mtmp); + + if (nolimbs(mtmp->data) + || is_floater(mtmp->data) || is_flyer(mtmp->data)) { + /* just "beneath " */ + Strcpy(buf, monnm); + } else { + Strcpy(buf, s_suffix(monnm)); + p = eos(strcat(buf, " ")); + Strcpy(p, makeplural(mbodypart(mtmp, FOOT))); + /* avoid "beneath 'rear paws'" or 'rear hooves' */ + (void) strsubst(p, "rear ", ""); + } + You_see("a strange vibration beneath %s.", buf); + } else { + /* notice something (hearing uses a larger threshold + for 'nearby') */ + You_see("the ground vibrate %s.", + (distu(mtmp->mx, mtmp->my) <= 2 * 2) + ? "nearby" : "in the distance"); + } } break; default: diff --git a/src/vault.c b/src/vault.c index 59a672ea3..71605514e 100644 --- a/src/vault.c +++ b/src/vault.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vault.c $NHDT-Date: 1545217597 2018/12/19 11:06:37 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.58 $ */ +/* NetHack 3.6 vault.c $NHDT-Date: 1545269451 2018/12/20 01:30:51 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.59 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -15,6 +15,7 @@ STATIC_DCL boolean FDECL(find_guard_dest, (struct monst *, xchar *, xchar *)); STATIC_DCL void FDECL(move_gold, (struct obj *, int)); STATIC_DCL void FDECL(wallify_vault, (struct monst *)); STATIC_DCL void FDECL(gd_mv_monaway, (struct monst *, int, int)); +STATIC_OVL void FDECL(gd_pick_corridor_gold, (struct monst *, int, int)); void newegd(mtmp) @@ -604,9 +605,9 @@ struct monst *grd; } STATIC_OVL void -gd_mv_monaway(grd, nx,ny) +gd_mv_monaway(grd, nx, ny) register struct monst *grd; -int nx,ny; +int nx, ny; { if (MON_AT(nx, ny) && !(nx == grd->mx && ny == grd->my)) { if (!Deaf) @@ -616,6 +617,97 @@ int nx,ny; } } +/* have guard pick gold off the floor, possibly moving to the gold's + position before message and back to his current spot after */ +STATIC_OVL void +gd_pick_corridor_gold(grd, goldx, goldy) +struct monst *grd; +int goldx, goldy; /* ox, gold->oy> */ +{ + struct obj *gold; + coord newcc, bestcc; + int gdelta, newdelta, bestdelta, tryct, + guardx = grd->mx, guardy = grd->my; + boolean under_u = (goldx == u.ux && goldy == u.uy), + see_it = cansee(goldx, goldy); + + if (under_u) { + /* Grab the gold from between the hero's feet. + If guard is two or more steps away; bring him closer first. */ + gold = g_at(goldx, goldy); + if (!gold) { + impossible("vault guard: no gold at hero's feet?"); + return; + } + gdelta = distu(guardx, guardy); + if (gdelta > 2 && see_it) { /* skip if player won't see it */ + bestdelta = gdelta; + bestcc.x = (xchar) guardx, bestcc.y = (xchar) guardy; + tryct = 9; + do { + /* pick an available spot nearest the hero and also try + to find the one meeting that criterium which is nearest + the guard's current location */ + if (enexto(&newcc, goldx, goldy, grd->data)) { + if ((newdelta = distu(newcc.x, newcc.y)) < bestdelta + || (newdelta == bestdelta + && dist2(newcc.x, newcc.y, guardx, guardy) + < dist2(bestcc.x, bestcc.y, guardx, guardy))) { + bestdelta = newdelta; + bestcc = newcc; + } + } + } while (--tryct >= 0); + + if (bestdelta < gdelta) { + remove_monster(guardx, guardy); + newsym(guardx, guardy); + place_monster(grd, (int) bestcc.x, (int) bestcc.y); + newsym(grd->mx, grd->my); + } + } + obj_extract_self(gold); + add_to_minv(grd, gold); + newsym(goldx, goldy); + + /* guard is already at gold's location */ + } else if (goldx == guardx && goldy == guardy) { + mpickgold(grd); /* does a newsym */ + + /* gold is at some third spot, neither guard's nor hero's */ + } else { + /* just for insurance... */ + gd_mv_monaway(grd, goldx, goldy); /* make room for guard */ + if (see_it) { /* skip if player won't see the message */ + remove_monster(grd->mx, grd->my); + newsym(grd->mx, grd->my); + place_monster(grd, goldx, goldy); /* sets mx, grd->my> */ + } + mpickgold(grd); /* does a newsym */ + } + + if (see_it) { /* cansee(goldx, goldy) */ + char monnambuf[BUFSZ]; + + Strcpy(monnambuf, Monnam(grd)); + if (!strcmpi(monnambuf, "It")) + Strcpy(monnambuf, "Someone"); + pline("%s%s picks up the gold%s.", monnambuf, + (grd->mpeaceful && EGD(grd)->warncnt > 5) + ? " calms down and" : "", + under_u ? " from beneath you" : ""); + } + + /* if guard was moved to get the gold, move him back */ + if (grd->mx != guardx || grd->my != guardy) { + remove_monster(grd->mx, grd->my); + newsym(grd->mx, grd->my); + place_monster(grd, guardx, guardy); + newsym(guardx, guardy); + } + return; +} + /* * return 1: guard moved, 0: guard didn't, -1: let m_move do it, -2: died */ @@ -774,35 +866,12 @@ register struct monst *grd; m = egrd->fakecorr[fci].fx; n = egrd->fakecorr[fci].fy; goldincorridor = TRUE; + break; } + /* new gold can appear if it was embedded in stone and hero kicks it + (on even via wish and drop) so don't assume hero has been warned */ if (goldincorridor && !egrd->gddone) { - x = grd->mx; - y = grd->my; - if (m == u.ux && n == u.uy) { - struct obj *gold = g_at(m, n); - /* Grab the gold from between the hero's feet. */ - obj_extract_self(gold); - add_to_minv(grd, gold); - newsym(m, n); - } else if (m == x && n == y) { - mpickgold(grd); /* does a newsym */ - } else { - /* just for insurance... */ - gd_mv_monaway(grd, m,n); - remove_monster(grd->mx, grd->my); - newsym(grd->mx, grd->my); - place_monster(grd, m, n); - mpickgold(grd); /* does a newsym */ - } - if (cansee(m, n)) - pline("%s%s picks up the gold.", Monnam(grd), - grd->mpeaceful ? " calms down and" : ""); - if (x != grd->mx || y != grd->my) { - remove_monster(grd->mx, grd->my); - newsym(grd->mx, grd->my); - place_monster(grd, x, y); - newsym(x, y); - } + gd_pick_corridor_gold(grd, m, n); if (!grd->mpeaceful) return -1; egrd->warncnt = 5; diff --git a/src/zap.c b/src/zap.c index 9ec946dfd..d71164a96 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1544442714 2018/12/10 11:51:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.302 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1545431660 2018/12/21 22:34:20 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.303 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4032,8 +4032,12 @@ boolean say; /* Announce out of sight hit/miss events if true */ /* hit() and miss() need bhitpos to match the target */ bhitpos.x = sx, bhitpos.y = sy; /* Fireballs only damage when they explode */ - if (type != ZT_SPELL(ZT_FIRE)) + if (type != ZT_SPELL(ZT_FIRE)) { range += zap_over_floor(sx, sy, type, &shopdamage, 0); + /* zap with fire -> melt ice -> drown monster, so monster + found and cached above might not be here any more */ + mon = m_at(sx, sy); + } if (mon) { if (type == ZT_SPELL(ZT_FIRE)) @@ -4236,6 +4240,7 @@ const char *msg; { struct rm *lev = &levl[x][y]; struct obj *otmp; + struct monst *mtmp; if (!msg) msg = "The ice crackles and melts."; @@ -4273,6 +4278,8 @@ const char *msg; } if (x == u.ux && y == u.uy) spoteffects(TRUE); /* possibly drown, notice objects */ + else if (is_pool(x, y) && (mtmp = m_at(x, y)) != 0) + (void) minliquid(mtmp); } #define MIN_ICE_TIME 50 @@ -4319,11 +4326,15 @@ long timeout UNUSED; { xchar x, y; long where = arg->a_long; + boolean save_mon_moving = context.mon_moving; /* will be False */ + /* melt_ice -> minliquid -> mondead|xkilled shouldn't credit/blame hero */ + context.mon_moving = TRUE; /* hero isn't causing this ice to melt */ y = (xchar) (where & 0xFFFF); x = (xchar) ((where >> 16) & 0xFFFF); /* melt_ice does newsym when appropriate */ melt_ice(x, y, "Some ice melts away."); + context.mon_moving = save_mon_moving; } /* Burn floor scrolls, evaporate pools, etc... in a single square.