Skip to content

Commit

Permalink
pull request #386 - discovering teleport scroll
Browse files Browse the repository at this point in the history
Since teleporation gives a "you matrialize" message even when
arriving close by, the old behavior of not learning a scroll of
teleportation when you land quite close to your original spot
no longer made sense.  Always [almost] discover teleport scroll
when reading it.

Also adds one-shot teleport control when reading a blessed scroll
of teleportation.  I changed that to be prevented when hero is
stunned, same as with full-fledged teleport control.

I reworded or reformatted several of the comments.  And removed
the EDITLEVEL increment in patchlevel.h; save and bones file
contents are not affected.

I've also added an unrelated comment about reading mechanics to
doread().

Closes #386
  • Loading branch information
PatR committed Sep 18, 2020
1 parent 7592eeb commit 81ec2bf
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 46 deletions.
5 changes: 4 additions & 1 deletion doc/fixes37.0
@@ -1,4 +1,4 @@
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.302 $ $NHDT-Date: 1600179998 2020/09/15 14:26:38 $
NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.303 $ $NHDT-Date: 1600468452 2020/09/18 22:34:12 $

General Fixes and Modified Features
-----------------------------------
Expand Down Expand Up @@ -330,6 +330,8 @@ change default for lit attribute in special level des.terrain directives to
'unchanged' instead of 'unlit'
replace worm tail placement code that reportedly led to a sanity_check warning
[no actual code problem found; might be compiler bug for 'xchar']
learn scroll of teleportation after reading even when random destination is
right by starting spot

curses: 'msg_window' option wasn't functional for curses unless the binary
also included tty support
Expand Down Expand Up @@ -524,6 +526,7 @@ add section marker [] support to run-time config file; CHOOSE section1,section2
for the remainder of the file
render the color names in the corresponding color when using the pick-a-color
menu for adding status highlights or menu colors via 'O'
reading blessed scroll of teleportation confers one-shot teleport control


Platform- and/or Interface-Specific New Features
Expand Down
3 changes: 1 addition & 2 deletions include/decl.h
@@ -1,4 +1,4 @@
/* NetHack 3.7 decl.h $NHDT-Date: 1599778430 2020/09/10 22:53:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.241 $ */
/* NetHack 3.7 decl.h $NHDT-Date: 1600468452 2020/09/18 22:34:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.242 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2007. */
/* NetHack may be freely redistributed. See license for details. */
Expand Down Expand Up @@ -1147,7 +1147,6 @@ struct instance_globals {
unsigned int stealmid; /* monster doing the stealing */

/* teleport.c */
struct obj *telescroll; /* non-null when teleporting via this scroll */

/* timeout.c */
/* ordered timer list */
Expand Down
4 changes: 2 additions & 2 deletions include/extern.h
@@ -1,4 +1,4 @@
/* NetHack 3.7 extern.h $NHDT-Date: 1599559379 2020/09/08 10:02:59 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.856 $ */
/* NetHack 3.7 extern.h $NHDT-Date: 1600468452 2020/09/18 22:34:12 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.857 $ */
/* Copyright (c) Steve Creps, 1988. */
/* NetHack may be freely redistributed. See license for details. */

Expand Down Expand Up @@ -2586,7 +2586,7 @@ E void FDECL(teleds, (int, int, int));
E boolean FDECL(safe_teleds, (int));
E boolean FDECL(teleport_pet, (struct monst *, BOOLEAN_P));
E void NDECL(tele);
E boolean FDECL(scrolltele, (struct obj *));
E void FDECL(scrolltele, (struct obj *));
E int NDECL(dotelecmd);
E int FDECL(dotele, (BOOLEAN_P));
E void NDECL(level_tele);
Expand Down
3 changes: 1 addition & 2 deletions src/decl.c
@@ -1,4 +1,4 @@
/* NetHack 3.7 decl.c $NHDT-Date: 1599778430 2020/09/10 22:53:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.217 $ */
/* NetHack 3.7 decl.c $NHDT-Date: 1600468453 2020/09/18 22:34:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.218 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Michael Allison, 2009. */
/* NetHack may be freely redistributed. See license for details. */
Expand Down Expand Up @@ -646,7 +646,6 @@ const struct instance_globals g_init = {
0, /* stealmid */

/* teleport.c */
NULL, /* telescroll */

/* timeout.c */
UNDEFINED_PTR, /* timer_base */
Expand Down
28 changes: 26 additions & 2 deletions src/read.c
@@ -1,4 +1,4 @@
/* NetHack 3.7 read.c $NHDT-Date: 1596498202 2020/08/03 23:43:22 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.201 $ */
/* NetHack 3.7 read.c $NHDT-Date: 1600468453 2020/09/18 22:34:13 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.202 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
Expand Down Expand Up @@ -217,9 +217,27 @@ doread()
register struct obj *scroll;
boolean confused, nodisappear;

/*
* Reading while blind is allowed in most cases, including the
* Book of the Dead but not regular spellbooks. For scrolls, the
* description has to have been seen or magically learned (so only
* when scroll->dknown is true): hero recites the label while
* holding the unfurled scroll. We deliberately don't require
* free hands because that would cripple scroll of remove curse,
* but we ought to be requiring hands or at least limbs. The
* recitation could be sub-vocal; actual speech isn't required.
*
* Reading while confused is allowed and can produce alternate
* outcome.
*
* Reading while stunned is currently allowed but probably should
* be prevented....
*/

g.known = FALSE;
if (check_capacity((char *) 0))
return 0;

scroll = getobj(readable, "read");
if (!scroll)
return 0;
Expand Down Expand Up @@ -1358,8 +1376,14 @@ struct obj *sobj; /* scroll, or fake spellbook object for scroll-like spell */
case SCR_TELEPORTATION:
if (confused || scursed) {
level_tele();
/* gives "materialize on different/same level!" message, must
be a teleport scroll */
g.known = TRUE;
} else {
g.known = scrolltele(sobj);
scrolltele(sobj);
/* this will call learnscroll() as appropriate, and has results
which maybe shouldn't result in the scroll becoming known;
either way, no need to set g.known here */
}
break;
case SCR_GOLD_DETECTION:
Expand Down
62 changes: 25 additions & 37 deletions src/teleport.c
@@ -1,4 +1,4 @@
/* NetHack 3.7 teleport.c $NHDT-Date: 1596498216 2020/08/03 23:43:36 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.126 $ */
/* NetHack 3.7 teleport.c $NHDT-Date: 1600468454 2020/09/18 22:34:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.127 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2011. */
/* NetHack may be freely redistributed. See license for details. */
Expand Down Expand Up @@ -401,15 +401,6 @@ int teleds_flags;
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 (g.telescroll) {
/* when teleporting by scroll, we need to handle discovery
now before getting feedback about any objects at our
destination since we might land on another such scroll */
if (distu(u.ux0, u.uy0) >= 16 || !couldsee(u.ux0, u.uy0))
learnscroll(g.telescroll);
else
g.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
Expand Down Expand Up @@ -493,26 +484,22 @@ boolean force_it;
void
tele()
{
(void) scrolltele((struct obj *) 0);
scrolltele((struct obj *) 0);
}

/* teleport the hero; return true if scroll of teleportation should become
discovered; teleds() will usually do the actual discovery, since the
outcome sometimes depends upon destination and discovery needs to be
performed before arrival, in case we land on another teleport scroll */
boolean
/* teleport the hero; usually discover scroll of teleporation if via scroll */
void
scrolltele(scroll)
struct obj *scroll;
{
coord cc;
boolean result = FALSE; /* don't learn scroll */

/* Disable teleportation in stronghold && Vlad's Tower */
if (noteleport_level(&g.youmonst)) {
if (!wizard) {
pline("A mysterious force prevents you from teleporting!");
return TRUE;
}
if (noteleport_level(&g.youmonst) && !wizard) {
pline("A mysterious force prevents you from teleporting!");
if (scroll)
learnscroll(scroll); /* this is obviously a teleport scroll */
return;
}

/* don't show trap if "Sorry..." */
Expand All @@ -521,11 +508,13 @@ struct obj *scroll;

if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) {
You_feel("disoriented for a moment.");
/* don't discover the scroll [at least not yet for wizard override];
disorientation doesn't reveal that this is a teleport attempt */
if (!wizard || yn("Override?") != 'y')
return FALSE;
return;
}
if ((Teleport_control && !Stunned) || (scroll && scroll->blessed)
|| wizard) {
if (((Teleport_control || (scroll && scroll->blessed)) && !Stunned)
|| wizard) {
if (unconscious()) {
pline("Being unconscious, you cannot control your teleport.");
} else {
Expand All @@ -535,32 +524,31 @@ struct obj *scroll;
if (u.usteed)
Sprintf(eos(whobuf), " and %s", mon_nam(u.usteed));
pline("Where do %s want to be teleported?", whobuf);
if (scroll)
learnscroll(scroll);
cc.x = u.ux;
cc.y = u.uy;
if (getpos(&cc, TRUE, "the desired position") < 0)
return TRUE; /* abort */
return; /* abort */
/* possible extensions: introduce a small error if
magic power is low; allow transfer to solid rock */
if (teleok(cc.x, cc.y, FALSE)) {
/* for scroll, discover it regardless of destination */
if (scroll)
learnscroll(scroll);
teleds(cc.x, cc.y, TELEDS_TELEPORT);
return TRUE;
return;
}
pline("Sorry...");
result = TRUE;
}
}

g.telescroll = scroll;
/* we used to suppress discovery if hero teleported to a nearby
spot which was already within view, but now there is always a
"materialize" message regardless of how far you teleported so
discovery of scroll type is unconditional */
if (scroll)
learnscroll(scroll);

(void) safe_teleds(TELEDS_TELEPORT);
/* teleds() will leave g.telescroll intact iff random destination
is far enough away for scroll discovery to be warranted */
if (g.telescroll)
result = TRUE;
g.telescroll = 0; /* reset */
return result;
}

/* ^T command; 'm ^T' == choose among several teleport modes */
Expand Down

0 comments on commit 81ec2bf

Please sign in to comment.