-/* NetHack 3.6 teleport.c $NHDT-Date: 1523306912 2018/04/09 20:48:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.73 $ */
+/* NetHack 3.6 teleport.c $NHDT-Date: 1553885439 2019/03/29 18:50:39 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.86 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
mdat = &mons[u.umonster];
}
fakemon = zeromonst;
- set_mon_data(&fakemon, mdat, -1); /* set up for goodpos */
+ set_mon_data(&fakemon, mdat); /* set up for goodpos */
good_ptr = good;
range = 1;
boolean allow_drag;
{
boolean ball_active, ball_still_in_range;
+ struct monst *vault_guard = vault_occupied(u.urooms) ? findgd() : 0;
if (u.utraptype == TT_BURIEDBALL) {
/* unearth it */
}
}
}
- u.utrap = 0;
+ reset_utrap(FALSE);
u.ustuck = 0;
u.ux0 = u.ux;
u.uy0 = u.uy;
vision_full_recalc = 1;
nomul(0);
vision_recalc(0); /* vision before effects */
+ /* if terrain type changes, levitation or flying might become blocked
+ or unblocked; might issue message, so do this after map+vision has
+ been updated for new location instead of right after u_on_newpos() */
+ if (levl[u.ux][u.uy].typ != levl[u.ux0][u.uy0].typ)
+ switch_terrain();
if (telescroll) {
/* when teleporting by scroll, we need to handle discovery
now before getting feedback about any objects at our
else
telescroll = 0; /* no discovery by scrolltele()'s caller */
}
+ /* sequencing issue: we want guard's alarm, if any, to occur before
+ room entry message, if any, so need to check for vault exit prior
+ to spoteffects; but spoteffects() sets up new value for u.urooms
+ and vault code depends upon that value, so we need to fake it */
+ if (vault_guard) {
+ char save_urooms[5]; /* [sizeof u.urooms] */
+
+ Strcpy(save_urooms, u.urooms);
+ Strcpy(u.urooms, in_rooms(u.ux, u.uy, VAULT));
+ /* if hero has left vault, make guard notice */
+ if (!vault_occupied(u.urooms))
+ uleftvault(vault_guard);
+ Strcpy(u.urooms, save_urooms); /* reset prior to spoteffects() */
+ }
+ /* possible shop entry message comes after guard's shrill whistle */
spoteffects(TRUE);
invocation_message();
}
Strcpy(whobuf, "you");
if (u.usteed)
Sprintf(eos(whobuf), " and %s", mon_nam(u.usteed));
- pline("To what position do %s want to be teleported?", whobuf);
+ pline("Where do %s want to be teleported?", whobuf);
#else
pline("\82Ç\82Ì\88Ê\92u\82É\8fu\8aÔ\88Ú\93®\82µ\82Ü\82·\82©\81H");
#endif
return result;
}
+/* ^T command; 'm ^T' == choose among several teleport modes */
+int
+dotelecmd()
+{
+ long save_HTele, save_ETele;
+ int res, added, hidden;
+ boolean ignore_restrictions = FALSE;
+/* also defined in spell.c */
+#define NOOP_SPELL 0
+#define HIDE_SPELL 1
+#define ADD_SPELL 2
+#define UNHIDESPELL 3
+#define REMOVESPELL 4
+
+ /* normal mode; ignore 'm' prefix if it was given */
+ if (!wizard)
+ return dotele(FALSE);
+
+ added = hidden = NOOP_SPELL;
+ save_HTele = HTeleportation, save_ETele = ETeleportation;
+ if (!iflags.menu_requested) {
+ ignore_restrictions = TRUE;
+ } else {
+ static const struct tporttypes {
+ char menulet;
+ const char *menudesc;
+ } tports[] = {
+ /*
+ * Potential combinations:
+ * 1) attempt ^T without intrinsic, not know spell;
+ * 2) via intrinsic, not know spell, obey restrictions;
+ * 3) via intrinsic, not know spell, ignore restrictions;
+ * 4) via intrinsic, know spell, obey restrictions;
+ * 5) via intrinsic, know spell, ignore restrictions;
+ * 6) via spell, not have intrinsic, obey restrictions;
+ * 7) via spell, not have intrinsic, ignore restrictions;
+ * 8) force, obey other restrictions;
+ * 9) force, ignore restrictions.
+ * We only support the 1st (t), 2nd (n), 6th (s), and 9th (w).
+ *
+ * This ignores the fact that there is an experience level
+ * (or poly-form) requirement which might make normal ^T fail.
+ */
+ { 'n', "normal ^T on demand; no spell, obey restrictions" },
+ { 's', "via spellcast; no intrinsic teleport" },
+ { 't', "try ^T without having it; no spell" },
+ { 'w', "debug mode; ignore restrictions" }, /* trad wizard mode */
+ };
+ menu_item *picks = (menu_item *) 0;
+ anything any;
+ winid win;
+ int i, tmode;
+
+ win = create_nhwindow(NHW_MENU);
+ start_menu(win);
+ any = zeroany;
+ for (i = 0; i < SIZE(tports); ++i) {
+ any.a_int = (int) tports[i].menulet;
+ add_menu(win, NO_GLYPH, &any, (char) any.a_int, 0, ATR_NONE,
+ tports[i].menudesc,
+ (tports[i].menulet == 'w') ? MENU_SELECTED
+ : MENU_UNSELECTED);
+ }
+ end_menu(win, "Which way do you want to teleport?");
+ i = select_menu(win, PICK_ONE, &picks);
+ destroy_nhwindow(win);
+ if (i > 0) {
+ tmode = picks[0].item.a_int;
+ /* if we got 2, use the one which wasn't preselected */
+ if (i > 1 && tmode == 'w')
+ tmode = picks[1].item.a_int;
+ free((genericptr_t) picks);
+ } else if (i == 0) {
+ /* preselected one was explicitly chosen and got toggled off */
+ tmode = 'w';
+ } else { /* ESC */
+ return 0;
+ }
+ switch (tmode) {
+ case 'n':
+ HTeleportation |= I_SPECIAL; /* confer intrinsic teleportation */
+ hidden = tport_spell(HIDE_SPELL); /* hide teleport-away */
+ break;
+ case 's':
+ HTeleportation = ETeleportation = 0L; /* suppress intrinsic */
+ added = tport_spell(ADD_SPELL); /* add teleport-away */
+ break;
+ case 't':
+ HTeleportation = ETeleportation = 0L; /* suppress intrinsic */
+ hidden = tport_spell(HIDE_SPELL); /* hide teleport-away */
+ break;
+ case 'w':
+ ignore_restrictions = TRUE;
+ break;
+ }
+ }
+
+ /* if dotele() can be fatal, final disclosure might lie about
+ intrinsic teleportation; we should be able to live with that
+ since the menu finagling is only applicable in wizard mode */
+ res = dotele(ignore_restrictions);
+
+ HTeleportation = save_HTele;
+ ETeleportation = save_ETele;
+ if (added != NOOP_SPELL || hidden != NOOP_SPELL)
+ /* can't both be non-NOOP so addition will yield the non-NOOP one */
+ (void) tport_spell(added + hidden - NOOP_SPELL);
+
+ return res;
+}
+
int
-dotele()
+dotele(break_the_rules)
+boolean break_the_rules; /* True: wizard mode ^T */
{
struct trap *trap;
+ const char *cantdoit;
boolean trap_once = FALSE;
trap = t_at(u.ux, u.uy);
*/
pline("\88ê\93x\82©\82¬\82è\82Ì\91q\8cÉ\82Ö\82Ì\8fu\8aÔ\88Ú\93®\82Ìã©\82¾\81D");
/*JP
- if (yn("Jump in?") == 'n')
+ if (yn("Jump in?") == 'n') {
*/
- if (yn("\94ò\82Ñ\8d\9e\82Þ\81H") == 'n')
+ if (yn("\94ò\82Ñ\8d\9e\82Þ\81H") == 'n') {
trap = 0;
- else {
+ } else {
deltrap(trap);
newsym(u.ux, u.uy);
}
if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12)
&& !can_teleport(youmonst.data))) {
- /* Try to use teleport away spell. */
- if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion)
- for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
- if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) {
- castit = TRUE;
- break;
- }
- if (!wizard) {
- if (!castit) {
- if (!Teleportation)
-/*JP
- You("don't know that spell.");
-*/
- You("\82»\82ñ\82È\96\82\96@\82Í\92m\82ç\82È\82¢\81D");
- else
-/*JP
- You("are not able to teleport at will.");
-*/
- You("\8e©\95ª\82Ì\88Ó\8ev\82Å\8fu\8aÔ\88Ú\93®\82Å\82«\82È\82¢\81D");
- return 0;
- }
- }
- }
-
- if (u.uhunger <= 100 || ACURR(A_STR) < 6) {
- if (!wizard) {
+ /* Try to use teleport away spell.
+ 3.6.2: this used to require that you know the spellbook
+ (probably just intended as an optimization to skip the
+ lookup loop) but it is possible to know and cast a spell
+ after forgetting its book due to amnesia. */
+ for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
+ if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY)
+ break;
+ /* casting isn't inhibited by being Stunned (...it ought to be) */
+ castit = (sp_no < MAXSPELL && !Confusion);
+ if (!castit && !break_the_rules) {
#if 0 /*JP*/
- You("lack the strength %s.",
- castit ? "for a teleport spell" : "to teleport");
+ You("%s.",
+ !Teleportation ? ((sp_no < MAXSPELL)
+ ? "can't cast that spell"
+ : "don't know that spell")
+ : "are not able to teleport at will");
#else
- You("%s\82¾\82¯\82Ì\97Í\82ª\82È\82¢\81D",
- castit ? "\8fu\8aÔ\88Ú\93®\82Ì\96\82\96@\82ð\8f¥\82¦\82é" : "\8fu\8aÔ\88Ú\93®\82·\82é");
+ You("%s\81D",
+ !Teleportation ? ((sp_no < MAXSPELL)
+ ? "\82»\82Ì\96\82\96@\82Í\8f¥\82¦\82ç\82ê\82È\82¢"
+ : "\82»\82ñ\82È\96\82\96@\82Í\92m\82ç\82È\82¢")
+ : "\8e©\95ª\82Ì\88Ó\8ev\82Å\8fu\8aÔ\88Ú\93®\82Å\82«\82È\82¢");
#endif
- return 1;
+ return 0;
}
}
- energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2;
- if (u.uen <= energy) {
- if (wizard)
- energy = u.uen;
- else {
+ cantdoit = 0;
+ /* 3.6.2: the magic numbers for hunger, strength, and energy
+ have been changed to match the ones used in spelleffects().
+ Also, failing these tests used to return 1 and use a move
+ even though casting failure due to these reasons doesn't.
+ [Note: this spellev() is different from the one in spell.c
+ but they both yield the same result.] */
+#define spellev(spell_otyp) ((int) objects[spell_otyp].oc_level)
+ energy = 5 * spellev(SPE_TELEPORT_AWAY);
+ if (break_the_rules) {
+ if (!castit)
+ energy = 0;
+ /* spell will cost more if carrying the Amulet, but the
+ amount is rnd(2 * energy) so we can't know by how much;
+ average is twice the normal cost, but could be triple;
+ the extra energy is spent even if that results in not
+ having enough to cast (which also uses the move) */
+ else if (u.uen < energy)
+ u.uen = energy;
+ } else if (u.uhunger <= 10) {
+/*JP
+ cantdoit = "are too weak from hunger";
+*/
+ cantdoit = "\82É\82Í\82¨\82È\82©\82ª\8bó\82«\82·\82¬\82Ä\82¢\82é";
+ } else if (ACURR(A_STR) < 4) {
+/*JP
+ cantdoit = "lack the strength";
+*/
+ cantdoit = "\82¾\82¯\82Ì\97Í\82ª\82È\82¢";
+ } else if (energy > u.uen) {
+/*JP
+ cantdoit = "lack the energy";
+*/
+ cantdoit = "\82¾\82¯\82Ì\83G\83l\83\8b\83M\81[\82ª\82È\82¢";
+ }
+ if (cantdoit) {
#if 0 /*JP*/
- You("lack the energy %s.",
- castit ? "for a teleport spell" : "to teleport");
+ You("%s %s.", cantdoit,
+ castit ? "for a teleport spell" : "to teleport");
#else
- You("%s\82¾\82¯\82Ì\83G\83l\83\8b\83M\81[\82ª\82È\82¢\81D",
- castit ? "\8fu\8aÔ\88Ú\93®\82Ì\96\82\96@\82ð\8f¥\82¦\82é" : "\8fu\8aÔ\88Ú\93®\82·\82é");
+ You("%s%s\81D", cantdoit,
+ castit ? "\8fu\8aÔ\88Ú\93®\82Ì\96\82\96@\82ð\8f¥\82¦\82é" : "\8fu\8aÔ\88Ú\93®\82·\82é");
#endif
- return 1;
- }
- }
-
- if (check_capacity(
+ return 0;
+ } else if (check_capacity(
/*JP
- "Your concentration falters from carrying so much."))
+ "Your concentration falters from carrying so much.")) {
*/
- "\91ò\8eR\82à\82Ì\82ð\8e\9d\82¿\82·\82¬\82Ä\8fW\92\86\82Å\82«\82È\82¢\81D"))
- return 1;
+ "\91ò\8eR\82à\82Ì\82ð\8e\9d\82¿\82·\82¬\82Ä\8fW\92\86\82Å\82«\82È\82¢\81D")) {
+ return 1; /* this failure in spelleffects() also uses the move */
+ }
if (castit) {
+ /* energy cost is deducted in spelleffects() */
exercise(A_WIS, TRUE);
if (spelleffects(sp_no, TRUE))
return 1;
- else if (!wizard)
+ else if (!break_the_rules)
return 0;
} else {
+ /* bypassing spelleffects(); apply energy cost directly */
u.uen -= energy;
context.botl = 1;
}
tele();
(void) next_to_u();
} else {
- You1(shudder_for_moment);
+ You("%s", shudder_for_moment);
return 0;
}
if (!trap)
char buf[BUFSZ];
boolean force_dest = FALSE;
+ if (iflags.debug_fuzzer)
+ goto random_levtport;
if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz))
&& !wizard) {
/*JP
killer.name[0] = 0; /* still alive, so far... */
+ if (iflags.debug_fuzzer && newlev < 0)
+ goto random_levtport;
if (newlev < 0 && !force_dest) {
if (*u.ushops0) {
/* take unpaid inventory items off of shop bills */
Strcpy(killer.name, "\8eá\82\82µ\82Ä\93V\8d\91\82É\8ds\82Á\82½");
} else if (newlev == -9) {
/*JP
- You_feel("deliriously happy. ");
+ You_feel("deliriously happy.");
*/
You("\8b¶\82Á\82½\82æ\82¤\82È\8dK\82¹\82ð\8a´\82¶\82½\81D");
/*JP
- pline("(In fact, you're on Cloud 9!) ");
+ pline("(In fact, you're on Cloud 9!)");
*/
pline("(\96{\93\96\82É\8bê\82ð\8fæ\82è\89z\82¦\82½\8fê\8f\8a\82É\82¢\82é\81I) ");
display_nhwindow(WIN_MESSAGE, FALSE);
struct trap *trap;
unsigned trflags;
{
+#if 0 /*JP*/
char verbbuf[BUFSZ];
-#if 0 /*JP*/
if ((trflags & VIASITTING) != 0)
Strcpy(verbbuf, "trigger"); /* follows "You sit down." */
else
register int oldx = mtmp->mx, oldy = mtmp->my;
boolean resident_shk = mtmp->isshk && inhishop(mtmp);
- if (x == mtmp->mx && y == mtmp->my) /* that was easy */
- return;
+ if (x == mtmp->mx && y == mtmp->my && m_at(x,y) == mtmp)
+ return; /* that was easy */
if (oldx) { /* "pick up" monster */
if (mtmp->wormno) {
d_level tolevel;
int migrate_typ = MIGR_RANDOM;
- if ((tt == HOLE || tt == TRAPDOOR)) {
+ if (is_hole(tt)) {
if (Is_stronghold(&u.uz)) {
assign_level(&tolevel, &valley_level);
} else if (Is_botlevel(&u.uz)) {
if (nlev == depth(&u.uz)) {
if (in_sight)
/*JP
- pline("%s shudders for a moment.", Monnam(mtmp));
+ pline("%s shudders for a moment.", Monnam(mtmp));
*/
- pline("%s\82Í\88ê\8fu\90k\82¦\82½\81D", Monnam(mtmp));
+ pline("%s\82Í\88ê\8fu\90k\82¦\82½\81D", Monnam(mtmp));
return 0;
}
get_level(&tolevel, nlev);