still more Master Key of Thievery
Make #untrap while carrying the non-cursed (for rogues) or blessed (for non-rogues) Key work the same as #invoke has been doing (without regard to its bless/curse state): when used on trapped door or chest, that trap will always be found and disarming it will always succeed. It should work when carried by monsters too: if they try to open a trapped door while carrying the Key (must be blessed since they're not rogues) the trap will be automatically disarmed. (Caveat: that hasn't been adequately tested.) TODO (maybe...): change the #invoke property to detect unseen/secret door detection instead of #untrap. The latter isn't completely redundant; it works when the Key is cursed. But quest artifacts strongly resist becoming cursed so that isn't a particularly useful distinction. Also, trap hints when wielding the Key without gloves didn't notice adjacent door and chest traps. Now it does. And the behavior is slightly different: known traps covered by objects or monsters are treated like unknown traps as far as the hot/cold hints go.
This commit is contained in:
@@ -208,6 +208,9 @@ A("The Palantir of Westernesse", CRYSTAL_BALL,
|
|||||||
PHYS(5, 0), NO_DFNS, NO_CARY, CREATE_AMMO, A_CHAOTIC, PM_RANGER, NON_PM,
|
PHYS(5, 0), NO_DFNS, NO_CARY, CREATE_AMMO, A_CHAOTIC, PM_RANGER, NON_PM,
|
||||||
4000L, NO_COLOR),
|
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,
|
A("The Master Key of Thievery", SKELETON_KEY,
|
||||||
(SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_SPEAK),
|
(SPFX_NOGEN | SPFX_RESTR | SPFX_INTEL | SPFX_SPEAK),
|
||||||
(SPFX_WARN | SPFX_TCTRL | SPFX_HPHDAM), 0, NO_ATTK, NO_DFNS, NO_CARY,
|
(SPFX_WARN | SPFX_TCTRL | SPFX_HPHDAM), 0, NO_ATTK, NO_DFNS, NO_CARY,
|
||||||
|
|||||||
+4
-2
@@ -78,8 +78,8 @@ E int FDECL(spec_dbon, (struct obj *, struct monst *, int));
|
|||||||
E void FDECL(discover_artifact, (XCHAR_P));
|
E void FDECL(discover_artifact, (XCHAR_P));
|
||||||
E boolean FDECL(undiscovered_artifact, (XCHAR_P));
|
E boolean FDECL(undiscovered_artifact, (XCHAR_P));
|
||||||
E int FDECL(disp_artifact_discoveries, (winid));
|
E int FDECL(disp_artifact_discoveries, (winid));
|
||||||
E boolean FDECL(artifact_hit,
|
E boolean FDECL(artifact_hit, (struct monst *, struct monst *, struct obj *,
|
||||||
(struct monst *, struct monst *, struct obj *, int *, int));
|
int *, int));
|
||||||
E int NDECL(doinvoke);
|
E int NDECL(doinvoke);
|
||||||
E boolean FDECL(finesse_ahriman, (struct obj *));
|
E boolean FDECL(finesse_ahriman, (struct obj *));
|
||||||
E void FDECL(arti_speak, (struct obj *));
|
E void FDECL(arti_speak, (struct obj *));
|
||||||
@@ -93,6 +93,8 @@ E void FDECL(Sting_effects, (int));
|
|||||||
E int FDECL(retouch_object, (struct obj **, BOOLEAN_P));
|
E int FDECL(retouch_object, (struct obj **, BOOLEAN_P));
|
||||||
E void FDECL(retouch_equipment, (int));
|
E void FDECL(retouch_equipment, (int));
|
||||||
E void NDECL(mkot_trap_warn);
|
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 ### */
|
/* ### attrib.c ### */
|
||||||
|
|
||||||
|
|||||||
+83
-17
@@ -2055,36 +2055,102 @@ int dropflag; /* 0==don't drop, 1==drop all, 2==drop weapon */
|
|||||||
static int mkot_trap_warn_count = 0;
|
static int mkot_trap_warn_count = 0;
|
||||||
|
|
||||||
STATIC_OVL int
|
STATIC_OVL int
|
||||||
count_surround_traps(x,y)
|
count_surround_traps(x, y)
|
||||||
int x,y;
|
int x, y;
|
||||||
{
|
{
|
||||||
int dx, dy, ret = 0;
|
struct rm *levp;
|
||||||
|
struct obj *otmp;
|
||||||
struct trap *ttmp;
|
struct trap *ttmp;
|
||||||
|
int dx, dy, glyph, ret = 0;
|
||||||
|
|
||||||
for (dx = x-1; dx < x+2; dx++)
|
for (dx = x - 1; dx < x + 2; ++dx)
|
||||||
for (dy = y-1; dy < y+2; dy++)
|
for (dy = y - 1; dy < y + 2; ++dy) {
|
||||||
if (isok(dx,dy) && (ttmp = t_at(dx,dy))
|
if (!isok(dx, dy))
|
||||||
&& !ttmp->tseen)
|
continue;
|
||||||
ret++;
|
/* 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sense adjacent traps if wielding MKoT without wearing gloves */
|
||||||
void
|
void
|
||||||
mkot_trap_warn()
|
mkot_trap_warn()
|
||||||
{
|
{
|
||||||
if (!uarmg && uwep
|
static const char *const heat[7] = {
|
||||||
&& uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
|
"cool", "slightly warm", "warm", "very warm",
|
||||||
const char *const heat[7] = { "cold", "slightly warm", "warm",
|
"hot", "very hot", "like fire"
|
||||||
"very warm", "hot", "very hot",
|
};
|
||||||
"like fire" };
|
|
||||||
int ntraps = count_surround_traps(u.ux, u.uy);
|
|
||||||
|
|
||||||
if (ntraps != mkot_trap_warn_count)
|
if (!uarmg && uwep && uwep->oartifact == ART_MASTER_KEY_OF_THIEVERY) {
|
||||||
pline_The("key feels %s%c", heat[(ntraps > 6) ? 6 : ntraps],
|
int idx, ntraps = count_surround_traps(u.ux, u.uy);
|
||||||
ntraps > 3 ? '!' : '.');
|
|
||||||
|
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;
|
mkot_trap_warn_count = ntraps;
|
||||||
} else
|
} else
|
||||||
mkot_trap_warn_count = 0;
|
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*/
|
/*artifact.c*/
|
||||||
|
|||||||
-16
@@ -18,7 +18,6 @@ STATIC_PTR int NDECL(picklock);
|
|||||||
STATIC_PTR int NDECL(forcelock);
|
STATIC_PTR int NDECL(forcelock);
|
||||||
|
|
||||||
STATIC_DCL const char *NDECL(lock_action);
|
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 boolean FDECL(obstructed, (int, int, BOOLEAN_P));
|
||||||
STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *));
|
STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *));
|
||||||
|
|
||||||
@@ -275,21 +274,6 @@ maybe_reset_pick()
|
|||||||
reset_pick();
|
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
|
/* for doapply(); if player gives a direction or resumes an interrupted
|
||||||
previous attempt then it costs hero a move even if nothing ultimately
|
previous attempt then it costs hero a move even if nothing ultimately
|
||||||
happens; when told "can't do that" before being asked for direction
|
happens; when told "can't do that" before being asked for direction
|
||||||
|
|||||||
@@ -1246,6 +1246,16 @@ postmov:
|
|||||||
boolean btrapped = (here->doormask & D_TRAPPED) != 0,
|
boolean btrapped = (here->doormask & D_TRAPPED) != 0,
|
||||||
observeit = canseeit && canspotmon(mtmp);
|
observeit = canseeit && canspotmon(mtmp);
|
||||||
|
|
||||||
|
/* if mon has MKoT, disarm door trap; no message given */
|
||||||
|
if (btrapped && has_magic_key(mtmp)) {
|
||||||
|
/* BUG: this lets a vampire or blob or a doorbuster
|
||||||
|
holding the Key disarm the trap even though it isn't
|
||||||
|
using that Key when squeezing under or smashing the
|
||||||
|
door. Not significant enough to worry about; perhaps
|
||||||
|
the Key's magic is more powerful for monsters? */
|
||||||
|
here->doormask &= ~D_TRAPPED;
|
||||||
|
btrapped = FALSE;
|
||||||
|
}
|
||||||
if ((here->doormask & (D_LOCKED | D_CLOSED)) != 0
|
if ((here->doormask & (D_LOCKED | D_CLOSED)) != 0
|
||||||
&& (amorphous(ptr)
|
&& (amorphous(ptr)
|
||||||
|| (can_fog(mtmp)
|
|| (can_fog(mtmp)
|
||||||
|
|||||||
@@ -4256,6 +4256,11 @@ boolean force;
|
|||||||
pline_The("perils lurking there are beyond your grasp.");
|
pline_The("perils lurking there are beyond your grasp.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* 'force' is true for #invoke; make it be true for #untrap if
|
||||||
|
carrying MKoT */
|
||||||
|
if (!force && has_magic_key(&youmonst))
|
||||||
|
force = TRUE;
|
||||||
|
|
||||||
ttmp = t_at(x, y);
|
ttmp = t_at(x, y);
|
||||||
if (ttmp && !ttmp->tseen)
|
if (ttmp && !ttmp->tseen)
|
||||||
ttmp = 0;
|
ttmp = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user