-/* NetHack 3.6 artifact.c $NHDT-Date: 1446369462 2015/11/01 09:17:42 $ $NHDT-Branch: master $:$NHDT-Revision: 1.96 $ */
+/* NetHack 3.6 artifact.c $NHDT-Date: 1553363416 2019/03/23 17:50:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.129 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2013. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
#define get_artifact(o) \
(((o) && (o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0)
-STATIC_DCL boolean
-FDECL(bane_applies, (const struct artifact *, struct monst *));
+STATIC_DCL boolean FDECL(bane_applies, (const struct artifact *,
+ struct monst *));
STATIC_DCL int FDECL(spec_applies, (const struct artifact *, struct monst *));
STATIC_DCL int FDECL(arti_invoke, (struct obj *));
-STATIC_DCL boolean
-FDECL(Mb_hit, (struct monst * magr, struct monst *mdef, struct obj *, int *,
- int, BOOLEAN_P, char *));
+STATIC_DCL boolean FDECL(Mb_hit, (struct monst * magr, struct monst *mdef,
+ struct obj *, int *, int, BOOLEAN_P, char *));
STATIC_DCL unsigned long FDECL(abil_to_spfx, (long *));
STATIC_DCL uchar FDECL(abil_to_adtyp, (long *));
+STATIC_DCL int FDECL(glow_strength, (int));
STATIC_DCL boolean FDECL(untouchable, (struct obj *, BOOLEAN_P));
+STATIC_DCL int FDECL(count_surround_traps, (int, int));
/* The amount added to the victim's total hit points to insure that the
victim will be killed even after damage bonus/penalty adjustments.
*/
void
set_artifact_intrinsic(otmp, on, wp_mask)
-register struct obj *otmp;
+struct obj *otmp;
boolean on;
long wp_mask;
{
long *mask = 0;
- register const struct artifact *oart = get_artifact(otmp);
+ register const struct artifact *art, *oart = get_artifact(otmp);
+ register struct obj *obj;
register uchar dtyp;
register long spfx;
mask = &EDisint_resistance;
else if (dtyp == AD_DRST)
mask = &EPoison_resistance;
+ else if (dtyp == AD_DRLI)
+ mask = &EDrain_resistance;
if (mask && wp_mask == W_ART && !on) {
- /* find out if some other artifact also confers this intrinsic */
- /* if so, leave the mask alone */
- register struct obj *obj;
- for (obj = invent; obj; obj = obj->nobj)
+ /* find out if some other artifact also confers this intrinsic;
+ if so, leave the mask alone */
+ for (obj = invent; obj; obj = obj->nobj) {
if (obj != otmp && obj->oartifact) {
- register const struct artifact *art = get_artifact(obj);
- if (art->cary.adtyp == dtyp) {
+ art = get_artifact(obj);
+ if (art && art->cary.adtyp == dtyp) {
mask = (long *) 0;
break;
}
}
+ }
}
if (mask) {
if (on)
spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx;
if (spfx && wp_mask == W_ART && !on) {
/* don't change any spfx also conferred by other artifacts */
- register struct obj *obj;
for (obj = invent; obj; obj = obj->nobj)
if (obj != otmp && obj->oartifact) {
- register const struct artifact *art = get_artifact(obj);
- spfx &= ~art->cspfx;
+ art = get_artifact(obj);
+ if (art)
+ spfx &= ~art->cspfx;
}
}
return 1;
yours = (mon == &youmonst);
- /* all quest artifacts are self-willed; it this ever changes, `badclass'
+ /* all quest artifacts are self-willed; if this ever changes, `badclass'
will have to be extended to explicitly include quest artifacts */
self_willed = ((oart->spfx & SPFX_INTEL) != 0);
if (yours) {
badclass = self_willed
&& ((oart->role != NON_PM && !Role_if(oart->role))
|| (oart->race != NON_PM && !Race_if(oart->race)));
- badalign =
- (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE
- && (oart->alignment != u.ualign.type || u.ualign.record < 0);
+ badalign = ((oart->spfx & SPFX_RESTR) != 0
+ && oart->alignment != A_NONE
+ && (oart->alignment != u.ualign.type
+ || u.ualign.record < 0));
} else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) {
badclass = self_willed && oart->role != NON_PM
&& oart != &artilist[ART_EXCALIBUR];
* stun attack. As of 3.4.1, those effects can occur but
* will be slightly less likely than they were in 3.3.x.]
*/
+
+enum mb_effect_indices {
+ MB_INDEX_PROBE = 0,
+ MB_INDEX_STUN,
+ MB_INDEX_SCARE,
+ MB_INDEX_CANCEL,
+
+ NUM_MB_INDICES
+};
+
#define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */
-static const char *const mb_verb[2][4] = {
+static const char *const mb_verb[2][NUM_MB_INDICES] = {
#if 0 /*JP*/
{ "probe", "stun", "scare", "cancel" },
{ "prod", "amaze", "tickle", "purge" },
{ "\97ã\82Ü\82µ", "\8bÁ\82©\82¹", "\82\82·\82®\82Á", "\90´\82ß" },
#endif
};
-#define MB_INDEX_PROBE 0
-#define MB_INDEX_STUN 1
-#define MB_INDEX_SCARE 2
-#define MB_INDEX_CANCEL 3
/* called when someone is being hit by Magicbane */
STATIC_OVL boolean
char *hittee; /* target's name: "you" or mon_nam(mdef) */
{
struct permonst *old_uasmon;
- const char *verb, *fakename;
+ const char *verb;
boolean youattack = (magr == &youmonst), youdefend = (mdef == &youmonst),
resisted = FALSE, do_stun, do_confuse, result;
+#if 0 /*JP*/
+ int attack_indx, fakeidx, scare_dieroll = MB_MAX_DIEROLL / 2;
+#else
int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2;
+#endif
result = FALSE; /* no message given yet */
/* the most severe effects are less likely at higher enchantment */
if (youmonst.data != old_uasmon)
*dmgptr = 0; /* rehumanized, so no more damage */
if (u.uenmax > 0) {
+ u.uenmax--;
+ if (u.uen > 0)
+ u.uen--;
+ context.botl = TRUE;
/*JP
You("lose magical energy!");
*/
You("\96\82\96@\82Ì\83G\83l\83\8b\83M\81[\82ð\8e¸\82Á\82½\81I");
- u.uenmax--;
- if (u.uen > 0)
- u.uen--;
- context.botl = 1;
}
} else {
if (mdef->data == &mons[PM_CLAY_GOLEM])
mdef->mhp = 1; /* cancelled clay golems will die */
if (youattack && attacktype(mdef->data, AT_MAGC)) {
+ u.uenmax++;
+ u.uen++;
+ context.botl = TRUE;
/*JP
You("absorb magical energy!");
*/
You("\96\82\96@\82Ì\83G\83l\83\8b\83M\81[\82ð\8bz\82¢\82Æ\82Á\82½\81I");
- u.uenmax++;
- u.uen++;
- context.botl = 1;
}
}
}
mdef->mconf = 1;
}
-#if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\95s\97v*/
- /* now give message(s) describing side-effects;
- don't let vtense() be fooled by assigned name ending in 's' */
- fakename = youdefend ? "you" : "mon";
+ /* now give message(s) describing side-effects; Use fakename
+ so vtense() won't be fooled by assigned name ending in 's' */
+#if 0 /*JP*/
+ fakeidx = youdefend ? 1 : 0;
#endif
if (youattack || youdefend || vis) {
(void) upstart(hittee); /* capitalize */
if (resisted) {
/*JP
- pline("%s %s!", hittee, vtense(fakename, "resist"));
+ pline("%s %s!", hittee, vtense(fakename[fakeidx], "resist"));
*/
pline("%s\82Í\96h\82¢\82¾\81I", hittee);
shieldeff(youdefend ? u.ux : mdef->mx,
char buf[BUFSZ];
buf[0] = '\0';
-#if 0 /*JP:T*/
+#if 0 /*JP*/
if (do_stun)
Strcat(buf, "stunned");
if (do_stun && do_confuse)
Strcat(buf, " and ");
if (do_confuse)
Strcat(buf, "confused");
- pline("%s %s %s%c", hittee, vtense(fakename, "are"), buf,
+ pline("%s %s %s%c", hittee, vtense(fakename[fakeidx], "are"), buf,
(do_stun && do_confuse) ? '!' : '.');
#else
if (do_stun && do_confuse)
pline("\8b\90\91å\82È\83n\83\93\83}\81[\82Í%s\82É\96½\92\86\82µ\82½%s", hittee,
!spec_dbon_applies ? "\81D" : "\81I\93d\8c\82\82ª\8fP\82Á\82½\81I");
#endif
+ if (spec_dbon_applies)
+ wake_nearto(mdef->mx, mdef->my, 4 * 4);
if (!rn2(5))
(void) destroy_mitem(mdef, RING_CLASS, AD_ELEC);
if (!rn2(5))
return (boolean) (youattack || vis);
}
if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
-/*JP
+#if 0 /*JP*/
pline("%s slices through %s %s.", wepdesc,
-*/
- pline("%s\82Í%s\82Ì%s\82ð\90Ø\82è\97\8e\82µ\82½\81D", wepdesc,
s_suffix(mon_nam(mdef)), mbodypart(mdef, NECK));
+#else
+ pline("%s\82Í%s\82Ì%s\82ð\90Ø\82è\97\8e\82µ\82½\81D", wepdesc,
+ mon_nam(mdef), mbodypart(mdef, NECK));
+#endif
return TRUE;
}
*dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER;
make_slimed(0L, (char *) 0);
if (Blinded > creamed)
make_blinded(creamed, FALSE);
- context.botl = 1;
+ context.botl = TRUE;
break;
}
case ENERGY_BOOST: {
int epboost = (u.uenmax + 1 - u.uen) / 2;
+
if (epboost > 120)
epboost = 120; /* arbitrary */
else if (epboost < 12)
epboost = u.uenmax - u.uen;
if (epboost) {
+ u.uen += epboost;
+ context.botl = TRUE;
/*JP
You_feel("re-energized.");
*/
You("\83G\83l\83\8b\83M\81[\82Å\96\9e\82½\82³\82ê\82½\81D");
- u.uen += epboost;
- context.botl = 1;
} else
goto nothing_special;
break;
obj->age = 0;
return 0;
}
- b_effect =
- obj->blessed && (Role_switch == oart->role || !oart->role);
+ b_effect = (obj->blessed && (oart->role == Role_switch
+ || oart->role == NON_PM));
recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0);
update_inventory();
break;
} else
otmp->quan += rnd(5);
otmp->owt = weight(otmp);
- otmp =
#if 0 /*JP*/
- hold_another_object(otmp, "Suddenly %s out.",
- aobjnam(otmp, "fall"), (const char *) 0);
+ otmp = hold_another_object(otmp, "Suddenly %s out.",
+ aobjnam(otmp, "fall"), (char *) 0);
#else
- hold_another_object(otmp, "\93Ë\91R%s\82ª\97\8e\82¿\82½\81D",
- xname(otmp), 0);
+ otmp = hold_another_object(otmp, "\93Ë\91R%s\82ª\97\8e\82¿\82½\81D",
+ xname(otmp), 0);
#endif
+ nhUse(otmp);
break;
}
}
}
if ((eprop & ~W_ARTI) || iprop) {
- nothing_special:
+ nothing_special:
/* you had the property from some other source too */
if (carried(obj))
/*JP
{ &EAntimagic, AD_MAGM },
{ &EDisint_resistance, AD_DISN },
{ &EPoison_resistance, AD_DRST },
+ { &EDrain_resistance, AD_DRLI },
};
int k;
long wornmask = (W_ARM | W_ARMC | W_ARMH | W_ARMS
| W_ARMG | W_ARMF | W_ARMU
| W_AMUL | W_RINGL | W_RINGR | W_TOOL
- /* [do W_ART and W_ARTI actually belong here?] */
| W_ART | W_ARTI);
if (u.twoweap)
if (art) {
if (dtyp) {
- if (art->cary.adtyp == dtyp || art->defn.adtyp == dtyp)
+ if (art->cary.adtyp == dtyp /* carried */
+ || (art->defn.adtyp == dtyp /* defends while worn */
+ && (obj->owornmask & ~(W_ART | W_ARTI))))
return obj;
}
if (spfx) {
return (struct obj *) 0;
}
+#if 1 /*JP*/
+/*JP colornames\82Í\90Ý\92è\83t\83@\83C\83\8b\82Å\8eg\82¤\82Ì\82Å\96|\96ó\82¹\82¸\81A
+ \93ú\96{\8cê\90ê\97p\82Ì\94z\97ñ\82ð\95Ê\82É\97p\88Ó\82·\82é\81B
+*/
+static const struct {
+ const char *name;
+ const int color;
+} colornames2[] = {
+ { "\8d\95\82¢", CLR_BLACK },
+ { "\90Ô\82¢", CLR_RED },
+ { "\97Î\90F\82Ì", CLR_GREEN },
+ { "\92\83\90F\82¢", CLR_BROWN },
+ { "\90Â\82¢", CLR_BLUE },
+ { "\83}\83[\83\93\83^\90F\82Ì", CLR_MAGENTA },
+ { "\83V\83A\83\93\90F\82Ì", CLR_CYAN },
+ { "\8aD\90F\82Ì", CLR_GRAY },
+ { "\8aD\90F\82Ì", CLR_GRAY },
+ { "\83I\83\8c\83\93\83W\90F\82Ì", CLR_ORANGE },
+ { "\92W\97Î\90F\82Ì", CLR_BRIGHT_GREEN },
+ { "\89©\90F\82¢", CLR_YELLOW },
+ { "\92W\90Â\90F\82Ì", CLR_BRIGHT_BLUE },
+ { "\96¾\82é\82¢\83}\83[\83\93\83^\90F\82Ì", CLR_BRIGHT_MAGENTA },
+ { "\96¾\82é\82¢\83V\83A\83\93\90F\82Ì", CLR_BRIGHT_CYAN },
+ { "\94\92\82¢", CLR_WHITE }
+};
+
+static const char *
+clr2colorname2(clr)
+int clr;
+{
+ int i;
+
+ for (i = 0; i < SIZE(colornames2); i++)
+ if (colornames2[i].color == clr)
+ return colornames2[i].name;
+ return (char *) 0;
+}
+#endif
+
const char *
glow_color(arti_indx)
int arti_indx;
{
int colornum = artilist[arti_indx].acolor;
+#if 0 /*JP*/
const char *colorstr = clr2colorname(colornum);
+#else
+ const char *colorstr = jconj_adj(clr2colorname2(colornum));
+#endif
return hcolor(colorstr);
}
+/* glow verb; [0] holds the value used when blind */
+static const char *glow_verbs[] = {
+/*JP
+ "quiver", "flicker", "glimmer", "gleam"
+*/
+ "\90k\82¦\82é", "\82Ü\82½\82½\82", "\8cõ\82é", "\8bP\82"
+};
+
+/* relative strength that Sting is glowing (0..3), to select verb */
+STATIC_OVL int
+glow_strength(count)
+int count;
+{
+ /* glow strength should also be proportional to proximity and
+ probably difficulty, but we don't have that information and
+ gathering it is more trouble than this would be worth */
+ return (count > 12) ? 3 : (count > 4) ? 2 : (count > 0);
+}
+
+const char *
+glow_verb(count, ingsfx)
+int count; /* 0 means blind rather than no applicable creatures */
+boolean ingsfx;
+{
+ static char resbuf[20];
+
+ Strcpy(resbuf, glow_verbs[glow_strength(count)]);
+ /* ing_suffix() will double the last consonant for all the words
+ we're using and none of them should have that, so bypass it */
+#if 0 /*JP*//*\93ú\96{\8cê\82Å\82Í\8eg\82í\82È\82¢*/
+ if (ingsfx)
+ Strcat(resbuf, "ing");
+#endif
+ return resbuf;
+}
+
/* use for warning "glow" for Sting, Orcrist, and Grimtooth */
void
Sting_effects(orc_count)
&& (uwep->oartifact == ART_STING
|| uwep->oartifact == ART_ORCRIST
|| uwep->oartifact == ART_GRIMTOOTH)) {
+ int oldstr = glow_strength(warn_obj_cnt),
+ newstr = glow_strength(orc_count);
+
if (orc_count == -1 && warn_obj_cnt > 0) {
/* -1 means that blindness has just been toggled; give a
'continue' message that eventual 'stop' message will match */
#if 0 /*JP*/
pline("%s is %s.", bare_artifactname(uwep),
- !Blind ? "glowing" : "quivering");
+ glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
#else
- pline("%s\82Í%s\82Ă¢\82é\81D", bare_artifactname(uwep),
- !Blind ? "\8bP\82¢" : "\90k\82¦");
+ pline("%s\82Í%s\82¢\82é\81D", bare_artifactname(uwep),
+ jconj(glow_verb(Blind ? 0 : warn_obj_cnt, TRUE), "\82Ä"));
#endif
- } else if (orc_count > 0 && warn_obj_cnt == 0) {
+ } else if (newstr > 0 && newstr != oldstr) {
/* 'start' message */
if (!Blind)
#if 0 /*JP*/
- pline("%s %s %s!", bare_artifactname(uwep),
- otense(uwep, "glow"), glow_color(uwep->oartifact));
+ pline("%s %s %s%c", bare_artifactname(uwep),
+ otense(uwep, glow_verb(orc_count, FALSE)),
+ glow_color(uwep->oartifact),
+ (newstr > oldstr) ? '!' : '.');
#else
- pline("%s\82Í%s\8bP\82¢\82½\81I", bare_artifactname(uwep),
- glow_color(uwep->oartifact));
+ pline("%s\82Í%s%s%s", bare_artifactname(uwep),
+ jconj_adj(glow_color(uwep->oartifact)),
+ jconj(glow_verb(orc_count, FALSE), "\82½"),
+ (newstr > oldstr) ? "\81I" : "\81D");
#endif
- else
-/*JP
- pline("%s quivers slightly.", bare_artifactname(uwep));
-*/
+ else if (oldstr == 0) /* quivers */
+#if 0 /*JP*/
+ pline("%s %s slightly.", bare_artifactname(uwep),
+ otense(uwep, glow_verb(0, FALSE)));
+#else
pline("%s\82Í\8f\82µ\90k\82¦\82½\81D", bare_artifactname(uwep));
+#endif
} else if (orc_count == 0 && warn_obj_cnt > 0) {
/* 'stop' message */
#if 0 /*JP*/
pline("%s stops %s.", bare_artifactname(uwep),
- !Blind ? "glowing" : "quivering");
+ glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
#else
- pline("%s\82Ì%s\82Í\8e~\82Ü\82Á\82½\81D", bare_artifactname(uwep),
- !Blind ? "\8bP\82«" : "\90k\82¦");
+ pline("%s\82Í%s\82Ì\82ð\82â\82ß\82½\81D", bare_artifactname(uwep),
+ glow_verb(Blind ? 0 : warn_obj_cnt, TRUE));
#endif
}
}
if (touch_artifact(obj, &youmonst)) {
char buf[BUFSZ];
int dmg = 0, tmp;
- boolean ag =
- (objects[obj->otyp].oc_material == SILVER && Hate_silver),
+ boolean ag = (objects[obj->otyp].oc_material == SILVER && Hate_silver),
bane = bane_applies(get_artifact(obj), &youmonst);
/* nothing else to do if hero can successfully handle this object */
if (loseit && obj) {
if (Levitation) {
freeinv(obj);
- hitfloor(obj);
+ hitfloor(obj, TRUE);
} else {
/* dropx gives a message iff item lands on an altar */
if (!IS_ALTAR(levl[u.ux][u.uy].typ))
dropit = (dropflag > 0); /* drop all or drop weapon */
/* check secondary weapon first, before possibly unwielding primary */
- if (u.twoweap)
+ if (u.twoweap) {
+ bypass_obj(uswapwep); /* so loop below won't process it again */
(void) untouchable(uswapwep, dropit);
+ }
/* check primary weapon next so that they're handled together */
- if (uwep)
+ if (uwep) {
+ bypass_obj(uwep); /* so loop below won't process it again */
(void) untouchable(uwep, dropit);
+ }
/* in case someone is daft enough to add artifact or silver saddle */
if (u.usteed && (obj = which_armor(u.usteed, W_SADDLE)) != 0) {
clear_bypasses(); /* reset upon final exit */
}
+static int mkot_trap_warn_count = 0;
+
+STATIC_OVL int
+count_surround_traps(x, y)
+int x, y;
+{
+ struct rm *levp;
+ struct obj *otmp;
+ struct trap *ttmp;
+ int dx, dy, glyph, ret = 0;
+
+ for (dx = x - 1; dx < x + 2; ++dx)
+ for (dy = y - 1; dy < y + 2; ++dy) {
+ if (!isok(dx, dy))
+ continue;
+ /* If a trap is shown here, don't count it; the hero
+ * should be expecting it. But if there is a trap here
+ * that's not shown, either undiscovered or covered by
+ * something, do count it.
+ */
+ glyph = glyph_at(dx, dy);
+ if (glyph_is_trap(glyph))
+ continue;
+ if ((ttmp = t_at(dx, dy)) != 0) {
+ ++ret;
+ continue;
+ }
+ levp = &levl[dx][dy];
+ if (IS_DOOR(levp->typ) && (levp->doormask & D_TRAPPED) != 0) {
+ ++ret;
+ continue;
+ }
+ for (otmp = level.objects[dx][dy]; otmp; otmp = otmp->nexthere)
+ if (Is_container(otmp) && otmp->otrapped) {
+ ++ret; /* we're counting locations, so just */
+ break; /* count the first one in a pile */
+ }
+ }
+ /*
+ * [Shouldn't we also check inventory for a trapped container?
+ * Even if its trap has already been found, there's no 'tknown'
+ * flag to help hero remember that so we have nothing comparable
+ * to a shown glyph to justify skipping it.]
+ */
+ return ret;
+}
+
+/* sense adjacent traps if wielding MKoT without wearing gloves */
+void
+mkot_trap_warn()
+{
+#if 0 /*JP*/
+ static const char *const heat[7] = {
+ "cool", "slightly warm", "warm", "very warm",
+ "hot", "very hot", "like fire"
+ };
+#else
+ static const char *const heat[7] = {
+ "\97â\82½\82", "\8f\82µ\89·\82©\82", "\89·\82©\82", "\82Æ\82Ä\82à\89·\82©\82",
+ "\94M\82", "\82Æ\82Ä\82à\94M\82", "\89\8a\82Ì\82æ\82¤\82É"
+ };
+#endif
+
+ if (!uarmg && uwep && uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
+ int idx, ntraps = count_surround_traps(u.ux, u.uy);
+
+ if (ntraps != mkot_trap_warn_count) {
+ idx = min(ntraps, SIZE(heat) - 1);
+/*JP
+ pline_The("Key feels %s%c", heat[idx], (ntraps > 3) ? '!' : '.');
+*/
+ pline_The("\8c®\82Í%s\8a´\82¶\82½%s", heat[idx], (ntraps > 3) ? "\81I" : "\81D");
+ }
+ mkot_trap_warn_count = ntraps;
+ } else
+ mkot_trap_warn_count = 0;
+}
+
+/* Master Key is magic key if its bless/curse state meets our criteria:
+ not cursed for rogues or blessed for non-rogues */
+boolean
+is_magic_key(mon, obj)
+struct monst *mon; /* if null, non-rogue is assumed */
+struct obj *obj;
+{
+ if (((obj && obj->oartifact == ART_MASTER_KEY_OF_THIEVERY)
+ && ((mon == &youmonst) ? Role_if(PM_ROGUE)
+ : (mon && mon->data == &mons[PM_ROGUE])))
+ ? !obj->cursed : obj->blessed)
+ return TRUE;
+ return FALSE;
+}
+
+/* figure out whether 'mon' (usually youmonst) is carrying the magic key */
+struct obj *
+has_magic_key(mon)
+struct monst *mon; /* if null, hero assumed */
+{
+ struct obj *o;
+ short key = artilist[ART_MASTER_KEY_OF_THIEVERY].otyp;
+
+ if (!mon)
+ mon = &youmonst;
+ for (o = ((mon == &youmonst) ? invent : mon->minvent); o;
+ o = nxtobj(o, key, FALSE)) {
+ if (is_magic_key(mon, o))
+ return o;
+ }
+ return (struct obj *) 0;
+}
+
/*artifact.c*/