From: Alex Smith Date: Fri, 24 Nov 2017 00:42:42 +0000 (+0000) Subject: Some traps on early depths were triggered already X-Git-Tag: NetHack-3.6.1_RC01~206 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=865e69ebca3000128c89365eb290f608c0adb5b9;p=nethack 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). --- diff --git a/src/mklev.c b/src/mklev.c index 6fd50f7fe..a0e6a3ed7 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -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