Merge branch 'NetHack-3.6.2-beta01' into win-minor

This commit is contained in:
nhmall
2018-11-13 13:32:01 -05:00
13 changed files with 178 additions and 49 deletions

View File

@@ -194,6 +194,8 @@ avoid potential buffer overflow if object with very long name knocks other
objects down stairs when dropped, thrown, or kicked there
#wizintrinsic for 'flying' didn't update status line when flying ended
#wizintrinsic for 'warn_of_mon' didn't set any type of monster (now grid bugs)
clairvoyance would show trap instead of a monster on/in that trap, which was
intentional, but when clairvoyance finished the monster wasn't shown
Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository

View File

@@ -390,7 +390,7 @@ E void FDECL(revive_mon, (ANY_P *, long));
E int NDECL(donull);
E int NDECL(dowipe);
E void FDECL(set_wounded_legs, (long, int));
E void NDECL(heal_legs);
E void FDECL(heal_legs, (int));
/* ### do_name.c ### */

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 detect.c $NHDT-Date: 1541144458 2018/11/02 07:40:58 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.85 $ */
/* NetHack 3.6 detect.c $NHDT-Date: 1522891623 2018/04/05 01:27:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2018. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1300,25 +1300,82 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */
{
register int zx, zy;
struct monst *mtmp;
struct obj *otmp;
long save_EDetect_mons;
char save_viz_uyux;
boolean unconstrained, refresh = FALSE, mdetected = FALSE,
extended = (sobj && sobj->blessed);
int lo_y = ((u.uy - 5 < 0) ? 0 : u.uy - 5),
/* fake spellbook 'sobj' implies hero has cast the spell;
when book is blessed, casting is skilled or expert level;
if already clairvoyant, non-skilled spell acts like skilled */
extended = (sobj && (sobj->blessed || Clairvoyant));
int newglyph, oldglyph,
lo_y = ((u.uy - 5 < 0) ? 0 : u.uy - 5),
hi_y = ((u.uy + 6 >= ROWNO) ? ROWNO - 1 : u.uy + 6),
lo_x = ((u.ux - 9 < 1) ? 1 : u.ux - 9), /* avoid column 0 */
hi_x = ((u.ux + 10 >= COLNO) ? COLNO - 1 : u.ux + 10),
ter_typ = TER_DETECT | TER_MAP | TER_TRP | TER_OBJ;
/*
* 3.6.0 attempted to emphasize terrain over transient map
* properties (monsters and objects) but that led to problems.
* Notably, known trap would be displayed instead of a monster
* on or in it and then the display remained that way after the
* clairvoyant snapshot finished. That could have been fixed by
* issuing --More-- and then regular vision update, but we want
* to avoid that when having a clairvoyant episode every N turns
* (from donating to a temple priest or by carrying the Amulet).
* Unlike when casting the spell, it is much too intrustive when
* in the midst of walking around or combatting monsters.
*
* For 3.6.2, show terrain, then object, then monster like regular
* map updating, except in this case the map locations get marked
* as seen from every direction rather than just from direction of
* hero. Skilled spell marks revealed objects as 'seen up close'
* (but for piles, only the top item) and shows monsters as if
* detected. Non-skilled and timed clairvoyance reveals non-visible
* monsters as 'remembered, unseen'.
*/
/* if hero is engulfed, show engulfer at <u.ux,u.uy> */
save_viz_uyux = viz_array[u.uy][u.ux];
if (u.uswallow)
viz_array[u.uy][u.ux] |= IN_SIGHT; /* <x,y> are reversed to [y][x] */
save_EDetect_mons = EDetect_monsters;
/* for skilled spell, getpos() scanning of the map will display all
monsters within range; otherwise, "unseen creature" will be shown */
EDetect_monsters |= I_SPECIAL;
unconstrained = unconstrain_map();
for (zx = lo_x; zx <= hi_x; zx++)
for (zy = lo_y; zy <= hi_y; zy++) {
oldglyph = glyph_at(zx, zy);
/* this will remove 'remembered, unseen mon' (and objects) */
show_map_spot(zx, zy);
if (extended && (mtmp = m_at(zx, zy)) != 0
/* if there are any objects here, see the top one */
if (OBJ_AT(zx, zy)) {
/* not vobj_at(); this is not vision-based access;
unlike object detection, we don't notice buried items */
otmp = level.objects[zx][zy];
if (extended)
otmp->dknown = 1;
map_object(otmp, TRUE);
}
/* if there is a monster here, see or detect it,
possibly as "remembered, unseen monster" */
if ((mtmp = m_at(zx, zy)) != 0
&& mtmp->mx == zx && mtmp->my == zy) { /* skip worm tails */
int oldglyph = glyph_at(zx, zy);
map_monst(mtmp, FALSE);
if (glyph_at(zx, zy) != oldglyph)
/* if we're going to offer browse_map()/getpos() scanning of
the map and we're not doing extended/blessed clairvoyance
(hence must be swallowed or underwater), show "unseen
creature" unless map already displayed a monster here */
if ((unconstrained || !level.flags.hero_memory)
&& !extended && (zx != u.ux || zy != u.uy)
&& !glyph_is_monster(oldglyph))
map_invisible(zx, zy);
else
map_monst(mtmp, FALSE);
newglyph = glyph_at(zx, zy);
if (extended && newglyph != oldglyph
&& !glyph_is_invisible(newglyph))
mdetected = TRUE;
}
}
@@ -1331,13 +1388,26 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */
You("sense your surroundings.");
if (extended || glyph_is_monster(glyph_at(u.ux, u.uy)))
ter_typ |= TER_MON;
if (extended)
EDetect_monsters |= I_SPECIAL;
browse_map(ter_typ, "anything of interest");
EDetect_monsters &= ~I_SPECIAL;
refresh = TRUE;
}
reconstrain_map();
EDetect_monsters = save_EDetect_mons;
viz_array[u.uy][u.ux] = save_viz_uyux;
/* replace monsters with remembered,unseen monster, then run
see_monsters() to update visible ones and warned-of ones */
for (zx = lo_x; zx <= hi_x; zx++)
for (zy = lo_y; zy <= hi_y; zy++) {
if (zx == u.ux && zy == u.uy)
continue;
newglyph = glyph_at(zx, zy);
if (glyph_is_monster(newglyph)
&& glyph_to_mon(newglyph) != PM_LONG_WORM_TAIL)
map_invisible(zx, zy);
}
see_monsters();
if (refresh)
docrt();
}

View File

@@ -1882,7 +1882,8 @@ register int timex;
}
void
heal_legs()
heal_legs(how)
int how; /* 0: ordinary, 1: dismounting steed, 2: limbs turn to stone */
{
if (Wounded_legs) {
if (ATEMP(A_DEX) < 0) {
@@ -1890,7 +1891,11 @@ heal_legs()
context.botl = 1;
}
if (!u.usteed) {
/* when mounted, wounded legs applies to the steed;
during petrification countdown, "your limbs turn to stone"
before the final stages and that calls us (how==2) to cure
wounded legs, but we want to suppress the feel better message */
if (!u.usteed && how != 2) {
const char *legs = body_part(LEG);
if ((EWounded_legs & BOTH_SIDES) == BOTH_SIDES)
@@ -1900,7 +1905,7 @@ heal_legs()
Your("%s %s better.", legs, vtense(legs, "feel"));
}
HWounded_legs = EWounded_legs = 0;
HWounded_legs = EWounded_legs = 0L;
/* Wounded_legs reduces carrying capacity, so we want
an encumbrance check when they're healed. However,
@@ -1912,7 +1917,7 @@ heal_legs()
it might be immediately contradicted [able to carry
more when steed becomes healthy, then possible floor
feedback, then able to carry less when back on foot]. */
if (!in_steed_dismounting)
if (how == 0)
(void) encumber_msg();
}
}

View File

@@ -26,7 +26,8 @@ nhsym l_syms[SYM_MAX] = DUMMY; /* loaded symbols */
nhsym r_syms[SYM_MAX] = DUMMY; /* rogue symbols */
nhsym warnsyms[WARNCOUNT] = DUMMY; /* the current warning display symbols */
const char invisexplain[] = "remembered, unseen, creature";
const char invisexplain[] = "remembered, unseen, creature",
altinvisexplain[] = "unseen creature"; /* for clairvoyance */
/* Default object class symbols. See objclass.h.
* {symbol, name, explain}

View File

@@ -2217,7 +2217,7 @@ struct obj *otmp;
}
}
if (!otmp->cursed)
heal_legs();
heal_legs(0);
break;
case EGG:
if (flesh_petrifies(&mons[otmp->corpsenm])) {
@@ -3181,7 +3181,8 @@ vomit() /* A good idea from David Neves */
dealing with some esoteric body_part() */
Your("jaw gapes convulsively.");
} else {
make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
if (Sick && (u.usick_type & SICK_VOMITABLE) != 0)
make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
/* if not enough in stomach to actually vomit then dry heave;
vomiting_dialog() gives a vomit message when its countdown
reaches 0, but only if u.uhs < FAINTING (and !cantvomit()) */

View File

@@ -895,12 +895,17 @@ struct permonst **for_supplement;
}
if (sym == DEF_INVISIBLE) {
extern const char altinvisexplain[]; /* drawing.c */
/* for active clairvoyance, use alternate "unseen creature" */
boolean usealt = (EDetect_monsters & I_SPECIAL) != 0L;
const char *unseen_explain = !usealt ? invisexplain : altinvisexplain;
if (!found) {
Sprintf(out_str, "%s%s", prefix, an(invisexplain));
*firstmatch = invisexplain;
Sprintf(out_str, "%s%s", prefix, an(unseen_explain));
*firstmatch = unseen_explain;
found++;
} else {
found += append_str(out_str, an(invisexplain));
found += append_str(out_str, an(unseen_explain));
}
}

View File

@@ -106,6 +106,9 @@ boolean talk;
set_itimeout(&HStun, xtime);
}
/* Sick is overloaded with both fatal illness and food poisoning (via
u.usick_type bit mask), but delayed killer can only support one or
the other at a time. They should become separate intrinsics.... */
void
make_sick(xtime, cause, talk, type)
long xtime;
@@ -113,9 +116,10 @@ const char *cause; /* sickness cause */
boolean talk;
int type;
{
struct kinfo *kptr;
long old = Sick;
#if 0
#if 0 /* tell player even if hero is unconscious */
if (Unaware)
talk = FALSE;
#endif
@@ -148,11 +152,20 @@ int type;
context.botl = TRUE;
}
kptr = find_delayed_killer(SICK);
if (Sick) {
exercise(A_CON, FALSE);
delayed_killer(SICK, KILLED_BY_AN, cause);
/* setting delayed_killer used to be unconditional, but that's
not right when make_sick(0) is called to cure food poisoning
if hero was also fatally ill; this is only approximate */
if (xtime || !old || !kptr) {
int kpfx = ((cause && !strcmp(cause, "#wizintrinsic"))
? KILLED_BY : KILLED_BY_AN);
delayed_killer(SICK, kpfx, cause);
}
} else
dealloc_killer(find_delayed_killer(SICK));
dealloc_killer(kptr);
}
void
@@ -162,7 +175,7 @@ const char *msg;
{
long old = Slimed;
#if 0
#if 0 /* tell player even if hero is unconscious */
if (Unaware)
msg = 0;
#endif
@@ -170,7 +183,7 @@ const char *msg;
if ((xtime != 0L) ^ (old != 0L)) {
context.botl = TRUE;
if (msg)
pline1(msg);
pline("%s", msg);
}
if (!Slimed)
dealloc_killer(find_delayed_killer(SLIMED));
@@ -186,7 +199,7 @@ const char *killername;
{
long old = Stoned;
#if 0
#if 0 /* tell player even if hero is unconscious */
if (Unaware)
msg = 0;
#endif
@@ -194,7 +207,7 @@ const char *killername;
if ((xtime != 0L) ^ (old != 0L)) {
context.botl = TRUE;
if (msg)
pline1(msg);
pline("%s", msg);
}
if (!Stoned)
dealloc_killer(find_delayed_killer(STONED));
@@ -892,9 +905,9 @@ register struct obj *otmp;
}
break;
case POT_SPEED:
/* skip when mounted; heal_legs() would heal steed's legs */
if (Wounded_legs && !otmp->cursed && !u.usteed) {
/* heal_legs() would heal steeds legs */
heal_legs();
heal_legs(0);
unkn++;
break;
}

View File

@@ -524,7 +524,7 @@ int trouble;
break;
}
case TROUBLE_WOUNDED_LEGS:
heal_legs();
heal_legs(0);
break;
case TROUBLE_STUNNED:
make_stunned(0L, TRUE);
@@ -2181,6 +2181,7 @@ blocked_boulder(dx, dy)
int dx, dy;
{
register struct obj *otmp;
int nx, ny;
long count = 0L;
for (otmp = level.objects[u.ux + dx][u.uy + dy]; otmp;
@@ -2189,6 +2190,7 @@ int dx, dy;
count += otmp->quan;
}
nx = u.ux + 2 * dx, ny = u.uy + 2 * dy; /* next spot beyond boulder(s) */
switch (count) {
case 0:
/* no boulders--not blocked */
@@ -2196,17 +2198,24 @@ int dx, dy;
case 1:
/* possibly blocked depending on if it's pushable */
break;
case 2:
/* this is only approximate since multiple boulders might sink */
if (is_pool_or_lava(nx, ny)) /* does its own isok() check */
break; /* still need Sokoban check below */
/*FALLTHRU*/
default:
/* more than one boulder--blocked after they push the top one;
don't force them to push it first to find out */
return TRUE;
}
if (!isok(u.ux + 2 * dx, u.uy + 2 * dy))
if (dx && dy && Sokoban) /* can't push boulder diagonally in Sokoban */
return TRUE;
if (IS_ROCK(levl[u.ux + 2 * dx][u.uy + 2 * dy].typ))
if (!isok(nx, ny))
return TRUE;
if (sobj_at(BOULDER, u.ux + 2 * dx, u.uy + 2 * dy))
if (IS_ROCK(levl[nx][ny].typ))
return TRUE;
if (sobj_at(BOULDER, nx, ny))
return TRUE;
return FALSE;

View File

@@ -188,7 +188,7 @@ dosit()
u.ucreamed = 0;
make_blinded(0L, TRUE);
make_sick(0L, (char *) 0, FALSE, SICK_ALL);
heal_legs();
heal_legs(0);
context.botl = 1;
break;
case 5:

View File

@@ -221,7 +221,7 @@ boolean force; /* Quietly force this animal */
if (Wounded_legs) {
Your("%s are in no shape for riding.", makeplural(body_part(LEG)));
if (force && wizard && yn("Heal your legs?") == 'y')
HWounded_legs = EWounded_legs = 0;
HWounded_legs = EWounded_legs = 0L;
else
return (FALSE);
}
@@ -542,12 +542,8 @@ int reason; /* Player was thrown off etc. */
}
/* While riding, Wounded_legs refers to the steed's legs;
after dismounting, it reverts to the hero's legs. */
if (repair_leg_damage) {
/* [TODO: make heal_legs() take a parameter to handle this] */
in_steed_dismounting = TRUE;
heal_legs();
in_steed_dismounting = FALSE;
}
if (repair_leg_damage)
heal_legs(1);
/* Release the steed and saddle */
u.usteed = 0;

View File

@@ -136,10 +136,19 @@ stoned_dialogue()
nomul(-3); /* can't move anymore */
multi_reason = "getting stoned";
nomovemsg = You_can_move_again; /* not unconscious */
/* "your limbs have turned to stone" so terminate wounded legs */
if (Wounded_legs && !u.usteed)
heal_legs(2);
break;
case 2:
case 2: /* turned to stone */
if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
/* if also vomiting or turning into slime, stop those (no messages) */
if (Vomiting)
make_vomiting(0L, FALSE);
if (Slimed)
make_slimed(0L, (char *) 0);
break;
default:
break;
}
@@ -318,15 +327,25 @@ slime_dialogue()
} else
pline1(buf);
}
if (i == 3L) { /* limbs becoming oozy */
switch (i) {
case 3L: /* limbs becoming oozy */
HFast = 0L; /* lose intrinsic speed */
if (!Popeye(SLIMED))
stop_occupation();
if (multi > 0)
nomul(0);
break;
case 2L: /* skin begins to peel */
if ((HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
break;
case 1L: /* turning into slime */
/* if also turning to stone, stop doing that (no message) */
if (Stoned)
make_stoned(0L, (char *) 0, KILLED_BY_AN, (char *) 0);
break;
}
if (i == 2L && (HDeaf & TIMEOUT) > 0L && (HDeaf & TIMEOUT) < 5L)
set_itimeout(&HDeaf, 5L); /* avoid Hear_again at tail end */
exercise(A_DEX, FALSE);
}
@@ -534,7 +553,7 @@ nh_timeout()
stop_occupation();
break;
case WOUNDED_LEGS:
heal_legs();
heal_legs(0);
stop_occupation();
break;
case HALLUC:

View File

@@ -1334,6 +1334,7 @@ $(DAT)\dungeon: $(O)utility.tag $(DAT)\dungeon.def
$(O)nttty.o: $(HACK_H) $(TILE_H) $(MSWSYS)\win32api.h $(MSWSYS)\nttty.c
@$(cc) $(cflagsBuild) -I$(WSHR) -Fo$@ $(MSWSYS)\nttty.c
$(O)winnt.o: $(HACK_H) $(MSWSYS)\win32api.h $(MSWSYS)\winnt.c
@$(cc) $(cflagsBuild) -I$(MSWSYS) -I$(MSWIN) -Fo$@ $(MSWSYS)\win10.c
@$(cc) $(cflagsBuild) -Fo$@ $(MSWSYS)\winnt.c
$(O)ntsound.o: $(HACK_H) $(MSWSYS)\ntsound.c
@$(cc) $(cflagsBuild) -Fo$@ $(MSWSYS)\ntsound.c
@@ -1344,6 +1345,13 @@ $(O)ntsound.o: $(HACK_H) $(MSWSYS)\ntsound.c
$(O)guistub.o: $(HACK_H) $(MSWSYS)\stubs.c
@$(cc) $(cflagsBuild) -DGUISTUB -Fo$@ $(MSWSYS)\stubs.c
#
# WIN32 dependencies
#
$(O)winhack.o: $(HACK_H) $(MSWIN)\winhack.c
@$(cc) $(cflagsBuild) -I$(MSWSYS) -I$(MSWIN) -Fo$@ $(MSWIN)\winhack.c
#if you aren't linking in the full tty then
#include the following stub for proper linkage.