Merge branch 'NetHack-3.6'

This commit is contained in:
nhmall
2019-06-01 18:05:42 -04:00
9 changed files with 287 additions and 47 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 cmd.c $NHDT-Date: 1557088405 2019/05/05 20:33:25 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.333 $ */
/* NetHack 3.6 cmd.c $NHDT-Date: 1559382745 2019/06/01 09:52:25 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.335 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */
@@ -23,6 +23,9 @@
#define C(c) (0x1f & (c))
#endif
#define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
#define unmeta(c) (0x7f & (c))
#ifdef ALTMETA
STATIC_VAR boolean alt_esc = FALSE;
#endif
@@ -3444,14 +3447,71 @@ struct ext_func_tab extcmdlist[] = {
{ '\0', (char *) 0, (char *) 0, donull, 0, (char *) 0 } /* sentinel */
};
/* for key2extcmddesc() to support dowhatdoes() */
struct movcmd {
uchar k1, k2, k3, k4; /* 'normal', 'qwertz', 'numpad', 'phone' */
const char *txt, *alt; /* compass direction, screen direction */
};
static const struct movcmd movtab[] = {
{ 'h', 'h', '4', '4', "west", "left" },
{ 'j', 'j', '2', '8', "south", "down" },
{ 'k', 'k', '8', '2', "north", "up" },
{ 'l', 'l', '6', '6', "east", "right" },
{ 'b', 'b', '1', '7', "southwest", "lower left" },
{ 'n', 'n', '3', '9', "southeast", "lower right" },
{ 'u', 'u', '9', '3', "northeast", "upper right" },
{ 'y', 'z', '7', '1', "northwest", "upper left" },
{ 0, 0, 0, 0, (char *) 0, (char *) 0 }
};
int extcmdlist_length = SIZE(extcmdlist) - 1;
const char *
key2extcmddesc(key)
uchar key;
{
if (g.Cmd.commands[key] && g.Cmd.commands[key]->ef_txt)
return g.Cmd.commands[key]->ef_desc;
static char key2cmdbuf[48];
const struct movcmd *mov;
int k, c;
uchar M_5 = (uchar) M('5'), M_0 = (uchar) M('0');
/* need to check for movement commands before checking the extended
commands table because it contains entries for number_pad commands
that match !number_pad movement (like 'j' for "jump") */
key2cmdbuf[0] = '\0';
if (movecmd(k = key))
Strcpy(key2cmdbuf, "move"); /* "move or attack"? */
else if (movecmd(k = unctrl(key)))
Strcpy(key2cmdbuf, "rush");
else if (movecmd(k = (g.Cmd.num_pad ? unmeta(key) : lowc(key))))
Strcpy(key2cmdbuf, "run");
if (*key2cmdbuf) {
for (mov = &movtab[0]; mov->k1; ++mov) {
c = !g.Cmd.num_pad ? (!g.Cmd.swap_yz ? mov->k1 : mov->k2)
: (!g.Cmd.phone_layout ? mov->k3 : mov->k4);
if (c == k) {
Sprintf(eos(key2cmdbuf), " %s (screen %s)",
mov->txt, mov->alt);
return key2cmdbuf;
}
}
} else if (digit(key) || (g.Cmd.num_pad && digit(unmeta(key)))) {
key2cmdbuf[0] = '\0';
if (!g.Cmd.num_pad)
Strcpy(key2cmdbuf, "start of, or continuation of, a count");
else if (key == '5' || key == M_5)
Sprintf(key2cmdbuf, "%s prefix",
(!!g.Cmd.pcHack_compat ^ (key == M_5)) ? "run" : "rush");
else if (key == '0' || (g.Cmd.pcHack_compat && key == M_0))
Strcpy(key2cmdbuf, "synonym for 'i'");
if (*key2cmdbuf)
return key2cmdbuf;
}
if (g.Cmd.commands[key]) {
if (g.Cmd.commands[key]->ef_txt)
return g.Cmd.commands[key]->ef_desc;
}
return (char *) 0;
}
@@ -4122,9 +4182,6 @@ wiz_migrate_mons()
}
#endif
#define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c))
#define unmeta(c) (0x7f & (c))
struct {
int nhkf;
char key;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 mkmaze.c $NHDT-Date: 1559299316 2019/05/31 10:41:56 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.73 $ */
/* NetHack 3.6 mkmaze.c $NHDT-Date: 1559422240 2019/06/01 20:50:40 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.74 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Pasi Kallinen, 2018. */
/* NetHack may be freely redistributed. See license for details. */
@@ -644,14 +644,14 @@ unsigned long mflags;
/* once in a blue moon, he won't be at the very bottom */
if (!rn2(40))
nlev--;
mtmp->mspare1 = MIGR_LEFTOVERS;
mtmp->mspare1 |= MIGR_LEFTOVERS;
} else {
nlev = rn2((max_depth - cur_depth) + 1) + cur_depth;
if (nlev == cur_depth)
nlev++;
if (nlev > max_depth)
nlev = max_depth;
mtmp->mspare1 = 0L;
mtmp->mspare1 = (mtmp->mspare1 & ~MIGR_LEFTOVERS);
}
get_level(&dest, nlev);
migrate_to_level(mtmp, ledger_no(&dest), MIGR_RANDOM, (coord *) 0);
@@ -1456,6 +1456,7 @@ movebubbles()
newsym(x, y); /* clean up old position */
mon->mx = mon->my = 0;
mon->mstate |= MON_BUBBLEMOVE;
}
if (!u.uswallow && x == u.ux && y == u.uy) {
cons = (struct container *) alloc(sizeof *cons);
@@ -1887,12 +1888,10 @@ boolean ini;
case CONS_MON: {
struct monst *mon = (struct monst *) cons->list;
/* mnearto() might fail, and putting the monster into limbo
to try next time hero comes to this level makes no sense
because we can't leave and return (outside wizard mode) */
if (!mnearto(mon, cons->x, cons->y, TRUE)) {
; /* ? */
}
/* mnearto() might fail. We can jump right to elemental_clog
from here rather than deal_with_overcrowding() */
if (!mnearto(mon, cons->x, cons->y, TRUE))
elemental_clog(mon);
break;
}

178
src/mon.c
View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 mon.c $NHDT-Date: 1559227828 2019/05/30 14:50:28 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.286 $ */
/* NetHack 3.6 mon.c $NHDT-Date: 1559422247 2019/06/01 20:50:47 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.287 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Derek S. Ray, 2015. */
/* NetHack may be freely redistributed. See license for details. */
@@ -26,6 +26,9 @@ STATIC_DCL struct permonst *FDECL(accept_newcham_form, (int));
STATIC_DCL struct obj *FDECL(make_corpse, (struct monst *, unsigned));
STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *));
STATIC_DCL void FDECL(lifesaved_monster, (struct monst *));
STATIC_DCL void FDECL(migrate_mon, (struct monst *, XCHAR_P, XCHAR_P));
STATIC_DCL boolean FDECL(ok_to_obliterate, (struct monst *));
STATIC_DCL void FDECL(deal_with_overcrowding, (struct monst *));
/* note: duplicated in dog.c */
#define LEVEL_SPECIFIC_NOCORPSE(mdat) \
@@ -612,7 +615,8 @@ register struct monst *mtmp;
xkilled(mtmp, XKILL_NOMSG);
if (!DEADMONSTER(mtmp)) {
water_damage_chain(mtmp->minvent, FALSE);
(void) rloc(mtmp, FALSE);
if (!rloc(mtmp, TRUE))
deal_with_overcrowding(mtmp);
return 0;
}
return 1;
@@ -1599,7 +1603,9 @@ dmonsfree()
{
struct monst **mtmp, *freetmp;
int count = 0;
char buf[QBUFSZ];
buf[0] = '\0';
for (mtmp = &fmon; *mtmp;) {
freetmp = *mtmp;
if (DEADMONSTER(freetmp) && !freetmp->isgd) {
@@ -1611,9 +1617,11 @@ dmonsfree()
mtmp = &(freetmp->nmon);
}
if (count != iflags.purge_monsters)
impossible("dmonsfree: %d removed doesn't match %d pending",
count, iflags.purge_monsters);
if (count != iflags.purge_monsters) {
describe_level(buf);
impossible("dmonsfree: %d removed doesn't match %d pending on %s",
count, iflags.purge_monsters, buf);
}
iflags.purge_monsters = 0;
}
@@ -1789,8 +1797,13 @@ void
dealloc_monst(mon)
struct monst *mon;
{
if (mon->nmon)
panic("dealloc_monst with nmon");
char buf[QBUFSZ];
buf[0] = '\0';
if (mon->nmon) {
describe_level(buf);
panic("dealloc_monst with nmon on %s", buf);
}
if (mon->mextra)
dealloc_mextra(mon);
free((genericptr_t) mon);
@@ -1832,6 +1845,11 @@ struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */
shkgone(mtmp);
if (mtmp->wormno)
wormgone(mtmp);
if (In_endgame(&u.uz)) {
mtmp->mx = mtmp->my = 0;
mtmp->mstate |= MON_ENDGAME_FREE;
}
mtmp->mstate |= MON_DETACH;
iflags.purge_monsters++;
}
@@ -2571,10 +2589,121 @@ struct monst *mtmp;
void
m_into_limbo(mtmp)
struct monst *mtmp;
{
xchar target_lev = ledger_no(&u.uz), xyloc = MIGR_APPROX_XY;
mtmp->mstate |= MON_LIMBO;
migrate_mon(mtmp, target_lev, xyloc);
}
STATIC_OVL void
migrate_mon(mtmp, target_lev, xyloc)
struct monst *mtmp;
xchar target_lev, xyloc;
{
unstuck(mtmp);
mdrop_special_objs(mtmp);
migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_APPROX_XY, (coord *) 0);
migrate_to_level(mtmp, target_lev, xyloc, (coord *) 0);
mtmp->mstate |= MON_MIGRATING;
}
STATIC_OVL boolean
ok_to_obliterate(mtmp)
struct monst *mtmp;
{
/*
* Add checks for monsters that should not be obliterated
* here (return FALSE).
*/
if (mtmp->data == &mons[PM_WIZARD_OF_YENDOR] || is_rider(mtmp->data)
|| has_emin(mtmp) || has_epri(mtmp) || has_eshk(mtmp))
return FALSE;
return TRUE;
}
void
elemental_clog(mon)
struct monst *mon;
{
int m_lev = 0;
static long msgmv = 0L;
struct monst *mtmp, *m1, *m2, *m3, *m4, *m5, *zm;
if (In_endgame(&u.uz)) {
m1 = m2 = m3 = m4 = m5 = zm = (struct monst *) 0;
if (!msgmv || (g.moves - msgmv) > 200L) {
if (!msgmv || rn2(2))
You("feel besieged.");
msgmv = g.moves;
}
/*
* m1 an elemental from another plane.
* m2 an elemental from this plane.
* m3 the least powerful monst encountered in loop so far.
* m4 some other non-tame monster.
* m5 a pet.
*/
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (mtmp->mx == 0 && mtmp->my == 0)
continue;
if (mon_has_amulet(mtmp) || !ok_to_obliterate(mtmp))
continue;
if (mtmp->data->mlet == S_ELEMENTAL) {
if (!is_home_elemental(mtmp->data)) {
if (!m1)
m1 = mtmp;
} else {
if (!m2)
m2 = mtmp;
}
} else {
if (!mtmp->mtame) {
if (!m_lev || mtmp->m_lev < m_lev) {
m_lev = mtmp->m_lev;
m3 = mtmp;
} else if (!m4) {
m4 = mtmp;
}
} else {
if (!m5)
m5 = mtmp;
break;
}
}
}
mtmp = m1 ? m1 : m2 ? m2 : m3 ? m3 : m4 ? m4 : m5 ? m5 : zm;
if (mtmp) {
int mx = mtmp->mx, my = mtmp->my;
mtmp->mstate |= MON_OBLITERATE;
mongone(mtmp);
mtmp->mx = mtmp->my = 0;
rloc_to(mon, mx, my);
} else {
/* last resort - migrate mon to the next plane */
if (Is_waterlevel(&u.uz) || Is_firelevel(&u.uz) || Is_earthlevel(&u.uz)) {
/* try sending mon on to the next plane */
xchar target_lev = 0, xyloc = 0;
struct trap *trap = g.ftrap;
while (trap) {
if (trap->ttyp == MAGIC_PORTAL)
break;
trap = trap->ntrap;
}
if (trap) {
target_lev = ledger_no(&trap->dst);
xyloc = MIGR_RANDOM;
}
if (target_lev) {
mon->mstate |= MON_ENDGAME_MIGR;
migrate_mon(mon, target_lev, xyloc);
}
}
}
}
}
/* make monster mtmp next to you (if possible);
@@ -2594,8 +2723,7 @@ struct monst *mtmp;
}
if (!enexto(&mm, u.ux, u.uy, mtmp->data) || !isok(mm.x, mm.y)) {
debugpline1("mnexto: sending %s into limbo", m_monnam(mtmp));
m_into_limbo(mtmp);
deal_with_overcrowding(mtmp);
return;
}
rloc_to(mtmp, mm.x, mm.y);
@@ -2608,6 +2736,19 @@ struct monst *mtmp;
return;
}
void
deal_with_overcrowding(mtmp)
struct monst *mtmp;
{
if (In_endgame(&u.uz)) {
debugpline1("overcrowding: elemental_clog on %s", m_monnam(mtmp));
elemental_clog(mtmp);
} else {
debugpline1("overcrowding: sending %s into limbo", m_monnam(mtmp));
m_into_limbo(mtmp);
}
}
/* like mnexto() but requires destination to be directly accessible */
void
maybe_mnexto(mtmp)
@@ -2662,6 +2803,7 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
remove_monster(x, y);
othermon->mx = othermon->my = 0; /* 'othermon' is not on the map */
othermon->mstate |= MON_OFFMAP;
}
newx = x;
@@ -2671,8 +2813,16 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
* Migrating_mons that need to be placed will cause
* no end of trouble.
*/
if (!enexto(&mm, newx, newy, mtmp->data) || !isok(mm.x, mm.y))
if (!enexto(&mm, newx, newy, mtmp->data) || !isok(mm.x, mm.y)) {
if (othermon) {
/* othermon already had its mx, my set to 0 above
* and this would shortly cause a sanity check to fail
* if we just return 0 here. The caller only possesses
* awareness of mtmp, not othermon. */
deal_with_overcrowding(othermon);
}
return 0;
}
newx = mm.x;
newy = mm.y;
}
@@ -2680,10 +2830,8 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */
if (move_other && othermon) {
res = 2; /* moving another monster out of the way */
if (!mnearto(othermon, x, y, FALSE)) { /* no 'move_other' this time */
debugpline1("mnearto: sending %s into limbo", m_monnam(othermon));
m_into_limbo(othermon);
}
if (!mnearto(othermon, x, y, FALSE)) /* no 'move_other' this time */
deal_with_overcrowding(othermon);
}
return res;

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 steed.c $NHDT-Date: 1545441042 2018/12/22 01:10:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.62 $ */
/* NetHack 3.6 steed.c $NHDT-Date: 1559422254 2019/06/01 20:50:54 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.64 $ */
/* Copyright (c) Kevin Hugo, 1998-1999. */
/* NetHack may be freely redistributed. See license for details. */
@@ -742,23 +742,35 @@ place_monster(mon, x, y)
struct monst *mon;
int x, y;
{
char buf[QBUFSZ];
buf[0] = '\0';
/* normal map bounds are <1..COLNO-1,0..ROWNO-1> but sometimes
vault guards (either living or dead) are parked at <0,0> */
if (!isok(x, y) && (x != 0 || y != 0 || !mon->isgd)) {
impossible("trying to place monster at <%d,%d>", x, y);
describe_level(buf);
impossible("trying to place monster at <%d,%d> mstate:%lx on %s",
x, y, mon->mstate, buf);
x = y = 0;
}
if (mon == u.usteed
/* special case is for convoluted vault guard handling */
|| (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) {
impossible("placing %s onto map?",
(mon == u.usteed) ? "steed" : "defunct monster");
describe_level(buf);
impossible("placing %s onto map, mstate:%lx, on %s?",
(mon == u.usteed) ? "steed" : "defunct monster",
mon->mstate, buf);
return;
}
if (g.level.monsters[x][y])
impossible("placing monster over another at <%d,%d>?", x, y);
if (g.level.monsters[x][y]) {
describe_level(buf);
impossible("placing monster over another at <%d,%d>, mstates:%lx %lx on %s?",
x, y, g.level.monsters[x][y]->mstate, mon->mstate, buf);
}
mon->mx = x, mon->my = y;
g.level.monsters[x][y] = mon;
mon->mstate &= ~(MON_OFFMAP | MON_MIGRATING | MON_LIMBO | MON_BUBBLEMOVE
| MON_ENDGAME_FREE | MON_ENDGAME_MIGR);
}
/*steed.c*/