From 8279aa4384cc0c26f569d8159f8ced038f8abb6f Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 5 Mar 2018 12:01:31 -0800 Subject: [PATCH] removing a monster from current level I ended up not using this, but it might as well be included for potential future use. Extend mlevel_tele_trap() to support forcing a monster off the current level to make room either for the hero or some other monster. goto_level() does something similar when the hero is arriving on a level. This is for situations where the hero is already there (such as divine aid attempting to fix STUCK_IN_WALL). mlevel_tele_trap(mon, (struct trap *) 0) will usually move 'mon' off the level, scheduled to migrate back if the hero leaves the level and subsequently returns. 'Usually' because it doesn't work in endgame and certain monsters are excluded regardless of dungeon location, so caller has to be prepared to try to move another monster (or resort to goto_level()'s unconditional forced migration). --- src/teleport.c | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/teleport.c b/src/teleport.c index 8fb3f8c84..bd3ada997 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -198,6 +198,8 @@ STATIC_OVL boolean tele_jump_ok(x1, y1, x2, y2) int x1, y1, x2, y2; { + if (!isok(x2, y2)) + return FALSE; if (dndest.nlx > 0) { /* if inside a restricted region, can't teleport outside */ if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx, @@ -1135,8 +1137,7 @@ struct trap *trap; boolean force_it; int in_sight; { - int tt = trap->ttyp; - struct permonst *mptr = mtmp->data; + int tt = (trap ? trap->ttyp : NO_TRAP); if (mtmp == u.ustuck) /* probably a vortex */ return 0; /* temporary? kludge */ @@ -1157,8 +1158,8 @@ int in_sight; } } else if (tt == MAGIC_PORTAL) { if (In_endgame(&u.uz) - && (mon_has_amulet(mtmp) || is_home_elemental(mptr))) { - if (in_sight && mptr->mlet != S_ELEMENTAL) { + && (mon_has_amulet(mtmp) || is_home_elemental(mtmp->data))) { + if (in_sight && mtmp->data->mlet != S_ELEMENTAL) { pline("%s seems to shimmer for a moment.", Monnam(mtmp)); seetrap(trap); } @@ -1167,27 +1168,44 @@ int in_sight; assign_level(&tolevel, &trap->dst); migrate_typ = MIGR_PORTAL; } - } else { /* (tt == LEVEL_TELEP) */ + } else if (tt == LEVEL_TELEP || tt == NO_TRAP) { int nlev; - if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { + if (mon_has_amulet(mtmp) || In_endgame(&u.uz) + /* NO_TRAP is used when forcing a monster off the level; + onscary(0,0,) is true for the Wizard, Riders, lawful + minions, Angels of any alignment, shopkeeper or priest + currently inside his or her own special room */ + || (tt == NO_TRAP && onscary(0, 0, mtmp))) { if (in_sight) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); return 0; } - nlev = random_teleport_level(); - if (nlev == depth(&u.uz)) { - if (in_sight) - pline("%s shudders for a moment.", Monnam(mtmp)); - return 0; + if (tt == NO_TRAP) { + /* creature is being forced off the level to make room; + it will try to return to this level (at a random spot + rather than its current one) if the level is left by + the hero and then revisited */ + assign_level(&tolevel, &u.uz); + } else { + nlev = random_teleport_level(); + if (nlev == depth(&u.uz)) { + if (in_sight) + pline("%s shudders for a moment.", Monnam(mtmp)); + return 0; + } + get_level(&tolevel, nlev); } - get_level(&tolevel, nlev); + } else { + impossible("mlevel_tele_trap: unexpected trap type (%d)", tt); + return 0; } if (in_sight) { pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp)); - seetrap(trap); + if (trap) + seetrap(trap); } migrate_to_level(mtmp, ledger_no(&tolevel), migrate_typ, (coord *) 0); return 3; /* no longer on this level */