sometimes generate the random mazes with wide corridors, thick walls,
or with dead ends changed to loops
put throne room gold in the chest
-wielding Trollsbane prevents trolls from reviving
-wielding Demonbane prevents demons summoning friends
-wielding Dragonbane confers reflection
-wielding Ogresmasher grants 25 constitution
-Cleaver can hit three monsters with one swing
-Master Key of Thievery warns about undetected traps if wielded
-Elbereth must now be on a square by itself to function
-Elbereth now erodes based on attacks by the player, not monsters scared
novels are made of paper, not gold
movement speeds are made less predictable by using random rounding, rather
than via adding a random offset
option force_invmenu to make commands asking for inventory items always
use a menu instead of a text line query
option hitpointbar to show a bar graph of hit points behind title field
+wielding Trollsbane prevents troll corpses from reviving
+wielding Demonbane prevents demons summoning friends
+wielding Dragonbane confers reflection
+wielding Ogresmasher grants 25 constitution
+Cleaver can hit three adjacent monsters with one swing
+Master Key of Thievery warns about undetected traps if wielded without gloves
+Master Key of Thievery always finds door and chest traps if used to lock or
+ unlock a trapped door or chest while non-cursed (for rogues) or
+ blessed (for non-rogues); player is offered the opportunity to disarm
+"Elbereth" must now be the only engraved text on a square to function
+"Elbereth" now erodes based on attacks by the player, not monsters scared
Platform- and/or Interface-Specific New Features
#include "hack.h"
-STATIC_PTR int NDECL(picklock);
-STATIC_PTR int NDECL(forcelock);
-
/* at most one of `door' and `box' should be non-null at any given time */
STATIC_VAR NEARDATA struct xlock_s {
struct rm *door;
struct obj *box;
int picktyp, /* key|pick|card for unlock, sharp vs blunt for #force */
chance, usedtime;
+ boolean magic_key;
} xlock;
+/* occupation callbacks */
+STATIC_PTR int NDECL(picklock);
+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 *));
if (rn2(100) >= xlock.chance)
return 1; /* still busy */
+ /* using the Master Key of Thievery finds traps if its bless/curse
+ state is adequate (non-cursed for rogues, blessed for others;
+ checked when setting up 'xlock') */
+ if ((!xlock.door ? (int) xlock.box->otrapped
+ : (xlock.door->doormask & D_TRAPPED) != 0)
+ && xlock.magic_key) {
+ xlock.chance += 20; /* less effort needed next time */
+ /* unfortunately we don't have a 'tknown' flag to record
+ "known to be trapped" so declining to disarm and then
+ retrying lock manipulation will find it all over again */
+ if (yn("You find a trap! Do you want to try to disarm it?") == 'y') {
+ const char *what;
+ boolean alreadyunlocked;
+
+ /* disarming while using magic key always succeeds */
+ if (xlock.door) {
+ xlock.door->doormask &= ~D_TRAPPED;
+ what = "door";
+ alreadyunlocked = !(xlock.door->doormask & D_LOCKED);
+ } else {
+ xlock.box->otrapped = 0;
+ what = (xlock.box->otyp == CHEST) ? "chest" : "box";
+ alreadyunlocked = !xlock.box->olocked;
+ }
+ You("succeed in disarming the trap. The %s is still %slocked.",
+ what, alreadyunlocked ? "un" : "");
+ exercise(A_WIS, TRUE);
+ } else {
+ You("stop %s.", lock_action());
+ exercise(A_WIS, FALSE);
+ }
+ return ((xlock.usedtime = 0));
+ }
+
You("succeed in %s.", lock_action());
if (xlock.door) {
if (xlock.door->doormask & D_TRAPPED) {
reset_pick()
{
xlock.usedtime = xlock.chance = xlock.picktyp = 0;
+ xlock.magic_key = FALSE;
xlock.door = 0;
xlock.box = 0;
}
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
if (nohands(youmonst.data)) {
const char *what = (picktyp == LOCK_PICK) ? "pick" : "key";
+
if (picktyp == CREDIT_CARD)
what = "card";
pline(no_longer, "hold the", what);
const char *action = lock_action();
You("resume your attempt at %s.", action);
+ xlock.magic_key = is_magic_key(&youmonst, pick);
set_occupation(picklock, action, 0);
return PICKLOCK_DID_SOMETHING;
}
return PICKLOCK_DID_NOTHING;
}
- if ((picktyp != LOCK_PICK && picktyp != CREDIT_CARD
- && picktyp != SKELETON_KEY)) {
+ if (picktyp != LOCK_PICK
+ && picktyp != CREDIT_CARD
+ && picktyp != SKELETON_KEY) {
impossible("picking lock with object %d?", picktyp);
return PICKLOCK_DID_NOTHING;
}
if (otmp->cursed)
ch /= 2;
- xlock.picktyp = picktyp;
xlock.box = otmp;
xlock.door = 0;
break;
} else if (mtmp && is_door_mappear(mtmp)) {
/* "The door actually was a <mimic>!" */
stumble_onto_mimic(mtmp);
- /* mimic might keep the key (50% chance, 10% for PYEC) */
+ /* mimic might keep the key (50% chance, 10% for PYEC or MKoT) */
maybe_absorb_item(mtmp, pick, 50, 10);
return PICKLOCK_LEARNED_SOMETHING;
}
context.move = 0;
xlock.chance = ch;
xlock.picktyp = picktyp;
+ xlock.magic_key = is_magic_key(&youmonst, pick);
xlock.usedtime = 0;
set_occupation(picklock, lock_action(), 0);
return PICKLOCK_DID_SOMETHING;
xlock.box = otmp;
xlock.chance = objects[uwep->otyp].oc_wldam * 2;
xlock.picktyp = picktyp;
+ xlock.magic_key = FALSE;
xlock.usedtime = 0;
break;
}