diff --git a/doc/fixes37.0 b/doc/fixes37.0 index 1495a7ae0..97365e891 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -449,6 +449,9 @@ turn off input autocompletion for '#twoweapon' since simple 'X' invokes it; likewise for #wizdetect (^E), #wizgenesis (^G), #wizidentify (^I), #wizlevelport (^V), #wizmap (^F), and #wizwish (^W); probably ought to do so for #overview (^O) too but that one still autocompletes +if a branch has only one level (Fort Ludios), prevent creation of any level + teleporters there (level definition doesn't have any but wizard mode + wishing could attempt to place one) Fixes to 3.7.0-x Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index a42769579..3da9d738e 100644 --- a/include/extern.h +++ b/include/extern.h @@ -618,6 +618,7 @@ extern boolean On_W_tower_level(d_level *); extern boolean In_W_tower(int, int, d_level *); extern void find_hell(d_level *); extern void goto_hell(boolean, boolean); +extern boolean single_level_branch(d_level *); extern void assign_level(d_level *, d_level *); extern void assign_rnd_level(d_level *, d_level *, int); extern unsigned int induced_align(int); diff --git a/src/dungeon.c b/src/dungeon.c index 427ec44fa..5f851a0a7 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1848,6 +1848,17 @@ goto_hell(boolean at_stairs, boolean falling) goto_level(&lev, at_stairs, falling, FALSE); } +/* is 'lev' the only level in its branch? affects level teleporters */ +boolean +single_level_branch(d_level *lev) +{ + /* + * TODO: this should be generalized instead of assuming that + * Fort Ludios is the only single level branch in the dungeon. + */ + return Is_knox(lev); +} + /* equivalent to dest = source */ void assign_level(d_level *dest, d_level *src) diff --git a/src/hack.c b/src/hack.c index 5422e4a03..435ad9b3a 100644 --- a/src/hack.c +++ b/src/hack.c @@ -178,6 +178,9 @@ moverock(void) } if (ttmp) { + int newlev = 0; /* lint suppression */ + d_level dest; + /* if a trap operates on the boulder, don't attempt to move any others at this location; return -1 if another boulder is in hero's way, or 0 if he @@ -236,16 +239,14 @@ moverock(void) newsym(rx, ry); return sobj_at(BOULDER, sx, sy) ? -1 : 0; case LEVEL_TELEP: - case TELEP_TRAP: { - int newlev = 0; /* lint suppression */ - d_level dest; - - if (ttmp->ttyp == LEVEL_TELEP) { - newlev = random_teleport_level(); - if (newlev == depth(&u.uz) || In_endgame(&u.uz)) - /* trap didn't work; skip "disappears" message */ - goto dopush; - } + /* 20% chance of picking current level; 100% chance for + that if in single-level branch (Knox) or in endgame */ + newlev = random_teleport_level(); + /* if trap doesn't work, skip "disappears" message */ + if (newlev == depth(&u.uz)) + goto dopush; + /*FALLTHRU*/ + case TELEP_TRAP: if (u.usteed) pline("%s pushes %s and suddenly it disappears!", upstart(y_monnam(u.usteed)), the(xname(otmp))); @@ -264,7 +265,6 @@ moverock(void) } seetrap(ttmp); return sobj_at(BOULDER, sx, sy) ? -1 : 0; - } default: break; /* boulder not affected by this trap */ } diff --git a/src/mklev.c b/src/mklev.c index dc606f7ad..53273bc14 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1377,7 +1377,8 @@ mktrap(int num, int mazeflag, struct mkroom *croom, coord *tm) kind = NO_TRAP; break; case LEVEL_TELEP: - if (lvl < 5 || g.level.flags.noteleport) + if (lvl < 5 || g.level.flags.noteleport + || single_level_branch(&u.uz)) kind = NO_TRAP; break; case SPIKED_PIT: diff --git a/src/teleport.c b/src/teleport.c index 1e901cb96..f79ddd147 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -892,7 +892,7 @@ level_tele(void) /* if in Knox and the requested level > 0, stay put. * we let negative values requests fall into the "heaven" loop. */ - if (Is_knox(&u.uz) && newlev > 0 && !force_dest) { + if (single_level_branch(&u.uz) && newlev > 0 && !force_dest) { You1(shudder_for_moment); return; } @@ -1532,7 +1532,7 @@ random_teleport_level(void) int nlev, max_depth, min_depth, cur_depth = (int) depth(&u.uz); /* [the endgame case can only occur in wizard mode] */ - if (!rn2(5) || Is_knox(&u.uz) || In_endgame(&u.uz)) + if (!rn2(5) || single_level_branch(&u.uz) || In_endgame(&u.uz)) return cur_depth; /* What I really want to do is as follows: diff --git a/src/trap.c b/src/trap.c index 1a7917b57..2b6f060e0 100644 --- a/src/trap.c +++ b/src/trap.c @@ -352,10 +352,12 @@ maketrap(int x, int y, int typ) || (u.utraptype == TT_LAVA && !is_lava(x, y)))) reset_utrap(FALSE); /* old remain valid */ - } else if (IS_FURNITURE(lev->typ) - && (!IS_GRAVE(lev->typ) || (typ != PIT && typ != HOLE))) { + } else if ((IS_FURNITURE(lev->typ) + && (!IS_GRAVE(lev->typ) || (typ != PIT && typ != HOLE))) + || (typ == LEVEL_TELEP && single_level_branch(&u.uz))) { /* no trap on top of furniture (caller usually screens the - location to inhibit this, but wizard mode wishing doesn't) */ + location to inhibit this, but wizard mode wishing doesn't) + and no level teleporter in branch with only one level */ return (struct trap *) 0; } else { oldplace = FALSE; @@ -2778,6 +2780,9 @@ launch_obj( } } if ((t = t_at(g.bhitpos.x, g.bhitpos.y)) != 0 && otyp == BOULDER) { + int newlev = 0; + d_level dest; + switch (t->ttyp) { case LANDMINE: if (rn2(10) > 2) { @@ -2801,20 +2806,22 @@ launch_obj( } break; case LEVEL_TELEP: + /* 20% chance of picking current level; 100% chance for + that if in single-level branch (Knox) or in endgame */ + newlev = random_teleport_level(); + /* if trap doesn't work, skip "disappears" message */ + if (newlev == depth(&u.uz)) + break; + /*FALLTHRU*/ case TELEP_TRAP: if (cansee(g.bhitpos.x, g.bhitpos.y)) pline("Suddenly the rolling boulder disappears!"); - else + else if (!Deaf) You_hear("a rumbling stop abruptly."); singleobj->otrapped = 0; - if (t->ttyp == TELEP_TRAP) + if (t->ttyp == TELEP_TRAP) { (void) rloco(singleobj); - else { - int newlev = random_teleport_level(); - d_level dest; - - if (newlev == depth(&u.uz) || In_endgame(&u.uz)) - continue; + } else { add_to_migration(singleobj); get_level(&dest, newlev); singleobj->ox = dest.dnum; @@ -2838,9 +2845,12 @@ launch_obj( } dist = -1; /* stop rolling immediately */ break; - } - if (used_up || dist == -1) + default: break; + } + + if (used_up || dist == -1) + break; /* from 'while' loop */ } if (flooreffects(singleobj, g.bhitpos.x, g.bhitpos.y, "fall")) { used_up = TRUE;