Merge remote-tracking branch 'origin/NetHack-3.6.0'

This commit is contained in:
keni
2017-12-24 15:28:18 -05:00
24 changed files with 370 additions and 143 deletions
+3
View File
@@ -4,3 +4,6 @@
*.hqx -text *.hqx -text
*.sln -text *.sln -text
*.vcxproj -text *.vcxproj -text
*.doc !diff
*.DOC !diff
+14 -6
View File
@@ -1,4 +1,4 @@
.\" $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.240 $ $NHDT-Date: 1512098127 2017/12/01 03:15:27 $ .\" $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.241 $ $NHDT-Date: 1512473628 2017/12/05 11:33:48 $
.ds h0 "NetHack Guidebook .ds h0 "NetHack Guidebook
.ds h1 .ds h1
.ds h2 % .ds h2 %
@@ -930,11 +930,19 @@ being moved.
``#adjust'' can also be used to split a stack of objects; when ``#adjust'' can also be used to split a stack of objects; when
choosing the item to adjust, enter a count prior to its letter. choosing the item to adjust, enter a count prior to its letter.
.lp "" .lp ""
When no count is given, other compatible stacks are merged with the source Adjusting without a count used to collect all compatible stacks when
stack as it's moved to the destination. When a split count is given, the moving to the destination. That behavior has been changed; to gather
only stack that might be merged is the one already in the destination. compatible stacks, ``#adjust'' a stack into its own inventory slot.
To move a whole stack without having other compatible ones merge with it, If it has a name assigned, other stacks with the same name or with
specify a ``split'' count which matches the full stack size. no name will merge provided that all their other attributes match.
If it does not have a name, only other stacks with no name are eligible.
In either case, otherwise compatible stacks with a different name
will not be merged. This contrasts with using ``#adjust'' to move
from one slot to a different slot. In that situation, moving (no
count given) a compatible stack will merge if either stack has a
name when the other doesn't and give that name to the result, while
splitting (count given) will ignore the source stack's name when
deciding whether to merge with the destination stack.
.lp #annotate .lp #annotate
Allows you to specify one line of text to associate with the current Allows you to specify one line of text to associate with the current
dungeon level. All levels with annotations are displayed by the dungeon level. All levels with annotations are displayed by the
+13 -5
View File
@@ -1110,11 +1110,19 @@ being moved.
``{\tt \#adjust}'' can also be used to split a stack of objects; when ``{\tt \#adjust}'' can also be used to split a stack of objects; when
choosing the item to adjust, enter a count prior to its letter.\\ choosing the item to adjust, enter a count prior to its letter.\\
%.lp "" %.lp ""
When no count is given, other compatible stacks are merged with the source Adjusting without a count used to collect all compatible stacks when
stack as it's moved to the destination. When a split count is given, the moving to the destination. That behavior has been changed; to gather
only stack that might be merged is the one already in the destination. compatible stacks, ``{\tt \#adjust}'' a stack into its own inventory slot.
To move a whole stack without having other compatible ones merge with it, If it has a name assigned, other stacks with the same name or with
specify a ``split'' count which matches the full stack size. no name will merge provided that all their other attributes match.
If it does not have a name, only other stacks with no name are eligible.
In either case, otherwise compatible stacks with a different name
will not be merged. This contrasts with using ``{\tt \#adjust}'' to move
from one slot to a different slot. In that situation, moving (no
count given) a compatible stack will merge if either stack has a
name when the other doesn't and give that name to the result, while
splitting (count given) will ignore the source stack's name when
deciding whether to merge with the destination stack.
%.lp %.lp
\item[\tb{\#annotate}] \item[\tb{\#annotate}]
Allows you to specify one line of text to associate with the current Allows you to specify one line of text to associate with the current
+22 -3
View File
@@ -478,6 +478,20 @@ monster holding hero takes double damage from an explosion for reaching into
or beyond the explosion radius or beyond the explosion radius
poly'd hero holding monster now takes double damage (if monster is within poly'd hero holding monster now takes double damage (if monster is within
explosion radious) instead of inflicting that upon the monster explosion radious) instead of inflicting that upon the monster
when trying to swap places with a pet and failing due to pet being unable
to move diagonally to hero's spot (grid bug or too tight squeeze), if
pet became untame the map would briefly show hero at pet's location
when trying to swap places with a pet and failing due to pet being trapped
or disallowed diagonal move, the arrive-on-new-spot code (autopickup,
trap triggering) executed even though hero didn't ultimately move
being "dead inside" (self-genocide while polymorphed) conferred partial
invulnerability--normal monster behavior stopped attacking hero
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'
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
@@ -508,6 +522,8 @@ DUMPLOG: genocided and extinct species was always a blank line;
vanquished creatures was just a blank line if nothing had been killed vanquished creatures was just a blank line if nothing had been killed
DUMPLOG: RIP tombstone was printed for characters who survived (ascended, DUMPLOG: RIP tombstone was printed for characters who survived (ascended,
escaped dungeon, quit, trickery or panic) escaped dungeon, quit, trickery or panic)
DUMPLOG: pets who accompany hero during ascension or dungeon escape were
already gone by the time known portion of the level map was dumped
artifact creation violated illiterate conduct when artifact name was assigned, artifact creation violated illiterate conduct when artifact name was assigned,
behavior intended only for creating Sting or Orcrist via naming behavior intended only for creating Sting or Orcrist via naming
tty: revert to pline() for issuing prompts (override MSGTYPE=hide differently) tty: revert to pline() for issuing prompts (override MSGTYPE=hide differently)
@@ -538,6 +554,9 @@ fix mention_walls reporting secret doors as solid stone
jumping over water unintentionally moved hero through that water, causing jumping over water unintentionally moved hero through that water, causing
drowning if not able to water walk or fly drowning if not able to water walk or fly
try again to fix achievement recording bug with mines and sokoban prizes try again to fix achievement recording bug with mines and sokoban prizes
the fix for secret doors on special levels always having vertical orientation
resulted in some--but not all--secret doors within vertical walls
being displayed as horizontal walls while still hidden
Platform- and/or Interface-Specific Fixes Platform- and/or Interface-Specific Fixes
@@ -720,9 +739,9 @@ Master Key of Thievery always finds door and chest traps if used to lock or
"Elbereth" now erodes based on attacks by the player, not monsters scared "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 option herecmd_menu to make a mouse click on your character pop up
a context menu, and extended command #herecmdmenu to do the same a context menu, and extended command #herecmdmenu to do the same
for #adjust, specifying a split count which matches an inventory slot's full change #adjust's behavior when collecting compatible stacks; that used to
size will move or swap that stack without combining other compatible occur for any #adjust which lacked a split count, now it only happens
stacks (except for the one in the destination slot, if applicable) when 'adjusting' into a stack's own inventory slot
Platform- and/or Interface-Specific New Features Platform- and/or Interface-Specific New Features
+3 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 extern.h $NHDT-Date: 1508549428 2017/10/21 01:30:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.619 $ */ /* NetHack 3.6 extern.h $NHDT-Date: 1513130012 2017/12/13 01:53:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.621 $ */
/* Copyright (c) Steve Creps, 1988. */ /* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1884,6 +1884,8 @@ E const char *FDECL(mbodypart, (struct monst *, int));
E const char *FDECL(body_part, (int)); E const char *FDECL(body_part, (int));
E int NDECL(poly_gender); E int NDECL(poly_gender);
E void FDECL(ugolemeffects, (int, int)); E void FDECL(ugolemeffects, (int, int));
E boolean NDECL(ugenocided);
E const char *NDECL(udeadinside);
/* ### potion.c ### */ /* ### potion.c ### */
+36 -1
View File
@@ -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. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -48,7 +48,42 @@ struct flag {
boolean showexp; /* show experience points */ boolean showexp; /* show experience points */
boolean showscore; /* show score */ boolean showscore; /* show score */
boolean silent; /* whether the bell rings or not */ 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) */ char sortloot; /* 'n'=none, 'l'=loot (pickup), 'f'=full ('l'+invent) */
#endif
boolean sortpack; /* sorted inventory */ boolean sortpack; /* sorted inventory */
boolean sparkle; /* show "resisting" special FX (Scott Bigham) */ boolean sparkle; /* show "resisting" special FX (Scott Bigham) */
boolean standout; /* use standout for --More-- */ boolean standout; /* use standout for --More-- */
+9 -4
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mondata.h $NHDT-Date: 1432512776 2015/05/25 00:12:56 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */ /* NetHack 3.6 mondata.h $NHDT-Date: 1513297342 2017/12/15 00:22:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.33 $ */
/* Copyright (c) 1989 Mike Threepoint */ /* Copyright (c) 1989 Mike Threepoint */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -175,9 +175,14 @@
#define is_vampire(ptr) ((ptr)->mlet == S_VAMPIRE) #define is_vampire(ptr) ((ptr)->mlet == S_VAMPIRE)
#define nonliving(ptr) \ /* used to vary a few messages */
(is_golem(ptr) || is_undead(ptr) || (ptr)->mlet == S_VORTEX \ #define weirdnonliving(ptr) (is_golem(ptr) || (ptr)->mlet == S_VORTEX)
|| (ptr) == &mons[PM_MANES]) #define nonliving(ptr) \
(is_undead(ptr) || (ptr) == &mons[PM_MANES] || weirdnonliving(ptr))
/* no corpse (ie, blank scrolls) if killed by fire */
#define completelyburns(ptr) \
((ptr) == &mons[PM_PAPER_GOLEM] || (ptr) == &mons[PM_STRAW_GOLEM])
/* Used for conduct with corpses, tins, and digestion attacks */ /* Used for conduct with corpses, tins, and digestion attacks */
/* G_NOCORPSE monsters might still be swallowed as a purple worm */ /* G_NOCORPSE monsters might still be swallowed as a purple worm */
+8 -1
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 allmain.c $NHDT-Date: 1463217182 2016/05/14 09:13:02 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.72 $ */ /* NetHack 3.6 allmain.c $NHDT-Date: 1513130016 2017/12/13 01:53:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -648,6 +648,13 @@ boolean new_game; /* false => restoring an old game */
char buf[BUFSZ]; char buf[BUFSZ];
boolean currentgend = Upolyd ? u.mfemale : flags.female; boolean currentgend = Upolyd ? u.mfemale : flags.female;
/* skip "welcome back" if restoring a doomed character */
if (!new_game && Upolyd && ugenocided()) {
/* death via self-genocide is pending */
pline("You're back, but you still feel %s inside.", udeadinside());
return;
}
/* /*
* The "welcome back" message always describes your innate form * The "welcome back" message always describes your innate form
* even when polymorphed or wearing a helm of opposite alignment. * even when polymorphed or wearing a helm of opposite alignment.
+8 -3
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 cmd.c $NHDT-Date: 1508880573 2017/10/24 21:29:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.275 $ */ /* NetHack 3.6 cmd.c $NHDT-Date: 1513130017 2017/12/13 01:53:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.277 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1887,8 +1887,13 @@ int final;
Strcpy(youtoo, You_); Strcpy(youtoo, You_);
/* not a traditional status but inherently obvious to player; more /* not a traditional status but inherently obvious to player; more
detail given below (attributes section) for magic enlightenment */ detail given below (attributes section) for magic enlightenment */
if (Upolyd) if (Upolyd) {
you_are("transformed", ""); Strcpy(buf, "transformed");
if (ugenocided())
Sprintf(eos(buf), " and %s %s inside",
final ? "felt" : "feel", udeadinside());
you_are(buf, "");
}
/* not a trouble, but we want to display riding status before maybe /* not a trouble, but we want to display riding status before maybe
reporting steed as trapped or hero stuck to cursed saddle */ reporting steed as trapped or hero stuck to cursed saddle */
if (Riding) { if (Riding) {
+10 -2
View File
@@ -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. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1617,6 +1617,14 @@ boolean noisy;
int err = 0; int err = 0;
const char *which; 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) which = is_cloak(otmp)
? c_cloak ? c_cloak
: is_shirt(otmp) : is_shirt(otmp)
@@ -1964,7 +1972,7 @@ dowear()
/* cantweararm() checks for suits of armor, not what we want here; /* cantweararm() checks for suits of armor, not what we want here;
verysmall() or nohands() checks for shields, gloves, etc... */ 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."); pline("Don't even bother.");
return 0; return 0;
} }
+8 -6
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 end.c $NHDT-Date: 1495232357 2017/05/19 22:19:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.131 $ */ /* NetHack 3.6 end.c $NHDT-Date: 1512803167 2017/12/09 07:06:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.137 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1142,11 +1142,6 @@ int how;
else if (how == TURNED_SLIME) else if (how == TURNED_SLIME)
u.ugrave_arise = PM_GREEN_SLIME; u.ugrave_arise = PM_GREEN_SLIME;
/* if pets will contribute to score, populate mydogs list now
(bones creation isn't a factor, but pline() messaging is) */
if (how == ESCAPED || how == ASCENDED)
keepdogs(TRUE);
if (how == QUIT) { if (how == QUIT) {
killer.format = NO_KILLER_PREFIX; killer.format = NO_KILLER_PREFIX;
if (u.uhp < 1) { if (u.uhp < 1) {
@@ -1194,6 +1189,13 @@ int how;
dump_everything(how, endtime); dump_everything(how, endtime);
} }
/* if pets will contribute to score, populate mydogs list now
(bones creation isn't a factor, but pline() messaging is; used to
be done ever sooner, but we need it to come after dump_everything()
so that any accompanying pets are still on the map during dump) */
if (how == ESCAPED || how == ASCENDED)
keepdogs(TRUE);
/* finish_paybill should be called after disclosure but before bones */ /* finish_paybill should be called after disclosure but before bones */
if (bones_ok && taken) if (bones_ok && taken)
finish_paybill(); finish_paybill();
+14 -6
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 explode.c $NHDT-Date: 1511658058 2017/11/26 01:00:58 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.54 $ */ /* NetHack 3.6 explode.c $NHDT-Date: 1513297345 2017/12/15 00:22:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.55 $ */
/* Copyright (C) 1990 by Ken Arromdee */ /* Copyright (C) 1990 by Ken Arromdee */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -443,8 +443,12 @@ int expltype;
mtmp->mhp -= (idamres + idamnonres); mtmp->mhp -= (idamres + idamnonres);
} }
if (mtmp->mhp <= 0) { if (mtmp->mhp <= 0) {
int xkflg = ((adtyp == AD_FIRE
&& completelyburns(mtmp->data))
? XKILL_NOCORPSE : 0);
if (!context.mon_moving) { if (!context.mon_moving) {
killed(mtmp); xkilled(mtmp, XKILL_GIVEMSG | xkflg);
} else if (mdef && mtmp == mdef) { } else if (mdef && mtmp == mdef) {
/* 'mdef' killed self trying to cure being turned /* 'mdef' killed self trying to cure being turned
* into slime due to some action by the player. * into slime due to some action by the player.
@@ -456,11 +460,15 @@ int expltype;
*/ */
if (cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp)) if (cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp))
pline("%s is %s!", Monnam(mtmp), pline("%s is %s!", Monnam(mtmp),
nonliving(mtmp->data) ? "destroyed" xkflg ? "burned completely"
: "killed"); : nonliving(mtmp->data) ? "destroyed"
xkilled(mtmp, XKILL_NOMSG | XKILL_NOCONDUCT); : "killed");
} else xkilled(mtmp, XKILL_NOMSG | XKILL_NOCONDUCT | xkflg);
} else {
if (xkflg)
adtyp = AD_RBRE; /* no corpse */
monkilled(mtmp, "", (int) adtyp); monkilled(mtmp, "", (int) adtyp);
}
} else if (!context.mon_moving) { } else if (!context.mon_moving) {
/* all affected monsters, even if mdef is set */ /* all affected monsters, even if mdef is set */
setmangry(mtmp, TRUE); setmangry(mtmp, TRUE);
+15 -2
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 hack.c $NHDT-Date: 1508549436 2017/10/21 01:30:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.180 $ */ /* NetHack 3.6 hack.c $NHDT-Date: 1512771130 2017/12/08 22:12:10 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.181 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1720,26 +1720,38 @@ domove()
yelp(mtmp); yelp(mtmp);
} }
} }
/* seemimic/newsym should be done before moving hero, otherwise
the display code will draw the hero here before we possibly
cancel the swap below (we can ignore steed mx,my here) */
u.ux = u.ux0, u.uy = u.uy0;
mtmp->mundetected = 0; mtmp->mundetected = 0;
if (mtmp->m_ap_type) if (mtmp->m_ap_type)
seemimic(mtmp); seemimic(mtmp);
else if (!mtmp->mtame) else if (!mtmp->mtame)
newsym(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my);
u.ux = mtmp->mx, u.uy = mtmp->my; /* resume swapping positions */
if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0 if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0
&& (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)
&& sobj_at(BOULDER, trap->tx, trap->ty)) { && sobj_at(BOULDER, trap->tx, trap->ty)) {
/* can't swap places with pet pinned in a pit by a boulder */ /* can't swap places with pet pinned in a pit by a boulder */
u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
if (u.usteed)
u.usteed->mx = u.ux, u.usteed->my = u.uy;
} else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) { } else if (u.ux0 != x && u.uy0 != y && NODIAG(mtmp->data - mons)) {
/* can't swap places when pet can't move to your spot */ /* can't swap places when pet can't move to your spot */
u.ux = u.ux0, u.uy = u.uy0; u.ux = u.ux0, u.uy = u.uy0;
if (u.usteed)
u.usteed->mx = u.ux, u.usteed->my = u.uy;
You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp))); You("stop. %s can't move diagonally.", upstart(y_monnam(mtmp)));
} else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0) } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0)
&& bad_rock(mtmp->data, u.ux0, y) && bad_rock(mtmp->data, u.ux0, y)
&& (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) {
/* can't swap places when pet won't fit thru the opening */ /* can't swap places when pet won't fit thru the opening */
u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */
if (u.usteed)
u.usteed->mx = u.ux, u.usteed->my = u.uy;
You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); You("stop. %s won't fit through.", upstart(y_monnam(mtmp)));
} else { } else {
char pnambuf[BUFSZ]; char pnambuf[BUFSZ];
@@ -1836,7 +1848,8 @@ domove()
if (Punished) /* put back ball and chain */ if (Punished) /* put back ball and chain */
move_bc(0, bc_control, ballx, bally, chainx, chainy); move_bc(0, bc_control, ballx, bally, chainx, chainy);
spoteffects(TRUE); if (u.umoved)
spoteffects(TRUE);
/* delay next move because of ball dragging */ /* delay next move because of ball dragging */
/* must come after we finished picking up, in spoteffects() */ /* must come after we finished picking up, in spoteffects() */
+72 -56
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 invent.c $NHDT-Date: 1512096431 2017/12/01 02:47:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.222 $ */ /* NetHack 3.6 invent.c $NHDT-Date: 1512473628 2017/12/05 11:33:48 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.223 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1472,9 +1472,6 @@ redo_menu:
else if (otmp->otyp == LOADSTONE && otmp->cursed) else if (otmp->otyp == LOADSTONE && otmp->cursed)
/* kludge for canletgo()'s can't-drop-this message */ /* kludge for canletgo()'s can't-drop-this message */
otmp->corpsenm = (int) cnt; otmp->corpsenm = (int) cnt;
} else if (!strcmp(word, "adjust")) {
/* specifying stack's full count means something to #adjust */
otmp->nomerge = 1;
} }
} }
return otmp; return otmp;
@@ -3539,10 +3536,18 @@ reassign()
* then a 'to' slot for its destination. Open slots and those * then a 'to' slot for its destination. Open slots and those
* filled by compatible stacks are listed as likely candidates * filled by compatible stacks are listed as likely candidates
* but user can pick any inventory letter (including 'from'). * but user can pick any inventory letter (including 'from').
* All compatible items found are gathered into the 'from'
* stack as it is moved. If the 'to' slot isn't empty and
* doesn't merge, then its stack is swapped to the 'from' slot.
* *
* to == from, 'from' has a name
* All compatible items (same name or no name) are gathered
* into the 'from' stack. No count is allowed.
* to == from, 'from' does not have a name
* All compatible items without a name are gathered into the
* 'from' stack. No count is allowed. Compatible stacks with
* names are left as-is.
* to != from, no count
* Move 'from' to 'to'. If 'to' is not empty, merge 'from'
* into it if possible, otherwise swap it with the 'from' slot.
* to != from, count given
* If the user specifies a count when choosing the 'from' slot, * If the user specifies a count when choosing the 'from' slot,
* and that count is less than the full size of the stack, * and that count is less than the full size of the stack,
* then the stack will be split. The 'count' portion is moved * then the stack will be split. The 'count' portion is moved
@@ -3552,10 +3557,19 @@ reassign()
* will be moved to an open slot; if there isn't any open slot * will be moved to an open slot; if there isn't any open slot
* available, the adjustment attempt fails. * available, the adjustment attempt fails.
* *
* Splitting has one special case: if 'to' slot is non-empty * To minimize merging for 'from == to', unnamed stacks will
* and is compatible with 'from' in all respects except for * merge with named 'from' but named ones won't merge with
* user-assigned names, the 'count' portion being moved is * unnamed 'from'. Otherwise attempting to collect all unnamed
* effectively renamed so that it will merge with 'to' stack. * stacks would lump the first compatible named stack with them
* and give them its name.
*
* To maximize merging for 'from != to', compatible stacks will
* merge when either lacks a name (or they already have the same
* name). When no count is given and one stack has a name and
* the other doesn't, the merged result will have that name.
* However, when splitting results in a merger, the name of the
* destination overrides that of the source, even if destination
* is unnamed and source is named.
*/ */
int int
doorganize() /* inventory organizer by Del Lamb */ doorganize() /* inventory organizer by Del Lamb */
@@ -3569,8 +3583,9 @@ doorganize() /* inventory organizer by Del Lamb */
char lets[1 + 52 + 1 + 1]; /* room for '$a-zA-Z#\0' */ char lets[1 + 52 + 1 + 1]; /* room for '$a-zA-Z#\0' */
char qbuf[QBUFSZ]; char qbuf[QBUFSZ];
char allowall[4]; /* { ALLOW_COUNT, ALL_CLASSES, 0, 0 } */ char allowall[4]; /* { ALLOW_COUNT, ALL_CLASSES, 0, 0 } */
char *objname, *otmpname;
const char *adj_type; const char *adj_type;
boolean ever_mind = FALSE, dont_collect = FALSE; boolean ever_mind = FALSE, collect;
if (!invent) { if (!invent) {
You("aren't carrying anything to adjust."); You("aren't carrying anything to adjust.");
@@ -3602,19 +3617,12 @@ doorganize() /* inventory organizer by Del Lamb */
/* figure out whether user gave a split count to getobj() */ /* figure out whether user gave a split count to getobj() */
splitting = bumped = 0; splitting = bumped = 0;
if (obj->nomerge) { for (otmp = invent; otmp; otmp = otmp->nobj)
/* player specified full count; no split occurred and we'll if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
avoid collecting compatible stacks when moving this one */ if (otmp->invlet == obj->invlet)
obj->nomerge = 0; splitting = otmp;
dont_collect = TRUE; break;
} else { }
for (otmp = invent; otmp; otmp = otmp->nobj)
if (otmp->nobj == obj) { /* knowledge of splitobj() operation */
if (otmp->invlet == obj->invlet)
splitting = otmp;
break;
}
}
/* initialize the list with all lower and upper case letters */ /* initialize the list with all lower and upper case letters */
lets[GOLD_INDX] = (obj->oclass == COIN_CLASS) ? GOLD_SYM : ' '; lets[GOLD_INDX] = (obj->oclass == COIN_CLASS) ? GOLD_SYM : ' ';
@@ -3668,7 +3676,7 @@ doorganize() /* inventory organizer by Del Lamb */
/* adjusting to same slot is meaningful since all /* adjusting to same slot is meaningful since all
compatible stacks get collected along the way, compatible stacks get collected along the way,
but splitting to same slot is not */ but splitting to same slot is not */
|| ((splitting || dont_collect) && let == obj->invlet)) { || (splitting && let == obj->invlet)) {
noadjust: noadjust:
if (splitting) if (splitting)
(void) merged(&splitting, &obj); (void) merged(&splitting, &obj);
@@ -3691,8 +3699,9 @@ doorganize() /* inventory organizer by Del Lamb */
pline("Select an inventory slot letter."); /* else try again */ pline("Select an inventory slot letter."); /* else try again */
} }
collect = (let == obj->invlet);
/* change the inventory and print the resulting item */ /* change the inventory and print the resulting item */
adj_type = !splitting ? "Moving:" : "Splitting:"; adj_type = collect ? "Collecting" : !splitting ? "Moving:" : "Splitting:";
/* /*
* don't use freeinv/addinv to avoid double-touching artifacts, * don't use freeinv/addinv to avoid double-touching artifacts,
@@ -3701,45 +3710,52 @@ doorganize() /* inventory organizer by Del Lamb */
extract_nobj(obj, &invent); extract_nobj(obj, &invent);
for (otmp = invent; otmp;) { for (otmp = invent; otmp;) {
if (!splitting && !dont_collect) { /* it's tempting to pull this outside the loop, but merged() could
if (merged(&otmp, &obj)) { free ONAME(obj) [via obfree()] and replace it with ONAME(otmp) */
objname = has_oname(obj) ? ONAME(obj) : (char *) 0;
if (collect) {
/* Collecting: #adjust an inventory stack into its same slot;
keep it there and merge other compatible stacks into it.
Traditional inventory behavior is to merge unnamed stacks
with compatible named ones; we only want that if it is
the 'from' stack (obj) with a name and candidate (otmp)
without one, not unnamed 'from' with named candidate. */
otmpname = has_oname(otmp) ? ONAME(otmp) : (char *) 0;
if ((!otmpname || (objname && !strcmp(objname, otmpname)))
&& merged(&otmp, &obj)) {
adj_type = "Merging:"; adj_type = "Merging:";
obj = otmp; obj = otmp;
otmp = otmp->nobj; otmp = otmp->nobj;
extract_nobj(obj, &invent); extract_nobj(obj, &invent);
continue; /* otmp has already been updated */ continue; /* otmp has already been updated */
} else if (otmp->invlet == let) { }
} else if (otmp->invlet == let) {
/* Moving or splitting: don't merge extra compatible stacks.
Found 'otmp' in destination slot; merge if compatible,
otherwise bump whatever is there to an open slot. */
if (!splitting) {
adj_type = "Swapping:"; adj_type = "Swapping:";
otmp->invlet = obj->invlet; otmp->invlet = obj->invlet;
} } else {
} else { /* strip 'from' name if it has one */
/* splitting: don't merge extra compatible stacks; if (objname && !obj->oartifact)
if destination is compatible, do merge with it,
otherwise bump whatever is there to an open slot */
if (otmp->invlet == let) {
int olth = 0;
if (has_oname(obj))
olth = strlen(ONAME(obj));
/* ugly hack: if these objects aren't going to merge
solely because they have conflicting user-assigned
names, strip off the name of the one being moved */
if (olth && !obj->oartifact && !mergable(otmp, obj)) {
char *holdname = ONAME(obj);
ONAME(obj) = (char *) 0; ONAME(obj) = (char *) 0;
/* restore name iff merging is still not possible */ if (!mergable(otmp, obj)) {
if (!mergable(otmp, obj)) { /* won't merge; put 'from' name back */
ONAME(obj) = holdname; if (objname)
holdname = (char *) 0; ONAME(obj) = objname;
} else } else {
free((genericptr_t) holdname); /* will merge; discard 'from' name */
if (objname)
free((genericptr_t) objname), objname = 0;
} }
if (merged(&otmp, &obj)) { if (merged(&otmp, &obj)) {
adj_type = "Splitting and merging:";
obj = otmp; obj = otmp;
extract_nobj(obj, &invent); extract_nobj(obj, &invent);
} else if (inv_cnt(FALSE) >= 52 && !dont_collect) { } else if (inv_cnt(FALSE) >= 52) {
(void) merged(&splitting, &obj); /* undo split */ (void) merged(&splitting, &obj); /* undo split */
/* "knapsack cannot accommodate any more items" */ /* "knapsack cannot accommodate any more items" */
Your("pack is too full."); Your("pack is too full.");
@@ -3748,9 +3764,9 @@ doorganize() /* inventory organizer by Del Lamb */
bumped = otmp; bumped = otmp;
extract_nobj(bumped, &invent); extract_nobj(bumped, &invent);
} }
break; } /* moving vs splitting */
} /* found 'to' slot */ break; /* not collecting and found 'to' slot */
} /* splitting */ } /* collect */
otmp = otmp->nobj; otmp = otmp->nobj;
} }
+3 -3
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mhitm.c $NHDT-Date: 1504999944 2017/09/09 23:32:24 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */ /* NetHack 3.6 mhitm.c $NHDT-Date: 1513297346 2017/12/15 00:22:26 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.99 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -935,10 +935,10 @@ register struct attack *mattk;
} }
if (vis && canseemon(mdef)) if (vis && canseemon(mdef))
pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk)); pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (completelyburns(pd)) { /* paper golem or straw golem */
if (vis && canseemon(mdef)) if (vis && canseemon(mdef))
pline("%s burns completely!", Monnam(mdef)); pline("%s burns completely!", Monnam(mdef));
mondied(mdef); mondead(mdef); /* was mondied() but that dropped paper scrolls */
if (mdef->mhp > 0) if (mdef->mhp > 0)
return 0; return 0;
else if (mdef->mtame && !vis) else if (mdef->mtame && !vis)
+8 -6
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mhitu.c $NHDT-Date: 1505001092 2017/09/09 23:51:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.147 $ */ /* NetHack 3.6 mhitu.c $NHDT-Date: 1513297347 2017/12/15 00:22:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.149 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1030,9 +1030,8 @@ register struct attack *mattk;
hitmsg(mtmp, mattk); hitmsg(mtmp, mattk);
if (uncancelled) { if (uncancelled) {
pline("You're %s!", on_fire(youmonst.data, mattk)); pline("You're %s!", on_fire(youmonst.data, mattk));
if (youmonst.data == &mons[PM_STRAW_GOLEM] if (completelyburns(youmonst.data)) { /* paper or straw golem */
|| youmonst.data == &mons[PM_PAPER_GOLEM]) { You("go up in flames!");
You("roast!");
/* KMH -- this is okay with unchanging */ /* KMH -- this is okay with unchanging */
rehumanize(); rehumanize();
break; break;
@@ -1629,8 +1628,11 @@ register struct attack *mattk;
dmg = 0; dmg = 0;
break; break;
} }
if (u.uhp < 1) if ((Upolyd ? u.mh : u.uhp) < 1) {
done_in_by(mtmp, DIED); /* already dead? call rehumanize() or done_in_by() as appropriate */
mdamageu(mtmp, 1);
dmg = 0;
}
/* Negative armor class reduces damage done instead of fully protecting /* Negative armor class reduces damage done instead of fully protecting
* against hits. * against hits.
+6
View File
@@ -1464,6 +1464,12 @@ coord *tm;
case 0: case 0:
/* elf corpses are the rarest as they're the most useful */ /* elf corpses are the rarest as they're the most useful */
victim_mnum = PM_ELF; victim_mnum = PM_ELF;
/* elven adventurers get sleep resistance early; so don't
generate elf corpses on sleeping gas traps unless a)
we're on dlvl 2 (1 is impossible) and b) we pass a coin
flip */
if (kind == SLP_GAS_TRAP && !(lvl <= 2 && rn2(2)))
victim_mnum = PM_HUMAN;
break; break;
case 1: case 2: case 1: case 2:
victim_mnum = PM_DWARF; victim_mnum = PM_DWARF;
+19 -7
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mkobj.c $NHDT-Date: 1501725405 2017/08/03 01:56:45 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.124 $ */ /* NetHack 3.6 mkobj.c $NHDT-Date: 1513298759 2017/12/15 00:45:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.129 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -2168,7 +2168,8 @@ static const char NEARDATA /* pline formats for insane_object() */
ofmt0[] = "%s obj %s %s: %s", ofmt0[] = "%s obj %s %s: %s",
ofmt3[] = "%s [not null] %s %s: %s", ofmt3[] = "%s [not null] %s %s: %s",
/* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */ /* " held by mon %p (%s)" will be appended, filled by M,mon_nam(M) */
mfmt1[] = "%s obj %s %s (%s)", mfmt2[] = "%s obj %s %s (%s) *not*"; mfmt1[] = "%s obj %s %s (%s)",
mfmt2[] = "%s obj %s %s (%s) *not*";
/* Check all object lists for consistency. */ /* Check all object lists for consistency. */
void void
@@ -2177,6 +2178,13 @@ obj_sanity_check()
int x, y; int x, y;
struct obj *obj; struct obj *obj;
/*
* TODO:
* Should check whether the obj->bypass and/or obj->nomerge bits
* are set. Those are both used for temporary purposes and should
* be clear between moves.
*/
objlist_sanity(fobj, OBJ_FLOOR, "floor sanity"); objlist_sanity(fobj, OBJ_FLOOR, "floor sanity");
/* check that the map's record of floor objects is consistent; /* check that the map's record of floor objects is consistent;
@@ -2186,12 +2194,12 @@ obj_sanity_check()
for (y = 0; y < ROWNO; y++) for (y = 0; y < ROWNO; y++)
for (obj = level.objects[x][y]; obj; obj = obj->nexthere) { for (obj = level.objects[x][y]; obj; obj = obj->nexthere) {
/* <ox,oy> should match <x,y>; <0,*> should always be empty */ /* <ox,oy> should match <x,y>; <0,*> should always be empty */
if (obj->where != OBJ_FLOOR || x == 0 || obj->ox != x if (obj->where != OBJ_FLOOR || x == 0
|| obj->oy != y) { || obj->ox != x || obj->oy != y) {
char at_fmt[BUFSZ]; char at_fmt[BUFSZ];
Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>", x, Sprintf(at_fmt, "%%s obj@<%d,%d> %%s %%s: %%s@<%d,%d>",
y, obj->ox, obj->oy); x, y, obj->ox, obj->oy);
insane_object(obj, at_fmt, "location sanity", insane_object(obj, at_fmt, "location sanity",
(struct monst *) 0); (struct monst *) 0);
} }
@@ -2219,7 +2227,11 @@ obj_sanity_check()
if (kickedobj) if (kickedobj)
insane_object(kickedobj, ofmt3, "kickedobj sanity", insane_object(kickedobj, ofmt3, "kickedobj sanity",
(struct monst *) 0); (struct monst *) 0);
/* [how about current_wand too?] */ /* current_wand isn't removed from invent while in use, but should
be Null between moves when we're called */
if (current_wand)
insane_object(current_wand, ofmt3, "current_wand sanity",
(struct monst *) 0);
} }
/* sanity check for objects on specified list (fobj, &c) */ /* sanity check for objects on specified list (fobj, &c) */
+3 -2
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 monmove.c $NHDT-Date: 1505265968 2017/09/13 01:26:08 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.93 $ */ /* NetHack 3.6 monmove.c $NHDT-Date: 1512808567 2017/12/09 08:36:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.95 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -617,7 +617,8 @@ toofar:
*/ */
if (!mtmp->mpeaceful || (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) { if (!mtmp->mpeaceful || (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) {
if (inrange && !noattacks(mdat) && u.uhp > 0 && !scared && tmp != 3) if (inrange && !noattacks(mdat)
&& (Upolyd ? u.mh : u.uhp) > 0 && !scared && tmp != 3)
if (mattacku(mtmp)) if (mattacku(mtmp))
return 1; /* monster died (e.g. exploded) */ return 1; /* monster died (e.g. exploded) */
+39 -11
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 polyself.c $NHDT-Date: 1497485548 2017/06/15 00:12:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.112 $ */ /* NetHack 3.6 polyself.c $NHDT-Date: 1513298347 2017/12/15 00:39:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.116 $ */
/* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -189,12 +189,7 @@ const char *fmt, *arg;
You(fmt, arg); You(fmt, arg);
/* check whether player foolishly genocided self while poly'd */ /* check whether player foolishly genocided self while poly'd */
if ((mvitals[urole.malenum].mvflags & G_GENOD) if (ugenocided()) {
|| (urole.femalenum != NON_PM
&& (mvitals[urole.femalenum].mvflags & G_GENOD))
|| (mvitals[urace.malenum].mvflags & G_GENOD)
|| (urace.femalenum != NON_PM
&& (mvitals[urace.femalenum].mvflags & G_GENOD))) {
/* intervening activity might have clobbered genocide info */ /* intervening activity might have clobbered genocide info */
struct kinfo *kptr = find_delayed_killer(POLYMORPH); struct kinfo *kptr = find_delayed_killer(POLYMORPH);
@@ -1015,10 +1010,16 @@ void
rehumanize() rehumanize()
{ {
/* You can't revert back while unchanging */ /* You can't revert back while unchanging */
if (Unchanging && (u.mh < 1)) { if (Unchanging) {
killer.format = NO_KILLER_PREFIX; if (u.mh < 1) {
Strcpy(killer.name, "killed while stuck in creature form"); killer.format = NO_KILLER_PREFIX;
done(DIED); Strcpy(killer.name, "killed while stuck in creature form");
done(DIED);
} else if (uamul && uamul->otyp == AMULET_OF_UNCHANGING) {
Your("%s %s!", simpleonames(uamul), otense(uamul, "fail"));
uamul->dknown = 1;
makeknown(AMULET_OF_UNCHANGING);
}
} }
if (emits_light(youmonst.data)) if (emits_light(youmonst.data))
@@ -1813,4 +1814,31 @@ polysense()
} }
} }
/* True iff hero's role or race has been genocided */
boolean
ugenocided()
{
return (boolean) ((mvitals[urole.malenum].mvflags & G_GENOD)
|| (urole.femalenum != NON_PM
&& (mvitals[urole.femalenum].mvflags & G_GENOD))
|| (mvitals[urace.malenum].mvflags & G_GENOD)
|| (urace.femalenum != NON_PM
&& (mvitals[urace.femalenum].mvflags & G_GENOD)));
}
/* how hero feels "inside" after self-genocide of role or race */
const char *
udeadinside()
{
/* self-genocide used to always say "you feel dead inside" but that
seems silly when you're polymorphed into something undead;
monkilled() distinguishes between living (killed) and non (destroyed)
for monster death message; we refine the nonliving aspect a bit */
return !nonliving(youmonst.data)
? "dead" /* living, including demons */
: !weirdnonliving(youmonst.data)
? "condemned" /* undead plus manes */
: "empty"; /* golems plus vortices */
}
/*polyself.c*/ /*polyself.c*/
+3 -3
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 read.c $NHDT-Date: 1508479721 2017/10/20 06:08:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.148 $ */ /* NetHack 3.6 read.c $NHDT-Date: 1513130018 2017/12/13 01:53:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.149 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -2088,7 +2088,7 @@ do_class_genocide()
u.uhp = -1; u.uhp = -1;
if (Upolyd) { if (Upolyd) {
if (!feel_dead++) if (!feel_dead++)
You_feel("dead inside."); You_feel("%s inside.", udeadinside());
} else { } else {
if (!feel_dead++) if (!feel_dead++)
You("die."); You("die.");
@@ -2269,7 +2269,7 @@ int how;
/* KMH -- Unchanging prevents rehumanization */ /* KMH -- Unchanging prevents rehumanization */
if (Upolyd && ptr != youmonst.data) { if (Upolyd && ptr != youmonst.data) {
delayed_killer(POLYMORPH, killer.format, killer.name); delayed_killer(POLYMORPH, killer.format, killer.name);
You_feel("dead inside."); You_feel("%s inside.", udeadinside());
} else } else
done(GENOCIDED); done(GENOCIDED);
} else if (ptr == youmonst.data) { } else if (ptr == youmonst.data) {
+32 -9
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 sp_lev.c $NHDT-Date: 1508879840 2017/10/24 21:17:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.90 $ */ /* 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 $ */
/* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1989 by Jean-Christophe Collet */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -4187,8 +4187,8 @@ int dx, dy;
genericptr_t arg; genericptr_t arg;
{ {
xchar typ = *(xchar *) arg; xchar typ = *(xchar *) arg;
xchar x = dx; xchar x = dx, y = dy;
xchar y = dy; boolean left_or_right, up_and_down;
if (!IS_DOOR(levl[x][y].typ) && levl[x][y].typ != SDOOR) if (!IS_DOOR(levl[x][y].typ) && levl[x][y].typ != SDOOR)
levl[x][y].typ = (typ & D_SECRET) ? SDOOR : DOOR; levl[x][y].typ = (typ & D_SECRET) ? SDOOR : DOOR;
@@ -4198,12 +4198,35 @@ genericptr_t arg;
typ = D_CLOSED; typ = D_CLOSED;
} }
if (((isok(x-1,y) && IS_DOORJOIN(levl[x-1][y].typ)) || !isok(x-1,y)) /* If there's a wall or door on either the left side or right
|| (isok(x+1,y) && IS_DOORJOIN(levl[x+1][y].typ)) || !isok(x+1,y)) * side (or both) of this secret door, make it be horizontal.
levl[x][y].horizontal = 1; *
else * It is feasible to put SDOOR in a corner, tee, or crosswall
levl[x][y].horizontal = 0; * position, although once the door is found and opened it won't
* make a lot sense (diagonal access required). Still, we try to
* handle that as best as possible. For top or bottom tee, using
* horizontal is the best we can do. For corner or crosswall,
* either horizontal or vertical are just as good as each other;
* we produce horizontal for corners and vertical for crosswalls.
* For left or right tee, using vertical is best.
*
* A secret door with no adjacent walls is also feasible and makes
* even less sense. It will be displayed as a vertical wall while
* hidden and become a vertical door when found.
*/
left_or_right = ((isok(x - 1, y) && (IS_WALL(levl[x - 1][y].typ)
|| IS_DOOR(levl[x - 1][y].typ)
|| levl[x - 1][y].typ == SDOOR))
|| (isok(x + 1, y) && (IS_WALL(levl[x + 1][y].typ)
|| IS_DOOR(levl[x + 1][y].typ)
|| levl[x + 1][y].typ == SDOOR)));
up_and_down = ((isok(x, y - 1) && (IS_WALL(levl[x][y - 1].typ)
|| IS_DOOR(levl[x][y - 1].typ)
|| levl[x][y - 1].typ == SDOOR))
&& (isok(x, y + 1) && (IS_WALL(levl[x][y + 1].typ)
|| IS_DOOR(levl[x][y + 1].typ)
|| levl[x][y + 1].typ == SDOOR)));
levl[x][y].horizontal = (left_or_right && !up_and_down) ? 1 : 0;
levl[x][y].doormask = typ; levl[x][y].doormask = typ;
SpLev_Map[x][y] = 1; SpLev_Map[x][y] = 1;
} }
+6 -2
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 uhitm.c $NHDT-Date: 1504999056 2017/09/09 23:17:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.167 $ */ /* NetHack 3.6 uhitm.c $NHDT-Date: 1513297347 2017/12/15 00:22:27 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.172 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -1543,9 +1543,13 @@ register struct attack *mattk;
} }
if (!Blind) if (!Blind)
pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk)); pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (completelyburns(pd)) { /* paper golem or straw golem */
if (!Blind) if (!Blind)
pline("%s burns completely!", Monnam(mdef)); pline("%s burns completely!", Monnam(mdef));
else
You("smell burning%s.",
(pd == &mons[PM_PAPER_GOLEM]) ? " paper"
: (pd == &mons[PM_STRAW_GOLEM]) ? " straw" : "");
xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE); xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE);
tmp = 0; tmp = 0;
break; break;
+16 -4
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 zap.c $NHDT-Date: 1505475171 2017/09/15 11:32:51 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.267 $ */ /* NetHack 3.6 zap.c $NHDT-Date: 1513297348 2017/12/15 00:22:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.270 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */ /* NetHack may be freely redistributed. See license for details. */
@@ -4022,10 +4022,22 @@ boolean say; /* Announce out of sight hit/miss events if true */
if (tmp == MAGIC_COOKIE) { /* disintegration */ if (tmp == MAGIC_COOKIE) { /* disintegration */
disintegrate_mon(mon, type, fltxt); disintegrate_mon(mon, type, fltxt);
} else if (mon->mhp < 1) { } else if (mon->mhp < 1) {
if (type < 0) if (type < 0) {
/* mon has just been killed by another monster */
monkilled(mon, fltxt, AD_RBRE); monkilled(mon, fltxt, AD_RBRE);
else } else {
killed(mon); int xkflags = XKILL_GIVEMSG; /* killed(mon); */
/* killed by hero; we know 'type' isn't negative;
if it's fire, highly flammable monsters leave
no corpse; don't bother reporting that they
"burn completely" -- unnecessary verbosity */
if ((type % 10 == ZT_FIRE)
/* paper golem or straw golem */
&& completelyburns(mon->data))
xkflags |= XKILL_NOCORPSE;
xkilled(mon, xkflags);
}
} else { } else {
if (!otmp) { if (!otmp) {
/* normal non-fatal hit */ /* normal non-fatal hit */