Some traps on early depths were triggered already

The hero isn't the only adventurer seeking the Amulet. It's clear
from various other events in the game that others have been there
beforehand. As such, we can expect many of the traps on the first
few levels to already have been triggered repeatedly by questing
adventurers.

This commit allows for the creation of adventurer corpses in
early-game traps, together with a small amount of cursed junk
(i.e. a miniature bones pile) and any items created by the trap
itself. On dungeon level 1, this is guaranteed for the vast
majority of harmful traps, in order to avoid near-unavoidable
deaths in the very early game due to not having enough max HP to
survive a trap hit.

Wizard mode testing shows that this case doesn't trigger very
often; maybe once a game on average. (Traps are rare on filler
levels, at least early on, and many types of trap would leave no
evidence, e.g. a teleportation trap won't kill people on its own
square.) As a result, the balance impact from the actual items
here is likely to be minimal (it may help out ranged combat roles
slightly but they could do with the boost). The main change,
therefore, is to reduce the number of unfair very early deaths
(replacing them with fairer "you shouldn't have investigated
what created that corpse!" deaths).
This commit is contained in:
Alex Smith
2017-11-24 00:42:42 +00:00
parent 59c357de9a
commit 865e69ebca

View File

@@ -1253,6 +1253,7 @@ struct mkroom *croom;
coord *tm;
{
register int kind;
unsigned lvl = level_difficulty();
coord m;
/* no traps in pools */
@@ -1289,8 +1290,6 @@ coord *tm;
/* bias the frequency of fire traps in Gehennom */
kind = FIRE_TRAP;
} else {
unsigned lvl = level_difficulty();
do {
kind = rnd(TRAPNUM - 1);
/* reject "too hard" traps */
@@ -1366,6 +1365,134 @@ coord *tm;
(void) maketrap(m.x, m.y, kind);
if (kind == WEB)
(void) makemon(&mons[PM_GIANT_SPIDER], m.x, m.y, NO_MM_FLAGS);
/* The hero isn't the only person who's entered the dungeon in
search of treasure. On the very shallowest levels, there's a
chance that a created trap will have killed something already
(and this is guaranteed on the first level).
This isn't meant to give any meaningful treasure (in fact, any
items we drop here are typically cursed, other than ammo fired
by the trap). Rather, it's mostly just for flavour and to give
players on very early levels a sufficient chance to avoid traps
that may end up killing them before they have a fair chance to
build max HP. Including cursed items gives the same fair chance
to the starting pet, and fits the rule that possessions of the
dead are normally cursed.
Some types of traps are excluded because they're entirely
nonlethal, even indirectly. We also exclude all of the
later/fancier traps because they tend to have special
considerations (e.g. webs, portals), often are indirectly
lethal, and tend not to generate on shallower levels anyway.
Finally, pits are excluded because it's weird to see an item
in a pit and yet not be able to identify that the pit is there. */
if (lvl <= rnd(4) && kind != SQKY_BOARD && kind != RUST_TRAP &&
kind != PIT && kind != SPIKED_PIT && kind < HOLE) {
/* Object generated by the trap; initially NULL, stays NULL if
we fail to generate an object or if the trap doesn't
generate objects */
struct obj *otmp = NULL;
/* Race of the victim */
int victim_mnum;
/* Not all trap types have special handling here; only the
ones that kill in a specific way that's obvious after the
fact. */
switch (kind) {
case ARROW_TRAP:
otmp = mksobj(ARROW, TRUE, FALSE);
otmp->opoisoned = 0;
/* don't adjust the quantity; maybe the trap shot multiple
times, there was an untrapping attempt, etc... */
break;
case DART_TRAP:
otmp = mksobj(DART, TRUE, FALSE);
break;
case ROCKTRAP:
otmp = mksobj(ROCK, TRUE, FALSE);
break;
default:
/* no item dropped by the trap */
break;
}
if (otmp) {
place_object(otmp, m.x, m.y);
}
/* now otmp is reused for other items we're placing */
/* Place a random possession. This could be a weapon, tool,
food, or gem, i.e. the item classes that are typically
nonmagical and not worthless. */
do {
int poss_class;
switch (rn2(4)) {
case 0:
poss_class = WEAPON_CLASS;
break;
case 1:
poss_class = TOOL_CLASS;
break;
case 2:
poss_class = FOOD_CLASS;
break;
case 3:
poss_class = GEM_CLASS;
break;
}
otmp = mkobj(poss_class, FALSE);
/* these items are always cursed, both for flavour (owned
by a dead adventurer, bones-pile-style) and for balance
(less useful to use, and encourage pets to avoid the
trap) */
if (otmp) {
otmp->blessed = 0;
otmp->cursed = 1;
otmp->owt = weight(otmp);
place_object(otmp, m.x, m.y);
}
/* 20% chance of placing an additional item, recursively */
} while (!rn2(5));
/* Place a corpse. */
switch (rn2(15)) {
case 0:
/* elf corpses are the rarest as they're the most useful */
victim_mnum = PM_ELF;
break;
case 1: case 2:
victim_mnum = PM_DWARF;
break;
case 3: case 4: case 5:
victim_mnum = PM_ORC;
break;
case 6: case 7: case 8: case 9:
/* more common as they could have come from the Mines */
victim_mnum = PM_GNOME;
/* 10% chance of a candle too */
if (!rn2(10)) {
otmp = mksobj(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE,
TRUE, FALSE);
otmp->quan = 1;
otmp->blessed = 0;
otmp->cursed = 1;
otmp->owt = weight(otmp);
place_object(otmp, m.x, m.y);
}
break;
default:
/* the most common race */
victim_mnum = PM_HUMAN;
break;
}
otmp = mkcorpstat(CORPSE, NULL, &mons[victim_mnum], m.x, m.y,
CORPSTAT_INIT);
if (otmp)
otmp->age -= 51; /* died too long ago to eat */
}
}
void