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

@@ -923,14 +923,14 @@ unsigned trflags;
*/
pline("Air currents pull you down into %s %s!",
a_your[trap->madeby_u],
defsyms[trap_to_defsym(ttype)].explanation);
trapname(ttype, TRUE)); /* do force "pit" while hallucinating */
/* then proceed to normal trap effect */
} else if (already_seen && !forcetrap) {
if ((Levitation || (Flying && !plunged))
&& (is_pit(ttype) || ttype == HOLE || ttype == BEAR_TRAP)) {
You("%s over %s %s.", Levitation ? "float" : "fly",
a_your[trap->madeby_u],
defsyms[trap_to_defsym(ttype)].explanation);
trapname(ttype, FALSE));
return;
}
if (!Fumbling && ttype != MAGIC_PORTAL && ttype != VIBRATING_SQUARE
@@ -941,7 +941,7 @@ unsigned trflags;
You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u)
? "an"
: a_your[trap->madeby_u],
defsyms[trap_to_defsym(ttype)].explanation);
trapname(ttype, FALSE));
return;
}
}
@@ -1290,7 +1290,7 @@ unsigned trflags;
if (!Can_fall_thru(&u.uz)) {
seetrap(trap); /* normally done in fall_through */
impossible("dotrap: %ss cannot exist on this level.",
defsyms[trap_to_defsym(ttype)].explanation);
trapname(ttype, TRUE));
break; /* don't activate it after all */
}
fall_through(TRUE, (trflags & TOOKPLUNGE));
@@ -2465,7 +2465,7 @@ register struct monst *mtmp;
case TRAPDOOR:
if (!Can_fall_thru(&u.uz)) {
impossible("mintrap: %ss cannot exist on this level.",
defsyms[trap_to_defsym(tt)].explanation);
trapname(tt, TRUE));
break; /* don't activate it after all */
}
if (is_flyer(mptr) || is_floater(mptr) || mptr == &mons[PM_WUMPUS]
@@ -4051,8 +4051,7 @@ boolean force_failure;
if ((g.invent && (inv_weight() + weight_cap() > 600))
|| bigmonst(g.youmonst.data)) {
/* don't allow untrap if they can't get thru to it */
You("are unable to reach the %s!",
defsyms[trap_to_defsym(ttype)].explanation);
You("are unable to reach the %s!", trapname(ttype, FALSE));
return 0;
}
}
@@ -4061,8 +4060,7 @@ boolean force_failure;
if (u.usteed && P_SKILL(P_RIDING) < P_BASIC)
rider_cant_reach();
else
You("are unable to reach the %s!",
defsyms[trap_to_defsym(ttype)].explanation);
You("are unable to reach the %s!", trapname(ttype, FALSE));
return 0;
}
@@ -4102,7 +4100,7 @@ boolean force_failure;
} else {
pline("%s %s is difficult to %s.",
ttmp->madeby_u ? "Your" : under_u ? "This" : "That",
defsyms[trap_to_defsym(ttype)].explanation,
trapname(ttype, FALSE),
(ttype == WEB) ? "remove" : "disarm");
}
return 1;
@@ -4381,7 +4379,7 @@ boolean force;
ttmp = t_at(x, y);
if (ttmp && !ttmp->tseen)
ttmp = 0;
trapdescr = ttmp ? defsyms[trap_to_defsym(ttmp->ttyp)].explanation : 0;
trapdescr = ttmp ? trapname(ttmp->ttyp, FALSE) : 0;
here = (x == u.ux && y == u.uy); /* !u.dx && !u.dy */
if (here) /* are there are one or more containers here? */
@@ -4641,7 +4639,7 @@ boolean *noticed; /* set to true iff hero notices the effect; */
}
if (!trapdescr)
trapdescr = defsyms[trap_to_defsym(t->ttyp)].explanation;
trapdescr = trapname(t->ttyp, FALSE);
if (!which)
which = t->tseen ? the_your[t->madeby_u]
: index(vowels, *trapdescr) ? "an" : "a";
@@ -5452,4 +5450,55 @@ maybe_finish_sokoban()
}
}
/* Return the string name of the trap type passed in, unless the player is
* hallucinating, in which case return a random or hallucinatory trap name.
* If the second argument is true, return the correct trap name even when
* hallucinating (for things like wizard mode wishing for traps and impossible
* calls).
* Originally I had intended for messages like "You begin setting the bear trap"
* to override as well, but the context in those bits of code indicated that it
* was meant to take a random name if the hero was hallucinating.
*/
const char *
trapname(ttyp, override)
int ttyp;
boolean override;
{
const char * halu_trapnames[] = {
/* riffs on actual nethack traps */
"bottomless pit", "polymorphism trap", "devil teleporter",
"falling boulder trap", "anti-anti-magic field", "weeping gas trap",
"queasy board", "electrified web", "owlbear trap", "sand mine",
/* some traps found in nethack variants */
"death trap", "disintegration trap", "ice trap", "monochrome trap",
/* plausible real-life traps */
"axeblade trap", "pool of boiling oil", "pool of quicksand",
"field of caltrops", "buzzsaw trap", "spiked floor", "revolving wall",
"uneven floor", "finger trap", "jack-in-a-box", "yellow snow",
"booby trap", "rat trap", "poisoned nail", "snare", "whirlpool",
"trip wire",
/* sci-fi */
"negative space", "tensor field", "singularity", "imperial fleet",
"black hole", "thermal detonator", "event horizon",
"entoptic phenomenon",
/* miscellaneous suggestions */
"sweet-smelling gas vent", "phone booth", "exploding runes",
"never-ending elevator", "slime pit", "warp zone", "illusory floor",
"pile of poo", "honey trap", "tourist trap"
};
int total_names = TRAPNUM + SIZE(halu_trapnames);
int nameidx = rn2_on_display_rng(total_names);
if (override || !Hallucination) {
return defsyms[trap_to_defsym(ttyp)].explanation;
}
if (nameidx < TRAPNUM) {
/* random but real trap name */
return defsyms[trap_to_defsym(nameidx)].explanation;
}
else {
nameidx -= TRAPNUM;
return halu_trapnames[nameidx];
}
}
/*trap.c*/