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:
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