github PR #259 - paranoid_confirmation:trap
Fairly old pull request from copperwater: add new paranoid_confirm setting 'trap'. The old commit suffered from bit rot and merging needed too much fixing up despite there not being many bands of change in the commit's diffs. I ultimately redid it from scratch, although the two biggest chunks of code started with copy+paste of the pull request's commit. It operates like paranoid:pray. Setting paranoid:trap adds a new "Really step into <trap>?" y/n prompt when attempting to move into/onto a known trap, even if an object covers it on the map. Setting both 'paranoid:Confirm trap' turns that into a yes/no prompt. (Adding 'Confirm' affects other paranoid confirmations; in addition to requiring yes<return> rather than just y to accept, it also forces no<return> to reject.) However, moving into a known trap that is considered to be harmless behaves as if no trap was present. Some of the trap classification might be out of date; several types of traps have undergone changes since implementation of the original pull request, notably anti-magic field. When the hero is hallucinating, all known traps are considered harmful since the map no longer reliably describes them. Preceding a movement command with the 'm' prefix also behaves as if no trap was present, bypassing confirmation for that move, similar to how paranoid:swim currently behaves. Being stunned or confused also behaves as if no trap was present, taking priority over hallucination. This updates the documentation. Supersedes #259 Closes #259
This commit is contained in:
@@ -214,7 +214,7 @@ packorder a list of default symbols for kinds of [")[%?+!=/(*`0_]
|
||||
paranoid_confirmation space separated list [paranoid_confirm:pray swim]
|
||||
of situations where alternate prompting is desired
|
||||
Confirm -- when requiring "yes", also require "no" to reject;
|
||||
also requires yes rather than y for pray, Autoall
|
||||
also requires yes rather than y for pray, trap, Autoall
|
||||
quit -- yes vs y to confirm quitting or to enter explore mode
|
||||
die -- yes vs y to confirm dying (for explore or debug mode)
|
||||
bones -- yes vs y to confirm saving bones data in debug mode
|
||||
@@ -224,6 +224,7 @@ paranoid_confirmation space separated list [paranoid_confirm:pray swim]
|
||||
Were-change -- yes vs y to confirm changing form due to
|
||||
lycanthropy when hero has polymorph control;
|
||||
pray -- y to confirm an attempt to pray; on by default
|
||||
trap -- y to enter a known trap unless it is harmless;
|
||||
swim -- require m prefix to move into water or lava when
|
||||
hero has seen it and isn't impaired; on by default;
|
||||
AutoAll -- y to confirm if using menustyle:Full and choice 'A'
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
.ds f0 "\*(vr
|
||||
.ds f1
|
||||
.\"DO NOT REMOVE NH_DATESUB .ds f2 "DATE(%B %-d, %Y)
|
||||
.ds f2 "August 5, 2023
|
||||
.ds f2 "September 8, 2023
|
||||
.
|
||||
.\" A note on some special characters:
|
||||
.\" \(lq = left double quote
|
||||
@@ -4246,6 +4246,11 @@ to lycanthropy when hero has polymorph control;
|
||||
require \(oqy\(cq to confirm an attempt to pray rather
|
||||
than immediately praying; on by default;
|
||||
(to require \(lqyes\(rq rather than just \(oqy\(cq, set Confirm too);
|
||||
.PL trap
|
||||
require \(oqy\(cq to confirm an attempt to move into or onto a known trap,
|
||||
unless doing so is considered to be harmless;
|
||||
(to require \(lqyes\(rq rather than just \(oqy\(cq, set Confirm too);
|
||||
confirmation can be skipped by using the \(oq\f(CRm\fP\(cq movement prefix;
|
||||
.PL swim
|
||||
prevent walking into water or lava; on by default; (to deliberately step
|
||||
onto/into such terrain when this is set, use the \(oq\f(CRm\fP\(cq
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
\author{Original version - Eric S. Raymond\\
|
||||
(Edited and expanded for 3.7.0 by Mike Stephenson and others)}
|
||||
%DO NOT REMOVE NH_DATESUB \date{DATE(%B %-d, %Y)}
|
||||
\date{August 5, 2023}
|
||||
\date{September 8, 2023}
|
||||
|
||||
\maketitle
|
||||
|
||||
@@ -4646,7 +4646,7 @@ a peaceful monster;
|
||||
\item[{\tt wand-break}]
|
||||
require ``{\tt yes}'' rather than `{\tt y}' to confirm breaking
|
||||
a wand with the {\it apply} command;
|
||||
\item[{\tt eating}]
|
||||
\item[{\tt eating~}]
|
||||
require ``{\tt yes}'' rather than `{\tt y}' to confirm whether to
|
||||
continue eating;
|
||||
\item[{\tt Were-change}]
|
||||
@@ -4656,6 +4656,11 @@ to lycanthropy when hero has polymorph control;
|
||||
require `{\tt y}' to confirm an attempt to pray rather
|
||||
than immediately praying; on by default;
|
||||
(to require ``yes'' rather than just `y', set Confirm too);
|
||||
\item[{\tt trap~~~}]
|
||||
require `{\tt y}' to confirm an attempt to move into or onto a known trap,
|
||||
unless doing so is considered to be harmless;
|
||||
(to require ``yes'' rather than just `y', set Confirm too);
|
||||
confirmation can be skipped by using the `{\tt m}' movement prefix;
|
||||
\item[{\tt swim~~~}]
|
||||
prevent walking into water or lava; on by default; (to deliberately step
|
||||
onto/into such terrain when this is set, use the `{\tt m}'
|
||||
|
||||
@@ -1234,6 +1234,8 @@ if Magicbane cancelled a shapeshifter, forcing it to 'unshift', subsequent
|
||||
a pet that was poison resistant but not stoning resistant would eat Medusa's
|
||||
corpse and be turned to stone
|
||||
ring of hunger prevents choking on your food
|
||||
paranoid_confirm:pray can be changed to require yes/no response instead of y/n
|
||||
by also setting paranoid_confirm:Confirm
|
||||
|
||||
|
||||
Fixes to 3.7.0-x General Problems Exposed Via git Repository
|
||||
@@ -2171,6 +2173,9 @@ reading a blessed scroll of light has a chance to improve bless/curse state
|
||||
added a chronicle of major events, and optional live logging of those
|
||||
paranoid_confirm:swim to prevent accidental dunking into dangerous liquids;
|
||||
joins paranoid_confirm:pray as the default setting
|
||||
paranoid_confirm:trap to confirm entering a known trap unless it is harmless;
|
||||
like revised paranoid_confirm:pray, requires y/n response; add
|
||||
paranoid_confirm:Confirm to require yes/no instead
|
||||
paranoid_confirm:Autoall to confirm picking 'A' in menustyle:Full filter menu
|
||||
looking at a monster will indicate whether it is asleep, and waking up a
|
||||
monster yields a message
|
||||
|
||||
@@ -2913,6 +2913,7 @@ extern struct monst *animate_statue(struct obj *, coordxy, coordxy,
|
||||
int, int *);
|
||||
extern struct monst *activate_statue_trap(struct trap *, coordxy, coordxy,
|
||||
boolean);
|
||||
extern int immune_to_trap(struct monst *, unsigned);
|
||||
extern void set_utrap(unsigned, unsigned);
|
||||
extern void reset_utrap(boolean);
|
||||
extern void dotrap(struct trap *, unsigned);
|
||||
|
||||
@@ -85,7 +85,8 @@ struct flag {
|
||||
#define PARANOID_WERECHANGE 0x0100
|
||||
#define PARANOID_EATING 0x0200
|
||||
#define PARANOID_SWIM 0x0400
|
||||
#define PARANOID_AUTOALL 0x0800
|
||||
#define PARANOID_TRAP 0x0800
|
||||
#define PARANOID_AUTOALL 0x1000
|
||||
int pickup_burden; /* maximum burden before prompt */
|
||||
int pile_limit; /* controls feedback when walking over objects */
|
||||
char discosort; /* order of dodiscovery/doclassdisco output: o,s,c,a */
|
||||
@@ -482,6 +483,8 @@ enum runmode_types {
|
||||
#define ParanoidEating ((flags.paranoia_bits & PARANOID_EATING) != 0)
|
||||
/* Prevent going into lava or water without explicitly forcing it */
|
||||
#define ParanoidSwim ((flags.paranoia_bits & PARANOID_SWIM) != 0)
|
||||
/* Prevent going onto/into known trap unless it is harmless */
|
||||
#define ParanoidTrap ((flags.paranoia_bits & PARANOID_TRAP) != 0)
|
||||
/* Require confirmation for choosing 'A' in class menu for menustyle:Full */
|
||||
#define ParanoidAutoAll ((flags.paranoia_bits & PARANOID_AUTOALL) != 0U)
|
||||
|
||||
|
||||
@@ -93,13 +93,22 @@ enum trap_types {
|
||||
};
|
||||
|
||||
/* some trap-related function return results */
|
||||
enum { Trap_Effect_Finished = 0,
|
||||
Trap_Is_Gone = 0,
|
||||
Trap_Caught_Mon = 1,
|
||||
Trap_Killed_Mon = 2,
|
||||
Trap_Moved_Mon = 3, /* new location, or new level */
|
||||
enum trap_result {
|
||||
Trap_Effect_Finished = 0,
|
||||
Trap_Is_Gone = 0,
|
||||
Trap_Caught_Mon = 1,
|
||||
Trap_Killed_Mon = 2,
|
||||
Trap_Moved_Mon = 3, /* new location, or new level */
|
||||
};
|
||||
|
||||
/* return codes from immune_to_trap() */
|
||||
enum trap_immunities {
|
||||
TRAP_NOT_IMMUNE = 0,
|
||||
TRAP_CLEARLY_IMMUNE = 1,
|
||||
TRAP_HIDDEN_IMMUNE = 2,
|
||||
};
|
||||
|
||||
|
||||
#define is_pit(ttyp) ((ttyp) == PIT || (ttyp) == SPIKED_PIT)
|
||||
#define is_hole(ttyp) ((ttyp) == HOLE || (ttyp) == TRAPDOOR)
|
||||
#define unhideable_trap(ttyp) ((ttyp) == HOLE) /* visible traps */
|
||||
|
||||
39
src/hack.c
39
src/hack.c
@@ -2459,6 +2459,45 @@ domove_core(void)
|
||||
if (u_rooted())
|
||||
return;
|
||||
|
||||
/* warn maybe player before walking into known traps */
|
||||
if (ParanoidTrap && (trap = t_at(x, y)) != 0 && trap->tseen
|
||||
&& (!gc.context.nopick || gc.context.run)
|
||||
&& !Stunned && !Confusion
|
||||
&& (immune_to_trap(&gy.youmonst, trap->ttyp) != TRAP_CLEARLY_IMMUNE
|
||||
/* hallucination: all traps still show as ^, but the
|
||||
hero can't tell what they are, so treat as dangerous */
|
||||
|| Hallucination)) {
|
||||
char qbuf[QBUFSZ];
|
||||
int traptype = (Hallucination ? rnd(TRAPNUM - 1) : (int) trap->ttyp);
|
||||
boolean into = FALSE; /* "onto" the trap vs "into" */
|
||||
|
||||
switch (traptype) {
|
||||
case BEAR_TRAP:
|
||||
case PIT:
|
||||
case SPIKED_PIT:
|
||||
case HOLE:
|
||||
case TELEP_TRAP:
|
||||
case LEVEL_TELEP:
|
||||
case MAGIC_PORTAL:
|
||||
case WEB:
|
||||
into = TRUE;
|
||||
break;
|
||||
}
|
||||
Snprintf(qbuf, sizeof qbuf, "Really %s %s that %s?",
|
||||
locomotion(gy.youmonst.data, "step"),
|
||||
into ? "into" : "onto",
|
||||
defsyms[trap_to_defsym(traptype)].explanation);
|
||||
/* handled like paranoid_confirm:pray; when paranoid_confirm:trap
|
||||
isn't set, don't ask at all but if it is set (checked above),
|
||||
ask via y/n if parnoid_confirm:confirm isn't also set or via
|
||||
yes/no if it is */
|
||||
if (!paranoid_query(ParanoidConfirm, qbuf)) {
|
||||
nomul(0);
|
||||
gc.context.move = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (u.utrap) {
|
||||
boolean moved = trapmove(x, y, trap);
|
||||
|
||||
|
||||
@@ -176,9 +176,12 @@ static const struct paranoia_opts {
|
||||
"yes vs y to continue eating after first bite when satiated" },
|
||||
{ PARANOID_WERECHANGE, "Were-change", 2, (const char *) 0, 0,
|
||||
"yes vs y to change form when lycanthropy is controllable" },
|
||||
/* extra y/n questions rather than changing y/n to yes/n[o] */
|
||||
/* extra y/n questions rather than changing y/n to yes/n[o];
|
||||
they switch to yes/no if paranoid:confirm is also set */
|
||||
{ PARANOID_PRAY, "pray", 1, 0, 0,
|
||||
"y required to pray (supersedes old \"prayconfirm\" option)" },
|
||||
{ PARANOID_TRAP, "trap", 1, "move-trap", 1,
|
||||
"y required to enter known trap unless considered harmless" },
|
||||
{ PARANOID_AUTOALL, "Autoall", 2, "autoselect-all", 2,
|
||||
"y required to pick filter choice 'A' for menustyle:Full" },
|
||||
/* not a yes/n[o] vs y/n change nor a y/n addition */
|
||||
|
||||
166
src/trap.c
166
src/trap.c
@@ -2544,6 +2544,172 @@ trapeffect_vibrating_square(
|
||||
return Trap_Effect_Finished;
|
||||
}
|
||||
|
||||
/*
|
||||
* for PR#259 - paranoid_confirm:trap
|
||||
*
|
||||
* Will a monster suffer any adverse effects from a certain trap?
|
||||
* Note: does NOT mean "will a monster trigger a trap in the first place",
|
||||
* though if it won't that does imply that they'll not suffer adverse effects.
|
||||
* For example, an elf is considered immune to sleeping gas traps even though
|
||||
* they'll set the trap off.
|
||||
* Return value:
|
||||
* TRAP_NOT_IMMUNE = not immune at the moment;
|
||||
* TRAP_CLEARLY_IMMUNE = obviously immune (if player is polymorphed, assume
|
||||
* they know which traps they are immune to in their current form);
|
||||
* TRAP_HIDDEN_IMMUNE = immune but in non-obvious way such as an unidentified
|
||||
* item or hidden intrinsic providing a resistance; the player should still
|
||||
* be warned of this trap, while monsters implicitly know they're immune.
|
||||
*/
|
||||
int
|
||||
immune_to_trap(struct monst *mon, unsigned ttype)
|
||||
{
|
||||
struct permonst *pm;
|
||||
struct obj *obj;
|
||||
boolean is_you;
|
||||
|
||||
if (!mon) {
|
||||
impossible("immune_to_trap: null monster");
|
||||
return TRAP_NOT_IMMUNE;
|
||||
}
|
||||
pm = mon->data;
|
||||
is_you = (mon == &gy.youmonst);
|
||||
|
||||
switch (ttype) {
|
||||
case ARROW_TRAP:
|
||||
case DART_TRAP:
|
||||
case ROCKTRAP:
|
||||
/* can hit anything; even noncorporeal monsters might get a blessed
|
||||
projectile */
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case BEAR_TRAP:
|
||||
if (pm->msize <= MZ_SMALL
|
||||
|| amorphous(pm) || is_whirly(pm) || unsolid(pm))
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
/*FALLTHRU*/
|
||||
case SQKY_BOARD:
|
||||
case LANDMINE:
|
||||
case ROLLING_BOULDER_TRAP:
|
||||
case HOLE:
|
||||
case TRAPDOOR:
|
||||
case PIT:
|
||||
case SPIKED_PIT:
|
||||
/* ground-based traps, which can be evaded by levitation, flying, or
|
||||
hanging to the ceiling */
|
||||
if (Sokoban && (is_pit(ttype) || is_hole(ttype)))
|
||||
return TRAP_NOT_IMMUNE;
|
||||
if (is_floater(pm) || is_flyer(pm)
|
||||
|| (is_clinger(pm) && has_ceiling(&u.uz)))
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
else if (is_you && (Levitation || Flying))
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case SLP_GAS_TRAP:
|
||||
if (breathless(pm))
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
else if (!is_you && resists_sleep(mon))
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
else if (is_you && Sleep_resistance)
|
||||
return TRAP_HIDDEN_IMMUNE;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case LEVEL_TELEP:
|
||||
case TELEP_TRAP:
|
||||
/* consider unintended teleporting to be an adverse effect; if in
|
||||
the endgame or carrying the Amulet, the teleport trap won't work
|
||||
anyway, so anything hitting it is immune. */
|
||||
if (In_endgame(&u.uz) || mon_has_amulet(mon))
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case POLY_TRAP:
|
||||
if (resists_magm(mon))
|
||||
/* covers Antimagic for player */
|
||||
return (is_you ? TRAP_HIDDEN_IMMUNE : TRAP_CLEARLY_IMMUNE);
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case STATUE_TRAP:
|
||||
/* no effect on monsters, only affects players; only trap detection
|
||||
can let player know that this is a statue trap there ahead of time;
|
||||
in the rare case this happens, do consider it an adverse effect */
|
||||
if (!is_you)
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case WEB:
|
||||
/* most of this code is lifted from mu_maybe_destroy_web */
|
||||
if (webmaker(pm) || amorphous(pm) || is_whirly(pm) || flaming(pm)
|
||||
|| unsolid(pm) || pm == &mons[PM_GELATINOUS_CUBE])
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case ANTI_MAGIC:
|
||||
/* doesn't hurt any non-magic-resistant monster with no magic */
|
||||
if (is_you) {
|
||||
if (Antimagic)
|
||||
return TRAP_NOT_IMMUNE;
|
||||
else if (u.uenmax == 0)
|
||||
/* player won't lose HP and can't lose more Pw */
|
||||
return TRAP_HIDDEN_IMMUNE;
|
||||
|
||||
/* following conditional lifted from mintrap ANTI_MAGIC logic */
|
||||
} else if (!resists_magm(mon)
|
||||
&& (mon->mcan || (!attacktype(pm, AT_MAGC)
|
||||
&& !attacktype(pm, AT_BREA)))) {
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
}
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case RUST_TRAP:
|
||||
/* harmful if wearing anything rustable or if mon is an iron golem */
|
||||
if (pm == &mons[PM_IRON_GOLEM])
|
||||
return TRAP_NOT_IMMUNE;
|
||||
|
||||
for (obj = is_you ? gi.invent : mon->minvent; obj; obj = obj->nobj) {
|
||||
/* rust traps can currently hit only worn armor and weapons */
|
||||
if (is_rustprone(obj) && obj->owornmask) {
|
||||
if (is_you && (obj == uquiver
|
||||
|| (obj == uswapwep && !u.twoweap)))
|
||||
continue;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
}
|
||||
}
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
case MAGIC_TRAP:
|
||||
/* for player, any number of bad effects;
|
||||
for monsters, only replicates fire trap, so fall through */
|
||||
if (is_you)
|
||||
return TRAP_NOT_IMMUNE;
|
||||
/*FALLTHRU*/
|
||||
case FIRE_TRAP: /* can always destroy items being carried */
|
||||
/* harmful if not resistant or if carrying anything that could burn */
|
||||
if (is_you ? !Fire_resistance : !resists_fire(mon))
|
||||
return TRAP_NOT_IMMUNE;
|
||||
|
||||
for (obj = is_you ? gi.invent : mon->minvent; obj; obj = obj->nobj) {
|
||||
if (obj->oclass == SCROLL_CLASS || obj->oclass == POTION_CLASS
|
||||
|| obj->oclass == SPBOOK_CLASS
|
||||
|| (obj->owornmask && is_flammable(obj))) {
|
||||
if ((obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
|
||||
/* mon knows scroll of fire or spellbook of fireball
|
||||
won't be affected; hero knows iff this one has been
|
||||
seen and its type has been discovered */
|
||||
&& (!is_you
|
||||
|| (obj->dknown && objects[obj->otyp].oc_name_known)))
|
||||
continue;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
}
|
||||
}
|
||||
return (is_you ? TRAP_HIDDEN_IMMUNE : TRAP_CLEARLY_IMMUNE);
|
||||
case MAGIC_PORTAL:
|
||||
/* never hurts anything, but player is considered non-immune so they
|
||||
can be asked about entering it */
|
||||
if (!is_you)
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
return TRAP_NOT_IMMUNE;
|
||||
case VIBRATING_SQUARE:
|
||||
/* no adverse effects */
|
||||
return TRAP_CLEARLY_IMMUNE;
|
||||
default:
|
||||
impossible("immune_to_trap: bad ttype %u", ttype);
|
||||
break;
|
||||
}
|
||||
return TRAP_NOT_IMMUNE;
|
||||
}
|
||||
|
||||
static int
|
||||
trapeffect_selector(
|
||||
struct monst* mtmp,
|
||||
|
||||
Reference in New Issue
Block a user