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

This commit is contained in:
keni
2016-12-09 17:47:54 -05:00
21 changed files with 145 additions and 65 deletions

View File

@@ -453,11 +453,13 @@ start: Blank
S_hbeam: \032
S_hcdbridge: \032
S_hcdoor: \032
S_hodbridge: \032
S_hodoor: \032
S_hole: \032
S_human: \032
S_humanoid: \032
S_hwall: \032
S_ice: \032
S_imp: \032
S_invisible: \032
S_jabberwock: \032
@@ -543,7 +545,9 @@ start: Blank
S_vbeam: \032
S_vcdbridge: \032
S_vcdoor: \032
S_venom: \032
S_vibrating_square: \032
S_vodbridge: \032
S_vodoor: \032
S_vortex: \032
S_vwall: \032

View File

@@ -3543,6 +3543,7 @@ h S_humanoid (humanoid)
- S_hwall (horizontal wall)
. S_ice (ice)
i S_imp (imp or minor demon)
I S_invisible (invisible monster)
J S_jabberwock (jabberwock)
j S_jelly (jelly)
k S_kobold (kobold)

View File

@@ -4334,6 +4334,7 @@ Default & Symbol Name & Description\\
\verb@-@ & S\verb+_+hwall & (horizontal wall)\\
\verb@.@ & S\verb+_+ice & (ice)\\
\verb@i@ & S\verb+_+imp & (imp or minor demon)\\
\verb@I@ & S\verb+_+invisible & (invisible monster)\\
\verb@J@ & S\verb+_+jabberwock & (jabberwock)\\
\verb@j@ & S\verb+_+jelly & (jelly)\\
\verb@k@ & S\verb+_+kobold & (kobold)\\

View File

@@ -353,9 +353,17 @@ sometimes generate the random mazes with wide corridors, thick walls,
put throne room gold in the chest
wielding Trollsbane prevents trolls from reviving
wielding Demonbane prevents demons summoning friends
wielding Dragonbane confers reflection
wielding Ogresmasher grants 25 constitution
Elbereth must now be on a square by itself to function
Elbereth now erodes based on attacks by the player, not monsters scared
novels are made of paper, not gold
movement speeds are made less predictable by using random rounding, rather
than via adding a random offset
some death by the-poison-was-deadly situations left stale non-zero HP shown
on the status line during final disclosure
when sitting at a trap spot: You sit down. You step on a level teleporter.
(likewise for polymorph trap, and similar issue for web)
Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository

View File

@@ -103,7 +103,8 @@ STATIC_OVL NEARDATA struct artifact artilist[] = {
FIRE(5, 0), FIRE(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 3000L,
NO_COLOR),
A("Dragonbane", BROADSWORD, (SPFX_RESTR | SPFX_DCLAS), 0, S_DRAGON,
A("Dragonbane", BROADSWORD,
(SPFX_RESTR | SPFX_DCLAS | SPFX_REFLECT), 0, S_DRAGON,
PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 500L,
NO_COLOR),

View File

@@ -1354,12 +1354,13 @@ E void FDECL(unstuck, (struct monst *));
E void FDECL(killed, (struct monst *));
E void FDECL(xkilled, (struct monst *, int));
E void FDECL(mon_to_stone, (struct monst *));
E void FDECL(m_into_limbo, (struct monst *));
E void FDECL(mnexto, (struct monst *));
E void FDECL(maybe_mnexto, (struct monst *));
E boolean FDECL(mnearto, (struct monst *, XCHAR_P, XCHAR_P, BOOLEAN_P));
E void FDECL(m_respond, (struct monst *));
E void FDECL(setmangry, (struct monst *, boolean));
E void FDECL(wakeup, (struct monst *, boolean));
E void FDECL(setmangry, (struct monst *, BOOLEAN_P));
E void FDECL(wakeup, (struct monst *, BOOLEAN_P));
E void NDECL(wake_nearby);
E void FDECL(wake_nearto, (int, int, int));
E void FDECL(seemimic, (struct monst *));
@@ -2284,8 +2285,8 @@ E boolean FDECL(stucksteed, (BOOLEAN_P));
E boolean FDECL(goodpos, (int, int, struct monst *, unsigned));
E boolean FDECL(enexto, (coord *, XCHAR_P, XCHAR_P, struct permonst *));
E boolean
FDECL(enexto_core, (coord *, XCHAR_P, XCHAR_P, struct permonst *, unsigned));
E boolean FDECL(enexto_core, (coord *, XCHAR_P, XCHAR_P,
struct permonst *, unsigned));
E void FDECL(teleds, (int, int, BOOLEAN_P));
E boolean FDECL(safe_teleds, (BOOLEAN_P));
E boolean FDECL(teleport_pet, (struct monst *, BOOLEAN_P));
@@ -2295,13 +2296,13 @@ E int NDECL(dotele);
E void NDECL(level_tele);
E void FDECL(domagicportal, (struct trap *));
E void FDECL(tele_trap, (struct trap *));
E void FDECL(level_tele_trap, (struct trap *));
E void FDECL(level_tele_trap, (struct trap *, unsigned));
E void FDECL(rloc_to, (struct monst *, int, int));
E boolean FDECL(rloc, (struct monst *, BOOLEAN_P));
E boolean FDECL(tele_restrict, (struct monst *));
E void FDECL(mtele_trap, (struct monst *, struct trap *, int));
E int FDECL(mlevel_tele_trap,
(struct monst *, struct trap *, BOOLEAN_P, int));
E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *,
BOOLEAN_P, int));
E boolean FDECL(rloco, (struct obj *));
E int NDECL(random_teleport_level);
E boolean FDECL(u_teleport_mon, (struct monst *, BOOLEAN_P));

View File

@@ -296,9 +296,9 @@ enum hmon_atkmode_types {
#define FORCETRAP 0x01 /* triggering not left to chance */
#define NOWEBMSG 0x02 /* suppress stumble into web message */
#define FORCEBUNGLE 0x04 /* adjustments appropriate for bungling */
#define RECURSIVETRAP 0x08 /* trap changed into another type this same turn \
*/
#define RECURSIVETRAP 0x08 /* trap changed into another type this same turn */
#define TOOKPLUNGE 0x10 /* used '>' to enter pit below you */
#define VIASITTING 0x20 /* #sit while at trap location (affects message) */
/* Flags to control test_move in hack.c */
#define DO_MOVE 0 /* really doing the move */

View File

@@ -132,14 +132,13 @@ boolean resuming;
moveamt = youmonst.data->mmove;
if (Very_fast) { /* speed boots or potion */
/* average movement is 1.67 times normal */
moveamt += NORMAL_SPEED / 2;
if (rn2(3) == 0)
moveamt += NORMAL_SPEED / 2;
} else if (Fast) {
/* average movement is 1.33 times normal */
/* gain a free action on 2/3 of turns */
if (rn2(3) != 0)
moveamt += NORMAL_SPEED / 2;
moveamt += NORMAL_SPEED;
} else if (Fast) {
/* gain a free action on 1/3 of turns */
if (rn2(3) == 0)
moveamt += NORMAL_SPEED;
}
}

View File

@@ -272,6 +272,7 @@ boolean thrown_weapon; /* thrown weapons are less deadly */
if (i == 0 && typ != A_CHA) {
/* instant kill */
u.uhp = -1;
context.botl = TRUE;
pline_The("poison was deadly...");
} else if (i > 5) {
/* HP damage; more likely--but less severe--with missiles */
@@ -1002,6 +1003,9 @@ int x;
&& (youmonst.data->mlet == S_NYMPH || u.umonnum == PM_SUCCUBUS
|| u.umonnum == PM_INCUBUS))
return (schar) 18;
} else if (x == A_CON) {
if (uwep && uwep->oartifact == ART_OGRESMASHER)
return (schar) 25;
} else if (x == A_INT || x == A_WIS) {
/* yes, this may raise int/wis if player is sufficiently
* stupid. there are lower levels of cognition than "dunce".
@@ -1047,6 +1051,9 @@ int attrindx;
/* lower limit for Str can also be 25 */
if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER)
lolimit = hilimit;
} else if (attrindx == A_CON) {
if (uwep && uwep->oartifact == ART_OGRESMASHER)
lolimit = hilimit;
}
/* this exception is hypothetical; the only other worn item affecting
Int or Wis is another helmet so can't be in use at the same time */

View File

@@ -1638,6 +1638,8 @@ int mode, final, attrindx;
break;
case A_CON:
attrname = "constitution";
if (uwep && uwep->oartifact == ART_OGRESMASHER && uwep->cursed)
hide_innate_value = TRUE;
break;
case A_INT:
attrname = "intelligence";

View File

@@ -430,9 +430,10 @@ boolean with_you;
mtmp->mx = 0; /*(already is 0)*/
mtmp->my = xyflags;
if (xlocale)
(void) mnearto(mtmp, xlocale, ylocale, FALSE);
else {
if (xlocale) {
if (!mnearto(mtmp, xlocale, ylocale, FALSE))
goto fail_mon_placement;
} else {
if (!rloc(mtmp, TRUE)) {
/*
* Failed to place migrating monster,
@@ -440,6 +441,7 @@ boolean with_you;
* Dump the monster's cargo and leave the monster dead.
*/
struct obj *obj;
fail_mon_placement:
while ((obj = mtmp->minvent) != 0) {
obj_extract_self(obj);
obj_no_longer_held(obj);

View File

@@ -922,6 +922,18 @@ int how;
return;
}
}
if (program_state.panicking
#ifdef HANGUPHANDLING
|| program_state.done_hup
#endif
) {
/* skip status update if panicking or disconnected */
context.botl = context.botlx = FALSE;
} else {
/* otherwise force full status update */
context.botlx = TRUE;
bot();
}
if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED))
killer.format = NO_KILLER_PREFIX;

View File

@@ -742,6 +742,7 @@ register struct attack *mattk;
if (cansee(dx, dy))
pline("%s is regurgitated!", Monnam(mdef));
remove_monster(dx,dy);
place_monster(magr, ax, ay);
place_monster(mdef, dx, dy);
newsym(ax, ay);

View File

@@ -5,7 +5,7 @@
#include "hack.h"
#include "artifact.h"
STATIC_VAR NEARDATA struct obj *otmp;
STATIC_VAR NEARDATA struct obj *mon_currwep = (struct obj *) 0;
STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *));
STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *,
@@ -646,6 +646,7 @@ register struct monst *mtmp;
for (i = 0; i < NATTK; i++) {
sum[i] = 0;
mon_currwep = (struct obj *)0;
mattk = getmattk(mtmp, &youmonst, i, sum, &alt_attk);
if ((u.uswallow && mattk->aatyp != AT_ENGL)
|| (skipnonmagc && mattk->aatyp != AT_MAGC))
@@ -747,18 +748,18 @@ register struct monst *mtmp;
break;
}
if (foundyou) {
otmp = MON_WEP(mtmp);
if (otmp) {
hittmp = hitval(otmp, &youmonst);
mon_currwep = MON_WEP(mtmp);
if (mon_currwep) {
hittmp = hitval(mon_currwep, &youmonst);
tmp += hittmp;
mswings(mtmp, otmp);
mswings(mtmp, mon_currwep);
}
if (tmp > (j = dieroll = rnd(20 + i)))
sum[i] = hitmu(mtmp, mattk);
else
missmu(mtmp, (tmp == j), mattk);
/* KMH -- Don't accumulate to-hit bonuses */
if (otmp)
if (mon_currwep)
tmp -= hittmp;
} else {
wildmiss(mtmp, mattk);
@@ -968,6 +969,7 @@ register struct attack *mattk;
: "crushed");
}
} else { /* hand to hand weapon */
struct obj *otmp = mon_currwep;
if (mattk->aatyp == AT_WEAP && otmp) {
int tmp;
@@ -2710,10 +2712,10 @@ register struct attack *mattk;
return 1;
}
case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
if (otmp) {
if (mon_currwep) {
/* by_you==True: passive counterattack to hero's action
is hero's fault */
(void) drain_item(otmp, TRUE);
(void) drain_item(mon_currwep, TRUE);
/* No message */
}
return 1;

View File

@@ -582,6 +582,7 @@ mcalcmove(mon)
struct monst *mon;
{
int mmove = mon->data->mmove;
int mmove_adj;
/* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0;
* MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op;
@@ -592,21 +593,24 @@ struct monst *mon;
else if (mon->mspeed == MFAST)
mmove = (4 * mmove + 2) / 3;
if (mon == u.usteed) {
if (u.ugallop && context.mv) {
/* average movement is 1.50 times normal */
mmove = ((rn2(2) ? 4 : 5) * mmove) / 3;
}
} else if (mmove) {
/* vary movement points allocated to slightly reduce predictability;
random increment (avg +2) exceeds random decrement (avg +1) by
a small amount; normal speed monsters will occasionally get an
extra move and slow ones won't be quite as slow */
mmove += rn2(5) - rn2(3); /* + 0..4 - 0..2, average net +1 */
if (mmove < 1)
mmove = 1;
if (mon == u.usteed && u.ugallop && context.mv) {
/* increase movement by a factor of 1.5; also increase variance of
movement speed (if it's naturally 24, we don't want it to always
become 36) */
mmove = ((rn2(2) ? 4 : 5) * mmove) / 3;
}
/* Randomly round the monster's speed to a multiple of NORMAL_SPEED. This
makes it impossible for the player to predict when they'll get a free
turn (thus preventing exploits like "melee kiting"), while retaining
guarantees about shopkeepers not being outsped by a normal-speed player,
normal-speed players being unable to open up a gap when fleeing a
normal-speed monster, etc.*/
mmove_adj = mmove % NORMAL_SPEED;
mmove -= mmove_adj;
if (rn2(NORMAL_SPEED) < mmove_adj)
mmove += NORMAL_SPEED;
return mmove;
}
@@ -2025,6 +2029,8 @@ struct monst *mdef;
/* hero is thrown from his steed when it disappears */
if (mdef == u.usteed)
dismount_steed(DISMOUNT_GENERIC);
/* stuck to you? release */
unstuck(mdef);
/* drop special items like the Amulet so that a dismissed Kop or nurse
can't remove them from the game */
mdrop_special_objs(mdef);
@@ -2445,6 +2451,16 @@ struct monst *mtmp;
return TRUE;
}
/* drop monster into "limbo" - that is, migrate to the current level */
void
m_into_limbo(mtmp)
struct monst *mtmp;
{
unstuck(mtmp);
mdrop_special_objs(mtmp);
migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_APPROX_XY, NULL);
}
/* make monster mtmp next to you (if possible);
might place monst on far side of a wall or boulder */
void
@@ -2461,7 +2477,11 @@ struct monst *mtmp;
return;
}
if (!enexto(&mm, u.ux, u.uy, mtmp->data))
if (!enexto(&mm, u.ux, u.uy, mtmp->data)) {
m_into_limbo(mtmp);
return;
}
if (!isok(mm.x, mm.y))
return;
rloc_to(mtmp, mm.x, mm.y);
if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) {
@@ -2530,6 +2550,8 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
*/
if (!enexto(&mm, newx, newy, mtmp->data))
return FALSE;
if (!isok(mm.x,mm.y))
return FALSE;
newx = mm.x;
newy = mm.y;
}
@@ -2541,12 +2563,10 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
othermon->mx = othermon->my = 0;
(void) mnearto(othermon, x, y, FALSE);
if (othermon->mx == 0 && othermon->my == 0) {
/* reloc failed, dump monster into "limbo"
(aka migrate to current level) */
/* reloc failed */
othermon->mx = oldx;
othermon->my = oldy;
mdrop_special_objs(othermon);
migrate_to_level(othermon, ledger_no(&u.uz), MIGR_APPROX_XY, NULL);
m_into_limbo(othermon);
}
}

View File

@@ -268,7 +268,7 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */
register struct objclass *ocl = &objects[typ];
int nn = ocl->oc_name_known, omndx = obj->corpsenm;
const char *actualn = OBJ_NAME(*ocl);
const char *dn = OBJ_DESCR(*ocl);
const char *dn = OBJ_DESCR(*ocl) ? OBJ_DESCR(*ocl) : actualn;
const char *un = ocl->oc_uname;
boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR);
boolean known, dknown, bknown;
@@ -327,15 +327,15 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */
Strcpy(buf, (obj->spe < 3) ? "moist " : "wet ");
if (!dknown)
Strcat(buf, dn ? dn : actualn);
Strcat(buf, dn);
else if (nn)
Strcat(buf, actualn);
else if (un) {
Strcat(buf, dn ? dn : actualn);
Strcat(buf, dn);
Strcat(buf, " called ");
Strcat(buf, un);
} else
Strcat(buf, dn ? dn : actualn);
Strcat(buf, dn);
/* If we use an() here we'd have to remember never to use */
/* it whenever calling doname() or xname(). */
if (typ == FIGURINE && omndx != NON_PM) {

View File

@@ -113,7 +113,7 @@ dosit()
}
} else {
You("sit down.");
dotrap(trap, 0);
dotrap(trap, VIASITTING);
}
} else if (Underwater || Is_waterlevel(&u.uz)) {
if (Is_waterlevel(&u.uz))

View File

@@ -872,12 +872,20 @@ struct trap *trap;
}
void
level_tele_trap(trap)
level_tele_trap(trap, trflags)
struct trap *trap;
unsigned trflags;
{
You("%s onto a level teleport trap!",
Levitation ? (const char *) "float"
: locomotion(youmonst.data, "step"));
char verbbuf[BUFSZ];
if ((trflags & VIASITTING) != 0)
Strcpy(verbbuf, "trigger"); /* follows "You sit down." */
else
Sprintf(verbbuf, "%s onto",
Levitation ? (const char *) "float"
: locomotion(youmonst.data, "step"));
You("%s a level teleport trap!", verbbuf);
if (Antimagic) {
shieldeff(u.ux, u.uy);
}

View File

@@ -850,6 +850,7 @@ unsigned trflags;
webmsgok = (trflags & NOWEBMSG) == 0,
forcebungle = (trflags & FORCEBUNGLE) != 0,
plunged = (trflags & TOOKPLUNGE) != 0,
viasitting = (trflags & VIASITTING) != 0,
adj_pit = conjoined_pits(trap, t_at(u.ux0, u.uy0), TRUE);
int oldumort;
int steed_article = ARTICLE_THE;
@@ -1237,7 +1238,7 @@ unsigned trflags;
case LEVEL_TELEP:
seetrap(trap);
level_tele_trap(trap);
level_tele_trap(trap, trflags);
break;
case WEB: /* Our luckless player has stumbled into a web. */
@@ -1253,7 +1254,7 @@ unsigned trflags;
if (webmsgok) {
char verbbuf[BUFSZ];
if (forcetrap) {
if (forcetrap || viasitting) {
Strcpy(verbbuf, "are caught by");
} else if (u.usteed) {
Sprintf(verbbuf, "lead %s into",
@@ -1382,15 +1383,17 @@ unsigned trflags;
char verbbuf[BUFSZ];
seetrap(trap);
if (u.usteed)
Sprintf(verbbuf, "lead %s",
if (viasitting)
Strcpy(verbbuf, "trigger"); /* follows "You sit down." */
else if (u.usteed)
Sprintf(verbbuf, "lead %s onto",
x_monnam(u.usteed, steed_article, (char *) 0,
SUPPRESS_SADDLE, FALSE));
else
Sprintf(verbbuf, "%s", Levitation
? (const char *) "float"
: locomotion(youmonst.data, "step"));
You("%s onto a polymorph trap!", verbbuf);
Sprintf(verbbuf, "%s onto",
Levitation ? (const char *) "float"
: locomotion(youmonst.data, "step"));
You("%s a polymorph trap!", verbbuf);
if (Antimagic || Unchanging) {
shieldeff(u.ux, u.uy);
You_feel("momentarily different.");

View File

@@ -96,6 +96,10 @@ register struct obj *obj;
if (!Blind)
pline("%s shining.", Tobjnam(olduwep, "stop"));
}
if (uwep == obj
&& ((uwep && uwep->oartifact == ART_OGRESMASHER)
|| (olduwep && olduwep->oartifact == ART_OGRESMASHER)))
context.botl = 1;
/* Note: Explicitly wielding a pick-axe will not give a "bashing"
* message. Wielding one via 'a'pplying it will.
* 3.2.2: Wielding arbitrary objects will give bashing message too.

View File

@@ -380,7 +380,10 @@ register struct monst *mtmp;
if (!rn2(3 + mtmp->mhp / 10))
(void) rloc(mtmp, TRUE);
} else if (sx && (mtmp->mx != sx || mtmp->my != sy)) {
(void) mnearto(mtmp, sx, sy, TRUE);
if (!mnearto(mtmp, sx, sy, TRUE)) {
m_into_limbo(mtmp);
return 0;
}
}
/* if you're not around, cast healing spells */
if (distu(mtmp->mx, mtmp->my) > (BOLT_LIM * BOLT_LIM))
@@ -433,7 +436,8 @@ register struct monst *mtmp;
return 0;
}
} else { /* a monster has it - 'port beside it. */
(void) mnearto(mtmp, tx, ty, FALSE);
if (!mnearto(mtmp, tx, ty, FALSE))
m_into_limbo(mtmp);
return 0;
}
}