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