Merge branch 'NetHack-3.6'

This commit is contained in:
nhmall
2019-06-22 22:03:07 -04:00
4 changed files with 119 additions and 97 deletions
+6 -1
View File
@@ -1,4 +1,4 @@
$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.62 $ $NHDT-Date: 1561081353 2019/06/21 01:42:33 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.64 $ $NHDT-Date: 1561233801 2019/06/22 20:03:21 $
This fixes36.3 file is here to capture information about updates in the 3.6.x This fixes36.3 file is here to capture information about updates in the 3.6.x
lineage following the release of 3.6.2 in May 2019. Please note, however, lineage following the release of 3.6.2 in May 2019. Please note, however,
@@ -79,6 +79,11 @@ for wizard mode 'monpolycontrol', allow usually disallowed type 'chameleon',
add Space, Return, and Escape to '? k' (help for menu control keys) add Space, Return, and Escape to '? k' (help for menu control keys)
hero can no longer negotiate a bribe with a demon lord when deaf hero can no longer negotiate a bribe with a demon lord when deaf
wishing for "foo amulet" now yields an "amulet of foo" rather than random one wishing for "foo amulet" now yields an "amulet of foo" rather than random one
code in parse_conf_file() to trim trailing blanks/cr was skipping over them
partly eaten food with one bite left had message anomalies when eaten; the
usual "you resume your meal" case lacked the "you're finished" message
when done; eating something else in between to clobber meal context
resulted in no messages at all when restarting and finishing last bite
Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository
+47 -35
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 eat.c $NHDT-Date: 1559670604 2019/06/04 17:50:04 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.202 $ */ /* NetHack 3.6 eat.c $NHDT-Date: 1561233801 2019/06/22 20:03:21 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.203 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -25,7 +25,7 @@ STATIC_DCL void FDECL(cpostfx, (int));
STATIC_DCL void FDECL(consume_tin, (const char *)); STATIC_DCL void FDECL(consume_tin, (const char *));
STATIC_DCL void FDECL(start_tin, (struct obj *)); STATIC_DCL void FDECL(start_tin, (struct obj *));
STATIC_DCL int FDECL(eatcorpse, (struct obj *)); STATIC_DCL int FDECL(eatcorpse, (struct obj *));
STATIC_DCL void FDECL(start_eating, (struct obj *)); STATIC_DCL void FDECL(start_eating, (struct obj *, BOOLEAN_P));
STATIC_DCL void FDECL(fprefx, (struct obj *)); STATIC_DCL void FDECL(fprefx, (struct obj *));
STATIC_DCL void FDECL(fpostfx, (struct obj *)); STATIC_DCL void FDECL(fpostfx, (struct obj *));
STATIC_DCL int NDECL(bite); STATIC_DCL int NDECL(bite);
@@ -1413,15 +1413,12 @@ const char *mesg;
gainstr(tin, 0, FALSE); gainstr(tin, 0, FALSE);
tin = costly_tin(COST_OPEN); tin = costly_tin(COST_OPEN);
lesshungry(tin->blessed ? 600 /* blessed */
lesshungry(tin->blessed : !tin->cursed ? (400 + rnd(200)) /* uncursed */
? 600 /* blessed */ : (200 + rnd(400))); /* cursed */
: !tin->cursed
? (400 + rnd(200)) /* uncursed */
: (200 + rnd(400))); /* cursed */
} }
use_up_tin: use_up_tin:
if (carried(tin)) if (carried(tin))
useup(tin); useup(tin);
else else
@@ -1499,7 +1496,7 @@ struct obj *otmp;
} }
pline("Using %s you try to open the tin.", yobjnam(uwep, (char *) 0)); pline("Using %s you try to open the tin.", yobjnam(uwep, (char *) 0));
} else { } else {
no_opener: no_opener:
pline("It is not so easy to open this tin."); pline("It is not so easy to open this tin.");
if (Glib) { if (Glib) {
pline_The("tin slips from your %s.", pline_The("tin slips from your %s.",
@@ -1723,8 +1720,9 @@ struct obj *otmp;
/* called as you start to eat */ /* called as you start to eat */
STATIC_OVL void STATIC_OVL void
start_eating(otmp) start_eating(otmp, already_partly_eaten)
struct obj *otmp; struct obj *otmp;
boolean already_partly_eaten;
{ {
const char *old_nomovemsg, *save_nomovemsg; const char *old_nomovemsg, *save_nomovemsg;
static char msgbuf[BUFSZ]; static char msgbuf[BUFSZ];
@@ -1769,7 +1767,8 @@ struct obj *otmp;
if (++g.context.victual.usedtime >= g.context.victual.reqtime) { if (++g.context.victual.usedtime >= g.context.victual.reqtime) {
/* print "finish eating" message if they just resumed -dlc */ /* print "finish eating" message if they just resumed -dlc */
done_eating(g.context.victual.reqtime > 1 ? TRUE : FALSE); done_eating((g.context.victual.reqtime > 1
|| already_partly_eaten) ? TRUE : FALSE);
return; return;
} }
@@ -1778,28 +1777,35 @@ struct obj *otmp;
} }
/* /*
* called on "first bite" of (non-corpse) food. * Called on "first bite" of (non-corpse) food, after touchfood() has
* used for non-rotten non-tin non-corpse food * marked it 'partly eaten'. Used for non-rotten non-tin non-corpse food.
* Messages should use present tense since multi-turn food won't be
* finishing at the time they're issued.
*/ */
STATIC_OVL void STATIC_OVL void
fprefx(otmp) fprefx(otmp)
struct obj *otmp; struct obj *otmp;
{ {
switch (otmp->otyp) { switch (otmp->otyp) {
case FOOD_RATION: case FOOD_RATION: /* nutrition 800 */
/* 200+800 remains below 1000+1, the satiation threshold */
if (u.uhunger <= 200) if (u.uhunger <= 200)
pline(Hallucination ? "Oh wow, like, superior, man!" pline("%s!", Hallucination ? "Oh wow, like, superior, man"
: "That food really hit the spot!"); : "This food really hits the spot");
else if (u.uhunger <= 700)
pline("That satiated your %s!", body_part(STOMACH)); /* 700-1+800 remains below 1500, the choking threshold which
triggers "you're having a hard time getting it down" feedback */
else if (u.uhunger < 700)
pline("This satiates your %s!", body_part(STOMACH));
/* [satiation message may be inaccurate if eating gets interrupted] */
break; break;
case TRIPE_RATION: case TRIPE_RATION:
if (carnivorous(g.youmonst.data) && !humanoid(g.youmonst.data)) if (carnivorous(g.youmonst.data) && !humanoid(g.youmonst.data)) {
pline("That tripe ration was surprisingly good!"); pline("This tripe ration is surprisingly good!");
else if (maybe_polyd(is_orc(g.youmonst.data), Race_if(PM_ORC))) } else if (maybe_polyd(is_orc(g.youmonst.data), Race_if(PM_ORC))) {
pline(Hallucination ? "Tastes great! Less filling!" pline(Hallucination ? "Tastes great! Less filling!"
: "Mmm, tripe... not bad!"); : "Mmm, tripe... not bad!");
else { } else {
pline("Yak - dog food!"); pline("Yak - dog food!");
more_experienced(1, 0); more_experienced(1, 0);
newexplevel(); newexplevel();
@@ -1832,7 +1838,7 @@ struct obj *otmp;
default: default:
if (otmp->otyp == SLIME_MOLD && !otmp->cursed if (otmp->otyp == SLIME_MOLD && !otmp->cursed
&& otmp->spe == g.context.current_fruit) { && otmp->spe == g.context.current_fruit) {
pline("My, that was a %s %s!", pline("My, this is a %s %s!",
Hallucination ? "primo" : "yummy", Hallucination ? "primo" : "yummy",
singular(otmp, xname)); singular(otmp, xname));
} else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) { } else if (otmp->otyp == APPLE && otmp->cursed && !Sleep_resistance) {
@@ -1851,9 +1857,7 @@ struct obj *otmp;
if (!Hallucination) { if (!Hallucination) {
pline("Core dumped."); pline("Core dumped.");
} else { } else {
/* This is based on an old Usenet joke, a fake a.out manual /* based on an old Usenet joke, a fake a.out manual page */
* page
*/
int x = rnd(100); int x = rnd(100);
pline("%s -- core dumped.", pline("%s -- core dumped.",
@@ -1871,7 +1875,7 @@ struct obj *otmp;
will be abused more times before illness completes */ will be abused more times before illness completes */
make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE); make_vomiting((Vomiting & TIMEOUT) + (long) d(10, 4), TRUE);
} else { } else {
give_feedback: give_feedback:
pline("This %s is %s", singular(otmp, xname), pline("This %s is %s", singular(otmp, xname),
otmp->cursed otmp->cursed
? (Hallucination ? "grody!" : "terrible!") ? (Hallucination ? "grody!" : "terrible!")
@@ -2438,7 +2442,8 @@ doeat()
{ {
struct obj *otmp; struct obj *otmp;
int basenutrit; /* nutrition of full item */ int basenutrit; /* nutrition of full item */
boolean dont_start = FALSE, nodelicious = FALSE; boolean dont_start = FALSE, nodelicious = FALSE,
already_partly_eaten;
if (Strangled) { if (Strangled) {
pline("If you can't breathe air, how can you consume solids?"); pline("If you can't breathe air, how can you consume solids?");
@@ -2600,8 +2605,10 @@ doeat()
g.context.victual.piece = touchfood(otmp); g.context.victual.piece = touchfood(otmp);
if (g.context.victual.piece) if (g.context.victual.piece)
g.context.victual.o_id = g.context.victual.piece->o_id; g.context.victual.o_id = g.context.victual.piece->o_id;
You("resume your meal."); You("resume %syour meal.",
start_eating(g.context.victual.piece); (g.context.victual.usedtime + 1 >= g.context.victual.reqtime)
? "the last bite of " : "");
start_eating(g.context.victual.piece, FALSE);
return 1; return 1;
} }
@@ -2616,7 +2623,7 @@ doeat()
/* KMH, conduct */ /* KMH, conduct */
u.uconduct.food++; u.uconduct.food++;
g.context.victual.o_id = 0; already_partly_eaten = otmp->oeaten ? TRUE : FALSE;
g.context.victual.piece = otmp = touchfood(otmp); g.context.victual.piece = otmp = touchfood(otmp);
if (g.context.victual.piece) if (g.context.victual.piece)
g.context.victual.o_id = g.context.victual.piece->o_id; g.context.victual.o_id = g.context.victual.piece->o_id;
@@ -2669,8 +2676,13 @@ doeat()
dont_start = TRUE; dont_start = TRUE;
} }
consume_oeaten(otmp, 1); /* oeaten >>= 1 */ consume_oeaten(otmp, 1); /* oeaten >>= 1 */
} else } else if (!already_partly_eaten) {
fprefx(otmp); fprefx(otmp);
} else {
You("%s %s.",
(g.context.victual.reqtime == 1) ? "eat" : "begin eating",
doname(otmp));
}
} }
/* re-calc the nutrition */ /* re-calc the nutrition */
@@ -2702,7 +2714,7 @@ doeat()
g.context.victual.canchoke = (u.uhs == SATIATED); g.context.victual.canchoke = (u.uhs == SATIATED);
if (!dont_start) if (!dont_start)
start_eating(otmp); start_eating(otmp, already_partly_eaten);
return 1; return 1;
} }
@@ -3159,7 +3171,7 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
} }
} }
skipfloor: skipfloor:
/* We cannot use ALL_CLASSES since that causes getobj() to skip its /* We cannot use ALL_CLASSES since that causes getobj() to skip its
* "ugly checks" and we need to check for inedible items. * "ugly checks" and we need to check for inedible items.
*/ */
+2 -2
View File
@@ -2994,9 +2994,9 @@ boolean FDECL((*proc), (char *));
*ep = '\0'; *ep = '\0';
/* trim off spaces at end of line */ /* trim off spaces at end of line */
while (--ep >= inbuf while (ep >= inbuf
&& (*ep == ' ' || *ep == '\t' || *ep == '\r')) && (*ep == ' ' || *ep == '\t' || *ep == '\r'))
*ep = '\0'; *ep-- = '\0';
if (!config_error_nextline(inbuf)) { if (!config_error_nextline(inbuf)) {
rv = FALSE; rv = FALSE;
+64 -59
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 makemon.c $NHDT-Date: 1559733390 2019/06/05 11:16:30 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.137 $ */ /* NetHack 3.6 makemon.c $NHDT-Date: 1561236435 2019/06/22 20:47:15 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.138 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -819,18 +819,20 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
if (x == 0) { if (x == 0) {
mm.x = mon->mx; mm.x = mon->mx;
mm.y = mon->my; mm.y = mon->my;
if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
return (struct monst *) 0;
} else if (!isok(x, y)) {
return (struct monst *) 0; /* paranoia */
} else { } else {
mm.x = x; mm.x = x;
mm.y = y; mm.y = y;
if (MON_AT(mm.x, mm.y)) {
if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
return (struct monst *) 0;
}
} }
if (!isok(mm.x, mm.y)) { /* paranoia */
impossible("clone_mon trying to create a monster at <%d,%d>?",
mm.x, mm.y);
return (struct monst *) 0;
}
if (MON_AT(mm.x, mm.y)) { /* (always True for the x==0 case) */
if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y))
return (struct monst *) 0;
}
m2 = newmonst(); m2 = newmonst();
*m2 = *mon; /* copy condition of old monster */ *m2 = *mon; /* copy condition of old monster */
m2->mextra = (struct mextra *) 0; m2->mextra = (struct mextra *) 0;
@@ -846,7 +848,7 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
m2->mtrapped = 0; m2->mtrapped = 0;
m2->mcloned = 1; m2->mcloned = 1;
m2->minvent = (struct obj *) 0; /* objects don't clone */ m2->minvent = (struct obj *) 0; /* objects don't clone */
m2->mleashed = FALSE; m2->mleashed = 0;
/* Max HP the same, but current HP halved for both. The caller /* Max HP the same, but current HP halved for both. The caller
* might want to override this by halving the max HP also. * might want to override this by halving the max HP also.
* When current HP is odd, the original keeps the extra point. * When current HP is odd, the original keeps the extra point.
@@ -856,21 +858,20 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
m2->mhp = mon->mhp / 2; m2->mhp = mon->mhp / 2;
mon->mhp -= m2->mhp; mon->mhp -= m2->mhp;
/* since shopkeepers and guards will only be cloned if they've been /* clone doesn't have mextra so mustn't retain special monster flags */
* polymorphed away from their original forms, the clone doesn't have m2->isshk = 0;
* room for the extra information. we also don't want two shopkeepers m2->isgd = 0;
* around for the same shop. m2->ispriest = 0;
*/ /* ms->isminion handled below */
if (mon->isshk)
m2->isshk = FALSE; /* clone shouldn't be reluctant to move on spots 'parent' just moved on */
if (mon->isgd) (void) memset((genericptr_t) m2->mtrack, 0, sizeof m2->mtrack);
m2->isgd = FALSE;
if (mon->ispriest)
m2->ispriest = FALSE;
place_monster(m2, m2->mx, m2->my); place_monster(m2, m2->mx, m2->my);
if (emits_light(m2->data)) if (emits_light(m2->data))
new_light_source(m2->mx, m2->my, emits_light(m2->data), LS_MONSTER, new_light_source(m2->mx, m2->my, emits_light(m2->data), LS_MONSTER,
monst_to_any(m2)); monst_to_any(m2));
/* if 'parent' is named, give the clone the same name */
if (has_mname(mon)) { if (has_mname(mon)) {
m2 = christen_monst(m2, MNAME(mon)); m2 = christen_monst(m2, MNAME(mon));
} else if (mon->isshk) { } else if (mon->isshk) {
@@ -878,31 +879,35 @@ xchar x, y; /* clone's preferred location or 0 (near mon) */
} }
/* not all clones caused by player are tame or peaceful */ /* not all clones caused by player are tame or peaceful */
if (!g.context.mon_moving) { if (!g.context.mon_moving && mon->mpeaceful) {
if (mon->mtame) if (mon->mtame)
m2->mtame = rn2(max(2 + u.uluck, 2)) ? mon->mtame : 0; m2->mtame = rn2(max(2 + u.uluck, 2)) ? mon->mtame : 0;
else if (mon->mpeaceful) else if (mon->mpeaceful)
m2->mpeaceful = rn2(max(2 + u.uluck, 2)) ? 1 : 0; m2->mpeaceful = rn2(max(2 + u.uluck, 2)) ? 1 : 0;
} }
/* if guardian angel could be cloned (maybe after polymorph?),
m2 could be both isminion and mtame; isminion takes precedence */
if (m2->isminion) {
int atyp;
newsym(m2->mx, m2->my); /* display the new monster */ newemin(m2);
if (m2->mtame) { *EMIN(m2) = *EMIN(mon);
if (mon->isminion) { /* renegade when same alignment as hero but not peaceful or
newemin(m2); when peaceful while being different alignment from hero */
if (EMIN(mon)) atyp = EMIN(m2)->min_align;
*(EMIN(m2)) = *(EMIN(mon)); EMIN(m2)->renegade = (atyp != u.ualign.type) ^ !m2->mpeaceful;
} else { } else if (m2->mtame) {
/* because m2 is a copy of mon it is tame but not init'ed. /* Because m2 is a copy of mon it is tame but not init'ed.
* however, tamedog will not re-tame a tame dog, so m2 However, tamedog() will not re-tame a tame dog, so m2
* must be made non-tame to get initialized properly. must be made non-tame to get initialized properly. */
*/ m2->mtame = 0;
m2->mtame = 0; if (tamedog(m2, (struct obj *) 0))
if (tamedog(m2, (struct obj *) 0)) { *EDOG(m2) = *EDOG(mon);
*(EDOG(m2)) = *(EDOG(mon)); /* [TODO? some (most? all?) edog fields probably should be
} reinitialized rather that retain the 'parent's values] */
}
} }
set_malign(m2); set_malign(m2);
newsym(m2->mx, m2->my); /* display the new monster */
return m2; return m2;
} }
@@ -1107,6 +1112,8 @@ register int x, y;
int mmflags; int mmflags;
{ {
register struct monst *mtmp; register struct monst *mtmp;
struct monst fakemon;
coord cc;
int mndx, mcham, ct, mitem; int mndx, mcham, ct, mitem;
boolean anymon = (!ptr); boolean anymon = (!ptr);
boolean byyou = (x == u.ux && y == u.uy); boolean byyou = (x == u.ux && y == u.uy);
@@ -1114,40 +1121,37 @@ int mmflags;
boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0); boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0);
unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0; unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0;
fakemon = cg.zeromonst;
cc.x = cc.y = 0;
/* if caller wants random location, do it here */ /* if caller wants random location, do it here */
if (x == 0 && y == 0) { if (x == 0 && y == 0) {
coord cc;
struct monst fakemon;
cc.x = cc.y = 0; /* lint suppression */
fakemon = cg.zeromonst;
fakemon.data = ptr; /* set up for goodpos */ fakemon.data = ptr; /* set up for goodpos */
if (!makemon_rnd_goodpos(ptr ? &fakemon : (struct monst *)0, if (!makemon_rnd_goodpos(ptr ? &fakemon : (struct monst *) 0,
gpflags, &cc)) gpflags, &cc))
return (struct monst *) 0; return (struct monst *) 0;
x = cc.x; x = cc.x;
y = cc.y; y = cc.y;
} else if (byyou && !g.in_mklev) { } else if (byyou && !g.in_mklev) {
coord bypos; if (!enexto_core(&cc, u.ux, u.uy, ptr, gpflags))
if (enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) {
x = bypos.x;
y = bypos.y;
} else
return (struct monst *) 0; return (struct monst *) 0;
x = cc.x;
y = cc.y;
}
/* sanity check */
if (!isok(x, y)) {
impossible("makemon trying to create a monster at <%d,%d>?", x, y);
return (struct monst *) 0;
} }
/* Does monster already exist at the position? */ /* Does monster already exist at the position? */
if (MON_AT(x, y)) { if (MON_AT(x, y)) {
if ((mmflags & MM_ADJACENTOK) != 0) { if (!(mmflags & MM_ADJACENTOK)
coord bypos; || !enexto_core(&cc, x, y, ptr, gpflags))
if (enexto_core(&bypos, x, y, ptr, gpflags)) {
x = bypos.x;
y = bypos.y;
} else
return (struct monst *) 0;
} else
return (struct monst *) 0; return (struct monst *) 0;
x = cc.x;
y = cc.y;
} }
if (ptr) { if (ptr) {
@@ -1167,7 +1171,6 @@ int mmflags;
* for instance.) * for instance.)
*/ */
int tryct = 0; /* maybe there are no good choices */ int tryct = 0; /* maybe there are no good choices */
struct monst fakemon;
do { do {
if (!(ptr = rndmonst())) { if (!(ptr = rndmonst())) {
@@ -1354,6 +1357,7 @@ int mmflags;
? !(mmflags & (MM_EPRI | MM_EMIN)) ? !(mmflags & (MM_EPRI | MM_EMIN))
: (mndx == PM_ANGEL && !(mmflags & MM_EMIN) && !rn2(3))) { : (mndx == PM_ANGEL && !(mmflags & MM_EMIN) && !rn2(3))) {
struct emin *eminp; struct emin *eminp;
newemin(mtmp); newemin(mtmp);
eminp = EMIN(mtmp); eminp = EMIN(mtmp);
@@ -1385,6 +1389,7 @@ int mmflags;
if (!rn2(100) && is_domestic(ptr) if (!rn2(100) && is_domestic(ptr)
&& can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); struct obj *otmp = mksobj(SADDLE, TRUE, FALSE);
put_saddle_on_mon(otmp, mtmp); put_saddle_on_mon(otmp, mtmp);
} }