diff --git a/dat/symbols b/dat/symbols index 619d436a7..c6afc4c5e 100644 --- a/dat/symbols +++ b/dat/symbols @@ -453,11 +453,13 @@ start: Blank S_hbeam: \032 S_hcdbridge: \032 S_hcdoor: \032 + S_hodbridge: \032 S_hodoor: \032 S_hole: \032 S_human: \032 S_humanoid: \032 S_hwall: \032 + S_ice: \032 S_imp: \032 S_invisible: \032 S_jabberwock: \032 @@ -543,7 +545,9 @@ start: Blank S_vbeam: \032 S_vcdbridge: \032 S_vcdoor: \032 + S_venom: \032 S_vibrating_square: \032 + S_vodbridge: \032 S_vodoor: \032 S_vortex: \032 S_vwall: \032 diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index cf4d13739..f5adc8b6e 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -3543,6 +3543,7 @@ h S_humanoid (humanoid) - S_hwall (horizontal wall) . S_ice (ice) i S_imp (imp or minor demon) +I S_invisible (invisible monster) J S_jabberwock (jabberwock) j S_jelly (jelly) k S_kobold (kobold) diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 5bf4fc351..0f3c83504 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -4334,6 +4334,7 @@ Default & Symbol Name & Description\\ \verb@-@ & S\verb+_+hwall & (horizontal wall)\\ \verb@.@ & S\verb+_+ice & (ice)\\ \verb@i@ & S\verb+_+imp & (imp or minor demon)\\ +\verb@I@ & S\verb+_+invisible & (invisible monster)\\ \verb@J@ & S\verb+_+jabberwock & (jabberwock)\\ \verb@j@ & S\verb+_+jelly & (jelly)\\ \verb@k@ & S\verb+_+kobold & (kobold)\\ diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 815b9f1ad..7142c52ca 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -353,9 +353,17 @@ sometimes generate the random mazes with wide corridors, thick walls, put throne room gold in the chest wielding Trollsbane prevents trolls from reviving wielding Demonbane prevents demons summoning friends +wielding Dragonbane confers reflection +wielding Ogresmasher grants 25 constitution Elbereth must now be on a square by itself to function Elbereth now erodes based on attacks by the player, not monsters scared novels are made of paper, not gold +movement speeds are made less predictable by using random rounding, rather + than via adding a random offset +some death by the-poison-was-deadly situations left stale non-zero HP shown + on the status line during final disclosure +when sitting at a trap spot: You sit down. You step on a level teleporter. + (likewise for polymorph trap, and similar issue for web) Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/include/artilist.h b/include/artilist.h index b3510386c..e06e99a7f 100644 --- a/include/artilist.h +++ b/include/artilist.h @@ -103,7 +103,8 @@ STATIC_OVL NEARDATA struct artifact artilist[] = { FIRE(5, 0), FIRE(0, 0), NO_CARY, 0, A_NONE, NON_PM, NON_PM, 3000L, NO_COLOR), - A("Dragonbane", BROADSWORD, (SPFX_RESTR | SPFX_DCLAS), 0, S_DRAGON, + A("Dragonbane", BROADSWORD, + (SPFX_RESTR | SPFX_DCLAS | SPFX_REFLECT), 0, S_DRAGON, PHYS(5, 0), NO_DFNS, NO_CARY, 0, A_NONE, NON_PM, NON_PM, 500L, NO_COLOR), diff --git a/include/extern.h b/include/extern.h index 919138203..b05688d98 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1354,12 +1354,13 @@ E void FDECL(unstuck, (struct monst *)); E void FDECL(killed, (struct monst *)); E void FDECL(xkilled, (struct monst *, int)); E void FDECL(mon_to_stone, (struct monst *)); +E void FDECL(m_into_limbo, (struct monst *)); E void FDECL(mnexto, (struct monst *)); E void FDECL(maybe_mnexto, (struct monst *)); E boolean FDECL(mnearto, (struct monst *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(m_respond, (struct monst *)); -E void FDECL(setmangry, (struct monst *, boolean)); -E void FDECL(wakeup, (struct monst *, boolean)); +E void FDECL(setmangry, (struct monst *, BOOLEAN_P)); +E void FDECL(wakeup, (struct monst *, BOOLEAN_P)); E void NDECL(wake_nearby); E void FDECL(wake_nearto, (int, int, int)); E void FDECL(seemimic, (struct monst *)); @@ -2284,8 +2285,8 @@ E boolean FDECL(stucksteed, (BOOLEAN_P)); E boolean FDECL(goodpos, (int, int, struct monst *, unsigned)); E boolean FDECL(enexto, (coord *, XCHAR_P, XCHAR_P, struct permonst *)); -E boolean -FDECL(enexto_core, (coord *, XCHAR_P, XCHAR_P, struct permonst *, unsigned)); +E boolean FDECL(enexto_core, (coord *, XCHAR_P, XCHAR_P, + struct permonst *, unsigned)); E void FDECL(teleds, (int, int, BOOLEAN_P)); E boolean FDECL(safe_teleds, (BOOLEAN_P)); E boolean FDECL(teleport_pet, (struct monst *, BOOLEAN_P)); @@ -2295,13 +2296,13 @@ E int NDECL(dotele); E void NDECL(level_tele); E void FDECL(domagicportal, (struct trap *)); E void FDECL(tele_trap, (struct trap *)); -E void FDECL(level_tele_trap, (struct trap *)); +E void FDECL(level_tele_trap, (struct trap *, unsigned)); E void FDECL(rloc_to, (struct monst *, int, int)); E boolean FDECL(rloc, (struct monst *, BOOLEAN_P)); E boolean FDECL(tele_restrict, (struct monst *)); E void FDECL(mtele_trap, (struct monst *, struct trap *, int)); -E int FDECL(mlevel_tele_trap, - (struct monst *, struct trap *, BOOLEAN_P, int)); +E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *, + BOOLEAN_P, int)); E boolean FDECL(rloco, (struct obj *)); E int NDECL(random_teleport_level); E boolean FDECL(u_teleport_mon, (struct monst *, BOOLEAN_P)); diff --git a/include/hack.h b/include/hack.h index cc878942c..bf2273b2b 100644 --- a/include/hack.h +++ b/include/hack.h @@ -296,9 +296,9 @@ enum hmon_atkmode_types { #define FORCETRAP 0x01 /* triggering not left to chance */ #define NOWEBMSG 0x02 /* suppress stumble into web message */ #define FORCEBUNGLE 0x04 /* adjustments appropriate for bungling */ -#define RECURSIVETRAP 0x08 /* trap changed into another type this same turn \ - */ +#define RECURSIVETRAP 0x08 /* trap changed into another type this same turn */ #define TOOKPLUNGE 0x10 /* used '>' to enter pit below you */ +#define VIASITTING 0x20 /* #sit while at trap location (affects message) */ /* Flags to control test_move in hack.c */ #define DO_MOVE 0 /* really doing the move */ diff --git a/src/allmain.c b/src/allmain.c index 988004bb0..3d3ba3414 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -132,14 +132,13 @@ boolean resuming; moveamt = youmonst.data->mmove; if (Very_fast) { /* speed boots or potion */ - /* average movement is 1.67 times normal */ - moveamt += NORMAL_SPEED / 2; - if (rn2(3) == 0) - moveamt += NORMAL_SPEED / 2; - } else if (Fast) { - /* average movement is 1.33 times normal */ + /* gain a free action on 2/3 of turns */ if (rn2(3) != 0) - moveamt += NORMAL_SPEED / 2; + moveamt += NORMAL_SPEED; + } else if (Fast) { + /* gain a free action on 1/3 of turns */ + if (rn2(3) == 0) + moveamt += NORMAL_SPEED; } } diff --git a/src/attrib.c b/src/attrib.c index 5c80c5ed2..c87afb683 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -272,6 +272,7 @@ boolean thrown_weapon; /* thrown weapons are less deadly */ if (i == 0 && typ != A_CHA) { /* instant kill */ u.uhp = -1; + context.botl = TRUE; pline_The("poison was deadly..."); } else if (i > 5) { /* HP damage; more likely--but less severe--with missiles */ @@ -1002,6 +1003,9 @@ int x; && (youmonst.data->mlet == S_NYMPH || u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS)) return (schar) 18; + } else if (x == A_CON) { + if (uwep && uwep->oartifact == ART_OGRESMASHER) + return (schar) 25; } else if (x == A_INT || x == A_WIS) { /* yes, this may raise int/wis if player is sufficiently * stupid. there are lower levels of cognition than "dunce". @@ -1047,6 +1051,9 @@ int attrindx; /* lower limit for Str can also be 25 */ if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER) lolimit = hilimit; + } else if (attrindx == A_CON) { + if (uwep && uwep->oartifact == ART_OGRESMASHER) + lolimit = hilimit; } /* this exception is hypothetical; the only other worn item affecting Int or Wis is another helmet so can't be in use at the same time */ diff --git a/src/cmd.c b/src/cmd.c index 35ffe9c1f..317405b45 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1638,6 +1638,8 @@ int mode, final, attrindx; break; case A_CON: attrname = "constitution"; + if (uwep && uwep->oartifact == ART_OGRESMASHER && uwep->cursed) + hide_innate_value = TRUE; break; case A_INT: attrname = "intelligence"; diff --git a/src/dog.c b/src/dog.c index fba998407..0b9d2ae9f 100644 --- a/src/dog.c +++ b/src/dog.c @@ -430,9 +430,10 @@ boolean with_you; mtmp->mx = 0; /*(already is 0)*/ mtmp->my = xyflags; - if (xlocale) - (void) mnearto(mtmp, xlocale, ylocale, FALSE); - else { + if (xlocale) { + if (!mnearto(mtmp, xlocale, ylocale, FALSE)) + goto fail_mon_placement; + } else { if (!rloc(mtmp, TRUE)) { /* * Failed to place migrating monster, @@ -440,6 +441,7 @@ boolean with_you; * Dump the monster's cargo and leave the monster dead. */ struct obj *obj; +fail_mon_placement: while ((obj = mtmp->minvent) != 0) { obj_extract_self(obj); obj_no_longer_held(obj); diff --git a/src/end.c b/src/end.c index d097292fb..08141258f 100644 --- a/src/end.c +++ b/src/end.c @@ -922,6 +922,18 @@ int how; return; } } + if (program_state.panicking +#ifdef HANGUPHANDLING + || program_state.done_hup +#endif + ) { + /* skip status update if panicking or disconnected */ + context.botl = context.botlx = FALSE; + } else { + /* otherwise force full status update */ + context.botlx = TRUE; + bot(); + } if (how == ASCENDED || (!killer.name[0] && how == GENOCIDED)) killer.format = NO_KILLER_PREFIX; diff --git a/src/mhitm.c b/src/mhitm.c index 937868841..d5f1e9463 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -742,6 +742,7 @@ register struct attack *mattk; if (cansee(dx, dy)) pline("%s is regurgitated!", Monnam(mdef)); + remove_monster(dx,dy); place_monster(magr, ax, ay); place_monster(mdef, dx, dy); newsym(ax, ay); diff --git a/src/mhitu.c b/src/mhitu.c index 1cdd7bce7..86a064f84 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -5,7 +5,7 @@ #include "hack.h" #include "artifact.h" -STATIC_VAR NEARDATA struct obj *otmp; +STATIC_VAR NEARDATA struct obj *mon_currwep = (struct obj *) 0; STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *)); STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *, @@ -646,6 +646,7 @@ register struct monst *mtmp; for (i = 0; i < NATTK; i++) { sum[i] = 0; + mon_currwep = (struct obj *)0; mattk = getmattk(mtmp, &youmonst, i, sum, &alt_attk); if ((u.uswallow && mattk->aatyp != AT_ENGL) || (skipnonmagc && mattk->aatyp != AT_MAGC)) @@ -747,18 +748,18 @@ register struct monst *mtmp; break; } if (foundyou) { - otmp = MON_WEP(mtmp); - if (otmp) { - hittmp = hitval(otmp, &youmonst); + mon_currwep = MON_WEP(mtmp); + if (mon_currwep) { + hittmp = hitval(mon_currwep, &youmonst); tmp += hittmp; - mswings(mtmp, otmp); + mswings(mtmp, mon_currwep); } if (tmp > (j = dieroll = rnd(20 + i))) sum[i] = hitmu(mtmp, mattk); else missmu(mtmp, (tmp == j), mattk); /* KMH -- Don't accumulate to-hit bonuses */ - if (otmp) + if (mon_currwep) tmp -= hittmp; } else { wildmiss(mtmp, mattk); @@ -968,6 +969,7 @@ register struct attack *mattk; : "crushed"); } } else { /* hand to hand weapon */ + struct obj *otmp = mon_currwep; if (mattk->aatyp == AT_WEAP && otmp) { int tmp; @@ -2710,10 +2712,10 @@ register struct attack *mattk; return 1; } case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ - if (otmp) { + if (mon_currwep) { /* by_you==True: passive counterattack to hero's action is hero's fault */ - (void) drain_item(otmp, TRUE); + (void) drain_item(mon_currwep, TRUE); /* No message */ } return 1; diff --git a/src/mon.c b/src/mon.c index 35966e381..23ebcdb45 100644 --- a/src/mon.c +++ b/src/mon.c @@ -582,6 +582,7 @@ mcalcmove(mon) struct monst *mon; { int mmove = mon->data->mmove; + int mmove_adj; /* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0; * MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op; @@ -592,21 +593,24 @@ struct monst *mon; else if (mon->mspeed == MFAST) mmove = (4 * mmove + 2) / 3; - if (mon == u.usteed) { - if (u.ugallop && context.mv) { - /* average movement is 1.50 times normal */ - mmove = ((rn2(2) ? 4 : 5) * mmove) / 3; - } - } else if (mmove) { - /* vary movement points allocated to slightly reduce predictability; - random increment (avg +2) exceeds random decrement (avg +1) by - a small amount; normal speed monsters will occasionally get an - extra move and slow ones won't be quite as slow */ - mmove += rn2(5) - rn2(3); /* + 0..4 - 0..2, average net +1 */ - if (mmove < 1) - mmove = 1; + if (mon == u.usteed && u.ugallop && context.mv) { + /* increase movement by a factor of 1.5; also increase variance of + movement speed (if it's naturally 24, we don't want it to always + become 36) */ + mmove = ((rn2(2) ? 4 : 5) * mmove) / 3; } + /* Randomly round the monster's speed to a multiple of NORMAL_SPEED. This + makes it impossible for the player to predict when they'll get a free + turn (thus preventing exploits like "melee kiting"), while retaining + guarantees about shopkeepers not being outsped by a normal-speed player, + normal-speed players being unable to open up a gap when fleeing a + normal-speed monster, etc.*/ + mmove_adj = mmove % NORMAL_SPEED; + mmove -= mmove_adj; + if (rn2(NORMAL_SPEED) < mmove_adj) + mmove += NORMAL_SPEED; + return mmove; } @@ -2025,6 +2029,8 @@ struct monst *mdef; /* hero is thrown from his steed when it disappears */ if (mdef == u.usteed) dismount_steed(DISMOUNT_GENERIC); + /* stuck to you? release */ + unstuck(mdef); /* drop special items like the Amulet so that a dismissed Kop or nurse can't remove them from the game */ mdrop_special_objs(mdef); @@ -2445,6 +2451,16 @@ struct monst *mtmp; return TRUE; } +/* drop monster into "limbo" - that is, migrate to the current level */ +void +m_into_limbo(mtmp) +struct monst *mtmp; +{ + unstuck(mtmp); + mdrop_special_objs(mtmp); + migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_APPROX_XY, NULL); +} + /* make monster mtmp next to you (if possible); might place monst on far side of a wall or boulder */ void @@ -2461,7 +2477,11 @@ struct monst *mtmp; return; } - if (!enexto(&mm, u.ux, u.uy, mtmp->data)) + if (!enexto(&mm, u.ux, u.uy, mtmp->data)) { + m_into_limbo(mtmp); + return; + } + if (!isok(mm.x, mm.y)) return; rloc_to(mtmp, mm.x, mm.y); if (!in_mklev && (mtmp->mstrategy & STRAT_APPEARMSG)) { @@ -2530,6 +2550,8 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */ */ if (!enexto(&mm, newx, newy, mtmp->data)) return FALSE; + if (!isok(mm.x,mm.y)) + return FALSE; newx = mm.x; newy = mm.y; } @@ -2541,12 +2563,10 @@ boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */ othermon->mx = othermon->my = 0; (void) mnearto(othermon, x, y, FALSE); if (othermon->mx == 0 && othermon->my == 0) { - /* reloc failed, dump monster into "limbo" - (aka migrate to current level) */ + /* reloc failed */ othermon->mx = oldx; othermon->my = oldy; - mdrop_special_objs(othermon); - migrate_to_level(othermon, ledger_no(&u.uz), MIGR_APPROX_XY, NULL); + m_into_limbo(othermon); } } diff --git a/src/objnam.c b/src/objnam.c index d395ea747..7a800d23a 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -268,7 +268,7 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ register struct objclass *ocl = &objects[typ]; int nn = ocl->oc_name_known, omndx = obj->corpsenm; const char *actualn = OBJ_NAME(*ocl); - const char *dn = OBJ_DESCR(*ocl); + const char *dn = OBJ_DESCR(*ocl) ? OBJ_DESCR(*ocl) : actualn; const char *un = ocl->oc_uname; boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR); boolean known, dknown, bknown; @@ -327,15 +327,15 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ Strcpy(buf, (obj->spe < 3) ? "moist " : "wet "); if (!dknown) - Strcat(buf, dn ? dn : actualn); + Strcat(buf, dn); else if (nn) Strcat(buf, actualn); else if (un) { - Strcat(buf, dn ? dn : actualn); + Strcat(buf, dn); Strcat(buf, " called "); Strcat(buf, un); } else - Strcat(buf, dn ? dn : actualn); + Strcat(buf, dn); /* If we use an() here we'd have to remember never to use */ /* it whenever calling doname() or xname(). */ if (typ == FIGURINE && omndx != NON_PM) { diff --git a/src/sit.c b/src/sit.c index 047e22338..a6c6a0906 100644 --- a/src/sit.c +++ b/src/sit.c @@ -113,7 +113,7 @@ dosit() } } else { You("sit down."); - dotrap(trap, 0); + dotrap(trap, VIASITTING); } } else if (Underwater || Is_waterlevel(&u.uz)) { if (Is_waterlevel(&u.uz)) diff --git a/src/teleport.c b/src/teleport.c index 5c42151a6..8fb3f8c84 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -872,12 +872,20 @@ struct trap *trap; } void -level_tele_trap(trap) +level_tele_trap(trap, trflags) struct trap *trap; +unsigned trflags; { - You("%s onto a level teleport trap!", - Levitation ? (const char *) "float" - : locomotion(youmonst.data, "step")); + char verbbuf[BUFSZ]; + + if ((trflags & VIASITTING) != 0) + Strcpy(verbbuf, "trigger"); /* follows "You sit down." */ + else + Sprintf(verbbuf, "%s onto", + Levitation ? (const char *) "float" + : locomotion(youmonst.data, "step")); + You("%s a level teleport trap!", verbbuf); + if (Antimagic) { shieldeff(u.ux, u.uy); } diff --git a/src/trap.c b/src/trap.c index 23e26dec3..0df86b1d7 100644 --- a/src/trap.c +++ b/src/trap.c @@ -850,6 +850,7 @@ unsigned trflags; webmsgok = (trflags & NOWEBMSG) == 0, forcebungle = (trflags & FORCEBUNGLE) != 0, plunged = (trflags & TOOKPLUNGE) != 0, + viasitting = (trflags & VIASITTING) != 0, adj_pit = conjoined_pits(trap, t_at(u.ux0, u.uy0), TRUE); int oldumort; int steed_article = ARTICLE_THE; @@ -1237,7 +1238,7 @@ unsigned trflags; case LEVEL_TELEP: seetrap(trap); - level_tele_trap(trap); + level_tele_trap(trap, trflags); break; case WEB: /* Our luckless player has stumbled into a web. */ @@ -1253,7 +1254,7 @@ unsigned trflags; if (webmsgok) { char verbbuf[BUFSZ]; - if (forcetrap) { + if (forcetrap || viasitting) { Strcpy(verbbuf, "are caught by"); } else if (u.usteed) { Sprintf(verbbuf, "lead %s into", @@ -1382,15 +1383,17 @@ unsigned trflags; char verbbuf[BUFSZ]; seetrap(trap); - if (u.usteed) - Sprintf(verbbuf, "lead %s", + if (viasitting) + Strcpy(verbbuf, "trigger"); /* follows "You sit down." */ + else if (u.usteed) + Sprintf(verbbuf, "lead %s onto", x_monnam(u.usteed, steed_article, (char *) 0, SUPPRESS_SADDLE, FALSE)); else - Sprintf(verbbuf, "%s", Levitation - ? (const char *) "float" - : locomotion(youmonst.data, "step")); - You("%s onto a polymorph trap!", verbbuf); + Sprintf(verbbuf, "%s onto", + Levitation ? (const char *) "float" + : locomotion(youmonst.data, "step")); + You("%s a polymorph trap!", verbbuf); if (Antimagic || Unchanging) { shieldeff(u.ux, u.uy); You_feel("momentarily different."); diff --git a/src/wield.c b/src/wield.c index 929d45c82..585e971c9 100644 --- a/src/wield.c +++ b/src/wield.c @@ -96,6 +96,10 @@ register struct obj *obj; if (!Blind) pline("%s shining.", Tobjnam(olduwep, "stop")); } + if (uwep == obj + && ((uwep && uwep->oartifact == ART_OGRESMASHER) + || (olduwep && olduwep->oartifact == ART_OGRESMASHER))) + context.botl = 1; /* Note: Explicitly wielding a pick-axe will not give a "bashing" * message. Wielding one via 'a'pplying it will. * 3.2.2: Wielding arbitrary objects will give bashing message too. diff --git a/src/wizard.c b/src/wizard.c index 6ab8e57bd..3f58433c8 100644 --- a/src/wizard.c +++ b/src/wizard.c @@ -380,7 +380,10 @@ register struct monst *mtmp; if (!rn2(3 + mtmp->mhp / 10)) (void) rloc(mtmp, TRUE); } else if (sx && (mtmp->mx != sx || mtmp->my != sy)) { - (void) mnearto(mtmp, sx, sy, TRUE); + if (!mnearto(mtmp, sx, sy, TRUE)) { + m_into_limbo(mtmp); + return 0; + } } /* if you're not around, cast healing spells */ if (distu(mtmp->mx, mtmp->my) > (BOLT_LIM * BOLT_LIM)) @@ -433,7 +436,8 @@ register struct monst *mtmp; return 0; } } else { /* a monster has it - 'port beside it. */ - (void) mnearto(mtmp, tx, ty, FALSE); + if (!mnearto(mtmp, tx, ty, FALSE)) + m_into_limbo(mtmp); return 0; } }