From 55c3a7c6c5b299d6e7528c0cb568d14d69c904e2 Mon Sep 17 00:00:00 2001 From: copperwater Date: Wed, 19 Feb 2025 16:54:19 -0500 Subject: [PATCH] Fix: sitting on bidirectional teleportation traps It is possible to create a bidirectional teleportation trap by making a pair of teleportation traps with a fixed destination of each other's coordinate. Moving or hurtling onto such a trap correctly materializes the hero on top of the other trap without triggering it, but for some reason I didn't dig into, sitting down to trigger the first trap does also trigger the second one at the destination end, causing you to counterintuitively teleport twice and end up back where you started. Fix this by stopping tele_trap() from doing anything if it's called recursively, using a static variable like spoteffects() does for the same purpose. I had to adjust a bit of other tele_trap code to remove its sole early return. --- src/teleport.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/teleport.c b/src/teleport.c index fdebacffe..3088c461c 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1458,6 +1458,14 @@ domagicportal(struct trap *ttmp) void tele_trap(struct trap *trap) { + /* a fixed-destination teleport trap could theoretically place hero onto a + * second teleport trap; prevent the recursive call from spoteffects() from + * triggering the trap at the destination */ + static boolean in_tele_trap = FALSE; + if (in_tele_trap) + return; + + in_tele_trap = TRUE; if (In_endgame(&u.uz) || Antimagic) { if (Antimagic) shieldeff(u.ux, u.uy); @@ -1478,13 +1486,19 @@ tele_trap(struct trap *trap) /* could not find some other place to put mtmp; the level must * be nearly or completely full */ You1(shudder_for_moment); - return; } - rloc_to(mtmp, cc.x, cc.y); + else { + rloc_to(mtmp, cc.x, cc.y); + mtmp = (struct monst *) 0; /* no longer a monster at dest */ + } + } + if (!mtmp) { + teleds(trap->teledest.x, trap->teledest.y, TELEDS_TELEPORT); } - teleds(trap->teledest.x, trap->teledest.y, TELEDS_TELEPORT); } else tele(); + + in_tele_trap = FALSE; } void