Merge branch 'NetHack-3.6.0'

This commit is contained in:
keni
2016-06-21 10:29:14 -04:00
84 changed files with 3167 additions and 1281 deletions
+1 -1
View File
@@ -378,7 +378,7 @@ boolean resuming;
clear_bypasses();
if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz)
&& !BClairvoyant && !(moves % 15) && !rn2(2))
do_vicinity_map();
do_vicinity_map((struct obj *) 0);
if (u.utrap && u.utraptype == TT_LAVA)
sink_into_lava();
/* when/if hero escapes from lava, he can't just stay there */
+104 -21
View File
@@ -36,6 +36,7 @@ STATIC_DCL boolean FDECL(figurine_location_checks, (struct obj *,
coord *, BOOLEAN_P));
STATIC_DCL void FDECL(add_class, (char *, CHAR_P));
STATIC_DCL void FDECL(setapplyclasses, (char *));
STATIC_PTR boolean FDECL(check_jump, (genericptr_t, int, int));
STATIC_DCL boolean FDECL(is_valid_jump_pos, (int, int, int, BOOLEAN_P));
STATIC_DCL boolean FDECL(find_poleable_mon, (coord *, int, int));
@@ -1450,7 +1451,48 @@ dojump()
return jump(0);
}
boolean
enum jump_trajectory {
jAny = 0, /* any direction => magical jump */
jHorz = 1,
jVert = 2,
jDiag = 3 /* jHorz|jVert */
};
/* callback routine for walk_path() */
STATIC_PTR boolean
check_jump(arg, x, y)
genericptr arg;
int x, y;
{
int traj = *(int *) arg;
struct rm *lev = &levl[x][y];
if (Passes_walls)
return TRUE;
if (IS_STWALL(lev->typ))
return FALSE;
if (IS_DOOR(lev->typ)) {
if (closed_door(x, y))
return FALSE;
if ((lev->doormask & D_ISOPEN) != 0 && traj != jAny
/* reject diagonal jump into or out-of or through open door */
&& (traj == jDiag
/* reject horizontal jump through horizontal open door
and non-horizontal (ie, vertical) jump through
non-horizontal (vertical) open door */
|| ((traj & jHorz) != 0) == (lev->horizontal != 0)))
return FALSE;
/* empty doorways aren't restricted */
}
/* let giants jump over boulders (what about Flying?
and is there really enough head room for giants to jump
at all, let alone over something tall?) */
if (sobj_at(BOULDER, x, y) && !throws_rocks(youmonst.data))
return FALSE;
return TRUE;
}
STATIC_OVL boolean
is_valid_jump_pos(x, y, magic, showmsg)
int x, y, magic;
boolean showmsg;
@@ -1466,14 +1508,54 @@ boolean showmsg;
if (showmsg)
pline("Too far!");
return FALSE;
} else if (!cansee(x, y)) {
if (showmsg)
You("cannot see where to land!");
return FALSE;
} else if (!isok(x, y)) {
if (showmsg)
You("cannot jump there!");
return FALSE;
} else if (!cansee(x, y)) {
if (showmsg)
You("cannot see where to land!");
return FALSE;
} else {
coord uc, tc;
struct rm *lev = &levl[u.ux][u.uy];
/* we want to categorize trajectory for use in determining
passage through doorways: horizonal, vertical, or diagonal;
since knight's jump and other irregular directions are
possible, we flatten those out to simplify door checks */
int diag, traj,
dx = x - u.ux, dy = y - u.uy,
ax = abs(dx), ay = abs(dy);
/* diag: any non-orthogonal destination classifed as diagonal */
diag = (magic || Passes_walls || (!dx && !dy)) ? jAny
: !dy ? jHorz : !dx ? jVert : jDiag;
/* traj: flatten out the trajectory => some diagonals re-classified */
if (ax >= 2 * ay)
ay = 0;
else if (ay >= 2 * ax)
ax = 0;
traj = (magic || Passes_walls || (!ax && !ay)) ? jAny
: !ay ? jHorz : !ax ? jVert : jDiag;
/* walk_path doesn't process the starting spot;
this is iffy: if you're starting on a closed door spot,
you _can_ jump diagonally from doorway (without needing
Passes_walls); that's intentional but is it correct? */
if (diag == jDiag && IS_DOOR(lev->typ)
&& (lev->doormask & D_ISOPEN) != 0
&& (traj == jDiag
|| ((traj & jHorz) != 0) == (lev->horizontal != 0))) {
if (showmsg)
You_cant("jump diagonally out of a doorway.");
return FALSE;
}
uc.x = u.ux, uc.y = u.uy;
tc.x = x, tc.y = y; /* target */
if (!walk_path(&uc, &tc, check_jump, (genericptr_t) &traj)) {
if (showmsg)
There("is an obstacle preventing that jump.");
return FALSE;
}
}
return TRUE;
}
@@ -1493,7 +1575,8 @@ int state;
for (dy = -4; dy <= 4; dy++) {
x = dx + (int) u.ux;
y = dy + (int) u.uy;
if (isok(x, y) && ACCESSIBLE(levl[x][y].typ)
if (isok(x, y)
&& (ACCESSIBLE(levl[x][y].typ) || Passes_walls)
&& is_valid_jump_pos(x, y, jumping_is_magic, FALSE))
tmp_at(x, y);
}
@@ -1621,7 +1704,7 @@ int magic; /* 0=Physical, otherwise skill level */
deltrap(t_at(u.ux, u.uy));
break;
case TT_LAVA:
You("pull yourself above the lava!");
You("pull yourself above the %s!", hliquid("lava"));
u.utrap = 0;
return 1;
case TT_BURIEDBALL:
@@ -2179,20 +2262,6 @@ struct obj *obj;
update_inventory();
}
static struct trapinfo {
struct obj *tobj;
xchar tx, ty;
int time_needed;
boolean force_bungle;
} trapinfo;
void
reset_trapset()
{
trapinfo.tobj = 0;
trapinfo.force_bungle = 0;
}
/* touchstones - by Ken Arnold */
STATIC_OVL void
use_stone(tstone)
@@ -2322,6 +2391,20 @@ struct obj *tstone;
return;
}
static struct trapinfo {
struct obj *tobj;
xchar tx, ty;
int time_needed;
boolean force_bungle;
} trapinfo;
void
reset_trapset()
{
trapinfo.tobj = 0;
trapinfo.force_bungle = 0;
}
/* Place a landmine/bear trap. Helge Hafting */
STATIC_OVL void
use_trap(otmp)
+1 -1
View File
@@ -1888,7 +1888,7 @@ boolean loseit; /* whether to drop it if hero can longer touch it */
bane = bane_applies(get_artifact(obj), &youmonst);
/* nothing else to do if hero can successfully handle this object */
if (!ag && !bane)
if (!ag && !bane && !touch_blasted)
return 1;
/* hero can't handle this object, but didn't get touch_artifact()'s
+1 -1
View File
@@ -716,7 +716,7 @@ xchar x, y;
deltrap(t_at(u.ux, u.uy));
break;
case TT_LAVA:
pline(pullmsg, "lava");
pline(pullmsg, hliquid("lava"));
break;
case TT_BEARTRAP: {
register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
+94 -48
View File
@@ -183,6 +183,7 @@ static const char *readchar_queue = "";
static coord clicklook_cc;
STATIC_DCL char *NDECL(parse);
STATIC_DCL void FDECL(show_direction_keys, (winid, BOOLEAN_P));
STATIC_DCL boolean FDECL(help_dir, (CHAR_P, const char *));
STATIC_PTR int
@@ -356,7 +357,7 @@ doextlist(VOID_ARGS)
return 0;
}
#if defined(TTY_GRAPHICS) || defined(CURSES_GRAPHICS)
#ifdef TTY_GRAPHICS
#define MAX_EXT_CMD 50 /* Change if we ever have > 50 ext cmds */
/*
@@ -1491,16 +1492,26 @@ int final;
}
you_are(buf, "");
/* report alignment (bypass you_are() in order to omit ending period) */
/* report alignment (bypass you_are() in order to omit ending period);
adverb is used to distinguish between temporary change (helm of opp.
alignment), permanent change (one-time conversion), and original */
Sprintf(buf, " %s%s%s, %son a mission for %s",
You_, !final ? are : were,
align_str(u.ualign.type),
/* helm of opposite alignment (might hide conversion) */
(u.ualign.type != u.ualignbase[A_CURRENT]) ? "temporarily "
(u.ualign.type != u.ualignbase[A_CURRENT])
/* what's the past tense of "currently"? if we used "formerly"
it would sound like a reference to the original alignment */
? (!final ? "currently " : "temporarily ")
/* permanent conversion */
: (u.ualign.type != u.ualignbase[A_ORIGINAL]) ? "now "
: (u.ualign.type != u.ualignbase[A_ORIGINAL])
/* and what's the past tense of "now"? certainly not "then"
in a context like this...; "belatedly" == weren't that
way sooner (in other words, didn't start that way) */
? (!final ? "now " : "belatedly ")
/* atheist (ignored in very early game) */
: (!u.uconduct.gnostic && moves > 1000L) ? "nominally "
: (!u.uconduct.gnostic && moves > 1000L)
? "nominally "
/* lastly, normal case */
: "",
u_gname());
@@ -2623,6 +2634,26 @@ int final;
} else {
Sprintf(buf, "used %ld wish%s", u.uconduct.wishes,
(u.uconduct.wishes > 1L) ? "es" : "");
if (u.uconduct.wisharti) {
/* if wisharti == wishes
* 1 wish (for an artifact)
* 2 wishes (both for artifacts)
* N wishes (all for artifacts)
* else (N is at least 2 in order to get here; M < N)
* N wishes (1 for an artifact)
* N wishes (M for artifacts)
*/
if (u.uconduct.wisharti == u.uconduct.wishes)
Sprintf(eos(buf), " (%s",
(u.uconduct.wisharti > 2L) ? "all "
: (u.uconduct.wisharti == 2L) ? "both " : "");
else
Sprintf(eos(buf), " (%ld ", u.uconduct.wisharti);
Sprintf(eos(buf), "for %s)",
(u.uconduct.wisharti == 1L) ? "an artifact"
: "artifacts");
}
you_have_X(buf);
if (!u.uconduct.wisharti)
@@ -3350,7 +3381,8 @@ boolean initial;
Cmd.num_pad = flagtemp;
++updated;
}
/* swap_yz mode (only applicable for !num_pad) */
/* swap_yz mode (only applicable for !num_pad); intended for
QWERTZ keyboard used in Central Europe, particularly Germany */
flagtemp = (iflags.num_pad_mode & 1) ? !Cmd.num_pad : FALSE;
if (flagtemp != Cmd.swap_yz) {
Cmd.swap_yz = flagtemp;
@@ -3384,12 +3416,12 @@ boolean initial;
++updated;
/* phone_layout has been toggled */
for (i = 0; i < 3; i++) {
c = '1' + i; /* 1,2,3 <-> 7,8,9 */
c = '1' + i; /* 1,2,3 <-> 7,8,9 */
cmdtmp = Cmd.commands[c]; /* tmp = [1] */
Cmd.commands[c] = Cmd.commands[c + 6]; /* [1] = [7] */
Cmd.commands[c + 6] = cmdtmp; /* [7] = tmp */
c = (M('1') & 0xff) + i; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
cmdtmp = Cmd.commands[c]; /* tmp = [M-1] */
c = (M('1') & 0xff) + i; /* M-1,M-2,M-3 <-> M-7,M-8,M-9 */
cmdtmp = Cmd.commands[c]; /* tmp = [M-1] */
Cmd.commands[c] = Cmd.commands[c + 6]; /* [M-1] = [M-7] */
Cmd.commands[c + 6] = cmdtmp; /* [M-7] = tmp */
}
@@ -3789,46 +3821,14 @@ retry:
return 1;
}
STATIC_OVL boolean
help_dir(sym, msg)
char sym;
const char *msg;
STATIC_OVL void
show_direction_keys(win, nodiag)
winid win;
boolean nodiag;
{
char ctrl;
winid win;
static const char wiz_only_list[] = "EFGIOVW";
char buf[BUFSZ], buf2[BUFSZ], *explain;
char buf[BUFSZ];
win = create_nhwindow(NHW_TEXT);
if (!win)
return FALSE;
if (msg) {
Sprintf(buf, "cmdassist: %s", msg);
putstr(win, 0, buf);
putstr(win, 0, "");
}
if (letter(sym)) {
sym = highc(sym);
ctrl = (sym - 'A') + 1;
if ((explain = dowhatdoes_core(ctrl, buf2))
&& (!index(wiz_only_list, sym) || wizard)) {
Sprintf(buf, "Are you trying to use ^%c%s?", sym,
index(wiz_only_list, sym)
? ""
: " as specified in the Guidebook");
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, explain);
putstr(win, 0, "");
putstr(win, 0, "To use that command, you press");
Sprintf(buf, "the <Ctrl> key, and the <%c> key at the same time.",
sym);
putstr(win, 0, buf);
putstr(win, 0, "");
}
}
if (NODIAG(u.umonnum)) {
putstr(win, 0, "Valid direction keys in your current form are:");
if (nodiag) {
Sprintf(buf, " %c ", Cmd.move_N);
putstr(win, 0, buf);
putstr(win, 0, " | ");
@@ -3838,7 +3838,6 @@ const char *msg;
Sprintf(buf, " %c ", Cmd.move_S);
putstr(win, 0, buf);
} else {
putstr(win, 0, "Valid direction keys are:");
Sprintf(buf, " %c %c %c", Cmd.move_NW, Cmd.move_N,
Cmd.move_NE);
putstr(win, 0, buf);
@@ -3850,6 +3849,53 @@ const char *msg;
Cmd.move_SE);
putstr(win, 0, buf);
};
}
STATIC_OVL boolean
help_dir(sym, msg)
char sym;
const char *msg;
{
static const char wiz_only_list[] = "EFGIVW";
char ctrl;
winid win;
char buf[BUFSZ], buf2[BUFSZ], *explain;
win = create_nhwindow(NHW_TEXT);
if (!win)
return FALSE;
if (msg) {
Sprintf(buf, "cmdassist: %s", msg);
putstr(win, 0, buf);
putstr(win, 0, "");
}
if (letter(sym) || sym == '[') { /* 'dat/cmdhelp' shows ESC as ^[ */
sym = highc(sym); /* @A-Z[ (note: letter() accepts '@') */
ctrl = (sym - 'A') + 1; /* 0-27 (note: 28-31 aren't applicable) */
if ((explain = dowhatdoes_core(ctrl, buf2)) != 0
&& (!index(wiz_only_list, sym) || wizard)) {
Sprintf(buf, "Are you trying to use ^%c%s?", sym,
index(wiz_only_list, sym)
? ""
: " as specified in the Guidebook");
putstr(win, 0, buf);
putstr(win, 0, "");
putstr(win, 0, explain);
putstr(win, 0, "");
putstr(win, 0,
"To use that command, hold down the <Ctrl> key as a shift");
Sprintf(buf, "and press the <%c> key.", sym);
putstr(win, 0, buf);
putstr(win, 0, "");
}
}
Sprintf(buf, "Valid direction keys %sare:",
NODIAG(u.umonnum) ? "in your current form " : "");
putstr(win, 0, buf);
show_direction_keys(win, NODIAG(u.umonnum));
putstr(win, 0, "");
putstr(win, 0, " < up");
putstr(win, 0, " > down");
+3 -3
View File
@@ -750,7 +750,7 @@ struct entity *etmp;
E_phrase(etmp, "drink"), lava ? "lava" : "moat");
else
pline("%s into the %s.", E_phrase(etmp, "fall"),
lava ? "lava" : "moat");
lava ? hliquid("lava") : "moat");
}
killer.format = NO_KILLER_PREFIX;
Strcpy(killer.name, "fell from a drawbridge");
@@ -901,13 +901,13 @@ int x, y;
if (lev1->typ == DRAWBRIDGE_UP) {
if (cansee(x2, y2))
pline_The("portcullis of the drawbridge falls into the %s!",
lava ? "lava" : "moat");
lava ? hliquid("lava") : "moat");
else if (!Deaf)
You_hear("a loud *SPLASH*!");
} else {
if (cansee(x, y))
pline_The("drawbridge collapses into the %s!",
lava ? "lava" : "moat");
lava ? hliquid("lava") : "moat");
else if (!Deaf)
You_hear("a loud *SPLASH*!");
}
+346 -152
View File
@@ -12,6 +12,10 @@
extern boolean known; /* from read.c */
STATIC_DCL boolean NDECL(unconstrain_map);
STATIC_DCL void NDECL(reconstrain_map);
STATIC_DCL void FDECL(browse_map, (int, const char *));
STATIC_DCL void FDECL(map_monst, (struct monst *, BOOLEAN_P));
STATIC_DCL void FDECL(do_dknown_of, (struct obj *));
STATIC_DCL boolean FDECL(check_map_spot, (int, int, CHAR_P, unsigned));
STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P, unsigned));
@@ -22,8 +26,130 @@ STATIC_PTR void FDECL(findone, (int, int, genericptr_t));
STATIC_PTR void FDECL(openone, (int, int, genericptr_t));
STATIC_DCL int FDECL(mfind0, (struct monst *, BOOLEAN_P));
/* Recursively search obj for an object in class oclass and return 1st found
*/
/* bring hero out from underwater or underground or being engulfed;
return True iff any change occurred */
STATIC_OVL boolean
unconstrain_map()
{
boolean res = u.uinwater || u.uburied || u.uswallow;
/* bring Underwater, buried, or swallowed hero to normal map */
iflags.save_uinwater = u.uinwater, u.uinwater = 0;
iflags.save_uburied = u.uburied, u.uburied = 0;
iflags.save_uswallow = u.uswallow, u.uswallow = 0;
return res;
}
/* put hero back underwater or underground or engulfed */
STATIC_OVL void
reconstrain_map()
{
u.uinwater = iflags.save_uinwater, iflags.save_uinwater = 0;
u.uburied = iflags.save_uburied, iflags.save_uburied = 0;
u.uswallow = iflags.save_uswallow, iflags.save_uswallow = 0;
}
/* use getpos()'s 'autodescribe' to view whatever is currently shown on map */
STATIC_DCL void
browse_map(ter_typ, ter_explain)
int ter_typ;
const char *ter_explain;
{
coord dummy_pos; /* don't care whether player actually picks a spot */
dummy_pos.x = u.ux, dummy_pos.y = u.uy; /* starting spot for getpos() */
iflags.autodescribe = TRUE;
iflags.terrainmode = ter_typ;
getpos(&dummy_pos, FALSE, ter_explain);
iflags.terrainmode = 0;
/* leave iflags.autodescribe 'on' even if previously 'off' */
}
/* extracted from monster_detection() so can be shared by do_vicinity_map() */
STATIC_DCL void
map_monst(mtmp, showtail)
struct monst *mtmp;
boolean showtail;
{
if (def_monsyms[(int) mtmp->data->mlet].sym == ' ')
show_glyph(mtmp->mx, mtmp->my, detected_mon_to_glyph(mtmp));
else
show_glyph(mtmp->mx, mtmp->my,
mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
if (showtail && mtmp->data == &mons[PM_LONG_WORM])
detect_wsegs(mtmp, 0);
}
/* this is checking whether a trap symbol represents a trapped chest,
not whether a trapped chest is actually present */
boolean
trapped_chest_at(ttyp, x, y)
int ttyp;
int x, y;
{
struct monst *mtmp;
struct obj *otmp;
if (!glyph_is_trap(glyph_at(x, y)))
return FALSE;
if (ttyp != BEAR_TRAP || (Hallucination && rn2(20)))
return FALSE;
/*
* TODO? We should check containers recursively like the trap
* detecting routine does. Chests and large boxes do not nest in
* themselves or each other, but could be contained inside statues.
*
* For farlook, we should also check for buried containers, but
* for '^' command to examine adjacent trap glyph, we shouldn't.
*/
/* on map, presence of any trappable container will do */
if (sobj_at(CHEST, x, y) || sobj_at(LARGE_BOX, x, y))
return TRUE;
/* in inventory, we need to find one which is actually trapped */
if (x == u.ux && y == u.uy) {
for (otmp = invent; otmp; otmp = otmp->nobj)
if (Is_box(otmp) && otmp->otrapped)
return TRUE;
if (u.usteed) { /* steed isn't on map so won't be found by m_at() */
for (otmp = u.usteed->minvent; otmp; otmp = otmp->nobj)
if (Is_box(otmp) && otmp->otrapped)
return TRUE;
}
}
if ((mtmp = m_at(x, y)) != 0)
for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
if (Is_box(otmp) && otmp->otrapped)
return TRUE;
return FALSE;
}
/* this is checking whether a trap symbol represents a trapped door,
not whether the door here is actually trapped */
boolean
trapped_door_at(ttyp, x, y)
int ttyp;
int x, y;
{
struct rm *lev;
if (!glyph_is_trap(glyph_at(x, y)))
return FALSE;
if (ttyp != BEAR_TRAP || (Hallucination && rn2(20)))
return FALSE;
lev = &levl[x][y];
if (!IS_DOOR(lev->typ))
return FALSE;
if ((lev->doormask & (D_NODOOR | D_BROKEN | D_ISOPEN)) != 0
&& trapped_chest_at(ttyp, x, y))
return FALSE;
return TRUE;
}
/* recursively search obj for an object in class oclass, return 1st found */
struct obj *
o_in(obj, oclass)
struct obj *obj;
@@ -39,7 +165,7 @@ char oclass;
for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
if (otmp->oclass == oclass)
return otmp;
else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)))
else if (Has_contents(otmp) && (temp = o_in(otmp, oclass)) != 0)
return temp;
}
return (struct obj *) 0;
@@ -64,7 +190,7 @@ unsigned material;
if (objects[otmp->otyp].oc_material == material)
return otmp;
else if (Has_contents(otmp)
&& (temp = o_material(otmp, material)))
&& (temp = o_material(otmp, material)) != 0)
return temp;
}
return (struct obj *) 0;
@@ -166,28 +292,36 @@ register struct obj *sobj;
{
register struct obj *obj;
register struct monst *mtmp;
struct obj *temp;
boolean stale;
struct obj gold, *temp = 0;
boolean stale, ugold = FALSE, steedgold = FALSE;
int ter_typ = TER_DETECT | TER_OBJ;
known = stale =
clear_stale_map(COIN_CLASS, (unsigned) (sobj->blessed ? GOLD : 0));
known = stale = clear_stale_map(COIN_CLASS,
(unsigned) (sobj->blessed ? GOLD : 0));
/* look for gold carried by monsters (might be in a container) */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue; /* probably not needed in this case but... */
if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
known = TRUE;
goto outgoldmap; /* skip further searching */
} else
if (mtmp == u.usteed) {
steedgold = TRUE;
} else {
known = TRUE;
goto outgoldmap; /* skip further searching */
}
} else {
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (sobj->blessed && o_material(obj, GOLD)) {
known = TRUE;
goto outgoldmap;
} else if (o_in(obj, COIN_CLASS)) {
known = TRUE;
goto outgoldmap; /* skip further searching */
if ((sobj->blessed && o_material(obj, GOLD))
|| o_in(obj, COIN_CLASS)) {
if (mtmp == u.usteed) {
steedgold = TRUE;
} else {
known = TRUE;
goto outgoldmap; /* skip further searching */
}
}
}
}
/* look for gold objects */
@@ -208,13 +342,22 @@ register struct obj *sobj;
adjust message if you have gold in your inventory */
if (sobj) {
char buf[BUFSZ];
if (youmonst.data == &mons[PM_GOLD_GOLEM]) {
if (youmonst.data == &mons[PM_GOLD_GOLEM])
Sprintf(buf, "You feel like a million %s!", currency(2L));
} else if (hidden_gold() || money_cnt(invent))
else if (money_cnt(invent) || hidden_gold())
Strcpy(buf,
"You feel worried about your future financial situation.");
else if (steedgold)
Sprintf(buf, "You feel interested in %s financial situation.",
s_suffix(x_monnam(u.usteed,
u.usteed->mtame ? ARTICLE_YOUR
: ARTICLE_THE,
(char *) 0,
SUPPRESS_SADDLE, FALSE)));
else
Strcpy(buf, "You feel materially poor.");
strange_feeling(sobj, buf);
}
return 1;
@@ -228,54 +371,64 @@ register struct obj *sobj;
outgoldmap:
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
/* Discover gold locations. */
for (obj = fobj; obj; obj = obj->nobj) {
if (sobj->blessed && (temp = o_material(obj, GOLD))) {
if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) {
if (temp != obj) {
temp->ox = obj->ox;
temp->oy = obj->oy;
}
map_object(temp, 1);
} else if ((temp = o_in(obj, COIN_CLASS))) {
} else if ((temp = o_in(obj, COIN_CLASS)) != 0) {
if (temp != obj) {
temp->ox = obj->ox;
temp->oy = obj->oy;
}
map_object(temp, 1);
}
if (temp && temp->ox == u.ux && temp->oy == u.uy)
ugold = TRUE;
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue; /* probably overkill here */
temp = 0;
if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) {
struct obj gold;
gold = zeroobj; /* ensure oextra is cleared too */
gold.otyp = GOLD_PIECE;
gold.quan = (long) rnd(10); /* usually more than 1 */
gold.ox = mtmp->mx;
gold.oy = mtmp->my;
map_object(&gold, 1);
} else
temp = &gold;
} else {
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (sobj->blessed && (temp = o_material(obj, GOLD))) {
if (sobj->blessed && (temp = o_material(obj, GOLD)) != 0) {
temp->ox = mtmp->mx;
temp->oy = mtmp->my;
map_object(temp, 1);
break;
} else if ((temp = o_in(obj, COIN_CLASS))) {
} else if ((temp = o_in(obj, COIN_CLASS)) != 0) {
temp->ox = mtmp->mx;
temp->oy = mtmp->my;
map_object(temp, 1);
break;
}
}
if (temp && temp->ox == u.ux && temp->oy == u.uy)
ugold = TRUE;
}
if (!ugold) {
newsym(u.ux, u.uy);
ter_typ |= TER_MON; /* so autodescribe will recognize hero */
}
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
You_feel("very greedy, and sense gold!");
exercise(A_WIS, TRUE);
display_nhwindow(WIN_MAP, TRUE);
browse_map(ter_typ, "gold");
reconstrain_map();
docrt();
if (Underwater)
under_water(2);
@@ -298,6 +451,8 @@ register struct obj *sobj;
const char *what = confused ? something : "food";
stale = clear_stale_map(oclass, 0);
if (u.usteed) /* some situations leave steed with stale coordinates */
u.usteed->mx = u.ux, u.usteed->my = u.uy;
for (obj = fobj; obj; obj = obj->nobj)
if (o_in(obj, oclass)) {
@@ -306,12 +461,14 @@ register struct obj *sobj;
else
ct++;
}
for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) {
/* no DEADMONSTER(mtmp) check needed since dmons never have inventory
*/
for (mtmp = fmon; mtmp && (!ct || !ctu); mtmp = mtmp->nmon) {
/* no DEADMONSTER(mtmp) check needed -- dmons never have inventory */
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (o_in(obj, oclass)) {
ct++;
if (mtmp->mx == u.ux && mtmp->my == u.uy)
ctu++; /* steed or an engulfer with inventory */
else
ct++;
break;
}
}
@@ -328,6 +485,7 @@ register struct obj *sobj;
}
} else if (sobj) {
char buf[BUFSZ];
Sprintf(buf, "Your %s twitches%s.", body_part(NOSE),
(sobj->blessed && !u.uedibility)
? " then starts to tingle"
@@ -353,10 +511,11 @@ register struct obj *sobj;
}
} else {
struct obj *temp;
int ter_typ = TER_DETECT | TER_OBJ;
known = TRUE;
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
for (obj = fobj; obj; obj = obj->nobj)
if ((temp = o_in(obj, oclass)) != 0) {
if (temp != obj) {
@@ -366,8 +525,7 @@ register struct obj *sobj;
map_object(temp, 1);
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
/* no DEADMONSTER(mtmp) check needed since dmons never have
* inventory */
/* no DEADMONSTER() check needed -- dmons never have inventory */
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if ((temp = o_in(obj, oclass)) != 0) {
temp->ox = mtmp->mx;
@@ -375,9 +533,10 @@ register struct obj *sobj;
map_object(temp, 1);
break; /* skip rest of this monster's inventory */
}
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (!ctu) {
newsym(u.ux, u.uy);
ter_typ |= TER_MON; /* for autodescribe of self */
}
if (sobj) {
if (sobj->blessed) {
Your("%s %s to tingle and you smell %s.", body_part(NOSE),
@@ -387,8 +546,11 @@ register struct obj *sobj;
Your("%s tingles and you smell %s.", body_part(NOSE), what);
} else
You("sense %s.", what);
display_nhwindow(WIN_MAP, TRUE);
exercise(A_WIS, TRUE);
browse_map(ter_typ, "food");
reconstrain_map();
docrt();
if (Underwater)
under_water(2);
@@ -418,7 +580,7 @@ int class; /* an object class, 0 for all */
int ct = 0, ctu = 0;
register struct obj *obj, *otmp = (struct obj *) 0;
register struct monst *mtmp;
int sym, boulder = 0;
int sym, boulder = 0, ter_typ = TER_DETECT | TER_OBJ;
if (class < 0 || class >= MAXOCLASSES) {
impossible("object_detect: illegal class %d", class);
@@ -468,6 +630,9 @@ int class; /* an object class, 0 for all */
do_dknown_of(obj);
}
if (u.usteed)
u.usteed->mx = u.ux, u.usteed->my = u.uy;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
@@ -499,13 +664,12 @@ int class; /* an object class, 0 for all */
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
/*
* Map all buried objects first.
*/
for (obj = level.buriedobjlist; obj; obj = obj->nobj)
if (!class || (otmp = o_in(obj, class))) {
if (!class || (otmp = o_in(obj, class)) != 0) {
if (class) {
if (otmp != obj) {
otmp->ox = obj->ox;
@@ -526,8 +690,8 @@ int class; /* an object class, 0 for all */
for (x = 1; x < COLNO; x++)
for (y = 0; y < ROWNO; y++)
for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
if ((!class && !boulder) || (otmp = o_in(obj, class))
|| (otmp = o_in(obj, boulder))) {
if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0
|| (otmp = o_in(obj, boulder)) != 0) {
if (class || boulder) {
if (otmp != obj) {
otmp->ox = obj->ox;
@@ -544,8 +708,8 @@ int class; /* an object class, 0 for all */
if (DEADMONSTER(mtmp))
continue;
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if ((!class && !boulder) || (otmp = o_in(obj, class))
|| (otmp = o_in(obj, boulder))) {
if ((!class && !boulder) || (otmp = o_in(obj, class)) != 0
|| (otmp = o_in(obj, boulder)) != 0) {
if (!class && !boulder)
otmp = obj;
otmp->ox = mtmp->mx; /* at monster location */
@@ -558,8 +722,9 @@ int class; /* an object class, 0 for all */
&& (!class || class == objects[mtmp->mappearance].oc_class)) {
struct obj temp;
temp.oextra = (struct oextra *) 0;
temp = zeroobj;
temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */
temp.quan = 1L;
temp.ox = mtmp->mx;
temp.oy = mtmp->my;
temp.corpsenm = PM_TENGU; /* if mimicing a corpse */
@@ -567,25 +732,28 @@ int class; /* an object class, 0 for all */
} else if (findgold(mtmp->minvent)
&& (!class || class == COIN_CLASS)) {
struct obj gold;
gold = zeroobj; /* ensure oextra is cleared too */
gold.otyp = GOLD_PIECE;
gold.quan = (long) rnd(10); /* usually more than 1 */
gold.ox = mtmp->mx;
gold.oy = mtmp->my;
map_object(&gold, 1);
}
}
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (!glyph_is_object(glyph_at(u.ux, u.uy))) {
newsym(u.ux, u.uy);
ter_typ |= TER_MON;
}
You("detect the %s of %s.", ct ? "presence" : "absence", stuff);
display_nhwindow(WIN_MAP, TRUE);
/*
* What are we going to do when the hero does an object detect while blind
* and the detected object covers a known pool?
*/
docrt(); /* this will correctly reset vision */
if (!ct)
display_nhwindow(WIN_MAP, TRUE);
else
browse_map(ter_typ, "object");
reconstrain_map();
docrt(); /* this will correctly reset vision */
if (Underwater)
under_water(2);
if (u.uburied)
@@ -625,26 +793,19 @@ int mclass; /* monster class, 0 for all */
: "You feel threatened.");
return 1;
} else {
boolean woken = FALSE;
boolean unconstrained, woken = FALSE;
unsigned swallowed = u.uswallow; /* before unconstrain_map() */
cls();
unconstrained = unconstrain_map();
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (!mclass || mtmp->data->mlet == mclass
|| (mtmp->data == &mons[PM_LONG_WORM]
&& mclass == S_WORM_TAIL))
if (mtmp->mx > 0) {
if (mclass && def_monsyms[mclass].sym == ' ')
show_glyph(mtmp->mx, mtmp->my,
detected_mon_to_glyph(mtmp));
else
show_glyph(mtmp->mx, mtmp->my,
mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp));
/* don't be stingy - display entire worm */
if (mtmp->data == &mons[PM_LONG_WORM])
detect_wsegs(mtmp, 0);
}
map_monst(mtmp, TRUE);
if (otmp && otmp->cursed
&& (mtmp->msleeping || !mtmp->mcanmove)) {
mtmp->msleeping = mtmp->mfrozen = 0;
@@ -652,12 +813,25 @@ int mclass; /* monster class, 0 for all */
woken = TRUE;
}
}
display_self();
if (!swallowed)
display_self();
You("sense the presence of monsters.");
if (woken)
pline("Monsters sense the presence of you.");
display_nhwindow(WIN_MAP, TRUE);
docrt();
if ((otmp && otmp->blessed) && !unconstrained) {
/* persistent detection--just show updated map */
display_nhwindow(WIN_MAP, TRUE);
} else {
/* one-shot detection--allow player to move cursor around and
get autodescribe feedback */
EDetect_monsters |= I_SPECIAL;
browse_map(TER_DETECT | TER_MON, "monster of interest");
EDetect_monsters &= ~I_SPECIAL;
}
reconstrain_map();
docrt(); /* redraw the screen to remove unseen monsters from map */
if (Underwater)
under_water(2);
if (u.uburied)
@@ -675,7 +849,7 @@ int src_cursed;
if (Hallucination || src_cursed) {
struct obj obj; /* fake object */
obj.oextra = (struct oextra *) 0;
obj = zeroobj;
if (trap) {
obj.ox = trap->tx;
obj.oy = trap->ty;
@@ -683,14 +857,18 @@ int src_cursed;
obj.ox = x;
obj.oy = y;
}
obj.otyp = (src_cursed) ? GOLD_PIECE : random_object();
obj.otyp = !Hallucination ? GOLD_PIECE : random_object();
obj.quan = (long) ((obj.otyp == GOLD_PIECE) ? rnd(10)
: objects[obj.otyp].oc_merge ? rnd(2) : 1);
obj.corpsenm = random_monster(); /* if otyp == CORPSE */
map_object(&obj, 1);
} else if (trap) {
map_trap(trap, 1);
trap->tseen = 1;
} else {
} else { /* trapped door or trapped chest */
struct trap temp_trap; /* fake trap */
(void) memset((genericptr_t) &temp_trap, 0, sizeof temp_trap);
temp_trap.tx = x;
temp_trap.ty = y;
temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */
@@ -715,6 +893,11 @@ int how; /* 1 for misleading map feedback */
xchar x, y;
int result = OTRAP_NONE;
/*
* TODO? Display locations of unarmed land mine and beartrap objects.
* If so, should they be displayed as objects or as traps?
*/
for (otmp = objlist; otmp; otmp = otmp->nobj) {
if (Is_box(otmp) && otmp->otrapped
&& get_obj_location(otmp, &x, &y, BURIED_TOO | CONTAINED_TOO)) {
@@ -735,16 +918,18 @@ int how; /* 1 for misleading map feedback */
*/
int
trap_detect(sobj)
register struct obj *sobj;
/* sobj is null if crystal ball, *scroll if gold detection scroll */
struct obj *sobj; /* null if crystal ball, *scroll if gold detection scroll */
{
register struct trap *ttmp;
struct monst *mon;
int door, glyph, tr;
int door, glyph, tr, ter_typ = TER_DETECT | TER_TRP;
int cursed_src = sobj && sobj->cursed;
boolean found = FALSE;
coord cc;
if (u.usteed)
u.usteed->mx = u.ux, u.usteed->my = u.uy;
/* floor/ceiling traps */
for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) {
if (ttmp->tx != u.ux || ttmp->ty != u.uy)
@@ -759,8 +944,7 @@ register struct obj *sobj;
else
found = TRUE;
}
if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0))
!= OTRAP_NONE) {
if ((tr = detect_obj_traps(level.buriedobjlist, FALSE, 0)) != OTRAP_NONE) {
if (tr & OTRAP_THERE)
goto outtrapmap;
else
@@ -798,12 +982,11 @@ register struct obj *sobj;
/* traps exist, but only under me - no separate display required */
Your("%s itch.", makeplural(body_part(TOE)));
return 0;
outtrapmap:
cls();
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
(void) unconstrain_map();
/* show chest traps first, so that subsequent floor trap display
will override if both types are present at the same location */
(void) detect_obj_traps(fobj, TRUE, cursed_src);
@@ -826,15 +1009,16 @@ outtrapmap:
/* redisplay hero unless sense_trap() revealed something at <ux,uy> */
glyph = glyph_at(u.ux, u.uy);
if (!(glyph_is_trap(glyph) || glyph_is_object(glyph)))
if (!(glyph_is_trap(glyph) || glyph_is_object(glyph))) {
newsym(u.ux, u.uy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
ter_typ |= TER_MON; /* for autodescribe at <u.ux,u.uy> */
}
You_feel("%s.", cursed_src ? "very greedy" : "entrapped");
/* wait for user to respond, then reset map display to normal */
display_nhwindow(WIN_MAP, TRUE);
docrt();
browse_map(ter_typ, "trap of interest");
reconstrain_map();
docrt(); /* redraw the screen to remove unseen traps from the map */
if (Underwater)
under_water(2);
if (u.uburied)
@@ -993,10 +1177,10 @@ struct obj **optr;
nomul(-rnd(10));
multi_reason = "gazing into a crystal ball";
nomovemsg = "";
if (obj->spe <= 0)
if (obj->spe <= 0) {
pline_The("vision is unclear.");
else {
int class;
} else {
int class, i;
int ret = 0;
makeknown(CRYSTAL_BALL);
@@ -1019,11 +1203,10 @@ struct obj **optr;
case '^':
ret = trap_detect((struct obj *) 0);
break;
default: {
int i = rn2(SIZE(level_detects));
default:
i = rn2(SIZE(level_detects));
You_see("%s, %s.", level_detects[i].what,
level_distance(level_detects[i].where));
}
ret = 0;
break;
}
@@ -1087,40 +1270,67 @@ void
do_mapping()
{
register int zx, zy;
boolean unconstrained;
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
unconstrained = unconstrain_map();
for (zx = 1; zx < COLNO; zx++)
for (zy = 0; zy < ROWNO; zy++)
show_map_spot(zx, zy);
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (!level.flags.hero_memory || Underwater) {
if (!level.flags.hero_memory || unconstrained) {
flush_screen(1); /* flush temp screen */
display_nhwindow(WIN_MAP, TRUE); /* wait */
/* browse_map() instead of display_nhwindow(WIN_MAP, TRUE) */
browse_map(TER_DETECT | TER_MAP | TER_TRP | TER_OBJ,
"anything of interest");
docrt();
}
reconstrain_map();
exercise(A_WIS, TRUE);
}
/* clairvoyance */
void
do_vicinity_map()
do_vicinity_map(sobj)
struct obj *sobj; /* scroll--actually fake spellbook--object */
{
register int zx, zy;
int lo_y = (u.uy - 5 < 0 ? 0 : u.uy - 5),
hi_y = (u.uy + 6 > ROWNO ? ROWNO : u.uy + 6),
lo_x = (u.ux - 9 < 1 ? 1 : u.ux - 9), /* avoid column 0 */
hi_x = (u.ux + 10 > COLNO ? COLNO : u.ux + 10);
struct monst *mtmp;
boolean unconstrained, refresh = FALSE, mdetected = FALSE,
extended = (sobj && sobj->blessed);
int 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;
for (zx = lo_x; zx < hi_x; zx++)
for (zy = lo_y; zy < hi_y; zy++)
unconstrained = unconstrain_map();
for (zx = lo_x; zx <= hi_x; zx++)
for (zy = lo_y; zy <= hi_y; zy++) {
show_map_spot(zx, zy);
if (!level.flags.hero_memory || Underwater) {
if (extended && (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)
mdetected = TRUE;
}
}
if (!level.flags.hero_memory || unconstrained || mdetected) {
flush_screen(1); /* flush temp screen */
display_nhwindow(WIN_MAP, TRUE); /* wait */
docrt();
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();
if (refresh)
docrt();
}
/* convert a secret door into a normal door */
@@ -1334,12 +1544,10 @@ boolean via_warning;
exercise(A_WIS, TRUE);
if (!canspotmon(mtmp)) {
if (glyph_is_invisible(levl[x][y].glyph)) {
/* found invisible monster in a square
* which already has an 'I' in it.
* Logically, this should still take
* time and lead to a return(1), but
* if we did that the player would keep
* finding the same monster every turn.
/* Found invisible monster in a square which already has
* an 'I' in it. Logically, this should still take time
* and lead to a return 1, but if we did that the player
* would keep finding the same monster every turn.
*/
return -1;
} else {
@@ -1347,18 +1555,16 @@ boolean via_warning;
map_invisible(x, y);
}
} else if (!sensemon(mtmp))
You("find %s.", mtmp->mtame
? y_monnam(mtmp)
: a_monnam(mtmp));
You("find %s.",
mtmp->mtame ? y_monnam(mtmp) : a_monnam(mtmp));
return 1;
}
if (!canspotmon(mtmp)) {
if (mtmp->mundetected
&& (is_hider(mtmp->data)
|| mtmp->data->mlet == S_EEL))
&& (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL))
if (via_warning) {
Your("warning senses cause you to take a second %s.",
Blind ? "to check nearby" : "look close by");
Blind ? "to check nearby" : "look close by");
display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */
}
mtmp->mundetected = 0;
@@ -1373,10 +1579,10 @@ dosearch0(aflag)
register int aflag; /* intrinsic autosearch vs explicit searching */
{
#ifdef GCC_BUG
/* some versions of gcc seriously muck up nested loops. if you get strange
crashes while searching in a version compiled with gcc, try putting
#define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the
makefile).
/* Some old versions of gcc seriously muck up nested loops. If you get
* strange crashes while searching in a version compiled with gcc, try
* putting #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in
* the makefile).
*/
volatile xchar x, y;
#else
@@ -1521,21 +1727,16 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
} else {
int x, y, glyph, levl_glyph, default_glyph;
uchar seenv;
unsigned save_swallowed;
struct monst *mtmp;
struct trap *t;
coord pos;
char buf[BUFSZ];
/* there is a TER_MAP bit too; we always show map regardless of it */
boolean keep_traps = (which_subset & TER_TRP) !=0,
keep_objs = (which_subset & TER_OBJ) != 0,
keep_mons = (which_subset & TER_MON) != 0; /* not used */
unsigned swallowed = u.uswallow; /* before unconstrain_map() */
save_swallowed = u.uswallow;
iflags.save_uinwater = u.uinwater, iflags.save_uburied = u.uburied;
u.uinwater = u.uburied = 0;
u.uswallow = 0;
if (iflags.save_uinwater || iflags.save_uburied)
if (unconstrain_map())
docrt();
default_glyph = cmap_to_glyph(level.flags.arboreal ? S_tree : S_stone);
/* for 'full', show the actual terrain for the entire level,
@@ -1560,8 +1761,8 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
glyph, which will never be a monster (unless it is
the invisible monster glyph, which is handled like
an object, replacing any object or trap at its spot) */
glyph = !save_swallowed ? glyph_at(x, y) : levl_glyph;
if (keep_mons && x == u.ux && y == u.uy && save_swallowed)
glyph = !swallowed ? glyph_at(x, y) : levl_glyph;
if (keep_mons && x == u.ux && y == u.uy && swallowed)
glyph = mon_to_glyph(u.ustuck);
else if (((glyph_is_monster(glyph)
|| glyph_is_warning(glyph)) && !keep_mons)
@@ -1631,17 +1832,10 @@ int which_subset; /* when not full, whether to suppress objs and/or traps */
/* allow player to move cursor around and get autodescribe feedback
based on what is visible now rather than what is on 'real' map */
pos.x = u.ux, pos.y = u.uy;
iflags.autodescribe = TRUE;
iflags.terrainmode = which_subset | TER_MAP; /* guaranteed non-zero */
getpos(&pos, FALSE, "anything of interest");
iflags.terrainmode = 0;
/* leave iflags.autodescribe 'on' even if it was previously 'off' */
which_subset |= TER_MAP; /* guarantee non-zero */
browse_map(which_subset, "anything of interest");
u.uinwater = iflags.save_uinwater, u.uburied = iflags.save_uburied;
iflags.save_uinwater = iflags.save_uburied = 0;
if (save_swallowed)
u.uswallow = 1;
reconstrain_map();
docrt(); /* redraw the screen, restoring regular map */
if (Underwater)
under_water(2);
+3 -3
View File
@@ -209,7 +209,7 @@ int x, y;
return FALSE;
} else if (Is_waterlevel(&u.uz)) {
if (verbose)
pline_The("water splashes and subsides.");
pline_The("%s splashes and subsides.", hliquid("water"));
return FALSE;
} else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR
&& (levl[x][y].wall_info & W_NONDIGGABLE) != 0)
@@ -735,7 +735,7 @@ const char *fillmsg;
unearth_objs(x, y);
if (fillmsg)
pline(fillmsg, typ == LAVAPOOL ? "lava" : "water");
pline(fillmsg, hliquid(typ == LAVAPOOL ? "lava" : "water"));
if (u_spot && !(Levitation || Flying)) {
if (typ == LAVAPOOL)
(void) lava_effects();
@@ -780,7 +780,7 @@ coord *cc;
} else if (is_pool_or_lava(dig_x, dig_y)) {
pline_The("%s sloshes furiously for a moment, then subsides.",
is_lava(dig_x, dig_y) ? "lava" : "water");
hliquid(is_lava(dig_x, dig_y) ? "lava" : "water"));
wake_nearby(); /* splashing */
} else if (lev->typ == DRAWBRIDGE_DOWN
+23 -10
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 do.c $NHDT-Date: 1454033599 2016/01/29 02:13:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.153 $ */
/* NetHack 3.6 do.c $NHDT-Date: 1464487100 2016/05/29 01:58:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.156 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -103,7 +103,8 @@ boolean pushing;
You("find yourself on dry land again!");
} else if (lava && distu(rx, ry) <= 2) {
int dmg;
You("are hit by molten lava%c", Fire_resistance ? '.' : '!');
You("are hit by molten %s%c",
hliquid("lava"), Fire_resistance ? '.' : '!');
burn_away_slime();
dmg = d((Fire_resistance ? 1 : 3), 6);
losehp(Maybe_Half_Phys(dmg), /* lava damage */
@@ -379,18 +380,21 @@ register struct obj *obj;
You_hear("loud noises coming from the drain.");
break;
case RIN_SUSTAIN_ABILITY: /* KMH */
pline_The("water flow seems fixed.");
pline_The("%s flow seems fixed.", hliquid("water"));
break;
case RIN_GAIN_STRENGTH:
pline_The("water flow seems %ser now.",
pline_The("%s flow seems %ser now.",
hliquid("water"),
(obj->spe < 0) ? "weak" : "strong");
break;
case RIN_GAIN_CONSTITUTION:
pline_The("water flow seems %ser now.",
pline_The("%s flow seems %ser now.",
hliquid("water"),
(obj->spe < 0) ? "less" : "great");
break;
case RIN_INCREASE_ACCURACY: /* KMH */
pline_The("water flow %s the drain.",
pline_The("%s flow %s the drain.",
hliquid("water"),
(obj->spe < 0) ? "misses" : "hits");
break;
case RIN_INCREASE_DAMAGE:
@@ -456,10 +460,12 @@ register struct obj *obj;
pline_The("sink seems to blend into the floor for a moment.");
break;
case RIN_FIRE_RESISTANCE:
pline_The("hot water faucet flashes brightly for a moment.");
pline_The("hot %s faucet flashes brightly for a moment.",
hliquid("water"));
break;
case RIN_COLD_RESISTANCE:
pline_The("cold water faucet flashes brightly for a moment.");
pline_The("cold %s faucet flashes brightly for a moment.",
hliquid("water"));
break;
case RIN_PROTECTION_FROM_SHAPE_CHAN:
pline_The("sink looks nothing like a fountain.");
@@ -1532,13 +1538,20 @@ boolean at_stairs, falling, portal;
save_currentstate();
#endif
if ((annotation = get_annotation(&u.uz)))
if ((annotation = get_annotation(&u.uz)) != 0)
You("remember this level as %s.", annotation);
/* assume this will always return TRUE when changing level */
(void) in_out_region(u.ux, u.uy);
(void) pickup(1);
context.polearm.hitmon = NULL;
/* discard context which applied to previous level */
maybe_reset_pick(); /* for door or for box not accompanying hero */
reset_trapset(); /* even if to-be-armed trap obj is accompanying hero */
iflags.travelcc.x = iflags.travelcc.y = -1; /* travel destination cache */
context.polearm.hitmon = (struct monst *) 0; /* polearm target */
/* digging context is level-aware and can actually be resumed if
hero returns to the previous level without any intervening dig */
}
STATIC_OVL void
+154 -109
View File
@@ -8,6 +8,7 @@ STATIC_DCL char *NDECL(nextmbuf);
STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *));
STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *,
const void *));
STATIC_DCL boolean FDECL(gather_locs_interesting, (int, int, int));
STATIC_DCL void FDECL(gather_locs, (coord **, int *, int));
STATIC_DCL void FDECL(auto_describe, (int, int));
STATIC_DCL void NDECL(do_mname);
@@ -63,8 +64,15 @@ const char *goal;
putstr(tmpwin, 0, "Use m or M to move the cursor to next monster.");
if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0)
putstr(tmpwin, 0, "Use o or O to move the cursor to next object.");
if (!iflags.terrainmode || (iflags.terrainmode & TER_MAP) != 0) {
/* both of these are primarily useful when choosing a travel
destination for the '_' command */
putstr(tmpwin, 0,
"Use d or D to move the cursor to next door or doorway.");
putstr(tmpwin, 0,
"Use x or X to move the cursor to unexplored location.");
}
if (!iflags.terrainmode) {
putstr(tmpwin, 0, "Use d or D to move the cursor to next door or doorway.");
if (getpos_hilitefunc)
putstr(tmpwin, 0, "Use $ to display valid locations.");
putstr(tmpwin, 0, "Use # to toggle automatic description.");
@@ -121,28 +129,63 @@ const void *b;
return dist_1 - dist_2;
}
#define GLOC_MONS 0
#define GLOC_OBJS 1
#define GLOC_DOOR 2
enum gloctypes {
GLOC_MONS = 0,
GLOC_OBJS,
GLOC_DOOR,
GLOC_EXPLORE,
boolean
gather_locs_glyphmatch(glyph, gloc)
int glyph, gloc;
NUM_GLOCS
};
#define IS_UNEXPLORED_LOC(x,y) \
(isok((x), (y)) \
&& glyph_is_cmap(levl[(x)][(y)].glyph) \
&& glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \
&& !levl[(x)][(y)].seenv)
STATIC_OVL boolean
gather_locs_interesting(x,y, gloc)
int x,y, gloc;
{
/* TODO: if glyph is a pile glyph, convert to ordinary one
* in order to keep tail/boulder/rock check simple.
*/
int glyph = glyph_at(x, y);
switch (gloc) {
default:
case GLOC_MONS: return (glyph_is_monster(glyph)
&& glyph != monnum_to_glyph(PM_LONG_WORM_TAIL));
case GLOC_OBJS: return (glyph_is_object(glyph)
&& glyph != objnum_to_glyph(BOULDER)
&& glyph != objnum_to_glyph(ROCK));
case GLOC_DOOR: return (glyph_is_cmap(glyph)
&& ((glyph_to_cmap(glyph) == S_hcdoor)
|| (glyph_to_cmap(glyph) == S_vcdoor)
|| (glyph_to_cmap(glyph) == S_hodoor)
|| (glyph_to_cmap(glyph) == S_vodoor)
|| (glyph_to_cmap(glyph) == S_ndoor)));
case GLOC_MONS:
/* unlike '/M', this skips monsters revealed by
warning glyphs and remembered unseen ones */
return (glyph_is_monster(glyph)
&& glyph != monnum_to_glyph(PM_LONG_WORM_TAIL));
case GLOC_OBJS:
return (glyph_is_object(glyph)
&& glyph != objnum_to_glyph(BOULDER)
&& glyph != objnum_to_glyph(ROCK));
case GLOC_DOOR:
return (glyph_is_cmap(glyph)
&& (is_cmap_door(glyph_to_cmap(glyph))
|| is_cmap_drawbridge(glyph_to_cmap(glyph))
|| glyph_to_cmap(glyph) == S_ndoor));
case GLOC_EXPLORE:
return (glyph_is_cmap(glyph)
&& (is_cmap_door(glyph_to_cmap(glyph))
|| is_cmap_drawbridge(glyph_to_cmap(glyph))
|| glyph_to_cmap(glyph) == S_ndoor
|| glyph_to_cmap(glyph) == S_room
|| glyph_to_cmap(glyph) == S_darkroom
|| glyph_to_cmap(glyph) == S_corr
|| glyph_to_cmap(glyph) == S_litcorr)
&& (IS_UNEXPLORED_LOC(x + 1, y)
|| IS_UNEXPLORED_LOC(x - 1, y)
|| IS_UNEXPLORED_LOC(x, y + 1)
|| IS_UNEXPLORED_LOC(x, y - 1)));
}
/*NOTREACHED*/
return FALSE;
}
/* gather locations for monsters or objects shown on the map */
@@ -152,7 +195,7 @@ coord **arr_p;
int *cnt_p;
int gloc;
{
int x, y, pass, glyph, idx;
int x, y, pass, idx;
/*
* We always include the hero's location even if there is no monster
@@ -169,14 +212,8 @@ int gloc;
for (pass = 0; pass < 2; pass++) {
for (x = 1; x < COLNO; x++)
for (y = 0; y < ROWNO; y++) {
/* TODO: if glyph is a pile glyph, convert to ordinary one
* in order to keep tail/boulder/rock check simple.
*/
glyph = glyph_at(x, y);
/* unlike '/M', this skips monsters revealed by
warning glyphs and remembered invisible ones */
if ((x == u.ux && y == u.uy)
|| gather_locs_glyphmatch(glyph, gloc)) {
|| gather_locs_interesting(x, y, gloc)) {
if (!pass) {
++*cnt_p;
} else {
@@ -291,18 +328,18 @@ coord *ccp;
boolean force;
const char *goal;
{
static const char pick_chars[] = ".,;:",
mMoOdDxX[] = "mMoOdDxX";
const char *cp;
int result = 0;
int cx, cy, i, c;
int sidx, tx, ty;
boolean msg_given = TRUE; /* clear message window by default */
boolean show_goal_msg = FALSE;
static const char pick_chars[] = ".,;:";
const char *cp;
boolean hilite_state = FALSE;
coord *monarr = (coord *) 0, *objarr = (coord *) 0,
*doorarr = (coord *) 0;
int moncount = 0, monidx = 0, objcount = 0, objidx = 0,
doorcount = 0, dooridx = 0;
coord *garr[NUM_GLOCS] = DUMMY;
int gcount[NUM_GLOCS] = DUMMY;
int gidx[NUM_GLOCS] = DUMMY;
if (!goal)
goal = "desired location";
@@ -412,6 +449,10 @@ const char *goal;
}
goto nxtc;
} else if (c == '#') {
/* unfortunately, using '#' as a command means we can't move
cursor to sinks, iron bars, and poison clouds; perhaps
when autodescribe is already on, next '#' should try to
move to '#' rather than to toggle off? (or ask; ick...) */
iflags.autodescribe = !iflags.autodescribe;
pline("Automatic description %sis %s.",
flags.verbose ? "of features under cursor " : "",
@@ -421,53 +462,30 @@ const char *goal;
msg_given = TRUE;
goto nxtc;
} else if (c == '@') { /* return to hero's spot */
/* reset 'm','M' and 'o','O'; otherwise, there's no way for player
/* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
to achieve that except by manually cycling through all spots */
monidx = objidx = dooridx = 0;
for (i = 0; i < NUM_GLOCS; i++)
gidx[i] = 0;
cx = u.ux;
cy = u.uy;
goto nxtc;
} else if (c == 'm' || c == 'M') { /* nearest or farthest monster */
if (!monarr) {
gather_locs(&monarr, &moncount, GLOC_MONS);
monidx = 0; /* monarr[0] is hero's spot */
} else if ((cp = index(mMoOdDxX, c)) != 0) { /* 'm|M', 'o|O', &c */
/* nearest or farthest monster or object or door or unexplored */
int gtmp = (int) (cp - mMoOdDxX), /* 0..7 */
gloc = gtmp >> 1; /* 0..3 */
if (!garr[gloc]) {
gather_locs(&garr[gloc], &gcount[gloc], gloc);
gidx[gloc] = 0; /* garr[][0] is hero's spot */
}
if (c == 'm') {
monidx = (monidx + 1) % moncount;
} else {
if (--monidx < 0)
monidx = moncount - 1;
if (!(gtmp & 1)) { /* c=='m' || c=='o' || c=='d' || c=='x') */
gidx[gloc] = (gidx[gloc] + 1) % gcount[gloc];
} else { /* c=='M' || c=='O' || c=='D' || c=='X') */
if (--gidx[gloc] < 0)
gidx[gloc] = gcount[gloc] - 1;
}
cx = monarr[monidx].x;
cy = monarr[monidx].y;
goto nxtc;
} else if (c == 'o' || c == 'O') { /* nearest or farthest object */
if (!objarr) {
gather_locs(&objarr, &objcount, GLOC_OBJS);
objidx = 0; /* objarr[0] is hero's spot */
}
if (c == 'o') {
objidx = (objidx + 1) % objcount;
} else {
if (--objidx < 0)
objidx = objcount - 1;
}
cx = objarr[objidx].x;
cy = objarr[objidx].y;
goto nxtc;
} else if (c == 'd' || c == 'D') { /* door/doorway */
if (!doorarr) {
gather_locs(&doorarr, &doorcount, GLOC_DOOR);
dooridx = 0; /* objarr[0] is hero's spot */
}
if (c == 'd') {
dooridx = (dooridx + 1) % doorcount;
} else {
if (--dooridx < 0)
dooridx = doorcount - 1;
}
cx = doorarr[dooridx].x;
cy = doorarr[dooridx].y;
cx = garr[gloc][gidx[gloc]].x;
cy = garr[gloc][gidx[gloc]].y;
goto nxtc;
} else {
if (!index(quitchars, c)) {
@@ -475,9 +493,17 @@ const char *goal;
int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
(void) memset((genericptr_t) matching, 0, sizeof matching);
for (sidx = 1; sidx < MAXPCHARS; sidx++)
for (sidx = 1; sidx < MAXPCHARS; sidx++) { /* [0] left as 0 */
if (IS_DOOR(sidx) || IS_WALL(sidx)
|| sidx == SDOOR || sidx == SCORR
|| glyph_to_cmap(k) == S_room
|| glyph_to_cmap(k) == S_darkroom
|| glyph_to_cmap(k) == S_corr
|| glyph_to_cmap(k) == S_litcorr)
continue;
if (c == defsyms[sidx].sym || c == (int) showsyms[sidx])
matching[sidx] = (char) ++k;
}
if (k) {
for (pass = 0; pass <= 1; pass++) {
/* pass 0: just past current pos to lower right;
@@ -488,35 +514,39 @@ const char *goal;
lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
for (tx = lo_x; tx <= hi_x; tx++) {
/* look at dungeon feature, not at
user-visible glyph */
k = back_to_glyph(tx, ty);
/* uninteresting background glyph */
/* first, look at what is currently visible
(might be monster) */
k = glyph_at(tx, ty);
if (glyph_is_cmap(k)
&& (IS_DOOR(levl[tx][ty].typ)
|| glyph_to_cmap(k) == S_room
|| glyph_to_cmap(k) == S_darkroom
|| glyph_to_cmap(k) == S_corr
|| glyph_to_cmap(k) == S_litcorr)) {
/* what hero remembers to be at tx,ty */
k = glyph_at(tx, ty);
&& matching[glyph_to_cmap(k)])
goto foundc;
/* next, try glyph that's remembered here
(might be trap or object) */
if (level.flags.hero_memory
/* !terrainmode: don't move to remembered
trap or object if not currently shown */
&& !iflags.terrainmode) {
k = levl[tx][ty].glyph;
if (glyph_is_cmap(k)
&& matching[glyph_to_cmap(k)])
goto foundc;
}
if (glyph_is_cmap(k)
&& matching[glyph_to_cmap(k)]
&& (levl[tx][ty].seenv
|| iflags.terrainmode)
&& !IS_WALL(levl[tx][ty].typ)
&& levl[tx][ty].typ != SDOOR
&& glyph_to_cmap(k) != S_room
&& glyph_to_cmap(k) != S_corr
&& glyph_to_cmap(k) != S_litcorr) {
cx = tx, cy = ty;
if (msg_given) {
clear_nhwindow(WIN_MESSAGE);
msg_given = FALSE;
}
goto nxtc;
/* last, try actual terrain here (shouldn't
we be using lastseentyp[][] instead?) */
if (levl[tx][ty].seenv) {
k = back_to_glyph(tx, ty);
if (glyph_is_cmap(k)
&& matching[glyph_to_cmap(k)])
goto foundc;
}
continue;
foundc:
cx = tx, cy = ty;
if (msg_given) {
clear_nhwindow(WIN_MESSAGE);
msg_given = FALSE;
}
goto nxtc;
} /* column */
} /* row */
} /* pass */
@@ -539,10 +569,8 @@ const char *goal;
} /* !quitchars */
if (force)
goto nxtc;
if (!iflags.terrainmode) {
pline("Done.");
msg_given = FALSE; /* suppress clear */
}
pline("Done.");
msg_given = FALSE; /* suppress clear */
cx = -1;
cy = 0;
result = 0; /* not -1 */
@@ -563,10 +591,9 @@ const char *goal;
clear_nhwindow(WIN_MESSAGE);
ccp->x = cx;
ccp->y = cy;
if (monarr)
free((genericptr_t) monarr);
if (objarr)
free((genericptr_t) objarr);
for (i = 0; i < NUM_GLOCS; i++)
if (garr[i])
free((genericptr_t) garr[i]);
getpos_hilitefunc = (void FDECL((*), (int))) 0;
return result;
}
@@ -1564,6 +1591,24 @@ rndcolor()
: c_obj_colors[k];
}
static NEARDATA const char *const hliquids[] = {
"yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
"instant coffee", "tea", "herbal infusion", "liquid rainbow",
"creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
"ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
"caramel sauce", "ink", "aqueous humour", "milk substitute", "fruit juice",
"glowing lava", "gastric acid", "mineral water", "cough syrup", "quicksilver",
"sweet vitriol", "grey goo", "pink slime",
};
const char *
hliquid(liquidpref)
const char *liquidpref;
{
return (Hallucination || !liquidpref) ? hliquids[rn2(SIZE(hliquids))]
: liquidpref;
}
/* Aliases for road-runner nemesis
*/
static const char *const coynames[] = {
@@ -1586,7 +1631,7 @@ char *buf;
Sprintf(buf, "%s - %s",
x_monnam(mtmp, ARTICLE_NONE, (char *) 0, 0, TRUE),
mtmp->mcan ? coynames[SIZE(coynames) - 1]
: coynames[rn2(SIZE(coynames) - 1)]);
: coynames[mtmp->m_id % (SIZE(coynames) - 1)]);
}
return buf;
}
+2 -1
View File
@@ -773,7 +773,8 @@ Amulet_off()
setworn((struct obj *) 0, W_AMUL);
if (!breathless(youmonst.data) && !amphibious(youmonst.data)
&& !Swimming) {
You("suddenly inhale an unhealthy amount of water!");
You("suddenly inhale an unhealthy amount of %s!",
hliquid("water"));
(void) drown();
}
return;
+304 -16
View File
@@ -11,6 +11,10 @@ extern boolean notonhead;
STATIC_DCL boolean FDECL(dog_hunger, (struct monst *, struct edog *));
STATIC_DCL int FDECL(dog_invent, (struct monst *, struct edog *, int));
STATIC_DCL int FDECL(dog_goal, (struct monst *, struct edog *, int, int, int));
STATIC_DCL struct monst *FDECL(find_targ, (struct monst *, int, int, int));
STATIC_OVL int FDECL(find_friends, (struct monst *, struct monst *, int));
STATIC_DCL struct monst *FDECL(best_target, (struct monst *));
STATIC_DCL long FDECL(score_targ, (struct monst *, struct monst *));
STATIC_DCL boolean FDECL(can_reach_location, (struct monst *, XCHAR_P,
XCHAR_P, XCHAR_P, XCHAR_P));
STATIC_DCL boolean FDECL(could_reach_item, (struct monst *, XCHAR_P, XCHAR_P));
@@ -280,8 +284,8 @@ boolean devour;
Strcpy(objnambuf, xname(obj));
iflags.suppress_price--;
}
/* It's a reward if it's DOGFOOD and the player dropped/threw it. */
/* We know the player had it if invlet is set -dlc */
/* It's a reward if it's DOGFOOD and the player dropped/threw it.
We know the player had it if invlet is set. -dlc */
if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet)
#ifdef LINT
edog->apport = 0;
@@ -347,8 +351,8 @@ boolean devour;
/* hunger effects -- returns TRUE on starvation */
STATIC_OVL boolean
dog_hunger(mtmp, edog)
register struct monst *mtmp;
register struct edog *edog;
struct monst *mtmp;
struct edog *edog;
{
if (monstermoves > edog->hungrytime + 500) {
if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
@@ -419,7 +423,8 @@ int udist;
edog->droptime = monstermoves;
}
} else {
if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass)
if ((obj = level.objects[omx][omy]) != 0
&& !index(nofetch, obj->oclass)
#ifdef MAIL
&& obj->otyp != SCR_MAIL
#endif
@@ -557,16 +562,12 @@ int after, udist, whappr;
appr = 1;
}
/* if you have dog food it'll follow you more closely */
if (appr == 0) {
obj = invent;
while (obj) {
if (appr == 0)
for (obj = invent; obj; obj = obj->nobj)
if (dogfood(mtmp, obj) == DOGFOOD) {
appr = 1;
break;
}
obj = obj->nobj;
}
}
} else
appr = 1; /* gtyp != UNDEF */
if (mtmp->mconf)
@@ -585,7 +586,7 @@ int after, udist, whappr;
} else {
/* assume master hasn't moved far, and reuse previous goal */
if (edog && edog->ogoal.x
&& ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
&& (edog->ogoal.x != omx || edog->ogoal.y != omy)) {
gx = edog->ogoal.x;
gy = edog->ogoal.y;
edog->ogoal.x = 0;
@@ -610,6 +611,236 @@ int after, udist, whappr;
return appr;
}
STATIC_OVL struct monst *
find_targ(mtmp, dx, dy, maxdist)
register struct monst *mtmp;
int dx, dy;
int maxdist;
{
struct monst *targ = 0;
int curx = mtmp->mx, cury = mtmp->my;
int dist = 0;
/* Walk outwards */
for ( ; dist < maxdist; ++dist) {
curx += dx;
cury += dy;
if (!isok(curx, cury))
break;
/* FIXME: Check if we hit a wall/door/boulder to
* short-circuit unnecessary subsequent checks
*/
/* If we can't see up to here, forget it - will this
* mean pets in corridors don't breathe at monsters
* in rooms? If so, is that necessarily bad?
*/
if (!m_cansee(mtmp, curx, cury))
break;
targ = m_at(curx, cury);
if (curx == mtmp->mux && cury == mtmp->muy)
return &youmonst;
if (targ) {
/* Is the monster visible to the pet? */
if ((!targ->minvis || perceives(mtmp->data)) &&
!targ->mundetected)
break;
/* If the pet can't see it, it assumes it aint there */
targ = 0;
}
}
return targ;
}
STATIC_OVL int
find_friends(mtmp, mtarg, maxdist)
struct monst *mtmp, *mtarg;
int maxdist;
{
struct monst *pal;
int dx = sgn(mtarg->mx - mtmp->mx),
dy = sgn(mtarg->my - mtmp->my);
int curx = mtarg->mx, cury = mtarg->my;
int dist = distmin(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my);
for ( ; dist <= maxdist; ++dist) {
curx += dx;
cury += dy;
if (!isok(curx, cury))
return 0;
/* If the pet can't see beyond this point, don't
* check any farther
*/
if (!m_cansee(mtmp, curx, cury))
return 0;
/* Does pet think you're here? */
if (mtmp->mux == curx && mtmp->muy == cury)
return 1;
pal = m_at(curx, cury);
if (pal) {
if (pal->mtame) {
/* Pet won't notice invisible pets */
if (!pal->minvis || perceives(mtmp->data))
return 1;
} else {
/* Quest leaders and guardians are always seen */
if (pal->data->msound == MS_LEADER
|| pal->data->msound == MS_GUARDIAN)
return 1;
}
}
}
return 0;
}
STATIC_OVL long
score_targ(mtmp, mtarg)
struct monst *mtmp, *mtarg;
{
long score = 0L;
/* If the monster is confused, normal scoring is disrupted -
* anything may happen
*/
/* Give 1 in 3 chance of safe breathing even if pet is confused or
* if you're on the quest start level */
if (!mtmp->mconf || !rn2(3) || Is_qstart(&u.uz)) {
aligntyp align1 = A_NONE, align2 = A_NONE; /* For priests, minions */
boolean faith1 = TRUE, faith2 = TRUE;
if (mtmp->isminion)
align1 = EMIN(mtmp)->min_align;
else if (mtmp->ispriest)
align1 = EPRI(mtmp)->shralign;
else
faith1 = FALSE;
if (mtarg->isminion)
align2 = EMIN(mtarg)->min_align; /* MAR */
else if (mtarg->ispriest)
align2 = EPRI(mtarg)->shralign; /* MAR */
else
faith2 = FALSE;
/* Never target quest friendlies */
if (mtarg->data->msound == MS_LEADER
|| mtarg->data->msound == MS_GUARDIAN)
return -5000L;
/* D: Fixed angelic beings using gaze attacks on coaligned priests */
if (faith1 && faith2 && align1 == align2 && mtarg->mpeaceful) {
score -= 5000L;
return score;
}
/* Is monster adjacent? */
if (distmin(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) <= 1) {
score -= 3000L;
return score;
}
/* Is the monster peaceful or tame? */
if (/*mtarg->mpeaceful ||*/ mtarg->mtame || mtarg == &youmonst) {
/* Pets will never be targeted */
score -= 3000L;
return score;
}
/* Is master/pet behind monster? Check up to 15 squares beyond pet. */
if (find_friends(mtmp, mtarg, 15)) {
score -= 3000L;
return score;
}
/* Target hostile monsters in preference to peaceful ones */
if (!mtarg->mpeaceful)
score += 10;
/* Is the monster passive? Don't waste energy on it, if so */
if (mtarg->data->mattk[0].aatyp == AT_NONE)
score -= 1000;
/* Even weak pets with breath attacks shouldn't take on very
low-level monsters. Wasting breath on lichens is ridiculous. */
if ((mtarg->m_lev < 2 && mtmp->m_lev > 5)
|| (mtmp->m_lev > 12 && mtarg->m_lev < mtmp->m_lev - 9
&& u.ulevel > 8 && mtarg->m_lev < u.ulevel - 7))
score -= 25;
/* And pets will hesitate to attack vastly stronger foes.
This penalty will be discarded if master's in trouble. */
if (mtarg->m_lev > mtmp->m_lev + 4L)
score -= (mtarg->m_lev - mtmp->m_lev) * 20L;
/* All things being the same, go for the beefiest monster. This
bonus should not be large enough to override the pet's aversion
to attacking much stronger monsters. */
score += mtarg->m_lev * 2 + mtarg->mhp / 3;
}
/* Fuzz factor to make things less predictable when very
similar targets are abundant. */
score += rnd(5);
/* Pet may decide not to use ranged attack when confused */
if (mtmp->mconf && !rn2(3))
score -= 1000;
return score;
}
STATIC_OVL struct monst *
best_target(mtmp)
struct monst *mtmp; /* Pet */
{
int dx, dy;
long bestscore = -40000L, currscore;
struct monst *best_targ = 0, *temp_targ = 0;
/* Help! */
if (!mtmp)
return 0;
/* If the pet is blind, it's not going to see any target */
if (!mtmp->mcansee)
return 0;
/* Search for any monsters lined up with the pet, within an arbitrary
* distance from the pet (7 squares, even along diagonals). Monsters
* are assigned scores and the best score is chosen.
*/
for (dy = -1; dy < 2; ++dy) {
for (dx = -1; dx < 2; ++dx) {
if (!dx && !dy)
continue;
/* Traverse the line to find the first monster within 7
* squares. Invisible monsters are skipped (if the
* pet doesn't have see invisible).
*/
temp_targ = find_targ(mtmp, dx, dy, 7);
/* Nothing in this line? */
if (!temp_targ)
continue;
/* Decide how attractive the target is */
currscore = score_targ(mtmp, temp_targ);
if (currscore > bestscore) {
bestscore = currscore;
best_targ = temp_targ;
}
}
}
/* Filter out targets the pet doesn't like */
if (bestscore < 0L)
best_targ = 0;
return best_targ;
}
/* return 0 (no move), 1 (move) or 2 (dead) */
int
dog_move(mtmp, after)
@@ -872,6 +1103,63 @@ int after; /* this is extra fast monster movement */
nxti:
;
}
/* Pet hasn't attacked anything but is considering moving -
* now's the time for ranged attacks. Note that the pet can move
* after it performs its ranged attack. Should this be changed?
*/
{
struct monst *mtarg;
int hungry = 0;
/* How hungry is the pet? */
if (!mtmp->isminion) {
struct edog *dog = EDOG(mtmp);
hungry = (monstermoves > (dog->hungrytime + 300));
}
/* Identify the best target in a straight line from the pet;
* if there is such a target, we'll let the pet attempt an
* attack.
*/
mtarg = best_target(mtmp);
/* Hungry pets are unlikely to use breath/spit attacks */
if (mtarg && (!hungry || !rn2(5))) {
int mstatus;
if (mtarg == &youmonst) {
if (mattacku(mtmp))
return 2;
} else {
mstatus = mattackm(mtmp, mtarg);
/* Shouldn't happen, really */
if (mstatus & MM_AGR_DIED)
return 2;
/* Allow the targeted nasty to strike back - if
* the targeted beast doesn't have a ranged attack,
* nothing will happen.
*/
if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)
&& rn2(4) && mtarg != &youmonst) {
/* Can monster see? If it can, it can retaliate
* even if the pet is invisible, since it'll see
* the direction from which the ranged attack came;
* if it's blind or unseeing, it can't retaliate
*/
if (mtarg->mcansee && haseyes(mtarg->data)) {
mstatus = mattackm(mtarg, mtmp);
if (mstatus & MM_DEF_DIED)
return 2;
}
}
}
}
}
newdogpos:
if (nix != omx || niy != omy) {
boolean wasseen;
@@ -898,7 +1186,7 @@ newdogpos:
/* describe top item of pile, not necessarily cursed item itself;
don't use glyph_at() here--it would return the pet but we want
to know whether an object is remembered at this map location */
struct obj *o = (!Hallucination
struct obj *o = (!Hallucination && level.flags.hero_memory
&& glyph_is_object(levl[nix][niy].glyph))
? vobj_at(nix, niy) : 0;
const char *what = o ? distant_name(o, doname) : something;
@@ -1016,12 +1304,12 @@ wantdoor(x, y, distance)
int x, y;
genericptr_t distance;
{
int ndist;
int ndist, *dist_ptr = (int *) distance;
if (*(int *) distance > (ndist = distu(x, y))) {
if (*dist_ptr > (ndist = distu(x, y))) {
gx = x;
gy = y;
*(int *) distance = ndist;
*dist_ptr = ndist;
}
}
+1 -1
View File
@@ -947,7 +947,7 @@ dokick()
}
if (is_pool(x, y) ^ !!u.uinwater) {
/* objects normally can't be removed from water by kicking */
You("splash some water around.");
You("splash some %s around.", hliquid("water"));
return 1;
}
+8 -2
View File
@@ -544,9 +544,15 @@ int x, y;
}
if (!Passes_walls || !(may_pass = may_passwall(x, y))) {
if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
boolean odoor_diag = (IS_DOOR(levl[x][y].typ)
&& (levl[x][y].doormask & D_ISOPEN)
&& (u.ux - x) && (u.uy - y));
if (IS_ROCK(levl[x][y].typ) || closed_door(x, y) || odoor_diag) {
const char *s;
if (odoor_diag)
You("hit the door edge!");
pline("Ouch!");
if (IS_TREE(levl[x][y].typ))
s = "bumping into a tree";
@@ -729,7 +735,7 @@ boolean verbose;
u.utraptype == TT_WEB
? "web"
: u.utraptype == TT_LAVA
? "lava"
? hliquid("lava")
: u.utraptype == TT_INFLOOR
? surface(u.ux, u.uy)
: u.utraptype == TT_BURIEDBALL ? "buried ball"
+1 -1
View File
@@ -169,7 +169,7 @@ const struct symdef defsyms[MAXPCHARS] = {
{ '|', "grave", C(CLR_GRAY) }, /* grave */
{ '\\', "opulent throne", C(HI_GOLD) }, /* throne */
/*30*/ { '#', "sink", C(CLR_GRAY) }, /* sink */
{ '{', "fountain", C(CLR_BLUE) }, /* fountain */
{ '{', "fountain", C(CLR_BRIGHT_BLUE) }, /* fountain */
{ '}', "water", C(CLR_BLUE) }, /* pool */
{ '.', "ice", C(CLR_CYAN) }, /* ice */
{ '}', "molten lava", C(CLR_RED) }, /* lava */
+36 -10
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 eat.c $NHDT-Date: 1454715969 2016/02/05 23:46:09 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.163 $ */
/* NetHack 3.6 eat.c $NHDT-Date: 1466289475 2016/06/18 22:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.169 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -619,7 +619,9 @@ boolean allowmsg;
and also shouldn't eat current species when polymorphed
(even if having the form of something which doesn't care
about cannibalism--hero's innate traits aren't altered) */
&& (your_race(fptr) || (Upolyd && same_race(youmonst.data, fptr)))) {
&& (your_race(fptr)
|| (Upolyd && same_race(youmonst.data, fptr))
|| (u.ulycn >= LOW_PM && were_beastie(pm) == u.ulycn))) {
if (allowmsg) {
if (Upolyd && your_race(fptr))
You("have a bad feeling deep inside.");
@@ -2012,12 +2014,23 @@ eatspecial()
vault_gd_watching(GD_EATGOLD);
return;
}
if (objects[otmp->otyp].oc_material == PAPER) {
#ifdef MAIL
if (otmp->otyp == SCR_MAIL) {
/* no nutrition */
pline("This junk mail is less than satisfying.");
}
if (otmp->otyp == SCR_MAIL)
/* no nutrition */
pline("This junk mail is less than satisfying.");
else
#endif
if (otmp->otyp == SCR_SCARE_MONSTER)
/* to eat scroll, hero is currently polymorphed into a monster */
pline("Yuck%c", otmp->blessed ? '!' : '.');
else if (otmp->oclass == SCROLL_CLASS
/* check description after checking for specific scrolls */
&& !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM"))
pline("Yum%c", otmp->blessed ? '!' : '.');
else
pline("Needs salt...");
}
if (otmp->oclass == POTION_CLASS) {
otmp->quan++; /* dopotion() does a useup() */
(void) dopotion(otmp);
@@ -2451,8 +2464,11 @@ doeat()
u.uconduct.unvegan++;
u.uconduct.food++;
if (otmp->cursed)
if (otmp->cursed) {
(void) rottenfood(otmp);
nodelicious = TRUE;
} else if (objects[otmp->otyp].oc_material == PAPER)
nodelicious = TRUE;
if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
pline("Ecch - that must have been poisonous!");
@@ -2461,7 +2477,7 @@ doeat()
losehp(rnd(15), xname(otmp), KILLED_BY_AN);
} else
You("seem unaffected by the poison.");
} else if (!otmp->cursed && !nodelicious) {
} else if (!nodelicious) {
pline("%s%s is delicious!",
(obj_is_pname(otmp)
&& otmp->oartifact < ART_ORB_OF_DETECTION)
@@ -3009,6 +3025,16 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
char qsfx[QBUFSZ];
boolean one = (otmp->quan == 1L);
/* if blind and without gloves, attempting to eat (or tin or
offer) a cockatrice corpse is fatal before asking whether
or not to use it; otherwise, 'm<dir>' followed by 'e' could
be used to locate cockatrice corpses without touching them */
if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) {
feel_cockatrice(otmp, FALSE);
/* if life-saved (or poly'd into stone golem), terminate
attempt to eat off floor */
return (struct obj *) 0;
}
/* "There is <an object> here; <verb> it?" or
"There are <N objects> here; <verb> one?" */
Sprintf(qbuf, "There %s ", otense(otmp, "are"));
@@ -3026,8 +3052,8 @@ skipfloor:
/* We cannot use ALL_CLASSES since that causes getobj() to skip its
* "ugly checks" and we need to check for inedible items.
*/
otmp =
getobj(feeding ? allobj : offering ? offerfodder : comestibles, verb);
otmp = getobj(feeding ? allobj : offering ? offerfodder : comestibles,
verb);
if (corpsecheck && otmp && !(offering && otmp->oclass == AMULET_CLASS))
if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
You_cant("%s that!", verb);
+3 -1
View File
@@ -781,6 +781,8 @@ int how;
u.ugrave_arise = NON_PM;
HUnchanging = 0L;
curs_on_u();
if (!context.mon_moving)
endmultishot(FALSE);
}
/*
@@ -1678,7 +1680,7 @@ boolean ask;
pfx = !strncmpi(buf, "the ", 3) ? 0
: !strncmpi(buf, "an ", 3) ? 1
: !strncmpi(buf, "a ", 2) ? 2
: !isdigit(buf[2]) ? 4 : 0;
: !digit(buf[2]) ? 4 : 0;
if (class_header)
++pfx;
Sprintf(buftoo, "%*s%s", pfx, "", buf);
+3 -2
View File
@@ -185,11 +185,12 @@ register int x, y;
else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz))
return "air";
else if (is_pool(x, y))
return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water";
return (Underwater && !Is_waterlevel(&u.uz))
? "bottom" : hliquid("water");
else if (is_ice(x, y))
return "ice";
else if (is_lava(x, y))
return "lava";
return hliquid("lava");
else if (lev->typ == DRAWBRIDGE_DOWN)
return "bridge";
else if (IS_ALTAR(levl[x][y].typ))
+74 -60
View File
@@ -188,6 +188,7 @@ STATIC_DCL boolean FDECL(make_compressed_name, (const char *, char *));
#ifndef USE_FCNTL
STATIC_DCL char *FDECL(make_lockname, (const char *, char *));
#endif
STATIC_DCL void FDECL(set_configfile_name, (const char *));
STATIC_DCL FILE *FDECL(fopen_config_file, (const char *, int));
STATIC_DCL int FDECL(get_uchars, (FILE *, char *, char *, uchar *, BOOLEAN_P,
int, const char *));
@@ -1821,7 +1822,7 @@ const char *filename;
/* ---------- BEGIN CONFIG FILE HANDLING ----------- */
const char *configfile =
const char *default_configfile =
#ifdef UNIX
".nethackrc";
#else
@@ -1837,7 +1838,7 @@ const char *configfile =
#endif
/* used for messaging */
char lastconfigfile[BUFSZ];
char configfile[BUFSZ];
#ifdef MSDOS
/* conflict with speed-dial under windows
@@ -1850,6 +1851,16 @@ char lastconfigfile[BUFSZ];
const char *backward_compat_configfile = "nethack.cnf";
#endif
/* remember the name of the file we're accessing;
if may be used in option reject messages */
STATIC_OVL void
set_configfile_name(fname)
const char *fname;
{
(void) strncpy(configfile, fname, sizeof configfile - 1);
configfile[sizeof configfile - 1] = '\0';
}
#ifndef MFLOPPY
#define fopenp fopen
#endif
@@ -1865,84 +1876,86 @@ int src;
char *envp;
#endif
if (src == SET_IN_SYS) {
/* SYSCF_FILE; if we can't open it, caller will bail */
if (filename && *filename) {
set_configfile_name(fqname(filename, SYSCONFPREFIX, 0));
fp = fopenp(configfile, "r");
} else
fp = (FILE *) 0;
return fp;
}
/* If src != SET_IN_SYS, "filename" is an environment variable, so it
* should hang around. If set, it is expected to be a full path name
* (if relevant) */
if (filename) {
* (if relevant)
*/
if (filename && *filename) {
set_configfile_name(filename);
#ifdef UNIX
if ((src != SET_IN_SYS) && access(filename, 4) == -1) {
/* 4 is R_OK on newer systems */
if (access(configfile, 4) == -1) { /* 4 is R_OK on newer systems */
/* nasty sneaky attempt to read file through
* NetHack's setuid permissions -- this is the only
* place a file name may be wholly under the player's
* control (but SYSCF_FILE is not under the player's
* control so it's OK).
*/
raw_printf("Access to %s denied (%d).", filename, errno);
raw_printf("Access to %s denied (%d).", configfile, errno);
wait_synch();
/* fall through to standard names */
} else
#endif
#ifdef PREFIXES_IN_USE
if (src == SET_IN_SYS) {
(void) strncpy(lastconfigfile, fqname(filename, SYSCONFPREFIX, 0),
BUFSZ - 1);
} else
#endif
/* always honor sysconf first before anything else */
(void) strncpy(lastconfigfile, filename, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
return fp;
if ((fp = fopenp(filename, "r")) != (FILE *) 0) {
if ((fp = fopenp(configfile, "r")) != (FILE *) 0) {
return fp;
#if defined(UNIX) || defined(VMS)
} else {
/* access() above probably caught most problems for UNIX */
raw_printf("Couldn't open requested config file %s (%d).",
filename, errno);
configfile, errno);
wait_synch();
/* fall through to standard names */
#endif
}
}
/* fall through to standard names */
#if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32)
if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) != (FILE *) 0)
return fp;
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
set_configfile_name(fqname(default_configfile, CONFIGPREFIX, 0));
if ((fp = fopenp(configfile, "r")) != (FILE *) 0) {
return fp;
} else if (strcmp(default_configfile, configfile)) {
set_configfile_name(default_configfile);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
#ifdef MSDOS
if ((fp = fopenp(fqname(backward_compat_configfile, CONFIGPREFIX, 0),
"r")) != (FILE *) 0)
return fp;
if ((fp = fopenp(backward_compat_configfile, "r")) != (FILE *) 0)
set_configfile_name(fqname(backward_compat_configfile, CONFIGPREFIX, 0));
if ((fp = fopenp(configfile, "r")) != (FILE *) 0) {
return fp;
} else if (strcmp(backwad_compat_configfile, configfile)) {
set_configfile_name(backward_compat_configfile);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
#endif
#else
/* constructed full path names don't need fqname() */
#ifdef VMS
(void) strncpy(lastconfigfile, fqname("nethackini", CONFIGPREFIX, 0),
BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) {
/* no punctuation, so might be a logical name */
set_configfile_name(fqname("nethackini", CONFIGPREFIX, 0));
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
(void) strncpy(lastconfigfile, "sys$login:nethack.ini", BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0) {
set_configfile_name("sys$login:nethack.ini");
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
envp = nh_getenv("HOME");
if (!envp)
if (!envp || !*envp)
Strcpy(tmp_config, "NetHack.cnf");
else
Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(tmp_config, "r")) != (FILE *) 0)
Sprintf(tmp_config, "%s%s%s", envp,
!index(":]>/", envp[strlen(envp) - 1]) ? "/" : "",
"NetHack.cnf");
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
#else /* should be only UNIX left */
envp = nh_getenv("HOME");
@@ -1951,43 +1964,41 @@ int src;
else
Sprintf(tmp_config, "%s/%s", envp, ".nethackrc");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
#if defined(__APPLE__)
#if defined(__APPLE__) /* UNIX+__APPLE__ => MacOSX */
/* try an alternative */
if (envp) {
/* OSX-style configuration settings */
Sprintf(tmp_config, "%s/%s", envp,
"Library/Preferences/NetHack Defaults");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
/* may be easier for user to edit if filename as '.txt' suffix */
Sprintf(tmp_config, "%s/%s", envp,
"Library/Preferences/NetHack Defaults.txt");
(void) strncpy(lastconfigfile, tmp_config, BUFSZ - 1);
lastconfigfile[BUFSZ - 1] = '\0';
if ((fp = fopenp(lastconfigfile, "r")) != (FILE *) 0)
set_configfile_name(tmp_config);
if ((fp = fopenp(configfile, "r")) != (FILE *) 0)
return fp;
}
#endif
#endif /*__APPLE__*/
if (errno != ENOENT) {
const char *details;
/* e.g., problems when setuid NetHack can't search home
* directory restricted to user */
/* e.g., problems when setuid NetHack can't search home
directory restricted to user */
#if defined(NHSTDC) && !defined(NOTSTDC)
if ((details = strerror(errno)) == 0)
#endif
details = "";
raw_printf("Couldn't open default config file %s %s(%d).",
lastconfigfile, details, errno);
configfile, details, errno);
wait_synch();
}
#endif /* Unix */
#endif
#endif /* !VMS => Unix */
#endif /* !(MICRO || MAC || __BEOS__ || WIN32) */
return (FILE *) 0;
}
@@ -2252,6 +2263,9 @@ int src;
free((genericptr_t) sysopt.debugfiles);
sysopt.debugfiles = dupstr(bufp);
}
} else if (src == SET_IN_SYS && match_varname(buf, "GENERICUSERS", 12)) {
if (sysopt.genericusers) free(sysopt.genericusers);
sysopt.genericusers = dupstr(bufp);
} else if (src == SET_IN_SYS && match_varname(buf, "SUPPORT", 7)) {
if (sysopt.support)
free((genericptr_t) sysopt.support);
+19 -15
View File
@@ -337,7 +337,8 @@ drinkfountain()
{
register struct monst *mtmp;
pline("This water gives you bad breath!");
pline("This %s gives you bad breath!",
hliquid("water"));
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
@@ -349,7 +350,8 @@ drinkfountain()
dogushforth(TRUE);
break;
default:
pline("This tepid water is tasteless.");
pline("This tepid %s is tasteless.",
hliquid("water"));
break;
}
}
@@ -372,8 +374,8 @@ register struct obj *obj;
&& !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) {
if (u.ualign.type != A_LAWFUL) {
/* Ha! Trying to cheat her. */
pline(
"A freezing mist rises from the water and envelopes the sword.");
pline("A freezing mist rises from the %s and envelopes the sword.",
hliquid("water"));
pline_The("fountain disappears!");
curse(obj);
if (obj->spe > -6 && !rn2(3))
@@ -423,7 +425,7 @@ register struct obj *obj;
case 20: /* Uncurse the item */
if (obj->cursed) {
if (!Blind)
pline_The("water glows for a moment.");
pline_The("%s glows for a moment.", hliquid("water"));
uncurse(obj);
} else {
pline("A feeling of loss comes over you.");
@@ -490,7 +492,8 @@ register struct obj *obj;
+ 1) * 2) + 5),
u.ux, u.uy);
if (!Blind)
pline("Far below you, you see coins glistening in the water.");
pline("Far below you, you see coins glistening in the %s.",
hliquid("water"));
exercise(A_WIS, TRUE);
newsym(u.ux, u.uy);
break;
@@ -524,13 +527,13 @@ drinksink()
}
switch (rn2(20)) {
case 0:
You("take a sip of very cold water.");
You("take a sip of very cold %s.", hliquid("water"));
break;
case 1:
You("take a sip of very warm water.");
You("take a sip of very warm %s.", hliquid("water"));
break;
case 2:
You("take a sip of scalding hot water.");
You("take a sip of scalding hot %s.", hliquid("water"));
if (Fire_resistance)
pline("It seems quite tasty.");
else
@@ -573,19 +576,19 @@ drinksink()
exercise(A_WIS, TRUE);
newsym(u.ux, u.uy);
} else
pline("Some dirty water backs up in the drain.");
pline("Some dirty %s backs up in the drain.", hliquid("water"));
break;
case 6:
breaksink(u.ux, u.uy);
break;
case 7:
pline_The("water moves as though of its own will!");
pline_The("%s moves as though of its own will!", hliquid("water"));
if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE)
|| !makemon(&mons[PM_WATER_ELEMENTAL], u.ux, u.uy, NO_MM_FLAGS))
pline("But it quiets down.");
break;
case 8:
pline("Yuk, this water tastes awful.");
pline("Yuk, this %s tastes awful.", hliquid("water"));
more_experienced(1, 0);
newexplevel();
break;
@@ -595,7 +598,7 @@ drinksink()
vomit();
break;
case 10:
pline("This water contains toxic wastes!");
pline("This %s contains toxic wastes!", hliquid("water"));
if (!Unchanging) {
You("undergo a freakish metamorphosis!");
polyself(0);
@@ -614,8 +617,9 @@ drinksink()
break;
}
default:
You("take a sip of %s water.",
rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot");
You("take a sip of %s %s.",
rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot",
hliquid("water"));
}
}
+77 -19
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 hack.c $NHDT-Date: 1462663937 2016/05/07 23:32:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.165 $ */
/* NetHack 3.6 hack.c $NHDT-Date: 1464485934 2016/05/29 01:38:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.168 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -679,6 +679,14 @@ int mode;
feel_location(x, y);
if (Passes_walls && may_passwall(x, y)) {
; /* do nothing */
} else if (Underwater) {
/* note: if water_friction() changes direction due to
turbulence, new target destination will always be water,
so we won't get here, hence don't need to worry about
"there" being somewhere the player isn't sure of */
if (mode == DO_MOVE)
pline("There is an obstacle there.");
return FALSE;
} else if (tmpr->typ == IRONBARS) {
if ((dmgtype(youmonst.data, AD_RUST)
|| dmgtype(youmonst.data, AD_CORR)) && mode == DO_MOVE
@@ -686,7 +694,7 @@ int mode;
return FALSE;
}
if (!(Passes_walls || passes_bars(youmonst.data))) {
if (iflags.mention_walls)
if (mode == DO_MOVE && iflags.mention_walls)
You("cannot pass through the bars.");
return FALSE;
}
@@ -702,14 +710,16 @@ int mode;
return FALSE;
} else {
if (mode == DO_MOVE) {
if (Is_stronghold(&u.uz) && is_db_wall(x, y))
pline_The("drawbridge is up!");
if (is_db_wall(x, y))
pline("That drawbridge is up!");
/* sokoban restriction stays even after puzzle is solved */
else if (Passes_walls && !may_passwall(x, y)
&& In_sokoban(&u.uz))
pline_The("Sokoban walls resist your ability.");
else if (iflags.mention_walls)
pline("It's a wall.");
pline("It's %s.", IS_WALL(tmpr->typ) ? "a wall"
: IS_TREE(tmpr->typ) ? "a tree"
: "solid stone");
}
return FALSE;
}
@@ -722,6 +732,10 @@ int mode;
} else if (can_ooze(&youmonst)) {
if (mode == DO_MOVE)
You("ooze under the door.");
} else if (Underwater) {
if (mode == DO_MOVE)
pline("There is an obstacle there.");
return FALSE;
} else if (tunnels(youmonst.data) && !needspick(youmonst.data)) {
/* Eat the door. */
if (mode == DO_MOVE && still_chewing(x, y))
@@ -757,8 +771,12 @@ int mode;
if (dx && dy && !Passes_walls
&& (!doorless_door(x, y) || block_door(x, y))) {
/* Diagonal moves into a door are not allowed. */
if (Blind && mode == DO_MOVE)
feel_location(x, y);
if (mode == DO_MOVE) {
if (Blind)
feel_location(x, y);
if (Underwater || iflags.mention_walls)
You_cant("move diagonally into an intact doorway.");
}
return FALSE;
}
}
@@ -791,8 +809,7 @@ int mode;
/* Pick travel path that does not require crossing a trap.
* Avoid water and lava using the usual running rules.
* (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */
if (context.run == 8
&& (mode == TEST_MOVE || mode == TEST_TRAP)
if (context.run == 8 && (mode != DO_MOVE)
&& (x != u.ux || y != u.uy)) {
struct trap *t = t_at(x, y);
@@ -811,6 +828,8 @@ int mode;
if (dx && dy && !Passes_walls && IS_DOOR(ust->typ)
&& (!doorless_door(ux, uy) || block_entry(x, y))) {
/* Can't move at a diagonal out of a doorway with door. */
if (mode == DO_MOVE && iflags.mention_walls)
You_cant("move diagonally out of an intact doorway.");
return FALSE;
}
@@ -931,7 +950,44 @@ boolean guess;
int nx = x + xdir[ordered[dir]];
int ny = y + ydir[ordered[dir]];
if (!isok(nx, ny))
/*
* When guessing and trying to travel as close as possible
* to an unreachable target space, don't include spaces
* that would never be picked as a guessed target in the
* travel matrix describing hero-reachable spaces.
* This stops travel from getting confused and moving
* the hero back and forth in certain degenerate
* configurations of sight-blocking obstacles, e.g.
*
* T 1. Dig this out and carry enough to not be
* #### able to squeeze through diagonal gaps.
* #--.--- Stand at @ and target travel at space T.
* @.....
* |.....
*
* T 2. couldsee() marks spaces marked a and x
* #### as eligible guess spaces to move the hero
* a--.--- towards. Space a is closest to T, so it
* @xxxxx gets chosen. Travel system moves @ right
* |xxxxx to travel to space a.
*
* T 3. couldsee() marks spaces marked b, c and x
* #### as eligible guess spaces to move the hero
* a--c--- towards. Since findtravelpath() is called
* b@xxxx repeatedly during travel, it doesn't
* |xxxxx remember that it wanted to go to space a,
* so in comparing spaces b and c, b is
* chosen, since it seems like the closest
* eligible space to T. Travel system moves @
* left to go to space b.
*
* 4. Go to 2.
*
* By limiting the travel matrix here, space a in the
* example above is never included in it, preventing
* the cycle.
*/
if (!isok(nx, ny) || (guess && !couldsee(nx, ny)))
continue;
if ((!Passes_walls && !can_ooze(&youmonst)
&& closed_door(x, y)) || sobj_at(BOULDER, x, y)
@@ -960,8 +1016,7 @@ boolean guess;
nomul(0);
/* reset run so domove run checks work */
context.run = 8;
iflags.travelcc.x = iflags.travelcc.y =
-1;
iflags.travelcc.x = iflags.travelcc.y = -1;
}
return TRUE;
}
@@ -1134,9 +1189,11 @@ struct trap *desttrap; /* nonnull if another trap at <x,y> */
if ((u.utrap & 0xff) == 0) {
u.utrap = 0;
if (u.usteed)
You("lead %s to the edge of the lava.", steedname);
You("lead %s to the edge of the %s.", steedname,
hliquid("lava"));
else
You("pull yourself to the edge of the lava.");
You("pull yourself to the edge of the %s.",
hliquid("lava"));
}
}
u.umoved = TRUE;
@@ -1843,16 +1900,16 @@ boolean newspot; /* true if called by spoteffects */
if (Is_waterlevel(&u.uz))
You("pop into an air bubble.");
else if (is_lava(u.ux, u.uy))
You("leave the water..."); /* oops! */
You("leave the %s...", hliquid("water")); /* oops! */
else
You("are on solid %s again.",
is_ice(u.ux, u.uy) ? "ice" : "land");
} else if (Is_waterlevel(&u.uz)) {
still_inwater = TRUE;
} else if (Levitation) {
You("pop out of the water like a cork!");
You("pop out of the %s like a cork!", hliquid("water"));
} else if (Flying) {
You("fly out of the water.");
You("fly out of the %s.", hliquid("water"));
} else if (Wwalking) {
You("slowly rise above the surface.");
} else {
@@ -2363,7 +2420,8 @@ dopickup()
if (is_pool(u.ux, u.uy)) {
if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data)
|| (Flying && !Breathless)) {
You("cannot dive into the water to pick things up.");
You("cannot dive into the %s to pick things up.",
hliquid("water"));
return 0;
} else if (!Underwater) {
You_cant("even see the bottom, let alone pick up %s.", something);
@@ -2390,7 +2448,7 @@ dopickup()
else if (IS_GRAVE(lev->typ))
You("don't need a gravestone. Yet.");
else if (IS_FOUNTAIN(lev->typ))
You("could drink the water...");
You("could drink the %s...", hliquid("water"));
else if (IS_DOOR(lev->typ) && (lev->doormask & D_ISOPEN))
pline("It won't come off the hinges.");
else
+14 -2
View File
@@ -75,7 +75,8 @@ STATIC_PTR int
picklock(VOID_ARGS)
{
if (xlock.box) {
if ((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) {
if (xlock.box->where != OBJ_FLOOR
|| xlock.box->ox != u.ux || xlock.box->oy != u.uy) {
return ((xlock.usedtime = 0)); /* you or it moved */
}
} else { /* door */
@@ -228,6 +229,14 @@ reset_pick()
xlock.box = 0;
}
/* level change; don't reset if hero is carrying xlock.box with him/her */
void
maybe_reset_pick()
{
if (!xlock.box || !carried(xlock.box))
reset_pick();
}
/* for doapply(); if player gives a direction or resumes an interrupted
previous attempt then it costs hero a move even if nothing ultimately
happens; when told "can't do that" before being asked for direction
@@ -306,7 +315,7 @@ struct obj *pick;
pline("Doing that would probably melt %s.", yname(pick));
return PICKLOCK_LEARNED_SOMETHING;
} else if (is_pool(u.ux, u.uy) && !Underwater) {
pline_The("water has no lock.");
pline_The("%s has no lock.", hliquid("water"));
return PICKLOCK_LEARNED_SOMETHING;
}
@@ -609,6 +618,9 @@ int x, y;
There("is no obvious way to open the drawbridge.");
else if (portcullis || door->typ == DRAWBRIDGE_DOWN)
pline_The("drawbridge is already open.");
else if (container_at(cc.x, cc.y, TRUE))
pline("%s like something lootable over there.",
Blind ? "Feels" : "Seems");
else
You("%s no door there.", Blind ? "feel" : "see");
return res;
+6 -1
View File
@@ -90,7 +90,12 @@ free_maildata()
void
getmailstatus()
{
if (!mailbox && !(mailbox = nh_getenv("MAIL"))) {
char *emailbox;
if ((emailbox = nh_getenv("MAIL")) != 0) {
mailbox = (char *) alloc((unsigned) strlen(emailbox));
Strcpy(mailbox, emailbox);
}
if (!mailbox) {
#ifdef MAILPATH
#ifdef AMS
struct passwd ppasswd;
+7 -7
View File
@@ -54,6 +54,9 @@ static int explcolors[] = {
(currentgraphics == ROGUESET && SYMHANDLING(H_IBM))
#endif
#define is_objpile(x,y) (!Hallucination && level.objects[(x)][(y)] \
&& level.objects[(x)][(y)]->nexthere)
/*ARGSUSED*/
int
mapglyph(glyph, ochar, ocolor, ospecial, x, y)
@@ -83,7 +86,7 @@ unsigned *ospecial;
else
obj_color(STATUE);
special |= MG_STATUE;
if (level.objects[x][y] && level.objects[x][y]->nexthere)
if (is_objpile(x,y))
special |= MG_OBJPILE;
} else if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* warn flash */
idx = offset + SYM_OFF_W;
@@ -134,9 +137,7 @@ unsigned *ospecial;
} else if (!iflags.use_color && offset == S_lava
&& (showsyms[idx] == showsyms[S_pool + SYM_OFF_P]
|| showsyms[idx] == showsyms[S_water + SYM_OFF_P])) {
/* temporary? hack; makes tty use inverse video if the
corresponding boolean option is enabled */
special |= MG_DETECT;
special |= MG_BW_LAVA;
} else {
cmap_color(offset);
}
@@ -158,8 +159,7 @@ unsigned *ospecial;
}
} else
obj_color(offset);
if (offset != BOULDER && level.objects[x][y]
&& level.objects[x][y]->nexthere)
if (offset != BOULDER && is_objpile(x,y))
special |= MG_OBJPILE;
} else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* mon ridden */
idx = mons[offset].mlet + SYM_OFF_M;
@@ -178,7 +178,7 @@ unsigned *ospecial;
else
mon_color(offset);
special |= MG_CORPSE;
if (level.objects[x][y] && level.objects[x][y]->nexthere)
if (is_objpile(x,y))
special |= MG_OBJPILE;
} else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */
idx = mons[offset].mlet + SYM_OFF_M;
+67 -22
View File
@@ -291,7 +291,7 @@ register struct monst *magr, *mdef;
{
int i, /* loop counter */
tmp, /* amour class difference */
strike, /* hit this attack */
strike = 0, /* hit this attack */
attk, /* attack attempted this time */
struck = 0, /* hit at least once */
res[NATTK]; /* results of all attacks */
@@ -354,6 +354,15 @@ register struct monst *magr, *mdef;
attk = 1;
switch (mattk->aatyp) {
case AT_WEAP: /* "hand to hand" attacks */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1) {
/* D: Do a ranged attack here! */
strike = thrwmm(magr, mdef);
if (DEADMONSTER(mdef))
res[i] = MM_DEF_DIED;
if (DEADMONSTER(magr))
res[i] |= MM_AGR_DIED;
break;
}
if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
magr->weapon_check = NEED_HTH_WEAPON;
if (mon_wield_item(magr) != 0)
@@ -377,7 +386,8 @@ register struct monst *magr, *mdef;
case AT_TENT:
/* Nymph that teleported away on first attack? */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1)
return MM_MISS;
/* Continue because the monster may have a ranged attack. */
continue;
/* Monsters won't attack cockatrices physically if they
* have a weapon instead. This instinct doesn't work for
* players, or under conflict or confusion.
@@ -426,6 +436,10 @@ register struct monst *magr, *mdef;
break;
case AT_EXPL:
/* D: Prevent explosions from a distance */
if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1)
continue;
res[i] = explmm(magr, mdef, mattk);
if (res[i] == MM_MISS) { /* cancelled--no attack */
strike = 0;
@@ -435,20 +449,49 @@ register struct monst *magr, *mdef;
break;
case AT_ENGL:
if (u.usteed && (mdef == u.usteed)) {
if (u.usteed && mdef == u.usteed) {
strike = 0;
break;
}
/* Engulfing attacks are directed at the hero if
* possible. -dlc
*/
/* D: Prevent engulf from a distance */
if (distmin(magr->mx, magr->my, mdef->mx, mdef->my) > 1)
continue;
/* Engulfing attacks are directed at the hero if possible. -dlc */
if (u.uswallow && magr == u.ustuck)
strike = 0;
else {
if ((strike = (tmp > rnd(20 + i))))
res[i] = gulpmm(magr, mdef, mattk);
else
missmm(magr, mdef, mattk);
else if ((strike = (tmp > rnd(20 + i))) != 0)
res[i] = gulpmm(magr, mdef, mattk);
else
missmm(magr, mdef, mattk);
break;
case AT_BREA:
if (!monnear(magr, mdef->mx, mdef->my)) {
strike = breamm(magr, mattk, mdef);
/* We don't really know if we hit or not; pretend we did. */
if (strike)
res[i] |= MM_HIT;
if (DEADMONSTER(mdef))
res[i] = MM_DEF_DIED;
if (DEADMONSTER(magr))
res[i] |= MM_AGR_DIED;
}
else
strike = 0;
break;
case AT_SPIT:
if (!monnear(magr, mdef->mx, mdef->my)) {
strike = spitmm(magr, mattk, mdef);
/* We don't really know if we hit or not; pretend we did. */
if (strike)
res[i] |= MM_HIT;
if (DEADMONSTER(mdef))
res[i] = MM_DEF_DIED;
if (DEADMONSTER(magr))
res[i] |= MM_AGR_DIED;
}
break;
@@ -458,12 +501,12 @@ register struct monst *magr, *mdef;
break;
}
if (attk && !(res[i] & MM_AGR_DIED))
if (attk && !(res[i] & MM_AGR_DIED)
&& distmin(magr->mx, magr->my, mdef->mx, mdef->my) <= 1)
res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
if (res[i] & MM_DEF_DIED)
return res[i];
if (res[i] & MM_AGR_DIED)
return res[i];
/* return if aggressor can no longer attack */
@@ -548,9 +591,8 @@ struct attack *mattk;
pline("%s %s...", buf, mon_nam(mdef));
}
if (magr->mcan || !magr->mcansee
|| (magr->minvis && !perceives(mdef->data)) || !mdef->mcansee
|| mdef->msleeping) {
if (magr->mcan || !magr->mcansee || !mdef->mcansee
|| (magr->minvis && !perceives(mdef->data)) || mdef->msleeping) {
if (vis)
pline("but nothing happens.");
return MM_MISS;
@@ -562,8 +604,8 @@ struct attack *mattk;
if (mdef->mcansee) {
if (mon_reflects(magr, (char *) 0)) {
if (canseemon(magr))
(void) mon_reflects(
magr, "The gaze is reflected away by %s %s.");
(void) mon_reflects(magr,
"The gaze is reflected away by %s %s.");
return MM_MISS;
}
if (mdef->minvis && !perceives(magr->data)) {
@@ -676,7 +718,7 @@ register struct attack *mattk;
} else if (status & MM_AGR_DIED) { /* aggressor died */
place_monster(mdef, dx, dy);
newsym(dx, dy);
} else { /* both alive, put them back */
} else { /* both alive, put them back */
if (cansee(dx, dy))
pline("%s is regurgitated!", Monnam(mdef));
@@ -930,11 +972,12 @@ register struct attack *mattk;
}
if (resists_acid(mdef)) {
if (vis)
pline("%s is covered in acid, but it seems harmless.",
pline("%s is covered in %s, but it seems harmless.",
hliquid("acid"),
Monnam(mdef));
tmp = 0;
} else if (vis) {
pline("%s is covered in acid!", Monnam(mdef));
pline("%s is covered in %s!", hliquid("acid"), Monnam(mdef));
pline("It burns %s!", mon_nam(mdef));
}
if (!rn2(30))
@@ -1127,6 +1170,7 @@ register struct attack *mattk;
*/
{
struct obj *gold = findgold(mdef->minvent);
if (!gold)
break;
obj_extract_self(gold);
@@ -1447,7 +1491,8 @@ int mdead;
if (mhit && !rn2(2)) {
Strcpy(buf, Monnam(magr));
if (canseemon(magr))
pline("%s is splashed by %s acid!", buf,
pline("%s is splashed by %s %s!", buf,
hliquid("acid"),
s_suffix(mon_nam(mdef)));
if (resists_acid(magr)) {
if (canseemon(magr))
+90 -72
View File
@@ -8,11 +8,9 @@
STATIC_VAR NEARDATA struct obj *otmp;
STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *));
STATIC_DCL int FDECL(passiveum,
(struct permonst *, struct monst *, struct attack *));
STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *,
struct attack *));
STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
STATIC_DCL int FDECL(hitmu, (struct monst *, struct attack *));
STATIC_DCL int FDECL(gulpmu, (struct monst *, struct attack *));
@@ -20,7 +18,6 @@ STATIC_DCL int FDECL(explmu, (struct monst *, struct attack *, BOOLEAN_P));
STATIC_DCL void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *));
STATIC_DCL void FDECL(mswings, (struct monst *, struct obj *));
STATIC_DCL void FDECL(wildmiss, (struct monst *, struct attack *));
STATIC_DCL void FDECL(hitmsg, (struct monst *, struct attack *));
/* See comment in mhitm.c. If we use this a lot it probably should be */
@@ -33,41 +30,48 @@ register struct monst *mtmp;
register struct attack *mattk;
{
int compat;
const char *pfmt = 0;
char *Monst_name = Monnam(mtmp);
/* Note: if opposite gender, "seductively" */
/* If same gender, "engagingly" for nymph, normal msg for others */
if ((compat = could_seduce(mtmp, &youmonst, mattk)) && !mtmp->mcan
&& !mtmp->mspec_used) {
pline("%s %s you %s.", Monnam(mtmp), Blind ? "talks to" : "smiles at",
compat == 2 ? "engagingly" : "seductively");
} else
if ((compat = could_seduce(mtmp, &youmonst, mattk)) != 0
&& !mtmp->mcan && !mtmp->mspec_used) {
pline("%s %s you %s.", Monst_name,
Blind ? "talks to" : "smiles at",
(compat == 2) ? "engagingly" : "seductively");
} else {
switch (mattk->aatyp) {
case AT_BITE:
pline("%s bites!", Monnam(mtmp));
pfmt = "%s bites!";
break;
case AT_KICK:
pline("%s kicks%c", Monnam(mtmp),
pline("%s kicks%c", Monst_name,
thick_skinned(youmonst.data) ? '.' : '!');
break;
case AT_STNG:
pline("%s stings!", Monnam(mtmp));
pfmt = "%s stings!";
break;
case AT_BUTT:
pline("%s butts!", Monnam(mtmp));
pfmt = "%s butts!";
break;
case AT_TUCH:
pline("%s touches you!", Monnam(mtmp));
pfmt = "%s touches you!";
break;
case AT_TENT:
pline("%s tentacles suck you!", s_suffix(Monnam(mtmp)));
pfmt = "%s tentacles suck you!";
Monst_name = s_suffix(Monst_name);
break;
case AT_EXPL:
case AT_BOOM:
pline("%s explodes!", Monnam(mtmp));
pfmt = "%s explodes!";
break;
default:
pline("%s hits!", Monnam(mtmp));
pfmt = "%s hits!";
}
if (pfmt)
pline(pfmt, Monst_name);
}
}
/* monster missed you */
@@ -139,6 +143,7 @@ register struct monst *mtmp;
register struct attack *mattk;
{
int compat;
const char *Monst_name; /* Monnam(mtmp) */
/* no map_invisible() -- no way to tell where _this_ is coming from */
@@ -150,42 +155,41 @@ register struct attack *mattk;
compat = ((mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX)
&& could_seduce(mtmp, &youmonst, (struct attack *) 0));
Monst_name = Monnam(mtmp);
if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
const char *swings =
mattk->aatyp == AT_BITE
? "snaps"
: mattk->aatyp == AT_KICK
? "kicks"
: (mattk->aatyp == AT_STNG || mattk->aatyp == AT_BUTT
|| nolimbs(mtmp->data))
? "lunges"
: "swings";
const char *swings = (mattk->aatyp == AT_BITE) ? "snaps"
: (mattk->aatyp == AT_KICK) ? "kicks"
: (mattk->aatyp == AT_STNG
|| mattk->aatyp == AT_BUTT
|| nolimbs(mtmp->data)) ? "lunges"
: "swings";
if (compat)
pline("%s tries to touch you and misses!", Monnam(mtmp));
pline("%s tries to touch you and misses!", Monst_name);
else
switch (rn2(3)) {
case 0:
pline("%s %s wildly and misses!", Monnam(mtmp), swings);
pline("%s %s wildly and misses!", Monst_name, swings);
break;
case 1:
pline("%s attacks a spot beside you.", Monnam(mtmp));
pline("%s attacks a spot beside you.", Monst_name);
break;
case 2:
pline("%s strikes at %s!", Monnam(mtmp),
levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water"
: "thin air");
pline("%s strikes at %s!", Monst_name,
(levl[mtmp->mux][mtmp->muy].typ == WATER)
? "empty water"
: "thin air");
break;
default:
pline("%s %s wildly!", Monnam(mtmp), swings);
pline("%s %s wildly!", Monst_name, swings);
break;
}
} else if (Displaced) {
if (compat)
pline("%s smiles %s at your %sdisplaced image...", Monnam(mtmp),
compat == 2 ? "engagingly" : "seductively",
pline("%s smiles %s at your %sdisplaced image...", Monst_name,
(compat == 2) ? "engagingly" : "seductively",
Invis ? "invisible " : "");
else
pline("%s strikes at your %sdisplaced image and misses you!",
@@ -194,20 +198,20 @@ register struct attack *mattk;
* displaced image, since the displaced image is also
* invisible.
*/
Monnam(mtmp), Invis ? "invisible " : "");
Monst_name, Invis ? "invisible " : "");
} else if (Underwater) {
/* monsters may miss especially on water level where
bubbles shake the player here and there */
if (compat)
pline("%s reaches towards your distorted image.", Monnam(mtmp));
pline("%s reaches towards your distorted image.", Monst_name);
else
pline("%s is fooled by water reflections and misses!",
Monnam(mtmp));
Monst_name);
} else
impossible("%s attacks you without knowing your location?",
Monnam(mtmp));
Monst_name);
}
void
@@ -217,9 +221,9 @@ struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
boolean message;
{
if (message) {
if (is_animal(mdat))
if (is_animal(mdat)) {
You("get regurgitated!");
else {
} else {
char blast[40];
register int i;
@@ -227,9 +231,9 @@ boolean message;
for (i = 0; i < NATTK; i++)
if (mdat->mattk[i].aatyp == AT_ENGL)
break;
if (mdat->mattk[i].aatyp != AT_ENGL)
if (mdat->mattk[i].aatyp != AT_ENGL) {
impossible("Swallower has no engulfing attack?");
else {
} else {
if (is_whirly(mdat)) {
switch (mdat->mattk[i].adtyp) {
case AD_ELEC:
@@ -296,6 +300,20 @@ struct attack *alt_attk_buf;
/* note: 3d9 is slightly higher than previous 4d6 */
}
} else if (attk->aatyp == AT_ENGL && magr->mspec_used) {
/* can't re-engulf yet; switch to simpler attack */
*alt_attk_buf = *attk;
attk = alt_attk_buf;
if (attk->adtyp == AD_ACID || attk->adtyp == AD_ELEC
|| attk->adtyp == AD_COLD || attk->adtyp == AD_FIRE) {
attk->aatyp = AT_TUCH;
} else {
attk->aatyp = AT_CLAW; /* attack message will be "<foo> hits" */
attk->adtyp = AD_PHYS;
}
attk->damn = 1; /* relatively weak: 1d6 */
attk->damd = 6;
/* barrow wight, Nazgul, erinys have weapon attack for non-physical
damage; force physical damage if attacker has been cancelled or
if weapon is sufficiently interesting; a few unique creatures
@@ -306,11 +324,10 @@ struct attack *alt_attk_buf;
&& !(mptr->mattk[1].aatyp == AT_WEAP
&& mptr->mattk[1].adtyp == AD_PHYS)
&& (magr->mcan
|| (weap
&& ((weap->otyp == CORPSE
&& touch_petrifies(&mons[weap->corpsenm]))
|| weap->oartifact == ART_STORMBRINGER
|| weap->oartifact == ART_VORPAL_BLADE)))) {
|| (weap && ((weap->otyp == CORPSE
&& touch_petrifies(&mons[weap->corpsenm]))
|| weap->oartifact == ART_STORMBRINGER
|| weap->oartifact == ART_VORPAL_BLADE)))) {
*alt_attk_buf = *attk;
attk = alt_attk_buf;
attk->adtyp = AD_PHYS;
@@ -332,7 +349,7 @@ mattacku(mtmp)
register struct monst *mtmp;
{
struct attack *mattk, alt_attk;
int i, j, tmp, sum[NATTK];
int i, j = 0, tmp, sum[NATTK];
struct permonst *mdat = mtmp->data;
boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
/* Is it near you? Affects your actions */
@@ -681,10 +698,10 @@ register struct monst *mtmp;
case AT_ENGL:
if (!range2) {
if (foundyou) {
if (u.uswallow || tmp > (j = rnd(20 + i))) {
/* Force swallowing monster to be
* displayed even when player is
* moving away */
if (u.uswallow
|| (!mtmp->mspec_used && tmp > (j = rnd(20 + i)))) {
/* force swallowing monster to be displayed
even when hero is moving away */
flush_screen(1);
sum[i] = gulpmu(mtmp, mattk);
} else {
@@ -1157,7 +1174,8 @@ register struct attack *mattk;
break;
case AD_LEGS: {
register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left";
const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left",
*Monst_name = Monnam(mtmp), *leg = body_part(LEG);
/* This case is too obvious to ignore, but Nethack is not in
* general very good at considering height--most short monsters
@@ -1165,31 +1183,30 @@ register struct attack *mattk;
* [FIXME: why can't a flying attacker overcome this?]
*/
if (u.usteed || Levitation || Flying) {
pline("%s tries to reach your %s %s!", Monnam(mtmp), sidestr,
body_part(LEG));
pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg);
dmg = 0;
} else if (mtmp->mcan) {
pline("%s nuzzles against your %s %s!", Monnam(mtmp), sidestr,
body_part(LEG));
pline("%s nuzzles against your %s %s!", Monnam(mtmp),
sidestr, leg);
dmg = 0;
} else {
if (uarmf) {
if (rn2(2) && (uarmf->otyp == LOW_BOOTS
|| uarmf->otyp == IRON_SHOES))
|| uarmf->otyp == IRON_SHOES)) {
pline("%s pricks the exposed part of your %s %s!",
Monnam(mtmp), sidestr, body_part(LEG));
else if (!rn2(5))
pline("%s pricks through your %s boot!", Monnam(mtmp),
Monst_name, sidestr, leg);
} else if (!rn2(5)) {
pline("%s pricks through your %s boot!", Monst_name,
sidestr);
else {
pline("%s scratches your %s boot!", Monnam(mtmp),
} else {
pline("%s scratches your %s boot!", Monst_name,
sidestr);
dmg = 0;
break;
}
} else
pline("%s pricks your %s %s!", Monnam(mtmp), sidestr,
body_part(LEG));
pline("%s pricks your %s %s!", Monst_name, sidestr, leg);
set_wounded_legs(side, rnd(60 - ACURR(A_DEX)));
exercise(A_STR, FALSE);
exercise(A_DEX, FALSE);
@@ -1308,12 +1325,11 @@ register struct attack *mattk;
(void) rloc(mtmp, TRUE);
return 3;
} else if (mtmp->mcan) {
if (!Blind) {
if (!Blind)
pline("%s tries to %s you, but you seem %s.",
Adjmonnam(mtmp, "plain"),
flags.female ? "charm" : "seduce",
flags.female ? "unaffected" : "uninterested");
}
if (rn2(3)) {
if (!tele_restrict(mtmp))
(void) rloc(mtmp, TRUE);
@@ -1478,10 +1494,11 @@ register struct attack *mattk;
hitmsg(mtmp, mattk);
if (!mtmp->mcan && !rn2(3))
if (Acid_resistance) {
pline("You're covered in acid, but it seems harmless.");
pline("You're covered in %s, but it seems harmless.",
hliquid("acid"));
dmg = 0;
} else {
pline("You're covered in acid! It burns!");
pline("You're covered in %s! It burns!", hliquid("acid"));
exercise(A_STR, FALSE);
}
else
@@ -1705,6 +1722,7 @@ register struct attack *mattk;
newsym(mtmp->mx, mtmp->my);
if (is_animal(mtmp->data) && u.usteed) {
char buf[BUFSZ];
/* Too many quirks presently if hero and steed
* are swallowed. Pretend purple worms don't
* like horses for now :-)
@@ -2633,7 +2651,7 @@ register struct attack *mattk;
switch (olduasmon->mattk[i].adtyp) {
case AD_ACID:
if (!rn2(2)) {
pline("%s is splashed by your acid!", Monnam(mtmp));
pline("%s is splashed by your %s!", Monnam(mtmp), hliquid("acid"));
if (resists_acid(mtmp)) {
pline("%s is not affected.", Monnam(mtmp));
tmp = 0;
+2 -2
View File
@@ -1327,7 +1327,7 @@ xchar x, y;
ltyp = db_under_typ(lev->drawbridgemask);
if (ltyp == LAVAPOOL)
return "lava";
return hliquid("lava");
else if (ltyp == ICE)
return "ice";
else if (ltyp == POOL)
@@ -1339,7 +1339,7 @@ xchar x, y;
else if (ltyp == MOAT && !Is_medusa_level(&u.uz))
return "moat";
return "water";
return hliquid("water");
}
STATIC_OVL void
+3 -3
View File
@@ -872,9 +872,6 @@ boolean artif;
case BAG_OF_HOLDING:
mkbox_cnts(otmp);
break;
case LEASH:
otmp->leashmon = 0;
break;
case EXPENSIVE_CAMERA:
case TINNING_KIT:
case MAGIC_MARKER:
@@ -1034,6 +1031,9 @@ boolean artif;
/* case TIN: */
set_corpsenm(otmp, otmp->corpsenm);
break;
case LEASH:
otmp->leashmon = 0;
break;
case SPE_NOVEL:
otmp->novelidx = -1; /* "none of the above"; will be changed */
otmp = oname(otmp, noveltitle(&otmp->novelidx));
+80 -12
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 mon.c $NHDT-Date: 1463534459 2016/05/18 01:20:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.221 $ */
/* NetHack 3.6 mon.c $NHDT-Date: 1466289475 2016/06/18 22:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.227 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -554,7 +554,8 @@ register struct monst *mtmp;
if (u.ustuck && u.uswallow && u.ustuck == mtmp) {
/* This can happen after a purple worm plucks you off a
flying steed while you are over water. */
pline("%s sinks as water rushes in and flushes you out.",
pline("%s sinks as %s rushes in and flushes you out.",
hliquid("water"),
Monnam(mtmp));
}
mondead(mtmp);
@@ -907,7 +908,12 @@ struct monst *mtmp;
&& !resists_ston(mtmp))
/* don't engulf boulders and statues or ball&chain */
|| otmp->oclass == ROCK_CLASS
|| otmp == uball || otmp == uchain) {
|| otmp == uball || otmp == uchain
/* normally mtmp won't have stepped onto scare monster
scroll, but if it does, don't eat or engulf that
(note: scrolls inside eaten containers will still
become engulfed) */
|| otmp->otyp == SCR_SCARE_MONSTER) {
/* do nothing--neither eaten nor engulfed */
continue;
@@ -939,11 +945,18 @@ struct monst *mtmp;
} else {
/* devour */
++count;
if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
pline("%s eats %s!", Monnam(mtmp),
distant_name(otmp, doname));
else if (flags.verbose)
You_hear("a slurping sound.");
if (cansee(mtmp->mx, mtmp->my)) {
if (flags.verbose)
pline("%s eats %s!", Monnam(mtmp),
distant_name(otmp, doname));
/* give this one even if !verbose */
if (otmp->oclass == SCROLL_CLASS
&& !strcmpi(OBJ_DESCR(objects[otmp->otyp]), "YUM YUM"))
pline("Yum%c", otmp->blessed ? '!' : '.');
} else {
if (flags.verbose)
You_hear("a slurping sound.");
}
/* Heal up to the object's weight in hp */
if (mtmp->mhp < mtmp->mhpmax) {
mtmp->mhp += objects[otmp->otyp].oc_weight;
@@ -2146,6 +2159,10 @@ struct monst *mtmp;
placebc();
vision_full_recalc = 1;
docrt();
/* prevent swallower (mtmp might have just poly'd into something
without an engulf attack) from immediately re-engulfing */
if (attacktype(mtmp->data, AT_ENGL) && !mtmp->mspec_used)
mtmp->mspec_used = rnd(2);
}
u.ustuck = 0;
}
@@ -2178,14 +2195,16 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */
if (!noconduct) /* KMH, conduct */
u.uconduct.killer++;
if (!nomsg)
if (!nomsg) {
boolean namedpet = has_mname(mtmp) && !Hallucination;
You("%s %s!",
nonliving(mtmp->data) ? "destroy" : "kill",
!(wasinside || canspotmon(mtmp)) ? "it"
: !mtmp->mtame ? mon_nam(mtmp)
: x_monnam(mtmp, has_mname(mtmp) ? ARTICLE_NONE : ARTICLE_THE,
"poor", has_mname(mtmp) ? SUPPRESS_SADDLE : 0,
FALSE));
: x_monnam(mtmp, namedpet ? ARTICLE_NONE : ARTICLE_THE,
"poor", namedpet ? SUPPRESS_SADDLE : 0, FALSE));
}
if (mtmp->mtrapped && (t = t_at(x, y)) != 0
&& (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) {
@@ -2610,6 +2629,55 @@ struct monst *mtmp;
: makeplural(q_guardian->mname),
got_mad == 1 ? "s" : "");
}
/* make other peaceful monsters react */
if (!context.mon_moving) {
struct monst *mon;
for (mon = fmon; mon; mon = mon->nmon) {
if (DEADMONSTER(mon))
continue;
if (!mindless(mon->data) && mon->mpeaceful
&& couldsee(mon->mx, mon->my) && !mon->msleeping
&& mon->mcansee && m_canseeu(mon)) {
boolean exclaimed = FALSE;
if (humanoid(mon->data) || mon->isshk || mon->ispriest) {
if (is_watch(mon->data)) {
verbalize("Halt! You're under arrest!");
(void) angry_guards(!!Deaf);
} else {
const char *exclam[] = {
"Gasp!", "Uh-oh.", "Oh my!", "What?", "Why?"
};
if (!rn2(5)) {
verbalize("%s", exclam[mon->m_id % SIZE(exclam)]);
exclaimed = TRUE;
}
if (!mon->isshk && !mon->ispriest
&& (mon->data->mlevel < rn2(10))) {
monflee(mon, rn2(50)+25, TRUE, !exclaimed);
exclaimed = TRUE;
}
if (!mon->isshk && !mon->ispriest) {
mon->mpeaceful = 0;
adjalign(-1);
if (!exclaimed)
pline("%s gets angry!", Monnam(mon));
}
}
} else if ((mtmp->data == mon->data) && !rn2(3)) {
if (!rn2(4)) {
growl(mon);
exclaimed = TRUE;
}
if (rn2(6))
monflee(mon, rn2(25)+15, TRUE, !exclaimed);
}
}
}
}
}
/* wake up a monster, usually making it angry in the process */
+350 -122
View File
@@ -4,13 +4,18 @@
#include "hack.h"
STATIC_DCL int FDECL(monmulti, (struct monst *, struct obj *, struct obj *));
STATIC_DCL void FDECL(monshoot, (struct monst *, struct obj *, struct obj *));
STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
STATIC_DCL boolean FDECL(m_lined_up, (struct monst *, struct monst *));
#define URETREATING(x, y) \
(distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
#define POLE_LIM 5 /* How far monsters can use pole-weapons */
#define PET_MISSILE_RANGE2 36 /* Square of distance within which pets shoot */
/*
* Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
*/
@@ -48,9 +53,9 @@ const char *name; /* if null, then format `obj' */
|| !strncmpi(name, "a ", 2))
kprefix = KILLED_BY;
}
onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L)
? name
: an(name);
onm = (obj && obj_is_pname(obj)) ? the(name)
: (obj && obj->quan > 1L) ? name
: an(name);
is_acid = (obj && obj->otyp == ACID_VENOM);
if (u.uac + tlev <= rnd(20)) {
@@ -70,9 +75,9 @@ const char *name; /* if null, then format `obj' */
pline_The("silver sears your flesh!");
exercise(A_CON, FALSE);
}
if (is_acid && Acid_resistance)
if (is_acid && Acid_resistance) {
pline("It doesn't seem to hurt you.");
else {
} else {
if (is_acid)
pline("It burns!");
losehp(dam, knm, kprefix); /* acid damage */
@@ -113,8 +118,7 @@ int x, y;
if (down_gate(x, y) != -1)
objgone = ship_object(obj, x, y, FALSE);
if (!objgone) {
if (!flooreffects(obj, x, y,
"fall")) { /* don't double-dip on damage */
if (!flooreffects(obj, x, y, "fall")) {
place_object(obj, x, y);
if (!mtmp && x == u.ux && y == u.uy)
mtmp = &youmonst;
@@ -129,6 +133,155 @@ int x, y;
return retvalu;
}
/* The monster that's being shot at when one monster shoots at another */
STATIC_OVL struct monst *target = 0;
/* The monster that's doing the shooting/throwing */
STATIC_OVL struct monst *archer = 0;
/* calculate multishot volley count for mtmp throwing otmp (if not ammo) or
shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */
STATIC_OVL int
monmulti(mtmp, otmp, mwep)
struct monst *mtmp;
struct obj *otmp, *mwep;
{
int skill = (int) objects[otmp->otyp].oc_skill;
int multishot = 1;
if (otmp->quan > 1L /* no point checking if there's only 1 */
/* ammo requires corresponding launcher be wielded */
&& (is_ammo(otmp)
? matching_launcher(otmp, mwep)
/* otherwise any stackable (non-ammo) weapon */
: otmp->oclass == WEAPON_CLASS)
&& !mtmp->mconf) {
/* Assumes lords are skilled, princes are expert */
if (is_prince(mtmp->data))
multishot += 2;
else if (is_lord(mtmp->data))
multishot++;
/* fake players treated as skilled (regardless of role limits) */
else if (is_mplayer(mtmp->data))
multishot++;
/* this portion is different from hero multishot; from slash'em?
*/
/* Elven Craftsmanship makes for light, quick bows */
if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
multishot++;
if (ammo_and_launcher(otmp, uwep) && mwep->otyp == ELVEN_BOW
&& !mwep->cursed)
multishot++;
/* 1/3 of launcher enchantment */
if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
multishot += (long) rounddiv(mwep->spe, 3);
/* Some randomness */
multishot = (long) rnd((int) multishot);
/* class bonus */
switch (monsndx(mtmp->data)) {
case PM_CAVEMAN: /* give bonus for low-tech gear */
if (skill == -P_SLING || skill == P_SPEAR)
multishot++;
break;
case PM_MONK: /* allow higher volley count */
if (skill == -P_SHURIKEN)
multishot++;
break;
case PM_RANGER:
if (skill != P_DAGGER)
multishot++;
break;
case PM_ROGUE:
if (skill == P_DAGGER)
multishot++;
break;
case PM_NINJA:
if (skill == -P_SHURIKEN || skill == -P_DART)
multishot++;
/*FALLTHRU*/
case PM_SAMURAI:
if (otmp->otyp == YA && mwep->otyp == YUMI)
multishot++;
break;
default:
break;
}
/* racial bonus */
if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
&& mwep->otyp == ELVEN_BOW)
|| (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
&& mwep->otyp == ORCISH_BOW)
|| (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
&& mwep->otyp == CROSSBOW))
multishot++;
}
if (otmp->quan < multishot)
multishot = (int) otmp->quan;
if (multishot < 1)
multishot = 1;
return multishot;
}
/* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
STATIC_OVL void
monshoot(mtmp, otmp, mwep)
struct monst *mtmp;
struct obj *otmp, *mwep;
{
struct monst *mtarg = target;
int dm = distmin(mtmp->mx, mtmp->my,
mtarg ? mtarg->mx : mtmp->mux,
mtarg ? mtarg->my : mtmp->muy),
multishot = monmulti(mtmp, otmp, mwep);
/*
* Caller must have called linedup() to set up tbx, tby.
*/
if (canseemon(mtmp)) {
const char *onm;
char onmbuf[BUFSZ], trgbuf[BUFSZ];
if (multishot > 1) {
/* "N arrows"; multishot > 1 implies otmp->quan > 1, so
xname()'s result will already be pluralized */
Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
onm = onmbuf;
} else {
/* "an arrow" */
onm = singular(otmp, xname);
onm = obj_is_pname(otmp) ? the(onm) : an(onm);
}
m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
if (!strcmp(trgbuf, "it"))
Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
pline("%s %s %s%s%s!", Monnam(mtmp),
m_shot.s ? "shoots" : "throws", onm,
mtarg ? " at " : "", trgbuf);
m_shot.o = otmp->otyp;
} else {
m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
}
m_shot.n = multishot;
for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
/* conceptually all N missiles are in flight at once, but
if mtmp gets killed (shot kills adjacent gas spore and
triggers explosion, perhaps), inventory will be dropped
and otmp might go away via merging into another stack */
if (mtmp->mhp <= 0 && m_shot.i < m_shot.n)
/* cancel pending shots (perhaps ought to give a message here
since we gave one above about throwing/shooting N missiles) */
break; /* endmultishot(FALSE); */
}
/* reset 'm_shot' */
m_shot.n = m_shot.i = 0;
m_shot.o = STRANGE_OBJECT;
m_shot.s = FALSE;
}
/* an object launched by someone/thing other than player attacks a monster;
return 1 if the object has stopped moving (hit or its range used up) */
int
@@ -143,17 +296,27 @@ boolean verbose; /* give message(s) even when you can't see what happened */
int damage, tmp;
boolean vis, ismimic;
int objgone = 1;
struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
vis = cansee(bhitpos.x, bhitpos.y);
tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
/* High level monsters will be more likely to hit */
/* This check applies only if this monster is the target
* the archer was aiming at. */
if (archer && target == mtmp) {
if (archer->m_lev > 5)
tmp += archer->m_lev - 5;
if (mon_launcher && mon_launcher->oartifact)
tmp += spec_abon(mon_launcher, mtmp);
}
if (tmp < rnd(20)) {
if (!ismimic) {
if (vis)
miss(distant_name(otmp, mshot_xname), mtmp);
else if (verbose)
else if (verbose && !target)
pline("It is missed.");
}
if (!range) { /* Last position; object drops */
@@ -177,7 +340,7 @@ boolean verbose; /* give message(s) even when you can't see what happened */
mtmp->msleeping = 0;
if (vis)
hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
else if (verbose)
else if (verbose && !target)
pline("%s is hit%s", Monnam(mtmp), exclam(damage));
if (otmp->opoisoned && is_poisonable(otmp)) {
@@ -199,29 +362,27 @@ boolean verbose; /* give message(s) even when you can't see what happened */
&& mon_hates_silver(mtmp)) {
if (vis)
pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
else if (verbose)
else if (verbose && !target)
pline("Its flesh is seared!");
}
if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
if (resists_acid(mtmp)) {
if (vis || verbose)
if (vis || (verbose && !target))
pline("%s is unaffected.", Monnam(mtmp));
damage = 0;
} else {
if (vis)
pline_The("acid burns %s!", mon_nam(mtmp));
else if (verbose)
pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
else if (verbose && !target)
pline("It is burned!");
}
}
mtmp->mhp -= damage;
if (mtmp->mhp < 1) {
if (vis || verbose)
if (vis || (verbose && !target))
pline("%s is %s!", Monnam(mtmp),
(nonliving(mtmp->data) || is_vampshifter(mtmp)
|| !canspotmon(mtmp))
? "destroyed"
: "killed");
|| !canspotmon(mtmp)) ? "destroyed" : "killed");
/* don't blame hero for unknown rolling boulder trap */
if (!context.mon_moving
&& (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
@@ -231,8 +392,8 @@ boolean verbose; /* give message(s) even when you can't see what happened */
}
if (can_blnd((struct monst *) 0, mtmp,
(uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT
: AT_WEAP),
(uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
: AT_WEAP),
otmp)) {
if (vis && mtmp->mcansee)
pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
@@ -262,7 +423,7 @@ struct obj *obj; /* missile (or stack providing it) */
struct monst *mtmp;
struct obj *singleobj;
char sym = obj->oclass;
int hitu, oldumort, blindinc = 0;
int hitu = 0, oldumort, blindinc = 0;
bhitpos.x = x;
bhitpos.y = y;
@@ -354,9 +515,10 @@ struct obj *obj; /* missile (or stack providing it) */
You(
"accept %s gift in the spirit in which it was intended.",
s_suffix(mon_nam(mon)));
(void) hold_another_object(
singleobj, "You catch, but drop, %s.",
xname(singleobj), "You catch:");
(void) hold_another_object(singleobj,
"You catch, but drop, %s.",
xname(singleobj),
"You catch:");
}
break;
}
@@ -412,7 +574,7 @@ struct obj *obj; /* missile (or stack providing it) */
(u.umortality > oldumort) ? 0 : 10, TRUE);
}
if (hitu && can_blnd((struct monst *) 0, &youmonst,
(uchar) (singleobj->otyp == BLINDING_VENOM
(uchar) ((singleobj->otyp == BLINDING_VENOM)
? AT_SPIT
: AT_WEAP),
singleobj)) {
@@ -443,7 +605,7 @@ struct obj *obj; /* missile (or stack providing it) */
}
}
stop_occupation();
if (hitu || !range) {
if (hitu) {
(void) drop_throw(singleobj, hitu, u.ux, u.uy);
break;
}
@@ -463,8 +625,12 @@ struct obj *obj; /* missile (or stack providing it) */
!rn2(5), 0))
/* Thrown objects "sink" */
|| IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
if (singleobj) /* hits_bars might have destroyed it */
if (singleobj) { /* hits_bars might have destroyed it */
if (m_shot.n > 1 && (cansee(bhitpos.x, bhitpos.y)
|| (archer && canseemon(archer))))
pline("%s misses.", The(mshot_xname(singleobj)));
(void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
}
break;
}
tmp_at(bhitpos.x, bhitpos.y);
@@ -482,6 +648,155 @@ struct obj *obj; /* missile (or stack providing it) */
}
}
/* Monster throws item at another monster */
int
thrwmm(mtmp, mtarg)
struct monst *mtmp, *mtarg;
{
struct obj *otmp, *mwep;
register xchar x, y;
boolean ispole;
/* Polearms won't be applied by monsters against other monsters */
if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
mtmp->weapon_check = NEED_RANGED_WEAPON;
/* mon_wield_item resets weapon_check as appropriate */
if (mon_wield_item(mtmp) != 0)
return 0;
}
/* Pick a weapon */
otmp = select_rwep(mtmp);
if (!otmp)
return 0;
ispole = is_pole(otmp);
x = mtmp->mx;
y = mtmp->my;
mwep = MON_WEP(mtmp); /* wielded weapon */
if (!ispole && m_lined_up(mtarg, mtmp)) {
int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
if (!mtarg->mflee || !rn2(chance)) {
if (ammo_and_launcher(otmp, mwep)
&& dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
> PET_MISSILE_RANGE2)
return 0; /* Out of range */
/* Set target monster */
target = mtarg;
archer = mtmp;
monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
archer = target = (struct monst *) 0;
nomul(0);
return 1;
}
}
return 0;
}
/* monster spits substance at monster */
int
spitmm(mtmp, mattk, mtarg)
struct monst *mtmp, *mtarg;
struct attack *mattk;
{
struct obj *otmp;
if (mtmp->mcan) {
if (!Deaf)
pline("A dry rattle comes from %s throat.",
s_suffix(mon_nam(mtmp)));
return 0;
}
if (m_lined_up(mtarg, mtmp)) {
switch (mattk->adtyp) {
case AD_BLND:
case AD_DRST:
otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
break;
default:
impossible("bad attack type in spitmu");
/* fall through */
case AD_ACID:
otmp = mksobj(ACID_VENOM, TRUE, FALSE);
break;
}
if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
if (canseemon(mtmp))
pline("%s spits venom!", Monnam(mtmp));
target = mtarg;
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
target = (struct monst *)0;
nomul(0);
/* If this is a pet, it'll get hungry. Minions and
* spell beings won't hunger */
if (mtmp->mtame && !mtmp->isminion) {
struct edog *dog = EDOG(mtmp);
/* Hunger effects will catch up next move */
if (dog->hungrytime > 1)
dog->hungrytime -= 5;
}
return 1;
}
}
return 0;
}
/* monster breathes at monster (ranged) */
int
breamm(mtmp, mattk, mtarg)
struct monst *mtmp, *mtarg;
struct attack *mattk;
{
/* if new breath types are added, change AD_ACID to max type */
int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
if (m_lined_up(mtarg, mtmp)) {
if (mtmp->mcan) {
if (!Deaf) {
if (canseemon(mtmp))
pline("%s coughs.", Monnam(mtmp));
else
You_hear("a cough.");
}
return 0;
}
if (!mtmp->mspec_used && rn2(3)) {
if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
if (canseemon(mtmp))
pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
dobuzz((int) (-20 - (typ - 1)), (int)mattk->damn,
mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
nomul(0);
/* breath runs out sometimes. Also, give monster some
* cunning; don't breath if the target fell asleep.
*/
mtmp->mspec_used = 6 + rn2(18);
/* If this is a pet, it'll get hungry. Minions and
* spell beings won't hunger */
if (mtmp->mtame && !mtmp->isminion) {
struct edog *dog = EDOG(mtmp);
/* Hunger effects will catch up next move */
if (dog->hungrytime >= 10)
dog->hungrytime -= 10;
}
} else impossible("Breath weapon %d used", typ-1);
} else
return 0;
}
return 1;
}
/* remove an entire item from a monster's inventory; destroy that item */
void
m_useupall(mon, obj)
@@ -520,7 +835,6 @@ struct monst *mtmp;
{
struct obj *otmp, *mwep;
xchar x, y;
int multishot;
const char *onm;
/* Rearranged beginning so monsters can use polearms not in a line */
@@ -579,101 +893,7 @@ struct monst *mtmp;
return;
mwep = MON_WEP(mtmp); /* wielded weapon */
/* Multishot calculations */
multishot = 1;
if (otmp->quan > 1L /* no point checking if there's only 1 */
/* ammo requires corresponding launcher be wielded */
&& (is_ammo(otmp)
? matching_launcher(otmp, mwep)
/* otherwise any stackable (non-ammo) weapon */
: otmp->oclass == WEAPON_CLASS)
&& !mtmp->mconf) {
int skill = (int) objects[otmp->otyp].oc_skill;
/* Assumes lords are skilled, princes are expert */
if (is_prince(mtmp->data))
multishot += 2;
else if (is_lord(mtmp->data))
multishot++;
/* fake players treated as skilled (regardless of role limits) */
else if (is_mplayer(mtmp->data))
multishot++;
/* class bonus */
switch (monsndx(mtmp->data)) {
case PM_MONK:
if (skill == -P_SHURIKEN)
multishot++;
break;
case PM_RANGER:
multishot++;
break;
case PM_ROGUE:
if (skill == P_DAGGER)
multishot++;
break;
case PM_NINJA:
if (skill == -P_SHURIKEN || skill == -P_DART)
multishot++;
/*FALLTHRU*/
case PM_SAMURAI:
if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
multishot++;
break;
default:
break;
}
/* racial bonus */
if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep
&& mwep->otyp == ELVEN_BOW)
|| (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep
&& mwep->otyp == ORCISH_BOW))
multishot++;
multishot = rnd(multishot);
if ((long) multishot > otmp->quan)
multishot = (int) otmp->quan;
}
if (canseemon(mtmp)) {
char onmbuf[BUFSZ];
if (multishot > 1) {
/* "N arrows"; multishot > 1 implies otmp->quan > 1, so
xname()'s result will already be pluralized */
Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
onm = onmbuf;
} else {
/* "an arrow" */
onm = singular(otmp, xname);
onm = obj_is_pname(otmp) ? the(onm) : an(onm);
}
m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
m_shot.o = otmp->otyp;
} else {
m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
}
m_shot.n = multishot;
for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
/* conceptually all N missiles are in flight at once, but
if mtmp gets killed (shot kills adjacent gas spore and
triggers explosion, perhaps), inventory will be dropped
and otmp might go away via merging into another stack */
if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) {
/* cancel pending shots (ought to give a message here since
we gave one above about throwing/shooting N missiles) */
break; /* endmultishot(FALSE); */
}
}
m_shot.n = m_shot.i = 0;
m_shot.o = STRANGE_OBJECT;
m_shot.s = FALSE;
monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
nomul(0);
}
@@ -803,6 +1023,14 @@ int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
return FALSE;
}
STATIC_OVL boolean
m_lined_up(mtarg, mtmp)
struct monst *mtarg, *mtmp;
{
return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
}
/* is mtmp in position to use ranged attack? */
boolean
lined_up(mtmp)
+6 -3
View File
@@ -908,7 +908,8 @@ boolean with_price;
break;
}
if (obj->otyp == LEASH && obj->leashmon != 0) {
Strcat(bp, " (in use)");
Sprintf(eos(bp), " (attached to %s)",
a_monnam(find_mid(obj->leashmon, FM_FMON)));
break;
}
if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
@@ -2488,7 +2489,8 @@ char oclass;
long prob = rn2(maxprob);
i = 0;
while (i < n - 1 && (prob -= (objects[validobjs[i]].oc_prob + 1)) > 0)
while (i < n - 1
&& (prob -= (objects[validobjs[i]].oc_prob + 1)) >= 0)
i++;
return validobjs[i];
}
@@ -3568,7 +3570,8 @@ typfnd:
}
otmp = oname(otmp, name);
if (otmp->oartifact) {
/* name==aname => wished for artifact (otmp->oartifact => got it) */
if (otmp->oartifact || name == aname) {
otmp->quan = 1L;
u.uconduct.wisharti++; /* KMH, conduct */
}
+13 -12
View File
@@ -420,6 +420,8 @@ static struct Comp_Opt {
#else /* use rest of file */
extern char configfile[]; /* for messages */
extern struct symparse loadsyms[];
static boolean need_redraw; /* for doset() */
@@ -917,10 +919,10 @@ rejectoption(optname)
const char *optname;
{
#ifdef MICRO
pline("\"%s\" settable only from %s.", optname, lastconfigfile);
pline("\"%s\" settable only from %s.", optname, configfile);
#else
pline("%s can be set only from NETHACKOPTIONS or %s.", optname,
lastconfigfile);
configfile);
#endif
}
@@ -941,7 +943,7 @@ const char *opts;
#endif
if (from_file)
raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", lastconfigfile,
raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", configfile,
#ifdef WIN32
"\n",
#else
@@ -2207,12 +2209,13 @@ boolean tinitial, tfrom_file;
bad_negation(fullname, TRUE);
return;
}
#ifdef CHANGE_COLOR
if (match_optname(opts, "palette", 3, TRUE)
#ifdef MAC
|| match_optname(opts, "hicolor", 3, TRUE)
#endif
) {
) {
int color_number, color_incr;
#ifndef WIN32
@@ -2227,17 +2230,16 @@ boolean tinitial, tfrom_file;
}
color_number = CLR_MAX + 4; /* HARDCODED inverse number */
color_incr = -1;
} else {
} else
#endif
{
if (negated) {
bad_negation("palette", FALSE);
return;
}
color_number = 0;
color_incr = 1;
#ifdef MAC
}
#endif
#ifdef WIN32
op = string_for_opt(opts, TRUE);
if (!alternative_palette(op))
@@ -2264,8 +2266,8 @@ boolean tinitial, tfrom_file;
#else
rgb <<= 8;
#endif
tmp = *(pt++);
if (isalpha(tmp)) {
tmp = *pt++;
if (isalpha((uchar) tmp)) {
tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */
} else {
tmp &= 0xf; /* Digits in ASCII too... */
@@ -2277,9 +2279,8 @@ boolean tinitial, tfrom_file;
rgb += tmp;
}
}
if (*pt == '/') {
if (*pt == '/')
pt++;
}
change_color(color_number, rgb, reverse);
color_number += color_incr;
}
@@ -5319,7 +5320,7 @@ option_help()
winid datawin;
datawin = create_nhwindow(NHW_TEXT);
Sprintf(buf, "Set options as OPTIONS=<options> in %s", lastconfigfile);
Sprintf(buf, "Set options as OPTIONS=<options> in %s", configfile);
opt_intro[CONFIG_SLOT] = (const char *) buf;
for (i = 0; opt_intro[i]; i++)
putstr(datawin, 0, opt_intro[i]);
+303 -47
View File
@@ -1,4 +1,4 @@
/* NetHack 3.6 pager.c $NHDT-Date: 1463790247 2016/05/21 00:24:07 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.98 $ */
/* NetHack 3.6 pager.c $NHDT-Date: 1465114189 2016/06/05 08:09:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.107 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
@@ -17,6 +17,7 @@ STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *));
STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
STATIC_DCL void NDECL(whatdoes_help);
STATIC_DCL boolean FDECL(help_menu, (int *));
STATIC_DCL void NDECL(docontact);
#ifdef PORT_HELP
@@ -74,11 +75,13 @@ char *outbuf;
mons[u.umonnum].mname, plname);
if (u.usteed)
Sprintf(eos(outbuf), ", mounted on %s", y_monnam(u.usteed));
if (u.uundetected || (Upolyd && youmonst.m_ap_type))
mhidden_description(&youmonst, FALSE, eos(outbuf));
return outbuf;
}
/* describe a hidden monster; used for look_at during extended monster
detection and for probing */
detection and for probing; also when looking at self */
void
mhidden_description(mon, altmon, outbuf)
struct monst *mon;
@@ -86,8 +89,10 @@ boolean altmon; /* for probing: if mimicking a monster, say so */
char *outbuf;
{
struct obj *otmp;
boolean fakeobj;
int x = mon->mx, y = mon->my, glyph = levl[x][y].glyph;
boolean fakeobj, isyou = (mon == &youmonst);
int x = isyou ? u.ux : mon->mx, y = isyou ? u.uy : mon->my,
glyph = (level.flags.hero_memory && !isyou) ? levl[x][y].glyph
: glyph_at(x, y);
*outbuf = '\0';
if (mon->m_ap_type == M_AP_FURNITURE
@@ -113,7 +118,7 @@ char *outbuf;
if (altmon)
Sprintf(outbuf, ", masquerading as %s",
an(mons[mon->mappearance].mname));
} else if (mon->mundetected) {
} else if (isyou ? u.uundetected : mon->mundetected) {
Strcpy(outbuf, ", hiding");
if (hides_under(mon->data)) {
Strcat(outbuf, " under ");
@@ -141,10 +146,16 @@ struct obj **obj_p;
{
boolean fakeobj = FALSE;
struct monst *mtmp;
struct obj *otmp = vobj_at(x, y);
struct obj *otmp;
int glyphotyp = glyph_to_obj(glyph);
*obj_p = (struct obj *) 0;
/* TODO: check inside containers in case glyph came from detection */
if ((otmp = sobj_at(glyphotyp, x, y)) == 0)
for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj)
if (otmp->ox == x && otmp->oy == y && otmp->otyp == glyphotyp)
break;
/* there might be a mimic here posing as an object */
mtmp = m_at(x, y);
if (mtmp && is_obj_mappear(mtmp, (unsigned) glyphotyp))
@@ -169,6 +180,11 @@ struct obj **obj_p;
(corpse type will be known even if dknown is 0, so we don't need a
touch check for cockatrice corpse--we're looking without touching) */
if (otmp && distu(x, y) <= 2 && !Blind && !Hallucination
/* redundant: we only look for an object which matches current
glyph among floor and buried objects; when !Blind, any buried
object's glyph will have been replaced by whatever is present
on the surface as soon as we moved next to its spot */
&& otmp->where == OBJ_FLOOR /* not buried */
/* terrain mode views what's already known, doesn't learn new stuff */
&& !iflags.terrainmode) /* so don't set dknown when in terrain mode */
otmp->dknown = 1; /* if a pile, clearly see the top item only */
@@ -194,7 +210,9 @@ int x, y, glyph;
} else
Strcpy(buf, something); /* sanity precaution */
if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
if (otmp && otmp->where == OBJ_BURIED)
Strcat(buf, " (buried)");
else if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR)
Strcat(buf, " embedded in stone");
else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR)
Strcat(buf, " embedded in a wall");
@@ -229,9 +247,14 @@ int x, y;
? "peaceful "
: "",
name);
if (u.ustuck == mtmp)
Strcat(buf, (Upolyd && sticks(youmonst.data))
? ", being held" : ", holding you");
if (u.ustuck == mtmp) {
if (u.uswallow || iflags.save_uswallow) /* monster detection */
Strcat(buf, is_animal(mtmp->data)
? ", swallowing you" : ", engulfing you");
else
Strcat(buf, (Upolyd && sticks(youmonst.data))
? ", being held" : ", holding you");
}
if (mtmp->mleashed)
Strcat(buf, ", leashed to you");
@@ -328,6 +351,7 @@ char *buf, *monbuf;
buf[0] = monbuf[0] = '\0';
glyph = glyph_at(x, y);
if (u.ux == x && u.uy == y && canspotself()
&& !(iflags.save_uswallow && glyph == mon_to_glyph(u.ustuck))
&& (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) {
/* fill in buf[] */
(void) self_lookat(buf);
@@ -342,7 +366,8 @@ char *buf, *monbuf;
(even if you could also see yourself via other means).
Sensing self while blind or swallowed is treated as if it
were by normal vision (cf canseeself()). */
if ((Invisible || u.uundetected) && !Blind && !u.uswallow) {
if ((Invisible || u.uundetected) && !Blind
&& !(u.uswallow || iflags.save_uswallow)) {
unsigned how = 0;
if (Infravision)
@@ -379,7 +404,17 @@ char *buf, *monbuf;
} else if (glyph_is_trap(glyph)) {
int tnum = what_trap(glyph_to_trap(glyph));
Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
/* Trap detection displays a bear trap at locations having
* a trapped door or trapped container or both.
* TODO: we should create actual trap types for doors and
* chests so that they can have their own glyphs and tiles.
*/
if (trapped_chest_at(tnum, x, y))
Strcpy(buf, "trapped chest"); /* might actually be a large box */
else if (trapped_door_at(tnum, x, y))
Strcpy(buf, "trapped door"); /* not "trap door"... */
else
Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation);
} else if (glyph_is_warning(glyph)) {
int warnindx = glyph_to_warning(glyph);
@@ -692,10 +727,15 @@ const char **firstmatch;
* submerged will always both be False and skip this code.)
*/
x_str = 0;
if (looked && (u.uswallow || submerged) && distu(cc.x, cc.y) > 2) {
if (!looked) {
; /* skip special handling */
} else if (((u.uswallow || submerged) && distu(cc.x, cc.y) > 2)
/* detection showing some category, so mostly background */
|| ((iflags.terrainmode & (TER_DETECT | TER_MAP)) == TER_DETECT
&& glyph == cmap_to_glyph(S_stone))) {
x_str = unreconnoitered;
need_to_look = FALSE;
} else if (looked && u.uswallow && is_swallow_sym(sym)) {
} else if (is_swallow_sym(sym)) {
x_str = mon_interior;
need_to_look = TRUE; /* for specific monster type */
}
@@ -775,9 +815,6 @@ const char **firstmatch;
}
}
#define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap)
#define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge)
/* Now check for graphics symbols */
alt_i = (sym == (looked ? showsyms[0] : defsyms[0].sym)) ? 0 : (2 + 1);
for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) {
@@ -936,9 +973,7 @@ coord *click_cc;
if (quick) {
from_screen = TRUE; /* yes, we want to use the cursor */
i = 'y';
}
if (i != 'y') {
} else {
menu_item *pick_list = (menu_item *) 0;
winid win;
anything any;
@@ -1026,6 +1061,10 @@ coord *click_cc;
case '?':
from_screen = FALSE;
getlin("Specify what? (type the word)", out_str);
if (strcmp(out_str, " ")) /* keep single space as-is */
/* remove leading and trailing whitespace and
condense consecutive internal whitespace */
mungspaces(out_str);
if (out_str[0] == '\0' || out_str[0] == '\033')
return 0;
@@ -1220,12 +1259,24 @@ int
doidtrap()
{
register struct trap *trap;
int x, y, tt;
int x, y, tt, glyph;
if (!getdir("^"))
return 0;
x = u.ux + u.dx;
y = u.uy + u.dy;
/* check fake bear trap from confused gold detection */
glyph = glyph_at(x, y);
if (glyph_is_trap(glyph) && (tt = glyph_to_trap(glyph)) == BEAR_TRAP) {
boolean chesttrap = trapped_chest_at(tt, x, y);
if (chesttrap || trapped_door_at(tt, x, y)) {
pline("That is a trapped %s.", chesttrap ? "chest" : "door");
return 0; /* trap ID'd, but no time elapses */
}
}
for (trap = ftrap; trap; trap = trap->ntrap)
if (trap->tx == x && trap->ty == y) {
if (!trap->tseen)
@@ -1256,40 +1307,219 @@ doidtrap()
return 0;
}
STATIC_DCL void
whatdoes_help()
{
dlb *fp;
char *p, buf[BUFSZ];
winid tmpwin = create_nhwindow(NHW_TEXT);
fp = dlb_fopen(KEYHELP, "r");
if (!fp) {
pline("Cannot open \"%s\" data file!", KEYHELP);
display_nhwindow(WIN_MESSAGE, TRUE);
return;
}
while (dlb_fgets(buf, (int) sizeof buf, fp)) {
if (*buf == '#')
continue;
for (p = buf; *p; p++)
if (*p != ' ' && *p != '\t')
break;
putstr(tmpwin, 0, p);
}
(void) dlb_fclose(fp);
display_nhwindow(tmpwin, TRUE);
destroy_nhwindow(tmpwin);
}
#define WD_STACKLIMIT 5
struct wd_stack_frame {
Bitfield(active, 1);
Bitfield(been_true, 1);
Bitfield(else_seen, 1);
};
STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
int *, int));
STATIC_OVL boolean
whatdoes_cond(buf, stack, depth, lnum)
char *buf;
struct wd_stack_frame *stack;
int *depth, lnum;
{
const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
boolean newcond, neg, gotopt;
char *p, *q, act = buf[1];
int np = 0;
newcond = (act == '?' || !stack[*depth].been_true);
buf += 2;
mungspaces(buf);
if (act == '#' || *buf == '#' || !*buf || !newcond) {
gotopt = (*buf && *buf != '#');
*buf = '\0';
neg = FALSE; /* lint suppression */
p = q = (char *) 0;
} else {
gotopt = TRUE;
if ((neg = (*buf == '!')) != 0)
if (*++buf == ' ')
++buf;
p = index(buf, '='), q = index(buf, ':');
if (!p || (q && q < p))
p = q;
if (p) { /* we have a value specified */
/* handle a space before or after (or both) '=' (or ':') */
if (p > buf && p[-1] == ' ')
p[-1] = '\0'; /* end of keyword in buf[] */
*p++ = '\0'; /* terminate keyword, advance to start of value */
if (*p == ' ')
p++;
}
}
if (*buf && (act == '?' || act == ':')) {
if (!strcmpi(buf, "number_pad")) {
if (!p) {
newcond = iflags.num_pad;
} else {
/* convert internal encoding (separate yes/no and 0..3)
back to user-visible one (-1..4) */
np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
: (-1 * iflags.num_pad_mode); /* -1..0 */
newcond = FALSE;
for (; p; p = q) {
q = index(p, ',');
if (q)
*q++ = '\0';
if (atoi(p) == np) {
newcond = TRUE;
break;
}
}
}
} else if (!strcmpi(buf, "rest_on_space")) {
newcond = flags.rest_on_space;
} else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
newcond = flags.debug; /* == wizard */
} else if (!strcmpi(buf, "shell")) {
#ifdef SHELL
/* should we also check sysopt.shellers? */
newcond = TRUE;
#else
newcond = FALSE;
#endif
} else if (!strcmpi(buf, "suspend")) {
#ifdef SUSPEND
/* sysopt.shellers is also used for dosuspend()... */
newcond = TRUE;
#else
newcond = FALSE;
#endif
} else {
impossible(
"cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
act, lnum, buf);
neg = FALSE;
}
/* this works for number_pad too: &? !number_pad:-1,0
would be true for 1..4 after negation */
if (neg)
newcond = !newcond;
}
switch (act) {
default:
case '#': /* comment */
break;
case '.': /* endif */
if (--*depth < 0) {
impossible(badstackfmt, '.', lnum);
*depth = 0;
}
break;
case ':': /* else or elif */
if (*depth == 0 || stack[*depth].else_seen) {
impossible(badstackfmt, ':', lnum);
*depth = 1; /* so that stack[*depth - 1] is a valid access */
}
if (stack[*depth].active || stack[*depth].been_true
|| !stack[*depth - 1].active)
stack[*depth].active = 0;
else if (newcond)
stack[*depth].active = stack[*depth].been_true = 1;
if (!gotopt)
stack[*depth].else_seen = 1;
break;
case '?': /* if */
if (++*depth >= WD_STACKLIMIT) {
impossible(badstackfmt, '?', lnum);
*depth = WD_STACKLIMIT - 1;
}
stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
stack[*depth].been_true = stack[*depth].active;
stack[*depth].else_seen = 0;
break;
}
return stack[*depth].active ? TRUE : FALSE;
}
char *
dowhatdoes_core(q, cbuf)
char q;
char *cbuf;
{
dlb *fp;
char bufr[BUFSZ];
register char *buf = &bufr[6], ctrl, meta;
char buf[BUFSZ];
struct wd_stack_frame stack[WD_STACKLIMIT];
boolean cond;
int ctrl, meta, depth = 0, lnum = 0;
fp = dlb_fopen(CMDHELPFILE, "r");
if (!fp) {
pline("Cannot open data file!");
pline("Cannot open \"%s\" data file!", CMDHELPFILE);
return 0;
}
ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
meta = ((0x80 & q) ? (0x7f & q) : 0);
while (dlb_fgets(buf, BUFSZ - 6, fp)) {
if ((ctrl && *buf == '^' && *(buf + 1) == ctrl)
|| (meta && *buf == 'M' && *(buf + 1) == '-'
&& *(buf + 2) == meta) || *buf == q) {
meta = (0x80 & (uchar) q) != 0;
if (meta)
q &= 0x7f;
ctrl = (0x1f & (uchar) q) == (uchar) q;
if (ctrl)
q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
else if (q == 0x7f)
ctrl = 1, q = '?';
(void) memset((genericptr_t) stack, 0, sizeof stack);
cond = stack[0].active = 1;
while (dlb_fgets(buf, sizeof buf, fp)) {
++lnum;
if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
cond = whatdoes_cond(buf, stack, &depth, lnum);
continue;
}
if (!cond)
continue;
if (meta ? (buf[0] == 'M' && buf[1] == '-'
&& (ctrl ? buf[2] == '^' && highc(buf[3]) == q
: buf[2] == q))
: (ctrl ? buf[0] == '^' && highc(buf[1]) == q
: buf[0] == q)) {
(void) strip_newline(buf);
if (ctrl && buf[2] == '\t') {
buf = bufr + 1;
(void) strncpy(buf, "^? ", 8);
buf[1] = ctrl;
} else if (meta && buf[3] == '\t') {
buf = bufr + 2;
if (index(buf, '\t'))
(void) tabexpand(buf);
if (meta && ctrl && buf[4] == ' ') {
(void) strncpy(buf, "M-^? ", 8);
buf[3] = q;
} else if (meta && buf[3] == ' ') {
(void) strncpy(buf, "M-? ", 8);
buf[2] = meta;
} else if (buf[1] == '\t') {
buf = bufr;
buf[2] = q;
} else if (ctrl && buf[2] == ' ') {
(void) strncpy(buf, "^? ", 8);
buf[1] = q;
} else if (buf[1] == ' ') {
(void) strncpy(buf, "? ", 8);
buf[0] = q;
(void) strncpy(buf + 1, " ", 7);
}
(void) dlb_fclose(fp);
Strcpy(cbuf, buf);
@@ -1297,31 +1527,57 @@ char *cbuf;
}
}
(void) dlb_fclose(fp);
if (depth != 0)
impossible("cmdhelp: mismatched &? &: &. conditionals.");
return (char *) 0;
}
int
dowhatdoes()
{
static boolean once = FALSE;
char bufr[BUFSZ];
char q, *reslt;
if (!once) {
pline("Ask about '&' or '?' to get more info.%s",
#ifdef ALTMETA
iflags.altmeta ? " (For ESC, type it twice.)" :
#endif
"");
once = TRUE;
}
#if defined(UNIX) || defined(VMS)
introff();
introff(); /* disables ^C but not ^\ */
#endif
q = yn_function("What command?", (char *) 0, '\0');
#ifdef ALTMETA
if (q == '\033' && iflags.altmeta) {
/* in an ideal world, we would know whether another keystroke
was already pending, but this is not an ideal world...
if user typed ESC, we'll essentially hang until another
character is typed */
q = yn_function("]", (char *) 0, '\0');
if (q != '\033')
q = (char) ((uchar) q | 0200);
}
#endif /*ALTMETA*/
#if defined(UNIX) || defined(VMS)
intron();
intron(); /* reenables ^C */
#endif
reslt = dowhatdoes_core(q, bufr);
if (reslt)
pline1(reslt);
else
pline("I've never heard of such commands.");
if (reslt) {
if (q == '&' || q == '?')
whatdoes_help();
pline("%s", reslt);
} else {
pline("No such command '%s', char code %d (0%03o or 0x%02x).",
visctrl(q), (uchar) q, (uchar) q, (uchar) q);
}
return 0;
}
void
STATIC_OVL void
docontact()
{
winid cwin = create_nhwindow(NHW_TEXT);
+2 -3
View File
@@ -39,7 +39,6 @@ STATIC_DCL int FDECL(traditional_loot, (BOOLEAN_P));
STATIC_DCL int FDECL(menu_loot, (int, BOOLEAN_P));
STATIC_DCL char FDECL(in_or_out_menu, (const char *, struct obj *, BOOLEAN_P,
BOOLEAN_P, BOOLEAN_P, BOOLEAN_P));
STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P));
STATIC_DCL boolean FDECL(able_to_loot, (int, int, BOOLEAN_P));
STATIC_DCL boolean NDECL(reverse_loot);
STATIC_DCL boolean FDECL(mon_beside, (int, int));
@@ -1513,7 +1512,7 @@ encumber_msg()
}
/* Is there a container at x,y. Optional: return count of containers at x,y */
STATIC_OVL int
int
container_at(x, y, countem)
int x, y;
boolean countem;
@@ -1549,7 +1548,7 @@ boolean looting; /* loot vs tip */
/* at present, can't loot in water even when Underwater;
can tip underwater, but not when over--or stuck in--lava */
You("cannot %s things that are deep in the %s.", verb,
is_lava(x, y) ? "lava" : "water");
hliquid(is_lava(x, y) ? "lava" : "water"));
return FALSE;
} else if (nolimbs(youmonst.data)) {
pline("Without limbs, you cannot %s anything.", verb);
+8 -7
View File
@@ -807,7 +807,7 @@ int mntmp;
} else if (likes_lava(youmonst.data) && u.utrap
&& u.utraptype == TT_LAVA) {
u.utrap = 0;
pline_The("lava now feels soothing.");
pline_The("%s now feels soothing.", hliquid("lava"));
}
if (amorphous(youmonst.data) || is_whirly(youmonst.data)
|| unsolid(youmonst.data)) {
@@ -1399,11 +1399,12 @@ dohide()
(except for floor hiders [trapper or mimic] in pits) */
if (u.ustuck || (u.utrap && (u.utraptype != TT_PIT || on_ceiling))) {
You_cant("hide while you're %s.",
!u.ustuck ? "trapped" : !sticks(youmonst.data)
? "being held"
: humanoid(u.ustuck->data)
? "holding someone"
: "holding that creature");
!u.ustuck ? "trapped"
: u.uswallow ? (is_animal(u.ustuck->data) ? "swallowed"
: "engulfed")
: !sticks(youmonst.data) ? "being held"
: (humanoid(u.ustuck->data) ? "holding someone"
: "holding that creature"));
if (u.uundetected
|| (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) {
u.uundetected = 0;
@@ -1418,7 +1419,7 @@ dohide()
if (IS_FOUNTAIN(levl[u.ux][u.uy].typ))
The("fountain is not deep enough to hide in.");
else
There("is no water to hide in here.");
There("is no %s to hide in here.", hliquid("water"));
u.uundetected = 0;
return 0;
}
+33 -24
View File
@@ -578,7 +578,7 @@ register struct obj *otmp;
break;
case POT_WATER:
if (!otmp->blessed && !otmp->cursed) {
pline("This tastes like water.");
pline("This tastes like %s.", hliquid("water"));
u.uhunger += rnd(10);
newuhs(FALSE);
break;
@@ -587,7 +587,7 @@ register struct obj *otmp;
if (is_undead(youmonst.data) || is_demon(youmonst.data)
|| u.ualign.type == A_CHAOTIC) {
if (otmp->blessed) {
pline("This burns like acid!");
pline("This burns like %s!", hliquid("acid"));
exercise(A_CON, FALSE);
if (u.ulycn >= LOW_PM) {
Your("affinity to %s disappears!",
@@ -616,7 +616,7 @@ register struct obj *otmp;
/* make_confused(0L, TRUE); */
} else {
if (u.ualign.type == A_LAWFUL) {
pline("This burns like acid!");
pline("This burns like %s!", hliquid("acid"));
losehp(Maybe_Half_Phys(d(2, 6)), "potion of unholy water",
KILLED_BY_AN);
} else
@@ -1241,16 +1241,18 @@ boolean your_fault;
{
const char *botlnam = bottlename();
boolean isyou = (mon == &youmonst);
int distance;
int distance, tx, ty;
struct obj *saddle = (struct obj *) 0;
boolean hit_saddle = FALSE;
if (isyou) {
tx = u.ux, ty = u.uy;
distance = 0;
pline_The("%s crashes on your %s and breaks into shards.", botlnam,
body_part(HEAD));
losehp(Maybe_Half_Phys(rnd(2)), "thrown potion", KILLED_BY_AN);
} else {
tx = mon->mx, ty = mon->my;
/* sometimes it hits the saddle */
if (((mon->misc_worn_check & W_SADDLE)
&& (saddle = which_armor(mon, W_SADDLE)))
@@ -1259,10 +1261,10 @@ boolean your_fault;
&& ((rnl(10) > 7 && obj->cursed)
|| (rnl(10) < 4 && obj->blessed) || !rn2(3)))))
hit_saddle = TRUE;
distance = distu(mon->mx, mon->my);
if (!cansee(mon->mx, mon->my))
distance = distu(tx, ty);
if (!cansee(tx, ty)) {
pline("Crash!");
else {
} else {
char *mnam = mon_nam(mon);
char buf[BUFSZ];
@@ -1285,7 +1287,7 @@ boolean your_fault;
}
/* oil doesn't instantly evaporate; Neither does a saddle hit */
if (obj->otyp != POT_OIL && !hit_saddle && cansee(mon->mx, mon->my))
if (obj->otyp != POT_OIL && !hit_saddle && cansee(tx, ty))
pline("%s.", Tobjnam(obj, "evaporate"));
if (isyou) {
@@ -1313,7 +1315,7 @@ boolean your_fault;
} else if (hit_saddle && saddle) {
char *mnam, buf[BUFSZ], saddle_glows[BUFSZ];
boolean affected = FALSE;
boolean useeit = !Blind && canseemon(mon) && cansee(mon->mx, mon->my);
boolean useeit = !Blind && canseemon(mon) && cansee(tx, ty);
mnam = x_monnam(mon, ARTICLE_THE, (char *) 0,
(SUPPRESS_IT | SUPPRESS_SADDLE), FALSE);
@@ -1331,10 +1333,8 @@ boolean your_fault;
if (useeit && !affected)
pline("%s %s wet.", buf, aobjnam(saddle, "get"));
} else {
boolean angermon = TRUE;
boolean angermon = your_fault;
if (!your_fault)
angermon = FALSE;
switch (obj->otyp) {
case POT_HEALING:
case POT_EXTRA_HEALING:
@@ -1419,7 +1419,7 @@ boolean your_fault;
pline("%s %s in pain!", Monnam(mon),
is_silent(mon->data) ? "writhes" : "shrieks");
if (!is_silent(mon->data))
wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10);
wake_nearto(tx, ty, mon->data->mlevel * 10);
mon->mhp -= d(2, 6);
/* should only be by you */
if (mon->mhp < 1)
@@ -1451,14 +1451,14 @@ boolean your_fault;
break;
case POT_OIL:
if (obj->lamplit)
explode_oil(obj, mon->mx, mon->my);
explode_oil(obj, tx, ty);
break;
case POT_ACID:
if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) {
pline("%s %s in pain!", Monnam(mon),
is_silent(mon->data) ? "writhes" : "shrieks");
if (!is_silent(mon->data))
wake_nearto(mon->mx, mon->my, mon->data->mlevel * 10);
wake_nearto(tx, ty, mon->data->mlevel * 10);
mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8);
if (mon->mhp < 1) {
if (your_fault)
@@ -1480,27 +1480,36 @@ boolean your_fault;
break;
*/
}
if (angermon)
wakeup(mon);
else
mon->msleeping = 0;
/* target might have been killed */
if (mon->mhp > 0) {
if (angermon)
wakeup(mon);
else
mon->msleeping = 0;
}
}
/* Note: potionbreathe() does its own docall() */
if ((distance == 0 || ((distance < 3) && rn2(5)))
if ((distance == 0 || (distance < 3 && rn2(5)))
&& (!breathless(youmonst.data) || haseyes(youmonst.data)))
potionbreathe(obj);
else if (obj->dknown && !objects[obj->otyp].oc_name_known
&& !objects[obj->otyp].oc_uname && cansee(mon->mx, mon->my))
&& !objects[obj->otyp].oc_uname && cansee(tx, ty))
docall(obj);
if (*u.ushops && obj->unpaid) {
struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE));
if (shkp)
/* neither of the first two cases should be able to happen;
only the hero should ever have an unpaid item, and only
when inside a tended shop */
if (!shkp) /* if shkp was killed, unpaid ought to cleared already */
obj->unpaid = 0;
else if (context.mon_moving) /* obj thrown by monster */
subfrombill(obj, shkp);
else /* obj thrown by hero */
(void) stolen_value(obj, u.ux, u.uy, (boolean) shkp->mpeaceful,
FALSE);
else
obj->unpaid = 0;
}
obfree(obj, (struct obj *) 0);
}
+1 -1
View File
@@ -1973,7 +1973,7 @@ doturn()
}
}
}
nomul(-5);
nomul(-(5 - ((u.ulevel - 1) / 6))); /* -5 .. -1 */
multi_reason = "trying to turn the monsters";
nomovemsg = You_can_move_again;
return 1;
+5 -5
View File
@@ -491,11 +491,11 @@ int roomno;
if (!rn2(5)
&& (mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS))
!= 0) {
/* [TODO: alter this (at a minimum, by switching from
an exclamation to a simple declaration) if hero has
already killed enough ghosts.] */
int ngen = mvitals[PM_GHOST].born;
if (canspotmon(mtmp))
pline("An enormous ghost appears next to you!");
pline("A%s ghost appears next to you%c",
ngen < 5 ? "n enormous" : "",
ngen < 10 ? '!' : '.');
else
You("sense a presence close by!");
mtmp->mpeaceful = 0;
@@ -503,7 +503,7 @@ int roomno;
if (flags.verbose)
You("are frightened to death, and unable to move.");
nomul(-3);
multi_reason = "being terrified of a demon";
multi_reason = "being terrified of a ghost";
nomovemsg = "You regain your composure.";
}
}
+10 -3
View File
@@ -1571,7 +1571,7 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
break;
}
if (Underwater) {
pline_The("water around you vaporizes violently!");
pline_The("%s around you vaporizes violently!", hliquid("water"));
} else {
pline_The("scroll erupts in a tower of flame!");
iflags.last_msg = PLNMSG_TOWER_OF_FLAME; /* for explode() */
@@ -2371,7 +2371,8 @@ create_particular()
struct permonst *whichpm = NULL;
struct monst *mtmp;
boolean madeany = FALSE, randmonst = FALSE,
maketame, makepeaceful, makehostile, saddled, invisible;
maketame, makepeaceful, makehostile, saddled, invisible,
sleeping;
int fem;
tryct = 5;
@@ -2379,7 +2380,7 @@ create_particular()
monclass = MAXMCLASSES;
which = urole.malenum; /* an arbitrary index into mons[] */
maketame = makepeaceful = makehostile = FALSE;
saddled = invisible = FALSE;
sleeping = saddled = invisible = FALSE;
fem = -1; /* gender not specified */
getlin("Create what kind of monster? [type the name or symbol]", buf);
bufp = mungspaces(buf);
@@ -2389,6 +2390,10 @@ create_particular()
saddled = TRUE;
(void) memset(tmpp, ' ', sizeof "saddled " - 1);
}
if ((tmpp = strstri(bufp, "sleeping ")) != 0) {
sleeping = TRUE;
(void) memset(tmpp, ' ', sizeof "sleeping " - 1);
}
if ((tmpp = strstri(bufp, "invisible ")) != 0) {
invisible = TRUE;
(void) memset(tmpp, ' ', sizeof "invisible " - 1);
@@ -2478,6 +2483,8 @@ create_particular()
}
if (invisible)
mon_set_minvis(mtmp);
if (sleeping)
mtmp->msleeping = 1;
madeany = TRUE;
/* in case we got a doppelganger instead of what was asked
for, make it start out looking like what was asked for */
+10 -11
View File
@@ -1700,18 +1700,17 @@ plnamesuffix()
char *sptr, *eptr;
int i;
#ifdef GENERIC_USERNAMES
{
/* some generic user names will be ignored in favor of prompting */
const char *uptr = GENERIC_USERNAMES;
i = (int) strlen(plname);
if ((sptr = strstri(uptr, plname)) != 0
&& (sptr == uptr || sptr[-1] == ' ')
&& (sptr[i] == ' ' || sptr[i] == '\0'))
*plname = '\0'; /* call askname() */
/* some generic user names will be ignored in favor of prompting */
if (sysopt.genericusers) {
if (*sysopt.genericusers == '*') *plname = '\0';
else {
i = (int)strlen(plname);
if ((sptr = strstri(sysopt.genericusers, plname)) != 0
&& (sptr == sysopt.genericusers || sptr[-1] == ' ')
&& (sptr[i] == ' ' || sptr[i] == '\0'))
*plname = '\0'; /* call askname() */
}
}
#endif
do {
if (!*plname)
+2
View File
@@ -115,6 +115,8 @@ dosave0()
a few of things before saving so that they won't be restored in
an improper state; these will be no-ops for normal save sequence */
u.uinvulnerable = 0;
if (iflags.save_uswallow)
u.uswallow = 1, iflags.save_uswallow = 0;
if (iflags.save_uinwater)
u.uinwater = 1, iflags.save_uinwater = 0;
if (iflags.save_uburied)
+5 -5
View File
@@ -100,7 +100,7 @@ dosit()
u.utrap += rn1(10, 5);
} else if (u.utraptype == TT_LAVA) {
/* Must have fire resistance or they'd be dead already */
You("sit in the lava!");
You("sit in the %s!", hliquid("lava"));
if (Slimed)
burn_away_slime();
u.utrap += rnd(4);
@@ -122,7 +122,7 @@ dosit()
You("sit down on the muddy bottom.");
} else if (is_pool(u.ux, u.uy)) {
in_water:
You("sit in the water.");
You("sit in the %s.", hliquid("water"));
if (!rn2(10) && uarm)
(void) water_damage(uarm, "armor", TRUE);
if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS)
@@ -141,13 +141,13 @@ dosit()
You(sit_message, "ladder");
} else if (is_lava(u.ux, u.uy)) {
/* must be WWalking */
You(sit_message, "lava");
You(sit_message, hliquid("lava"));
burn_away_slime();
if (likes_lava(youmonst.data)) {
pline_The("lava feels warm.");
pline_The("%s feels warm.", hliquid("lava"));
return 1;
}
pline_The("lava burns you!");
pline_The("%s burns you!", hliquid("lava"));
losehp(d((Fire_resistance ? 2 : 10), 10), /* lava damage */
"sitting on lava", KILLED_BY);
} else if (is_ice(u.ux, u.uy)) {
+27 -6
View File
@@ -43,6 +43,7 @@ STATIC_DCL int NDECL(throwspell);
STATIC_DCL void NDECL(cast_protection);
STATIC_DCL void FDECL(spell_backfire, (int));
STATIC_DCL const char *FDECL(spelltypemnemonic, (int));
STATIC_DCL boolean FDECL(spell_hurtle_step, (genericptr_t, int, int));
/* The roles[] table lists the role-specific values for tuning
* percent_success().
@@ -812,11 +813,11 @@ cast_protection()
? "maw"
: "ooze")
: (u.uinwater
? "water"
? hliquid("water")
: (rmtyp == CLOUD)
? "cloud"
: IS_TREE(rmtyp)
? "vegitation"
? "vegetation"
: IS_STWALL(rmtyp)
? "stone"
: "air");
@@ -1136,6 +1137,7 @@ boolean atme;
case SPE_INVISIBILITY:
(void) peffects(pseudo);
break;
/* end of potion-like spells */
case SPE_CURE_BLINDNESS:
healup(0, 0, FALSE, TRUE);
@@ -1151,10 +1153,12 @@ boolean atme;
(void) make_familiar((struct obj *) 0, u.ux, u.uy, FALSE);
break;
case SPE_CLAIRVOYANCE:
if (!BClairvoyant)
do_vicinity_map();
if (!BClairvoyant) {
if (role_skill >= P_SKILLED)
pseudo->blessed = 1; /* detect monsters as well as map */
do_vicinity_map(pseudo);
/* at present, only one thing blocks clairvoyance */
else if (uarmh && uarmh->otyp == CORNUTHAUM)
} else if (uarmh && uarmh->otyp == CORNUTHAUM)
You("sense a pointy hat on top of your %s.", body_part(HEAD));
break;
case SPE_PROTECTION:
@@ -1177,11 +1181,23 @@ boolean atme;
return 1;
}
STATIC_OVL boolean
spell_hurtle_step(arg, x, y)
genericptr_t arg;
int x, y;
{
if (!isok(x,y)) return FALSE;
if (!ZAP_POS(levl[x][y].typ)
&& !(IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & D_ISOPEN)))
return FALSE;
return TRUE;
}
/* Choose location where spell takes effect. */
STATIC_OVL int
throwspell()
{
coord cc;
coord cc, uc;
struct monst *mtmp;
if (u.uinwater) {
@@ -1214,6 +1230,11 @@ throwspell()
return 0;
}
uc.x = u.ux;
uc.y = u.uy;
walk_path(&uc, &cc, spell_hurtle_step, NULL);
u.dx = cc.x;
u.dy = cc.y;
return 1;
+4 -2
View File
@@ -289,7 +289,8 @@ boolean force; /* Quietly force this animal */
return (FALSE);
}
if (!force && Underwater && !is_swimmer(ptr)) {
You_cant("ride that creature while under water.");
You_cant("ride that creature while under %s.",
hliquid("water"));
return (FALSE);
}
if (!can_saddle(mtmp) || !can_ride(mtmp)) {
@@ -565,7 +566,8 @@ int reason; /* Player was thrown off etc. */
adjalign(-1);
}
} else if (is_lava(u.ux, u.uy)) {
pline("%s is pulled into the lava!", Monnam(mtmp));
pline("%s is pulled into the %s!", Monnam(mtmp),
hliquid("lava"));
if (!likes_lava(mdat)) {
killed(mtmp);
adjalign(-1);
+4
View File
@@ -35,6 +35,7 @@ sys_early_init()
sysopt.env_dbgfl = 0; /* haven't checked getenv("DEBUGFILES") yet */
sysopt.shellers = (char *) 0;
sysopt.explorers = (char *) 0;
sysopt.genericusers = (char *) 0;
sysopt.maxplayers = 0; /* XXX eventually replace MAX_NR_OF_PLAYERS */
/* record file */
@@ -94,6 +95,9 @@ sysopt_release()
if (sysopt.debugfiles)
free((genericptr_t) sysopt.debugfiles),
sysopt.debugfiles = (char *) 0;
if (sysopt.genericusers)
free((genericptr_t) sysopt.genericusers),
sysopt.genericusers = (char *) 0;
#ifdef PANICTRACE
if (sysopt.gdbpath)
free((genericptr_t) sysopt.gdbpath), sysopt.gdbpath = (char *) 0;
+9 -7
View File
@@ -3560,7 +3560,8 @@ drown()
}
if (!u.uinwater) {
You("%s into the water%c", Is_waterlevel(&u.uz) ? "plunge" : "fall",
You("%s into the %s%c", Is_waterlevel(&u.uz) ? "plunge" : "fall",
hliquid("water"),
Amphibious || Swimming ? '.' : '!');
if (!Swimming && !Is_waterlevel(&u.uz))
You("sink like %s.", Hallucination ? "the Titanic" : "a rock");
@@ -3657,7 +3658,7 @@ crawl:
/* time to do some strip-tease... */
boolean succ = Is_waterlevel(&u.uz) ? TRUE : emergency_disrobe(&lost);
You("try to crawl out of the water.");
You("try to crawl out of the %s.", hliquid("water"));
if (lost)
You("dump some of your gear to lose weight...");
if (succ) {
@@ -5026,13 +5027,13 @@ lava_effects()
if (!Fire_resistance) {
if (Wwalking) {
pline_The("lava here burns you!");
pline_The("%s here burns you!", hliquid("lava"));
if (usurvive) {
losehp(dmg, lava_killer, KILLED_BY); /* lava damage */
goto burn_stuff;
}
} else
You("fall into the lava!");
You("fall into the %s!", hliquid("lava"));
usurvive = Lifesaved || discover;
if (wizard)
@@ -5089,9 +5090,10 @@ lava_effects()
hero needs to escape immediately */
u.utrap = rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8);
u.utraptype = TT_LAVA;
You("sink into the lava%s!", !boil_away
? ", but it only burns slightly"
: " and are about to be immolated");
You("sink into the %s%s!", hliquid("lava"),
!boil_away
? ", but it only burns slightly"
: " and are about to be immolated");
if (u.uhp > 1)
losehp(!boil_away ? 1 : (u.uhp / 2), lava_killer,
KILLED_BY); /* lava damage */
+2
View File
@@ -1013,6 +1013,8 @@ register struct trobj *trop;
|| otyp == RIN_AGGRAVATE_MONSTER
|| otyp == RIN_HUNGER
|| otyp == WAN_NOTHING
/* orcs start with poison resistance */
|| (otyp == RIN_POISON_RESISTANCE && Race_if(PM_ORC))
/* Monks don't use weapons */
|| (otyp == SCR_ENCHANT_WEAPON && Role_if(PM_MONK))
/* wizard patch -- they already have one */
+3 -1
View File
@@ -2325,7 +2325,8 @@ boolean wep_was_destroyed;
if (Blind || !flags.verbose)
You("are splashed!");
else
You("are splashed by %s acid!", s_suffix(mon_nam(mon)));
You("are splashed by %s %s!", s_suffix(mon_nam(mon)),
hliquid("acid"));
if (!Acid_resistance)
mdamageu(mon, tmp);
@@ -2695,6 +2696,7 @@ int dmg;
pline("%s %s!", Monnam(mon),
(dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
mon->mhp -= dmg;
wake_nearto(mon->mx, mon->my, 30);
if (mon->mhp <= 0) {
if (context.mon_moving)
monkilled(mon, (char *) 0, AD_BLND);
+13 -12
View File
@@ -47,17 +47,17 @@ int pm;
{
switch (pm) {
case PM_WEREWOLF:
return (PM_HUMAN_WEREWOLF);
return PM_HUMAN_WEREWOLF;
case PM_HUMAN_WEREWOLF:
return (PM_WEREWOLF);
return PM_WEREWOLF;
case PM_WEREJACKAL:
return (PM_HUMAN_WEREJACKAL);
return PM_HUMAN_WEREJACKAL;
case PM_HUMAN_WEREJACKAL:
return (PM_WEREJACKAL);
return PM_WEREJACKAL;
case PM_WERERAT:
return (PM_HUMAN_WERERAT);
return PM_HUMAN_WERERAT;
case PM_HUMAN_WERERAT:
return (PM_WERERAT);
return PM_WERERAT;
default:
return NON_PM;
}
@@ -121,7 +121,8 @@ register struct monst *mon;
}
/* were-creature (even you) summons a horde */
int were_summon(ptr, yours, visible, genbuf)
int
were_summon(ptr, yours, visible, genbuf)
struct permonst *ptr;
boolean yours;
int *visible; /* number of visible helpers created */
@@ -138,20 +139,20 @@ char *genbuf;
switch (pm) {
case PM_WERERAT:
case PM_HUMAN_WERERAT:
typ =
rn2(3) ? PM_SEWER_RAT : rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT;
typ = rn2(3) ? PM_SEWER_RAT
: rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT;
if (genbuf)
Strcpy(genbuf, "rat");
break;
case PM_WEREJACKAL:
case PM_HUMAN_WEREJACKAL:
typ = PM_JACKAL;
typ = rn2(7) ? PM_JACKAL : rn2(3) ? PM_COYOTE : PM_FOX;
if (genbuf)
Strcpy(genbuf, "jackal");
break;
case PM_WEREWOLF:
case PM_HUMAN_WEREWOLF:
typ = rn2(5) ? PM_WOLF : PM_WINTER_WOLF;
typ = rn2(5) ? PM_WOLF : rn2(2) ? PM_WARG : PM_WINTER_WOLF;
if (genbuf)
Strcpy(genbuf, "wolf");
break;
@@ -176,7 +177,7 @@ you_were()
char qbuf[QBUFSZ];
boolean controllable_poly = Polymorph_control && !(Stunned || Unaware);
if (Unchanging || (u.umonnum == u.ulycn))
if (Unchanging || u.umonnum == u.ulycn)
return;
if (controllable_poly) {
/* `+4' => skip "were" prefix to get name of beast */
+25 -10
View File
@@ -3719,10 +3719,10 @@ xchar sx, sy;
break;
case ZT_ACID:
if (Acid_resistance) {
pline_The("acid doesn't hurt.");
pline_The("%s doesn't hurt.", hliquid("acid"));
dam = 0;
} else {
pline_The("acid burns!");
pline_The("%s burns!", hliquid("acid"));
dam = d(nd, 6);
exercise(A_STR, FALSE);
}
@@ -3869,6 +3869,15 @@ const char *fltxt;
xkilled(mon, XKILL_NOMSG | XKILL_NOCORPSE);
}
void
buzz(type,nd,sx,sy,dx,dy)
int type, nd;
xchar sx,sy;
int dx,dy;
{
dobuzz(type, nd, sx, sy, dx, dy, TRUE);
}
/*
* type == 0 to 9 : you shooting a wand
* type == 10 to 19 : you casting a spell
@@ -3879,10 +3888,11 @@ const char *fltxt;
* called with dx = dy = 0 with vertical bolts
*/
void
buzz(type, nd, sx, sy, dx, dy)
dobuzz(type, nd, sx, sy, dx, dy,say)
register int type, nd;
register xchar sx, sy;
register int dx, dy;
boolean say; /* Announce out of sight hit/miss events if true */
{
int range, abstype = abs(type) % 10;
register xchar lsx, lsy;
@@ -4009,7 +4019,8 @@ register int dx, dy;
} else {
if (!otmp) {
/* normal non-fatal hit */
hit(fltxt, mon, exclam(tmp));
if (say || canseemon(mon))
hit(fltxt, mon, exclam(tmp));
} else {
/* some armor was destroyed; no damage done */
if (canseemon(mon))
@@ -4024,7 +4035,8 @@ register int dx, dy;
}
range -= 2;
} else {
miss(fltxt, mon);
if (say || canseemon(mon))
miss(fltxt, mon);
}
} else if (sx == u.ux && sy == u.uy && range >= 0) {
nomul(0);
@@ -4059,11 +4071,14 @@ register int dx, dy;
if (!ZAP_POS(levl[sx][sy].typ)
|| (closed_door(sx, sy) && range >= 0)) {
int bounce;
int bounce, bchance;
uchar rmn;
boolean fireball;
make_bounce:
bchance = (levl[sx][sy].typ == STONE) ? 10
: (In_mines(&u.uz) && IS_WALL(levl[sx][sy].typ)) ? 20
: 75;
bounce = 0;
fireball = (type == ZT_SPELL(ZT_FIRE));
if ((--range > 0 && isok(lsx, lsy) && cansee(lsx, lsy))
@@ -4080,7 +4095,7 @@ register int dx, dy;
} else
pline_The("%s bounces!", fltxt);
}
if (!dx || !dy || !rn2(20)) {
if (!dx || !dy || !rn2(bchance)) {
dx = -dx;
dy = -dy;
} else {
@@ -4291,7 +4306,7 @@ short exploding_wand_typ;
if (lev->typ == WATER) {
/* For now, don't let WATER freeze. */
if (see_it)
pline_The("water freezes for a moment.");
pline_The("%s freezes for a moment.", hliquid("water"));
else
You_hear("a soft crackling.");
rangemod -= 1000; /* stop */
@@ -4312,11 +4327,11 @@ short exploding_wand_typ;
bury_objs(x, y);
if (see_it) {
if (lava)
Norep("The lava cools and solidifies.");
Norep("The %s cools and solidifies.", hliquid("lava"));
else if (moat)
Norep("The %s is bridged with ice!", buf);
else
Norep("The water freezes.");
Norep("The %s freezes.", hliquid("water"));
newsym(x, y);
} else if (!lava)
You_hear("a crackling sound.");