PHYS(5, 0), NO_DFNS, NO_CARY, CREATE_AMMO, A_CHAOTIC, PM_RANGER, NON_PM,
4000L, NO_COLOR),
+ /* MKoT has an additional carry property if the Key is not cursed (for
+ rogues) or blessed (for non-rogues): #untrap of doors and chests
+ will always find any traps and disarming those will always succeed */
A("The Master Key of Thievery", SKELETON_KEY,
(SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_SPEAK),
(SPFX_WARN | SPFX_TCTRL | SPFX_HPHDAM), 0, NO_ATTK, NO_DFNS, NO_CARY,
E void FDECL(discover_artifact, (XCHAR_P));
E boolean FDECL(undiscovered_artifact, (XCHAR_P));
E int FDECL(disp_artifact_discoveries, (winid));
-E boolean FDECL(artifact_hit,
- (struct monst *, struct monst *, struct obj *, int *, int));
+E boolean FDECL(artifact_hit, (struct monst *, struct monst *, struct obj *,
+ int *, int));
E int NDECL(doinvoke);
E boolean FDECL(finesse_ahriman, (struct obj *));
E void FDECL(arti_speak, (struct obj *));
E int FDECL(retouch_object, (struct obj **, BOOLEAN_P));
E void FDECL(retouch_equipment, (int));
E void NDECL(mkot_trap_warn);
+E boolean FDECL(is_magic_key, (struct monst *, struct obj *));
+E struct obj *FDECL(has_magic_key, (struct monst *));
/* ### attrib.c ### */
static int mkot_trap_warn_count = 0;
STATIC_OVL int
-count_surround_traps(x,y)
-int x,y;
+count_surround_traps(x, y)
+int x, y;
{
- int dx, dy, ret = 0;
+ struct rm *levp;
+ struct obj *otmp;
struct trap *ttmp;
-
- for (dx = x-1; dx < x+2; dx++)
- for (dy = y-1; dy < y+2; dy++)
- if (isok(dx,dy) && (ttmp = t_at(dx,dy))
- && !ttmp->tseen)
- ret++;
+ 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 (!uarmg && uwep
- && uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
- const char *const heat[7] = { "cold", "slightly warm", "warm",
- "very warm", "hot", "very hot",
- "like fire" };
- int ntraps = count_surround_traps(u.ux, u.uy);
-
- if (ntraps != mkot_trap_warn_count)
- pline_The("key feels %s%c", heat[(ntraps > 6) ? 6 : ntraps],
- ntraps > 3 ? '!' : '.');
+ static const char *const heat[7] = {
+ "cool", "slightly warm", "warm", "very warm",
+ "hot", "very hot", "like fire"
+ };
+
+ 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);
+ pline_The("Key feels %s%c", heat[idx], (ntraps > 3) ? '!' : '.');
+ }
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*/
STATIC_PTR int NDECL(forcelock);
STATIC_DCL const char *NDECL(lock_action);
-STATIC_DCL boolean FDECL(is_magic_key, (struct monst *, struct obj *));
STATIC_DCL boolean FDECL(obstructed, (int, int, BOOLEAN_P));
STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *));
reset_pick();
}
-/* Master Key is magic key if its bless/curse state meets our criteria:
- not cursed for rogues or blessed for non-rogues */
-STATIC_OVL 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;
-}
-
/* 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