Port the autounlock feature, hallucinatory trap names from UnNetHack

This adds a boolean option, autounlock, defaulting to true. When this is
set to TRUE, messages stating that some door or container is locked are
automatically followed by a prompt asking if you would like to unlock
it, if you are carrying an unlocking tool (key, lock pick, or credit
card).

Architecturally, this extends the pick_lock function to take three
additional arguments (door coordinates or a box on the ground you are
autounlocking).

The code that selects an unlocking tool will always look first for a
skeleton key, then a lock pick, then a credit card. Since curses, rust,
and other attributes don't really have an effect on the viability of the
unlocking device, it didn't seem to warrant making a more complex
function for that.

Add hallucinatory trap names

This adds many funny, realistic, and nonsensical traps to the game, to
be shown when the player is hallucinating.

Architecturally, the biggest change is merging the what_trap macro and
the "defsyms[trap_to_defsym(ttyp)].explanation" pattern into a single
function "trapname", which returns the name of the trap, handling the
hallucination case. There is also a second parameter used for overriding
hallucination in the occasional cases where the actual trap name should
always be returned.

In addition, the what_trap and random_trap macros are now obsolete and
not used anywhere, so they are removed.

reinstate anti-rng abuse bit on hallucination

updates to hallucinatory trap names and fixes37.0 entry
This commit is contained in:
copperwater
2019-09-30 20:56:03 -04:00
committed by nhmall
parent 193f369e5d
commit 277dcc05b5
19 changed files with 145 additions and 74 deletions

View File

@@ -294,14 +294,18 @@ struct obj *container; /* passed from obfree() */
/* player is applying a key, lock pick, or credit card */
int
pick_lock(pick)
pick_lock(pick, rx, ry, container)
struct obj *pick;
xchar rx, ry; /* coordinates of doors/container, for autounlock: does not
prompt for direction if these are set */
struct obj *container; /* container, for autounlock */
{
int picktyp, c, ch;
coord cc;
struct rm *door;
struct obj *otmp;
char qbuf[QBUFSZ];
boolean autounlock = (rx != 0 && ry != 0) || (container != NULL);
picktyp = pick->otyp;
@@ -348,8 +352,13 @@ struct obj *pick;
}
ch = 0; /* lint suppression */
if (!get_adjacent_loc((char *) 0, "Invalid location!", u.ux, u.uy, &cc))
if (rx != 0 && ry != 0) { /* autounlock; caller has provided coordinates */
cc.x = rx;
cc.y = ry;
}
else if (!get_adjacent_loc((char *) 0, "Invalid location!", u.ux, u.uy, &cc)) {
return PICKLOCK_DID_NOTHING;
}
if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */
const char *verb;
@@ -372,7 +381,9 @@ struct obj *pick;
count = 0;
c = 'n'; /* in case there are no boxes here */
for (otmp = g.level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere)
if (Is_box(otmp)) {
/* autounlock on boxes: only the one that just informed you it was
* locked. Don't include any other boxes which might be here. */
if ((!autounlock && Is_box(otmp)) || (otmp == container)) {
++count;
if (!can_reach_floor(TRUE)) {
You_cant("reach %s from up here.", the(xname(otmp)));
@@ -388,17 +399,24 @@ struct obj *pick;
else
verb = "pick";
/* "There is <a box> here; <verb> <it|its lock>?" */
Sprintf(qsfx, " here; %s %s?", verb, it ? "it" : "its lock");
(void) safe_qbuf(qbuf, "There is ", qsfx, otmp, doname,
ansimpleoname, "a box");
otmp->lknown = 1;
if (autounlock) {
Sprintf(qbuf, "Unlock it with %s?", yname(pick));
c = yn(qbuf);
if (c == 'n')
return 0;
} else {
/* "There is <a box> here; <verb> <it|its lock>?" */
Sprintf(qsfx, " here; %s %s?", verb, it ? "it" : "its lock");
(void) safe_qbuf(qbuf, "There is ", qsfx, otmp, doname,
ansimpleoname, "a box");
otmp->lknown = 1;
c = ynq(qbuf);
if (c == 'q')
return 0;
if (c == 'n')
continue;
c = ynq(qbuf);
if (c == 'q')
return 0;
if (c == 'n')
continue;
}
if (otmp->obroken) {
You_cant("fix its broken lock with %s.", doname(pick));
@@ -484,8 +502,10 @@ struct obj *pick;
return PICKLOCK_LEARNED_SOMETHING;
}
Sprintf(qbuf, "%s it?",
(door->doormask & D_LOCKED) ? "Unlock" : "Lock");
Sprintf(qbuf, "%s it%s%s?",
(door->doormask & D_LOCKED) ? "Unlock" : "Lock",
autounlock ? " with " : "",
autounlock ? yname(pick) : "");
c = yn(qbuf);
if (c == 'n')
@@ -685,6 +705,8 @@ int x, y;
if (!(door->doormask & D_CLOSED)) {
const char *mesg;
boolean locked = FALSE;
struct obj* unlocktool;
switch (door->doormask) {
case D_BROKEN:
@@ -698,9 +720,16 @@ int x, y;
break;
default:
mesg = " is locked";
locked = TRUE;
break;
}
pline("This door%s.", mesg);
if (locked && flags.autounlock &&
((unlocktool = carrying(SKELETON_KEY)) ||
(unlocktool = carrying(LOCK_PICK)) ||
(unlocktool = carrying(CREDIT_CARD)))) {
pick_lock(unlocktool, cc.x, cc.y, (struct obj *) 0);
}
return res;
}