Guest User

NetHack guiding candle patch v1.2

a guest
Jun 9th, 2020
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 69.71 KB | None | 0 0
  1. diff --git c/include/display.h w/include/display.h
  2. index 233b840..09d36b3 100644
  3. --- c/include/display.h
  4. +++ w/include/display.h
  5. @@ -61,13 +61,13 @@
  6.  #if 0
  7.  #define mon_visible(mon) \
  8.      (/* The hero can see the monster IF the monster                     */ \
  9. -     (!mon->minvis || See_invisible)  /*     1. is not invisible        */ \
  10. +     (!minvisible(mon) || See_invisible) /*      1. is not invisible    */ \
  11.       && !mon->mundetected             /* AND 2. not an undetected hider */ \
  12.       && !(mon->mburied || u.uburied)) /* AND 3. neither you nor it is buried */
  13.  #else   /* without 'mburied' and 'uburied' */
  14.  #define mon_visible(mon) \
  15.      (/* The hero can see the monster IF the monster                     */ \
  16. -     (!mon->minvis || See_invisible)  /*     1. is not invisible        */ \
  17. +     (!minvisible(mon) || See_invisible) /*      1. is not invisible    */ \
  18.       && !mon->mundetected)            /* AND 2. not an undetected hider */
  19.  #endif
  20.  
  21. @@ -117,7 +117,8 @@
  22.   */
  23.  #define knowninvisible(mon)                                               \
  24.      (mtmp->minvis                                                         \
  25. -     && ((cansee(mon->mx, mon->my) && (See_invisible || Detect_monsters)) \
  26. +     && ((cansee(mon->mx, mon->my) && (See_invisible || Detect_monsters   \
  27. +                                       || candetect(mon->mx, mon->my)))   \
  28.           || (!Blind && (HTelepat & ~INTRINSIC)                            \
  29.               && distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM))))
  30.  
  31. diff --git c/include/extern.h w/include/extern.h
  32. index a1b32f7..d4448a2 100644
  33. --- c/include/extern.h
  34. +++ w/include/extern.h
  35. @@ -292,6 +292,7 @@ E void FDECL(use_crystal_ball, (struct obj **));
  36.  E void NDECL(do_mapping);
  37.  E void FDECL(do_vicinity_map, (struct obj *));
  38.  E void FDECL(cvt_sdoor_to_door, (struct rm *));
  39. +E int FDECL(findone_core, (int, int));
  40.  #ifdef USE_TRAMPOLI
  41.  E void FDECL(findone, (int, int, genericptr_t));
  42.  E void FDECL(openone, (int, int, genericptr_t));
  43. @@ -1094,7 +1095,7 @@ E void FDECL(obj_split_light_source, (struct obj *, struct obj *));
  44.  E void FDECL(obj_merge_light_sources, (struct obj *, struct obj *));
  45.  E void FDECL(obj_adjust_light_radius, (struct obj *, int));
  46.  E int FDECL(candle_light_range, (struct obj *));
  47. -E int FDECL(arti_light_radius, (struct obj *));
  48. +E int FDECL(dynamic_light_radius, (struct obj *));
  49.  E const char *FDECL(arti_light_description, (struct obj *));
  50.  E int NDECL(wiz_light_sources);
  51.  
  52. @@ -1451,6 +1452,7 @@ E void FDECL(setmangry, (struct monst *, BOOLEAN_P));
  53.  E void FDECL(wakeup, (struct monst *, BOOLEAN_P));
  54.  E void NDECL(wake_nearby);
  55.  E void FDECL(wake_nearto, (int, int, int));
  56. +E void FDECL(seemimic_noredraw, (struct monst *));
  57.  E void FDECL(seemimic, (struct monst *));
  58.  E void NDECL(rescham);
  59.  E void NDECL(restartcham);
  60. diff --git c/include/mkroom.h w/include/mkroom.h
  61. index 3439889..00de981 100644
  62. --- c/include/mkroom.h
  63. +++ w/include/mkroom.h
  64. @@ -34,7 +34,7 @@ struct shclass {
  65.      struct itp {
  66.          int iprob;    /* probability of an item type */
  67.          int itype;    /* item type: if >=0 a class, if < 0 a specific item */
  68. -    } iprobs[6];
  69. +    } iprobs[7];
  70.      const char *const *shknms; /* list of shopkeeper names for this type */
  71.  };
  72.  
  73. diff --git c/include/mondata.h w/include/mondata.h
  74. index 155ebfa..19e64d5 100644
  75. --- c/include/mondata.h
  76. +++ w/include/mondata.h
  77. @@ -86,6 +86,7 @@
  78.      (lays_eggs(ptr) && (ptr)->mlet == S_EEL && is_swimmer(ptr))
  79.  #define regenerates(ptr) (((ptr)->mflags1 & M1_REGEN) != 0L)
  80.  #define perceives(ptr) (((ptr)->mflags1 & M1_SEE_INVIS) != 0L)
  81. +#define perceives_you(ptr) (perceives(ptr) || candetect(u.ux, u.uy))
  82.  #define can_teleport(ptr) (((ptr)->mflags1 & M1_TPORT) != 0L)
  83.  #define control_teleport(ptr) (((ptr)->mflags1 & M1_TPORT_CNTRL) != 0L)
  84.  #define telepathic(ptr)                                                \
  85. diff --git c/include/monst.h w/include/monst.h
  86. index 3a2c40c..63d234b 100644
  87. --- c/include/monst.h
  88. +++ w/include/monst.h
  89. @@ -187,6 +187,9 @@ struct monst {
  90.      ((mon)->cham == PM_VAMPIRE || (mon)->cham == PM_VAMPIRE_LORD \
  91.       || (mon)->cham == PM_VLAD_THE_IMPALER)
  92.  
  93. +/* guiding candle makes monsters effectively visible */
  94. +#define minvisible(mon) ((mon)->minvis && !candetect((mon)->mx, (mon)->my))
  95. +
  96.  /* mimic appearances that block vision/light */
  97.  #define is_lightblocker_mappear(mon)                       \
  98.      (is_obj_mappear(mon, BOULDER)                          \
  99. diff --git c/include/obj.h w/include/obj.h
  100. index 62e20b7..6796141 100644
  101. --- c/include/obj.h
  102. +++ w/include/obj.h
  103. @@ -302,7 +302,9 @@ struct obj {
  104.  
  105.  /* Light sources */
  106.  #define Is_candle(otmp) \
  107. -    (otmp->otyp == TALLOW_CANDLE || otmp->otyp == WAX_CANDLE)
  108. +    (otmp->otyp == TALLOW_CANDLE || otmp->otyp == WAX_CANDLE \
  109. +     || otmp->otyp == GUIDING_CANDLE)
  110. +#define candle_burn_time(otmp) ((otmp)->otyp == TALLOW_CANDLE ? 200L : 400L)
  111.  #define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */
  112.  
  113.  /* MAGIC_LAMP intentionally excluded below */
  114. diff --git c/include/rm.h w/include/rm.h
  115. index 37b3fff..3602ef4 100644
  116. --- c/include/rm.h
  117. +++ w/include/rm.h
  118. @@ -395,6 +395,19 @@ extern struct symsetentry symset[NUM_GRAPHICS]; /* from drawing.c */
  119.  #define W_NONDIGGABLE 0x08
  120.  #define W_NONPASSWALL 0x10
  121.  
  122. +/*
  123. + * Filled trapdoors in the Castle can be dug out again.
  124. + * Won't work on trapdoors under doorways because doors have their own flags,
  125. + * but currently this combination doesn't occur.
  126. + */
  127. +
  128. +#define FL_DIGGABLE 0x10
  129. +#define Can_dig_hole(x,y,z) (Can_dig_down(z)                                 \
  130. +                             || Can_fall_thru(z)                             \
  131. +                                && level.locations[x][y].flags & FL_DIGGABLE \
  132. +                                && (level.locations[x][y].typ == ROOM        \
  133. +                                    || level.locations[x][y].typ == CORR))
  134. +
  135.  /*
  136.   * Ladders (in Vlad's tower) may be up or down.
  137.   */
  138. @@ -426,7 +439,7 @@ struct rm {
  139.  
  140.      Bitfield(roomno, 6); /* room # for special rooms */
  141.      Bitfield(edge, 1);   /* marks boundaries for special rooms*/
  142. -    Bitfield(candig, 1); /* Exception to Can_dig_down; was a trapdoor */
  143. +    Bitfield(buried, 1); /* true iff there are buried objects here */
  144.  };
  145.  
  146.  #define SET_TYPLIT(x, y, ttyp, llit)                              \
  147. diff --git c/include/vision.h w/include/vision.h
  148. index 4b1f1a7..e426a36 100644
  149. --- c/include/vision.h
  150. +++ w/include/vision.h
  151. @@ -14,12 +14,14 @@ extern char *viz_rmax;          /* max could see indices */
  152.  #define COULD_SEE 0x1 /* location could be seen, if it were lit */
  153.  #define IN_SIGHT 0x2  /* location can be seen */
  154.  #define TEMP_LIT 0x4  /* location is temporarily lit */
  155. +#define TEMP_DETECT 0x8 /* lit by a guiding candle */
  156.  
  157.  /*
  158.   * Light source sources
  159.   */
  160.  #define LS_OBJECT 0
  161.  #define LS_MONSTER 1
  162. +#define LS_DETECT 2  /* guiding candle */
  163.  
  164.  /*
  165.   *  cansee()   - Returns true if the hero can see the location.
  166. @@ -30,6 +32,7 @@ extern char *viz_rmax;            /* max could see indices */
  167.  #define cansee(x, y) (viz_array[y][x] & IN_SIGHT)
  168.  #define couldsee(x, y) (viz_array[y][x] & COULD_SEE)
  169.  #define templit(x, y) (viz_array[y][x] & TEMP_LIT)
  170. +#define candetect(x, y) (viz_array[y][x] & TEMP_DETECT)
  171.  
  172.  /*
  173.   *  The following assume the monster is not blind.
  174. @@ -45,12 +48,12 @@ extern char *viz_rmax;          /* max could see indices */
  175.  
  176.  #if 0
  177.  #define m_canseeu(m) \
  178. -    ((!Invis || perceives((m)->data))                      \
  179. +    ((!Invis || perceives_you((m)->data))                      \
  180.       && !(Underwater || u.uburied || (m)->mburied)         \
  181.       && couldsee((m)->mx, (m)->my))
  182.  #else   /* without 'uburied' and 'mburied' */
  183.  #define m_canseeu(m) \
  184. -    ((!Invis || perceives((m)->data))                      \
  185. +    ((!Invis || perceives_you((m)->data))                      \
  186.       && !Underwater                                        \
  187.       && couldsee((m)->mx, (m)->my))
  188.  #endif
  189. diff --git c/include/youprop.h w/include/youprop.h
  190. index c9656aa..faae14f 100644
  191. --- c/include/youprop.h
  192. +++ w/include/youprop.h
  193. @@ -177,7 +177,7 @@
  194.  #define EInvis u.uprops[INVIS].extrinsic
  195.  #define BInvis u.uprops[INVIS].blocked
  196.  #define Invis ((HInvis || EInvis) && !BInvis)
  197. -#define Invisible (Invis && !See_invisible)
  198. +#define Invisible (Invis && !See_invisible && !candetect(u.ux, u.uy))
  199.  /* Note: invisibility also hides inventory and steed */
  200.  
  201.  #define EDisplaced u.uprops[DISPLACED].extrinsic
  202. diff --git c/src/allmain.c w/src/allmain.c
  203. index 5111c69..2757b0d 100644
  204. --- c/src/allmain.c
  205. +++ w/src/allmain.c
  206. @@ -336,6 +336,16 @@ boolean resuming;
  207.              /* when/if hero escapes from lava, he can't just stay there */
  208.              else if (!u.umoved)
  209.                  (void) pooleffects(FALSE);
  210. +            if (candetect(u.ux, u.uy)
  211. +                && (u.uundetected || U_AP_TYPE != M_AP_NOTHING)) {
  212. +                if (multi < 0 && U_AP_TYPE == M_AP_OBJECT
  213. +                    && youmonst.data->mlet != S_MIMIC)
  214. +                    /* must be under effect of a mimic corpse */
  215. +                    unmul("Your disguise is disrupted!");
  216. +                u.uundetected = 0;
  217. +                youmonst.m_ap_type = M_AP_NOTHING;
  218. +                newsym(u.ux, u.uy);
  219. +            }
  220.  
  221.          } /* actual time passed */
  222.  
  223. diff --git c/src/apply.c w/src/apply.c
  224. index e77984d..535bb71 100644
  225. --- c/src/apply.c
  226. +++ w/src/apply.c
  227. @@ -844,7 +844,7 @@ struct obj *obj;
  228.  
  229.      if (!getdir((char *) 0))
  230.          return 0;
  231. -    invis_mirror = Invis;
  232. +    invis_mirror = Invis && !candetect(u.ux, u.uy);
  233.      useeit = !Blind && (!invis_mirror || See_invisible);
  234.      uvisage = beautiful();
  235.      mirror = simpleonames(obj); /* "mirror" or "looking glass" */
  236. @@ -919,7 +919,7 @@ struct obj *obj;
  237.  #define SEENMON (MONSEEN_NORMAL | MONSEEN_SEEINVIS | MONSEEN_INFRAVIS)
  238.      how_seen = vis ? howmonseen(mtmp) : 0;
  239.      /* whether monster is able to use its vision-based capabilities */
  240. -    monable = !mtmp->mcan && (!mtmp->minvis || perceives(mtmp->data));
  241. +    monable = !mtmp->mcan && (!minvisible(mtmp) || perceives(mtmp->data));
  242.      mlet = mtmp->data->mlet;
  243.      if (mtmp->msleeping) {
  244.          if (vis)
  245. @@ -976,7 +976,7 @@ struct obj *obj;
  246.          if (!tele_restrict(mtmp))
  247.              (void) rloc(mtmp, TRUE);
  248.      } else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data)
  249. -               && (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) {
  250. +               && (!minvisible(mtmp) || perceives(mtmp->data)) && rn2(5)) {
  251.          boolean do_react = TRUE;
  252.  
  253.          if (mtmp->mfrozen) {
  254. @@ -992,9 +992,9 @@ struct obj *obj;
  255.              monflee(mtmp, d(2, 4), FALSE, FALSE);
  256.          }
  257.      } else if (!Blind) {
  258. -        if (mtmp->minvis && !See_invisible)
  259. +        if (minvisible(mtmp) && !See_invisible)
  260.              ;
  261. -        else if ((mtmp->minvis && !perceives(mtmp->data))
  262. +        else if ((minvisible(mtmp) && !perceives(mtmp->data))
  263.                   /* redundant: can't get here if these are true */
  264.                   || !haseyes(mtmp->data) || notonhead || !mtmp->mcansee)
  265.              pline("%s doesn't seem to notice %s reflection.", Monnam(mtmp),
  266. @@ -1232,6 +1232,9 @@ struct obj **optr;
  267.              *optr = 0;
  268.          You("attach %ld%s %s to %s.", obj->quan, !otmp->spe ? "" : " more", s,
  269.              the(xname(otmp)));
  270. +        if (objects[obj->otyp].oc_magic) /* hello SLASH'EM */
  271. +            pline("%s very ordinary.", (obj->quan > 1L) ? "They look"
  272. +                                                        : "It looks");
  273.          if (!otmp->spe || otmp->age > obj->age)
  274.              otmp->age = obj->age;
  275.          otmp->spe += (int) obj->quan;
  276. @@ -1330,6 +1333,12 @@ struct obj *obj;
  277.          if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
  278.               || obj->otyp == BRASS_LANTERN) && obj->cursed && !rn2(2))
  279.              return FALSE;
  280. +        if (obj->otyp == GUIDING_CANDLE && !obj->cursed) {
  281. +            if (obj->age <= 10)
  282. +                return FALSE;
  283. +            else
  284. +                obj->age -= 10;
  285. +        }
  286.          if (obj->where == OBJ_MINVENT ? cansee(x, y) : !Blind)
  287.              pline("%s %s light!", Yname2(obj), otense(obj, "catch"));
  288.          if (obj->otyp == POT_OIL)
  289. @@ -1352,6 +1361,7 @@ use_lamp(obj)
  290.  struct obj *obj;
  291.  {
  292.      char buf[BUFSZ];
  293. +    boolean wontburn = FALSE;
  294.  
  295.      if (obj->lamplit) {
  296.          if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
  297. @@ -1376,7 +1386,15 @@ struct obj *obj;
  298.              pline("This %s has no oil.", xname(obj));
  299.          return;
  300.      }
  301. -    if (obj->cursed && !rn2(2)) {
  302. +    if (obj->otyp == GUIDING_CANDLE && !obj->cursed) {
  303. +        /* don't allow the candle to last the entire game
  304. +         * by lighting it one turn at a time */
  305. +        if (obj->age <= 10)
  306. +            wontburn = TRUE;
  307. +        else
  308. +            obj->age -= 10;
  309. +    }
  310. +    if (wontburn || obj->cursed && !rn2(2)) {
  311.          if (!Blind)
  312.              pline("%s for a moment, then %s.", Tobjnam(obj, "flicker"),
  313.                    otense(obj, "die"));
  314. @@ -1389,7 +1407,7 @@ struct obj *obj;
  315.              pline("%s flame%s %s%s", s_suffix(Yname2(obj)), plur(obj->quan),
  316.                    otense(obj, "burn"), Blind ? "." : " brightly!");
  317.              if (obj->unpaid && costly_spot(u.ux, u.uy)
  318. -                && obj->age == 20L * (long) objects[obj->otyp].oc_cost) {
  319. +                && obj->age == candle_burn_time(obj)) {
  320.                  const char *ithem = (obj->quan > 1L) ? "them" : "it";
  321.  
  322.                  verbalize("You burn %s, you bought %s!", ithem, ithem);
  323. @@ -2131,7 +2149,7 @@ long timeout;
  324.          /* [m_monnam() yields accurate mon type, overriding hallucination] */
  325.          Sprintf(monnambuf, "%s", an(m_monnam(mtmp)));
  326.          and_vanish[0] = '\0';
  327. -        if ((mtmp->minvis && !See_invisible)
  328. +        if ((minvisible(mtmp) && !See_invisible)
  329.              || (mtmp->data->mlet == S_MIMIC
  330.                  && M_AP_TYPE(mtmp) != M_AP_NOTHING))
  331.              suppress_see = TRUE;
  332. @@ -3437,8 +3455,7 @@ struct obj *obj;
  333.                      fillmsg = TRUE;
  334.                  } else
  335.                      digactualhole(x, y, BY_OBJECT, (rn2(obj->spe) < 3
  336. -                                                    || (!Can_dig_down(&u.uz)
  337. -                                                        && !levl[x][y].candig))
  338. +                                                 || !Can_dig_hole(x, y, &u.uz))
  339.                                                        ? PIT
  340.                                                        : HOLE);
  341.              }
  342. @@ -3687,6 +3704,7 @@ doapply()
  343.          break;
  344.      case WAX_CANDLE:
  345.      case TALLOW_CANDLE:
  346. +    case GUIDING_CANDLE:
  347.          use_candle(&obj);
  348.          break;
  349.      case OIL_LAMP:
  350. diff --git c/src/detect.c w/src/detect.c
  351. index dfac26a..89d2586 100644
  352. --- c/src/detect.c
  353. +++ w/src/detect.c
  354. @@ -1455,9 +1455,22 @@ STATIC_PTR void
  355.  findone(zx, zy, num)
  356.  int zx, zy;
  357.  genericptr_t num;
  358. +{
  359. +    int hits = findone_core(zx, zy);
  360. +    if (hits > 0) {
  361. +        (*(int *) num) += hits;
  362. +        newsym(zx, zy);
  363. +    }
  364. +}
  365. +
  366. +/* also used in display.c */
  367. +int
  368. +findone_core(zx, zy)
  369. +int zx, zy;
  370.  {
  371.      register struct trap *ttmp;
  372.      register struct monst *mtmp;
  373. +    int result = 0;
  374.  
  375.      /*
  376.       * This used to use if/else-if/else-if/else/end-if but that only
  377. @@ -1469,42 +1482,41 @@ genericptr_t num;
  378.      if (levl[zx][zy].typ == SDOOR) {
  379.          cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */
  380.          magic_map_background(zx, zy, 0);
  381. -        newsym(zx, zy);
  382. -        (*(int *) num)++;
  383. +        result++;
  384.      } else if (levl[zx][zy].typ == SCORR) {
  385.          levl[zx][zy].typ = CORR;
  386.          unblock_point(zx, zy);
  387.          magic_map_background(zx, zy, 0);
  388. -        newsym(zx, zy);
  389. -        (*(int *) num)++;
  390. +        result++;
  391.      }
  392.  
  393.      if ((ttmp = t_at(zx, zy)) != 0 && !ttmp->tseen
  394.          /* [shouldn't successful 'find' reveal and activate statue traps?] */
  395.          && ttmp->ttyp != STATUE_TRAP) {
  396.          ttmp->tseen = 1;
  397. -        newsym(zx, zy);
  398. -        (*(int *) num)++;
  399. +        result++;
  400.      }
  401.  
  402.      if ((mtmp = m_at(zx, zy)) != 0
  403.          /* brings hidden monster out of hiding even if already sensed */
  404.          && (!canspotmon(mtmp) || mtmp->mundetected || M_AP_TYPE(mtmp))) {
  405.          if (M_AP_TYPE(mtmp)) {
  406. -            seemimic(mtmp);
  407. -            (*(int *) num)++;
  408. +            seemimic_noredraw(mtmp);
  409. +            result++;
  410.          } else if (mtmp->mundetected && (is_hider(mtmp->data)
  411.                                           || hides_under(mtmp->data)
  412.                                           || mtmp->data->mlet == S_EEL)) {
  413.              mtmp->mundetected = 0;
  414.              newsym(zx, zy);
  415. -            (*(int *) num)++;
  416. +            result++;
  417.          }
  418.          if (!canspotmon(mtmp) && !glyph_is_invisible(levl[zx][zy].glyph))
  419.              map_invisible(zx, zy);
  420. -    } else if (unmap_invisible(zx, zy)) {
  421. -        (*(int *) num)++;
  422. +    } else if (glyph_is_invisible(levl[zx][zy].glyph)) {
  423. +        unmap_object(zx, zy);
  424. +        result++;
  425.      }
  426. +    return result;
  427.  }
  428.  
  429.  STATIC_PTR void
  430. diff --git c/src/dig.c w/src/dig.c
  431. index 9b91f98..bd9e670 100644
  432. --- c/src/dig.c
  433. +++ w/src/dig.c
  434. @@ -219,7 +219,7 @@ int x, y;
  435.                 || (ttmp
  436.                     && (ttmp->ttyp == MAGIC_PORTAL
  437.                         || ttmp->ttyp == VIBRATING_SQUARE
  438. -                       || (!Can_dig_down(&u.uz) && !levl[x][y].candig)))) {
  439. +                       || !Can_dig_hole(x, y, &u.uz)))) {
  440.          if (verbose)
  441.              pline_The("%s here is too hard to %s.", surface(x, y), verb);
  442.          return FALSE;
  443. @@ -579,7 +579,7 @@ int ttyp;
  444.          return;
  445.      }
  446.  
  447. -    if (ttyp != PIT && (!Can_dig_down(&u.uz) && !lev->candig)) {
  448. +    if (ttyp != PIT && !Can_dig_hole(x, y, &u.uz)) {
  449.          impossible("digactualhole: can't dig %s on this level.",
  450.                     defsyms[trap_to_defsym(ttyp)].explanation);
  451.          ttyp = PIT;
  452. @@ -783,7 +783,7 @@ coord *cc;
  453.  
  454.      ttmp = t_at(dig_x, dig_y);
  455.      lev = &levl[dig_x][dig_y];
  456. -    nohole = (!Can_dig_down(&u.uz) && !lev->candig);
  457. +    nohole = !Can_dig_hole(dig_x, dig_y, &u.uz);
  458.  
  459.      if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL
  460.                    || ttmp->ttyp == VIBRATING_SQUARE || nohole))
  461. @@ -866,9 +866,9 @@ coord *cc;
  462.      } else {
  463.          typ = fillholetyp(dig_x, dig_y, FALSE);
  464.  
  465. -        lev->flags = 0;
  466.          if (typ != ROOM) {
  467.              lev->typ = typ;
  468. +            lev->flags = 0;
  469.              liquid_flow(dig_x, dig_y, typ, ttmp,
  470.                          "As you dig, the hole fills with %s!");
  471.              return TRUE;
  472. @@ -1931,23 +1931,27 @@ int x, y;
  473.      coord cc;
  474.  
  475.      debugpline2("unearth_objs: at <%d,%d>", x, y);
  476. -    cc.x = x;
  477. -    cc.y = y;
  478. -    bball = buried_ball(&cc);
  479. -    for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
  480. -        otmp2 = otmp->nobj;
  481. -        if (otmp->ox == x && otmp->oy == y) {
  482. -            if (bball && otmp == bball
  483. -                && u.utrap && u.utraptype == TT_BURIEDBALL) {
  484. -                buried_ball_to_punishment();
  485. -            } else {
  486. -                obj_extract_self(otmp);
  487. -                if (otmp->timed)
  488. -                    (void) stop_timer(ROT_ORGANIC, obj_to_any(otmp));
  489. -                place_object(otmp, x, y);
  490. -                stackobj(otmp);
  491. +
  492. +    if (levl[x][y].buried) {
  493. +        cc.x = x;
  494. +        cc.y = y;
  495. +        bball = buried_ball(&cc);
  496. +        for (otmp = level.buriedobjlist; otmp; otmp = otmp2) {
  497. +            otmp2 = otmp->nobj;
  498. +            if (otmp->ox == x && otmp->oy == y) {
  499. +                if (bball && otmp == bball
  500. +                    && u.utrap && u.utraptype == TT_BURIEDBALL) {
  501. +                    buried_ball_to_punishment();
  502. +                } else {
  503. +                    obj_extract_self(otmp);
  504. +                    if (otmp->timed)
  505. +                        (void) stop_timer(ROT_ORGANIC, obj_to_any(otmp));
  506. +                    place_object(otmp, x, y);
  507. +                    stackobj(otmp);
  508. +                }
  509.              }
  510.          }
  511. +        levl[x][y].buried = 0;
  512.      }
  513.      del_engr_at(x, y);
  514.      newsym(x, y);
  515. diff --git c/src/display.c w/src/display.c
  516. index 722c258..d021f03 100644
  517. --- c/src/display.c
  518. +++ w/src/display.c
  519. @@ -123,6 +123,7 @@
  520.   */
  521.  #include "hack.h"
  522.  
  523. +STATIC_DCL void FDECL(map_buried, (int, int, int));
  524.  STATIC_DCL void FDECL(show_mon_or_warn, (int, int, int));
  525.  STATIC_DCL void FDECL(display_monster,
  526.                        (XCHAR_P, XCHAR_P, struct monst *, int, XCHAR_P));
  527. @@ -265,6 +266,26 @@ register int show;
  528.          show_glyph(x, y, glyph);
  529.  }
  530.  
  531. +/*
  532. + * map_buried()
  533. + * Map the object buried under the specified tile.
  534. + * If there are several, we need to display the very last one
  535. + * to be consistent with object_detect().
  536. + */
  537. +
  538. +STATIC_OVL void
  539. +map_buried(x, y, show)
  540. +int x, y;
  541. +int show;
  542. +{
  543. +    struct obj *obj, *last_obj = NULL;
  544. +    for (obj = level.buriedobjlist; obj; obj = obj->nobj)
  545. +        if (obj->ox == x && obj->oy == y)
  546. +            last_obj = obj;
  547. +    if (last_obj)
  548. +        map_object(last_obj, show);
  549. +}
  550. +
  551.  /*
  552.   * map_invisible()
  553.   *
  554. @@ -345,8 +366,11 @@ register int x, y;
  555.          register struct obj *obj;                                           \
  556.          register struct trap *trap;                                         \
  557.                                                                              \
  558. -        if ((obj = vobj_at(x, y)) && !covers_objects(x, y))                 \
  559. +        if ((obj = vobj_at(x, y)) && (!covers_objects(x, y)                 \
  560. +                                      || candetect(x, y) && cansee(x, y)))  \
  561.              map_object(obj, show);                                          \
  562. +        else if (levl[x][y].buried && candetect(x, y) && cansee(x, y))      \
  563. +            map_buried(x, y, show);                                         \
  564.          else if ((trap = t_at(x, y)) && trap->tseen && !covers_traps(x, y)) \
  565.              map_trap(trap, show);                                           \
  566.          else                                                                \
  567. @@ -792,6 +816,10 @@ register int x, y;
  568.              return;
  569.          }
  570.  
  571. +        /* guiding candle! */
  572. +        if (candetect(x,y))
  573. +            findone_core(x,y);
  574. +
  575.          if (x == u.ux && y == u.uy) {
  576.              int see_self = canspotself();
  577.  
  578. diff --git c/src/do_name.c w/src/do_name.c
  579. index f1d8d5b..7f23606 100644
  580. --- c/src/do_name.c
  581. +++ w/src/do_name.c
  582. @@ -1151,7 +1151,7 @@ do_mname()
  583.              && (!(cansee(cx, cy) || see_with_infrared(mtmp))
  584.                  || mtmp->mundetected || M_AP_TYPE(mtmp) == M_AP_FURNITURE
  585.                  || M_AP_TYPE(mtmp) == M_AP_OBJECT
  586. -                || (mtmp->minvis && !See_invisible)))) {
  587. +                || (minvisible(mtmp) && !See_invisible)))) {
  588.          pline("I see no monster there.");
  589.          return;
  590.      }
  591. diff --git c/src/do_wear.c w/src/do_wear.c
  592. index b48c69d..e2adbb9 100644
  593. --- c/src/do_wear.c
  594. +++ w/src/do_wear.c
  595. @@ -303,8 +303,9 @@ Cloak_on(VOID_ARGS)
  596.          /* Note: it's already being worn, so we have to cheat here. */
  597.          if ((HInvis || EInvis) && !Blind) {
  598.              newsym(u.ux, u.uy);
  599. -            You("can %s!", See_invisible ? "no longer see through yourself"
  600. -                                         : see_yourself);
  601. +            You("can %s!", See_invisible || candetect(u.ux, u.uy)
  602. +                           ? "no longer see through yourself"
  603. +                           : see_yourself);
  604.          }
  605.          break;
  606.      case CLOAK_OF_INVISIBILITY:
  607. @@ -314,7 +315,7 @@ Cloak_on(VOID_ARGS)
  608.              makeknown(uarmc->otyp);
  609.              newsym(u.ux, u.uy);
  610.              pline("Suddenly you can%s yourself.",
  611. -                  See_invisible ? " see through" : "not see");
  612. +                  !Invisible ? " see through" : "not see");
  613.          }
  614.          break;
  615.      case OILSKIN_CLOAK:
  616. @@ -360,8 +361,8 @@ Cloak_off(VOID_ARGS)
  617.      case MUMMY_WRAPPING:
  618.          if (Invis && !Blind) {
  619.              newsym(u.ux, u.uy);
  620. -            You("can %s.", See_invisible ? "see through yourself"
  621. -                                         : "no longer see yourself");
  622. +            You("can %s.", !Invisible ? "see through yourself"
  623. +                                      : "no longer see yourself");
  624.          }
  625.          break;
  626.      case CLOAK_OF_INVISIBILITY:
  627. @@ -369,8 +370,9 @@ Cloak_off(VOID_ARGS)
  628.              makeknown(CLOAK_OF_INVISIBILITY);
  629.              newsym(u.ux, u.uy);
  630.              pline("Suddenly you can %s.",
  631. -                  See_invisible ? "no longer see through yourself"
  632. -                                : see_yourself);
  633. +                  See_invisible || candetect(u.ux, u.uy)
  634. +                  ? "no longer see through yourself"
  635. +                  : see_yourself);
  636.          }
  637.          break;
  638.      /* Alchemy smock gives poison _and_ acid resistance */
  639. @@ -932,7 +934,8 @@ register struct obj *obj;
  640.          set_mimic_blocking(); /* do special mimic handling */
  641.          see_monsters();
  642.  
  643. -        if (Invis && !oldprop && !HSee_invisible && !Blind) {
  644. +        if (Invis && !oldprop && !HSee_invisible
  645. +            && !Blind && !candetect(u.ux, u.uy)) {
  646.              newsym(u.ux, u.uy);
  647.              pline("Suddenly you are transparent, but there!");
  648.              learnring(obj, TRUE);
  649. @@ -1056,7 +1059,8 @@ boolean gone;
  650.          if (!Invis && !BInvis && !Blind) {
  651.              newsym(u.ux, u.uy);
  652.              Your("body seems to unfade%s.",
  653. -                 See_invisible ? " completely" : "..");
  654. +                 See_invisible || candetect(u.ux, u.uy) ? " completely"
  655. +                                                        : "..");
  656.              learnring(obj, TRUE);
  657.          }
  658.          break;
  659. diff --git c/src/dogmove.c w/src/dogmove.c
  660. index df3452f..d3e55aa 100644
  661. --- c/src/dogmove.c
  662. +++ w/src/dogmove.c
  663. @@ -649,7 +649,7 @@ int maxdist;
  664.  
  665.          if ((targ = m_at(curx, cury)) != 0) {
  666.              /* Is the monster visible to the pet? */
  667. -            if ((!targ->minvis || perceives(mtmp->data))
  668. +            if ((!minvisible(targ) || perceives(mtmp->data))
  669.                  && !targ->mundetected)
  670.                  break;
  671.              /* If the pet can't see it, it assumes it aint there */
  672. @@ -692,7 +692,7 @@ int    maxdist;
  673.          if (pal) {
  674.              if (pal->mtame) {
  675.                  /* Pet won't notice invisible pets */
  676. -                if (!pal->minvis || perceives(mtmp->data))
  677. +                if (!minvisible(pal) || perceives(mtmp->data))
  678.                      return 1;
  679.              } else {
  680.                  /* Quest leaders and guardians are always seen */
  681. @@ -1007,7 +1007,7 @@ int after; /* this is extra fast monster movement */
  682.              if ((int) mtmp2->m_lev >= (int) mtmp->m_lev + 2
  683.                  || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10)
  684.                      && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
  685. -                    && (perceives(mtmp->data) || !mtmp2->minvis))
  686. +                    && (perceives(mtmp->data) || !minvisible(mtmp2)))
  687.                  || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10))
  688.                  || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp)
  689.                  || ((mtmp->mhp * 4 < mtmp->mhpmax
  690. diff --git c/src/eat.c w/src/eat.c
  691. index 5e2aa1a..2fd812a 100644
  692. --- c/src/eat.c
  693. +++ w/src/eat.c
  694. @@ -1030,6 +1030,10 @@ int pm;
  695.              /* A pile of gold can't ride. */
  696.              if (u.usteed)
  697.                  dismount_steed(DISMOUNT_FELL);
  698. +            if (candetect(u.ux, u.uy)) {
  699. +                pline("But you can't stay hidden!");
  700. +                break;
  701. +            }
  702.              nomul(-tmp);
  703.              multi_reason = "pretending to be a pile of gold";
  704.              Sprintf(buf,
  705. @@ -1972,15 +1976,14 @@ struct obj *otmp;
  706.                  set_mimic_blocking();
  707.                  see_monsters();
  708.                  if (Invis && !oldprop && !ESee_invisible
  709. -                    && !perceives(youmonst.data) && !Blind) {
  710. +                    && !perceives_you(youmonst.data) && !Blind) {
  711.                      newsym(u.ux, u.uy);
  712.                      pline("Suddenly you can see yourself.");
  713.                      makeknown(typ);
  714.                  }
  715.                  break;
  716.              case RIN_INVISIBILITY:
  717. -                if (!oldprop && !EInvis && !BInvis && !See_invisible
  718. -                    && !Blind) {
  719. +                if (!oldprop && !EInvis && !BInvis && Invisible && !Blind) {
  720.                      newsym(u.ux, u.uy);
  721.                      Your("body takes on a %s transparency...",
  722.                           Hallucination ? "normal" : "strange");
  723. diff --git c/src/hack.c w/src/hack.c
  724. index 79fe740..6475486 100644
  725. --- c/src/hack.c
  726. +++ w/src/hack.c
  727. @@ -238,8 +238,10 @@ moverock()
  728.                      deltrap(ttmp);
  729.                      delobj(otmp);
  730.                      bury_objs(rx, ry);
  731. -                    levl[rx][ry].wall_info &= ~W_NONDIGGABLE;
  732. -                    levl[rx][ry].candig = 1;
  733. +                    if (!Can_dig_down(&u.uz)
  734. +                        && (levl[rx][ry].typ == ROOM
  735. +                            || levl[rx][ry].typ == CORR))
  736. +                        levl[rx][ry].flags |= FL_DIGGABLE;
  737.                      if (cansee(rx, ry))
  738.                          newsym(rx, ry);
  739.                      return sobj_at(BOULDER, sx, sy) ? -1 : 0;
  740. @@ -2707,7 +2709,8 @@ lookaround()
  741.              if ((mtmp = m_at(x, y)) != 0
  742.                  && M_AP_TYPE(mtmp) != M_AP_FURNITURE
  743.                  && M_AP_TYPE(mtmp) != M_AP_OBJECT
  744. -                && (!mtmp->minvis || See_invisible) && !mtmp->mundetected) {
  745. +                && (!minvisible(mtmp) || See_invisible)
  746. +                && !mtmp->mundetected) {
  747.                  if ((context.run != 1 && !mtmp->mtame)
  748.                      || (x == u.ux + u.dx && y == u.uy + u.dy
  749.                          && !context.travel)) {
  750. diff --git c/src/invent.c w/src/invent.c
  751. index 7e7e3b2..fc78123 100644
  752. --- c/src/invent.c
  753. +++ w/src/invent.c
  754. @@ -4438,6 +4438,9 @@ boolean as_if_seen;
  755.      menu_item *selected = 0;
  756.      int n;
  757.  
  758. +    if (!levl[x][y].buried)
  759. +        return 0; /* nothing to do here */
  760. +
  761.      /* count # of objects here */
  762.      for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
  763.          if (obj->ox == x && obj->oy == y) {
  764. diff --git c/src/light.c w/src/light.c
  765. index 7c2dc1f..71ce7a3 100644
  766. --- c/src/light.c
  767. +++ w/src/light.c
  768. @@ -41,6 +41,7 @@
  769.  /* flags */
  770.  #define LSF_SHOW 0x1        /* display the light source */
  771.  #define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */
  772. +#define LSF_DETECT 0x4      /* guiding candle */
  773.  
  774.  static light_source *light_base = 0;
  775.  
  776. @@ -71,9 +72,9 @@ anything *id;
  777.      ls->x = x;
  778.      ls->y = y;
  779.      ls->range = range;
  780. -    ls->type = type;
  781. +    ls->type = type & ~LS_DETECT;
  782.      ls->id = *id;
  783. -    ls->flags = 0;
  784. +    ls->flags = type & LS_DETECT ? LSF_DETECT : 0;
  785.      light_base = ls;
  786.  
  787.      vision_full_recalc = 1; /* make the source show up */
  788. @@ -157,9 +158,10 @@ char **cs_rows;
  789.          /* minor optimization: don't bother with duplicate light sources
  790.             at hero */
  791.          if (ls->x == u.ux && ls->y == u.uy) {
  792. -            if (at_hero_range >= ls->range)
  793. -                ls->flags &= ~LSF_SHOW;
  794. -            else
  795. +            if (at_hero_range >= ls->range) {
  796. +                if (!(ls->flags & LSF_DETECT))
  797. +                    ls->flags &= ~LSF_SHOW;
  798. +            } else
  799.                  at_hero_range = ls->range;
  800.          }
  801.  
  802. @@ -197,13 +199,19 @@ char **cs_rows;
  803.                       * does this.
  804.                       */
  805.                      for (x = min_x; x <= max_x; x++)
  806. -                        if (row[x] & COULD_SEE)
  807. +                        if (row[x] & COULD_SEE) {
  808.                              row[x] |= TEMP_LIT;
  809. +                            if (ls->flags & LSF_DETECT)
  810. +                                row[x] |= TEMP_DETECT;
  811. +                        }
  812.                  } else {
  813.                      for (x = min_x; x <= max_x; x++)
  814.                          if ((ls->x == x && ls->y == y)
  815. -                            || clear_path((int) ls->x, (int) ls->y, x, y))
  816. +                            || clear_path((int) ls->x, (int) ls->y, x, y)) {
  817.                              row[x] |= TEMP_LIT;
  818. +                            if (ls->flags & LSF_DETECT)
  819. +                                row[x] |= TEMP_DETECT;
  820. +                        }
  821.                  }
  822.              }
  823.          }
  824. @@ -676,10 +684,18 @@ struct obj *obj;
  825.  int new_radius;
  826.  {
  827.      light_source *ls;
  828. +    short old_flags;
  829.  
  830.      for (ls = light_base; ls; ls = ls->next)
  831.          if (ls->type == LS_OBJECT && ls->id.a_obj == obj) {
  832. -            if (new_radius != ls->range)
  833. +            old_flags = ls->flags;
  834. +            if (obj->otyp == GUIDING_CANDLE) {
  835. +                if (obj->cursed)
  836. +                    ls->flags &= ~LSF_DETECT;
  837. +                else
  838. +                    ls->flags |= LSF_DETECT;
  839. +            }
  840. +            if (new_radius != ls->range || ls->flags != old_flags)
  841.                  vision_full_recalc = 1;
  842.              ls->range = new_radius;
  843.              return;
  844. @@ -720,6 +736,8 @@ struct obj *obj;
  845.              radius++;
  846.              n /= 7L;
  847.          } while (n > 0L);
  848. +        if (obj->otyp == GUIDING_CANDLE && obj->blessed)
  849. +            radius++; /* make them less useless in late game */
  850.      } else {
  851.          /* we're only called for lit candelabrum or candles */
  852.          /* impossible("candlelight for %d?", obj->otyp); */
  853. @@ -730,7 +748,7 @@ struct obj *obj;
  854.  
  855.  /* light emitting artifact's range depends upon its curse/bless state */
  856.  int
  857. -arti_light_radius(obj)
  858. +dynamic_light_radius(obj)
  859.  struct obj *obj;
  860.  {
  861.      /*
  862. @@ -741,9 +759,12 @@ struct obj *obj;
  863.       */
  864.  
  865.      /* sanity check [simplifies usage by bless()/curse()/&c] */
  866. -    if (!obj->lamplit || !artifact_light(obj))
  867. +    if (!obj->lamplit || !artifact_light(obj) && obj->otyp != GUIDING_CANDLE)
  868.          return 0;
  869.  
  870. +    if (obj->otyp == GUIDING_CANDLE)
  871. +        return candle_light_range(obj);
  872. +
  873.      /* cursed radius of 1 is not noticeable for an item that's
  874.         carried by the hero but is if it's carried by a monster
  875.         or left lit on the floor (not applicable for Sunsword) */
  876. @@ -755,7 +776,7 @@ const char *
  877.  arti_light_description(obj)
  878.  struct obj *obj;
  879.  {
  880. -    switch (arti_light_radius(obj)) {
  881. +    switch (dynamic_light_radius(obj)) {
  882.      case 3:
  883.          return "brilliantly"; /* blessed */
  884.      case 2:
  885. diff --git c/src/mcastu.c w/src/mcastu.c
  886. index 1b2fb63..5d10ac1 100644
  887. --- c/src/mcastu.c
  888. +++ w/src/mcastu.c
  889. @@ -59,7 +59,7 @@ boolean undirected;
  890.  
  891.          if (undirected)
  892.              point_msg = "all around, then curses";
  893. -        else if ((Invis && !perceives(mtmp->data)
  894. +        else if ((Invis && !perceives_you(mtmp->data)
  895.                    && (mtmp->mux != u.ux || mtmp->muy != u.uy))
  896.                   || is_obj_mappear(&youmonst, STRANGE_OBJECT)
  897.                   || u.uundetected)
  898. @@ -264,7 +264,7 @@ boolean foundyou;
  899.                canspotmon(mtmp) ? Monnam(mtmp) : "Something",
  900.                is_undirected_spell(mattk->adtyp, spellnum)
  901.                    ? ""
  902. -                  : (Invis && !perceives(mtmp->data)
  903. +                  : (Invis && !perceives_you(mtmp->data)
  904.                       && (mtmp->mux != u.ux || mtmp->muy != u.uy))
  905.                          ? " at a spot near you"
  906.                          : (Displaced
  907. @@ -414,7 +414,7 @@ int spellnum;
  908.  
  909.              /* messages not quite right if plural monsters created but
  910.                 only a single monster is seen */
  911. -            if (Invis && !perceives(mtmp->data)
  912. +            if (Invis && !perceives_you(mtmp->data)
  913.                  && (mtmp->mux != u.ux || mtmp->muy != u.uy))
  914.                  pline("%s around a spot near you!", mappear);
  915.              else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
  916. @@ -463,7 +463,8 @@ int spellnum;
  917.          if (!mtmp->minvis && !mtmp->invis_blkd) {
  918.              if (canseemon(mtmp))
  919.                  pline("%s suddenly %s!", Monnam(mtmp),
  920. -                      !See_invisible ? "disappears" : "becomes transparent");
  921. +                      !See_invisible && !candetect(mtmp->mx, mtmp->my)
  922. +                      ? "disappears" : "becomes transparent");
  923.              mon_set_minvis(mtmp);
  924.              if (cansee(mtmp->mx, mtmp->my) && !canspotmon(mtmp))
  925.                  map_invisible(mtmp->mx, mtmp->my);
  926. @@ -640,7 +641,7 @@ int spellnum;
  927.              fmt = "%s casts at a clump of sticks, but nothing happens.";
  928.          else if (let == S_SNAKE)
  929.              fmt = "%s transforms a clump of sticks into snakes!";
  930. -        else if (Invis && !perceives(mtmp->data)
  931. +        else if (Invis && !perceives_you(mtmp->data)
  932.                   && (mtmp->mux != u.ux || mtmp->muy != u.uy))
  933.              fmt = "%s summons insects around a spot near you!";
  934.          else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
  935. diff --git c/src/mhitm.c w/src/mhitm.c
  936. index 5ebbd84..b58946c 100644
  937. --- c/src/mhitm.c
  938. +++ w/src/mhitm.c
  939. @@ -658,7 +658,7 @@ struct attack *mattk;
  940.      }
  941.  
  942.      if (magr->mcan || !magr->mcansee || !mdef->mcansee
  943. -        || (magr->minvis && !perceives(mdef->data)) || mdef->msleeping) {
  944. +        || (minvisible(magr) && !perceives(mdef->data)) || mdef->msleeping) {
  945.          if (vis && canspotmon(mdef))
  946.              pline("but nothing happens.");
  947.          return MM_MISS;
  948. @@ -674,7 +674,7 @@ struct attack *mattk;
  949.                                        "The gaze is reflected away by %s %s.");
  950.                  return MM_MISS;
  951.              }
  952. -            if (mdef->minvis && !perceives(magr->data)) {
  953. +            if (minvisible(mdef) && !perceives(magr->data)) {
  954.                  if (canseemon(magr)) {
  955.                      pline(
  956.                        "%s doesn't seem to notice that %s gaze was reflected.",
  957. @@ -1645,7 +1645,7 @@ int mdead;
  958.                  if (!rn2(4))
  959.                      tmp = 127;
  960.                  if (magr->mcansee && haseyes(madat) && mdef->mcansee
  961. -                    && (perceives(madat) || !mdef->minvis)) {
  962. +                    && (perceives(madat) || !minvisible(mdef))) {
  963.                      /* construct format string; guard against '%' in Monnam */
  964.                      Strcpy(buf, s_suffix(Monnam(mdef)));
  965.                      (void) strNsubst(buf, "%", "%%", 0);
  966. diff --git c/src/mhitu.c w/src/mhitu.c
  967. index 849ddb1..e5743d7 100644
  968. --- c/src/mhitu.c
  969. +++ w/src/mhitu.c
  970. @@ -159,7 +159,7 @@ struct attack *mattk;
  971.                ? could_seduce(mtmp, &youmonst, mattk) : 0);
  972.      Monst_name = Monnam(mtmp);
  973.  
  974. -    if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
  975. +    if (!mtmp->mcansee || (Invis && !perceives_you(mtmp->data))) {
  976.          const char *swings = (mattk->aatyp == AT_BITE) ? "snaps"
  977.                               : (mattk->aatyp == AT_KICK) ? "kicks"
  978.                                 : (mattk->aatyp == AT_STNG
  979. @@ -573,7 +573,7 @@ register struct monst *mtmp;
  980.      tmp += mtmp->m_lev;
  981.      if (multi < 0)
  982.          tmp += 4;
  983. -    if ((Invis && !perceives(mdat)) || !mtmp->mcansee)
  984. +    if ((Invis && !perceives_you(mdat)) || !mtmp->mcansee)
  985.          tmp -= 2;
  986.      if (mtmp->mtrapped)
  987.          tmp -= 2;
  988. @@ -2392,16 +2392,18 @@ struct attack *mattk; /* non-Null: current attack; Null: general capability */
  989.          pagr = youmonst.data;
  990.          agrinvis = (Invis != 0);
  991.          genagr = poly_gender();
  992. +        defperc = candetect(u.ux, u.uy);
  993.      } else {
  994.          pagr = magr->data;
  995.          agrinvis = magr->minvis;
  996.          genagr = gender(magr);
  997. +        defperc = candetect(magr->mx, magr->my);
  998.      }
  999.      if (mdef == &youmonst) {
  1000. -        defperc = (See_invisible != 0);
  1001. +        defperc = defperc || See_invisible;
  1002.          gendef = poly_gender();
  1003.      } else {
  1004. -        defperc = perceives(mdef->data);
  1005. +        defperc = defperc || perceives(mdef->data);
  1006.          gendef = gender(mdef);
  1007.      }
  1008.  
  1009. @@ -2883,7 +2885,7 @@ struct attack *mattk;
  1010.                  if (!rn2(4))
  1011.                      tmp = 127;
  1012.                  if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3)
  1013. -                    && (perceives(mtmp->data) || !Invis)) {
  1014. +                    && (perceives_you(mtmp->data) || !Invis)) {
  1015.                      if (Blind)
  1016.                          pline("As a blind %s, you cannot defend yourself.",
  1017.                                youmonst.data->mname);
  1018. diff --git c/src/mkobj.c w/src/mkobj.c
  1019. index 17265ff..b80cfde 100644
  1020. --- c/src/mkobj.c
  1021. +++ w/src/mkobj.c
  1022. @@ -10,6 +10,7 @@ STATIC_DCL unsigned FDECL(nextoid, (struct obj *, struct obj *));
  1023.  STATIC_DCL void FDECL(maybe_adjust_light, (struct obj *, int));
  1024.  STATIC_DCL void FDECL(obj_timer_checks, (struct obj *,
  1025.                                           XCHAR_P, XCHAR_P, int));
  1026. +STATIC_DCL void FDECL(recheck_buried, (int, int));
  1027.  STATIC_DCL void FDECL(container_weight, (struct obj *));
  1028.  STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *));
  1029.  STATIC_DCL void FDECL(objlist_sanity, (struct obj *, int, const char *));
  1030. @@ -898,11 +899,12 @@ boolean artif;
  1031.              switch (otmp->otyp) {
  1032.              case TALLOW_CANDLE:
  1033.              case WAX_CANDLE:
  1034. -                otmp->spe = 1;
  1035. -                otmp->age = 20L * /* 400 or 200 */
  1036. -                            (long) objects[otmp->otyp].oc_cost;
  1037. -                otmp->lamplit = 0;
  1038.                  otmp->quan = 1L + (long) (rn2(2) ? rn2(7) : 0);
  1039. +                /*FALLTHRU*/
  1040. +            case GUIDING_CANDLE:
  1041. +                otmp->spe = 1;
  1042. +                otmp->age = candle_burn_time(otmp);
  1043. +                otmp->lamplit = 0;
  1044.                  blessorcurse(otmp, 5);
  1045.                  break;
  1046.              case BRASS_LANTERN:
  1047. @@ -1230,12 +1232,13 @@ int old_range;
  1048.  {
  1049.      char buf[BUFSZ];
  1050.      xchar ox, oy;
  1051. -    int new_range = arti_light_radius(obj), delta = new_range - old_range;
  1052. +    int new_range = dynamic_light_radius(obj), delta = new_range - old_range;
  1053.  
  1054.      /* radius of light emitting artifact varies by curse/bless state
  1055.         so will change after blessing or cursing */
  1056. -    if (delta) {
  1057. +    if (new_range)
  1058.          obj_adjust_light_radius(obj, new_range);
  1059. +    if (delta) {
  1060.          /* simplifying assumptions:  hero is wielding this object;
  1061.             artifacts have to be in use to emit light and monsters'
  1062.             gear won't change bless or curse state */
  1063. @@ -1252,7 +1255,8 @@ int old_range;
  1064.                     when changing intensity, using "less brightly" is
  1065.                     straightforward for dimming, but we need "brighter"
  1066.                     rather than "more brightly" for brightening; ugh */
  1067. -                pline("%s %s %s%s.", buf, otense(obj, "shine"),
  1068. +                pline("%s %s %s%s.", buf, otense(obj, Is_candle(obj)
  1069. +                                                      ? "burn" : "shine"),
  1070.                        (abs(delta) > 1) ? "much " : "",
  1071.                        (delta > 0) ? "brighter" : "less brightly");
  1072.              }
  1073. @@ -1275,7 +1279,7 @@ register struct obj *otmp;
  1074.      if (otmp->oclass == COIN_CLASS)
  1075.          return;
  1076.      if (otmp->lamplit)
  1077. -        old_light = arti_light_radius(otmp);
  1078. +        old_light = dynamic_light_radius(otmp);
  1079.      otmp->cursed = 0;
  1080.      otmp->blessed = 1;
  1081.      if (carried(otmp) && confers_luck(otmp))
  1082. @@ -1296,7 +1300,7 @@ register struct obj *otmp;
  1083.      int old_light = 0;
  1084.  
  1085.      if (otmp->lamplit)
  1086. -        old_light = arti_light_radius(otmp);
  1087. +        old_light = dynamic_light_radius(otmp);
  1088.      otmp->blessed = 0;
  1089.      if (carried(otmp) && confers_luck(otmp))
  1090.          set_moreluck();
  1091. @@ -1316,7 +1320,7 @@ register struct obj *otmp;
  1092.      if (otmp->oclass == COIN_CLASS)
  1093.          return;
  1094.      if (otmp->lamplit)
  1095. -        old_light = arti_light_radius(otmp);
  1096. +        old_light = dynamic_light_radius(otmp);
  1097.      already_cursed = otmp->cursed;
  1098.      otmp->blessed = 0;
  1099.      otmp->cursed = 1;
  1100. @@ -1353,7 +1357,7 @@ register struct obj *otmp;
  1101.      int old_light = 0;
  1102.  
  1103.      if (otmp->lamplit)
  1104. -        old_light = arti_light_radius(otmp);
  1105. +        old_light = dynamic_light_radius(otmp);
  1106.      otmp->cursed = 0;
  1107.      if (carried(otmp) && confers_luck(otmp))
  1108.          set_moreluck();
  1109. @@ -1808,7 +1812,7 @@ boolean do_buried;
  1110.          if (otmp->timed)
  1111.              obj_timer_checks(otmp, x, y, 0);
  1112.      }
  1113. -    if (do_buried) {
  1114. +    if (do_buried && levl[x][y].buried) {
  1115.          for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) {
  1116.              if (otmp->ox == x && otmp->oy == y) {
  1117.                  if (otmp->timed)
  1118. @@ -1995,6 +1999,7 @@ struct obj *obj;
  1119.          break;
  1120.      case OBJ_BURIED:
  1121.          extract_nobj(obj, &level.buriedobjlist);
  1122. +        recheck_buried(obj->ox, obj->oy);
  1123.          break;
  1124.      case OBJ_ONBILL:
  1125.          extract_nobj(obj, &billobjs);
  1126. @@ -2135,6 +2140,25 @@ struct obj *obj;
  1127.      obj->where = OBJ_BURIED;
  1128.      obj->nobj = level.buriedobjlist;
  1129.      level.buriedobjlist = obj;
  1130. +    levl[obj->ox][obj->oy].buried = 1;
  1131. +}
  1132. +
  1133. +/*
  1134. + * Revalidate the buried flag.  Useful e.g. if we just removed
  1135. + * a single buried object and don't know if there are others here.
  1136. + */
  1137. +STATIC_OVL void
  1138. +recheck_buried(x, y)
  1139. +int x, y;
  1140. +{
  1141. +    struct obj *obj;
  1142. +    for (obj = level.buriedobjlist; obj; obj = obj->nobj)
  1143. +        if (obj->ox == x && obj->oy == y)
  1144. +          {
  1145. +            levl[x][y].buried = 1;
  1146. +            return;
  1147. +          }
  1148. +    levl[x][y].buried = 0;
  1149.  }
  1150.  
  1151.  /* Recalculate the weight of this container and all of _its_ containers. */
  1152. diff --git c/src/mon.c w/src/mon.c
  1153. index 4f0a13d..46aea52 100644
  1154. --- c/src/mon.c
  1155. +++ w/src/mon.c
  1156. @@ -1415,7 +1415,7 @@ long flag;
  1157.                  && (lavaok || !is_lava(nx, ny))) {
  1158.                  int dispx, dispy;
  1159.                  boolean monseeu = (mon->mcansee
  1160. -                                   && (!Invis || perceives(mdat)));
  1161. +                                   && (!Invis || perceives_you(mdat)));
  1162.                  boolean checkobj = OBJ_AT(nx, ny);
  1163.  
  1164.                  /* Displacement also displaces the Elbereth/scare monster,
  1165. @@ -3077,9 +3077,9 @@ int x, y, distance;
  1166.      }
  1167.  }
  1168.  
  1169. -/* NOTE: we must check for mimicry before calling this routine */
  1170. +/* also used in detect.c */
  1171.  void
  1172. -seemimic(mtmp)
  1173. +seemimic_noredraw(mtmp)
  1174.  register struct monst *mtmp;
  1175.  {
  1176.      boolean is_blocker_appear = (is_lightblocker_mappear(mtmp));
  1177. @@ -3096,7 +3096,14 @@ register struct monst *mtmp;
  1178.      if (is_blocker_appear
  1179.          && !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my]))
  1180.          unblock_point(mtmp->mx, mtmp->my);
  1181. +}
  1182.  
  1183. +/* NOTE: we must check for mimicry before calling this routine */
  1184. +void
  1185. +seemimic(mtmp)
  1186. +register struct monst *mtmp;
  1187. +{
  1188. +    seemimic_noredraw(mtmp);
  1189.      newsym(mtmp->mx, mtmp->my);
  1190.  }
  1191.  
  1192. @@ -3138,7 +3145,7 @@ restartcham()
  1193.          if (!mtmp->mcan)
  1194.              mtmp->cham = pm_to_cham(monsndx(mtmp->data));
  1195.          if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping
  1196. -            && cansee(mtmp->mx, mtmp->my)) {
  1197. +            && cansee(mtmp->mx, mtmp->my) && !candetect(mtmp->mx, mtmp->my)) {
  1198.              set_mimic_sym(mtmp);
  1199.              newsym(mtmp->mx, mtmp->my);
  1200.          }
  1201. @@ -3175,7 +3182,7 @@ register struct monst *mtmp;
  1202.      struct trap *t;
  1203.  
  1204.      if (mtmp->mcan || M_AP_TYPE(mtmp) || cansee(mtmp->mx, mtmp->my)
  1205. -        || rn2(3) || mtmp == u.ustuck
  1206. +        || candetect(mtmp->mx, mtmp->my) || rn2(3) || mtmp == u.ustuck
  1207.          /* can't hide while trapped except in pits */
  1208.          || (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0
  1209.              && !is_pit(t->ttyp))
  1210. @@ -3208,6 +3215,8 @@ struct monst *mtmp;
  1211.                      : (mtmp->mtrapped && (t = t_at(x, y)) != 0
  1212.                         && !is_pit(t->ttyp))) {
  1213.          ; /* can't hide while stuck in a non-pit trap */
  1214. +    } else if (candetect(x, y)) {
  1215. +        ; /* guiding candle blocks hiding */
  1216.      } else if (mtmp->data->mlet == S_EEL) {
  1217.          undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz));
  1218.      } else if (hides_under(mtmp->data) && OBJ_AT(x, y)) {
  1219. diff --git c/src/monmove.c w/src/monmove.c
  1220. index cd6ca98..a5a0a4d 100644
  1221. --- c/src/monmove.c
  1222. +++ w/src/monmove.c
  1223. @@ -330,7 +330,7 @@ int *inrange, *nearby, *scared;
  1224.       * running into you by accident but possibly attacking the spot
  1225.       * where it guesses you are.
  1226.       */
  1227. -    if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
  1228. +    if (!mtmp->mcansee || (Invis && !perceives_you(mtmp->data))) {
  1229.          seescaryx = mtmp->mux;
  1230.          seescaryy = mtmp->muy;
  1231.      } else {
  1232. @@ -913,7 +913,7 @@ register int after;
  1233.                                && (dist2(omx, omy, gx, gy) <= 36));
  1234.  
  1235.          if (!mtmp->mcansee
  1236. -            || (should_see && Invis && !perceives(ptr) && rn2(11))
  1237. +            || (should_see && Invis && !perceives_you(ptr) && rn2(11))
  1238.              || is_obj_mappear(&youmonst,STRANGE_OBJECT) || u.uundetected
  1239.              || (is_obj_mappear(&youmonst,GOLD_PIECE) && !likes_gold(ptr))
  1240.              || (mtmp->mpeaceful && !mtmp->isshk) /* allow shks to follow */
  1241. @@ -1550,7 +1550,7 @@ register struct monst *mtmp;
  1242.      if (mx == u.ux && my == u.uy)
  1243.          goto found_you;
  1244.  
  1245. -    notseen = (!mtmp->mcansee || (Invis && !perceives(mtmp->data)));
  1246. +    notseen = (!mtmp->mcansee || (Invis && !perceives_you(mtmp->data)));
  1247.      /* add cases as required.  eg. Displacement ... */
  1248.      if (notseen || Underwater) {
  1249.          /* Xorns can smell quantities of valuable metal
  1250. diff --git c/src/mthrowu.c w/src/mthrowu.c
  1251. index 7ecbbb2..5584e44 100644
  1252. --- c/src/mthrowu.c
  1253. +++ w/src/mthrowu.c
  1254. @@ -1180,8 +1180,8 @@ int whodidit;   /* 1==hero, 0=other, -1==just check whether it'll pass thru */
  1255.              break;
  1256.          case TOOL_CLASS:
  1257.              hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
  1258. -                    && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
  1259. -                    && obj_type != WAX_CANDLE && obj_type != LENSES
  1260. +                    && obj_type != CREDIT_CARD && !Is_candle(otmp)
  1261. +                    && obj_type != LENSES
  1262.                      && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
  1263.              break;
  1264.          case ROCK_CLASS: /* includes boulder */
  1265. diff --git c/src/muse.c w/src/muse.c
  1266. index 2dfb92f..8732cc6 100644
  1267. --- c/src/muse.c
  1268. +++ w/src/muse.c
  1269. @@ -755,7 +755,7 @@ struct monst *mtmp;
  1270.              pline_The("digging ray is ineffective.");
  1271.              return 2;
  1272.          }
  1273. -        if (!Can_dig_down(&u.uz) && !levl[mtmp->mx][mtmp->my].candig) {
  1274. +        if (!Can_dig_hole(mtmp->mx, mtmp->my, &u.uz)) {
  1275.              if (canseemon(mtmp))
  1276.                  pline_The("%s here is too hard to dig in.",
  1277.                            surface(mtmp->mx, mtmp->my));
  1278. diff --git c/src/objects.c w/src/objects.c
  1279. index fcca3b0..a3f8c99 100644
  1280. --- c/src/objects.c
  1281. +++ w/src/objects.c
  1282. @@ -658,8 +658,9 @@ TOOL("skeleton key",       "key", 0, 0, 0, 0, 80,  3, 10, IRON, HI_METAL),
  1283.  TOOL("lock pick",           None, 1, 0, 0, 0, 60,  4, 20, IRON, HI_METAL),
  1284.  TOOL("credit card",         None, 1, 0, 0, 0, 15,  1, 10, PLASTIC, CLR_WHITE),
  1285.  /* light sources */
  1286. -TOOL("tallow candle",   "candle", 0, 1, 0, 0, 20,  2, 10, WAX, CLR_WHITE),
  1287. +TOOL("tallow candle",   "candle", 0, 1, 0, 0, 17,  2, 10, WAX, CLR_WHITE),
  1288.  TOOL("wax candle",      "candle", 0, 1, 0, 0,  5,  2, 20, WAX, CLR_WHITE),
  1289. +TOOL("guiding candle",  "candle", 0, 1, 1, 0,  3,  2, 30, WAX, CLR_WHITE),
  1290.  TOOL("brass lantern",       None, 1, 0, 0, 0, 30, 30, 12, COPPER, CLR_YELLOW),
  1291.  TOOL("oil lamp",          "lamp", 0, 0, 0, 0, 45, 20, 10, COPPER, CLR_YELLOW),
  1292.  TOOL("magic lamp",        "lamp", 0, 0, 1, 0, 15, 20, 50, COPPER, CLR_YELLOW),
  1293. diff --git c/src/objnam.c w/src/objnam.c
  1294. index 7205bb4..60e003d 100644
  1295. --- c/src/objnam.c
  1296. +++ w/src/objnam.c
  1297. @@ -1111,8 +1111,7 @@ unsigned doname_flags;
  1298.              break;
  1299.          } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP
  1300.                     || obj->otyp == BRASS_LANTERN || Is_candle(obj)) {
  1301. -            if (Is_candle(obj)
  1302. -                && obj->age < 20L * (long) objects[obj->otyp].oc_cost)
  1303. +            if (Is_candle(obj) && obj->age < candle_burn_time(obj))
  1304.                  Strcat(prefix, "partly used ");
  1305.              if (obj->lamplit)
  1306.                  Strcat(bp, " (lit)");
  1307. @@ -2754,7 +2753,7 @@ struct o_range {
  1308.  STATIC_OVL NEARDATA const struct o_range o_ranges[] = {
  1309.      { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS },
  1310.      { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP },
  1311. -    { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE },
  1312. +    { "candle", TOOL_CLASS, TALLOW_CANDLE, GUIDING_CANDLE },
  1313.      { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY },
  1314.      { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION },
  1315.      { "hat", ARMOR_CLASS, FEDORA, DUNCE_CAP },
  1316. @@ -3846,7 +3845,8 @@ struct obj *no_wish;
  1317.  
  1318.      /* if player specified a reasonable count, maybe honor it */
  1319.      if (cnt > 0 && objects[typ].oc_merge
  1320. -        && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp))
  1321. +        && (wizard || cnt < rnd(6) || (cnt <= 7 && Is_candle(otmp)
  1322. +                                       && !objects[typ].oc_magic)
  1323.              || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp))
  1324.                                || typ == ROCK || is_missile(otmp)))))
  1325.          otmp->quan = (long) cnt;
  1326. diff --git c/src/pager.c w/src/pager.c
  1327. index 7f14b0f..f564387 100644
  1328. --- c/src/pager.c
  1329. +++ w/src/pager.c
  1330. @@ -167,7 +167,7 @@ struct obj **obj_p;
  1331.  
  1332.      *obj_p = (struct obj *) 0;
  1333.      /* TODO: check inside containers in case glyph came from detection */
  1334. -    if ((otmp = sobj_at(glyphotyp, x, y)) == 0)
  1335. +    if ((otmp = sobj_at(glyphotyp, x, y)) == 0 && levl[x][y].buried)
  1336.          for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj)
  1337.              if (otmp->ox == x && otmp->oy == y && otmp->otyp == glyphotyp)
  1338.                  break;
  1339. diff --git c/src/polyself.c w/src/polyself.c
  1340. index b053091..4158acc 100644
  1341. --- c/src/polyself.c
  1342. +++ w/src/polyself.c
  1343. @@ -1355,9 +1355,9 @@ dogaze()
  1344.              continue;
  1345.          if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) {
  1346.              looked++;
  1347. -            if (Invis && !perceives(mtmp->data)) {
  1348. +            if (Invis && !perceives_you(mtmp->data)) {
  1349.                  pline("%s seems not to notice your gaze.", Monnam(mtmp));
  1350. -            } else if (mtmp->minvis && !See_invisible) {
  1351. +            } else if (minvisible(mtmp) && !See_invisible) {
  1352.                  You_cant("see where to gaze at %s.", Monnam(mtmp));
  1353.              } else if (M_AP_TYPE(mtmp) == M_AP_FURNITURE
  1354.                         || M_AP_TYPE(mtmp) == M_AP_OBJECT) {
  1355. @@ -1505,6 +1505,11 @@ dohide()
  1356.      /* TODO? inhibit floor hiding at furniture locations, or
  1357.       * else make youhiding() give smarter messages at such spots.
  1358.       */
  1359. +    if (candetect(u.ux, u.uy))
  1360. +      {
  1361. +        You("try to hide, but cannot maintain your disguise!");
  1362. +        return 1;
  1363. +      }
  1364.  
  1365.      if (u.uundetected || (ismimic && U_AP_TYPE != M_AP_NOTHING)) {
  1366.          youhiding(FALSE, 1); /* "you are already hiding" */
  1367. diff --git c/src/potion.c w/src/potion.c
  1368. index c6dffc5..dd75432 100644
  1369. --- c/src/potion.c
  1370. +++ w/src/potion.c
  1371. @@ -457,7 +457,8 @@ self_invis_message()
  1372.      pline("%s %s.",
  1373.            Hallucination ? "Far out, man!  You"
  1374.                          : "Gee!  All of a sudden, you",
  1375. -          See_invisible ? "can see right through yourself"
  1376. +          See_invisible || candetect(u.ux, u.uy)
  1377. +                        ? "can see right through yourself"
  1378.                          : "can't see yourself");
  1379.  }
  1380.  
  1381. @@ -1707,8 +1708,9 @@ register struct obj *obj;
  1382.          if (!Blind && !Invis) {
  1383.              kn++;
  1384.              pline("For an instant you %s!",
  1385. -                  See_invisible ? "could see right through yourself"
  1386. -                                : "couldn't see yourself");
  1387. +                  See_invisible || candetect(u.ux, u.uy)
  1388. +                  ? "could see right through yourself"
  1389. +                  : "couldn't see yourself");
  1390.          }
  1391.          break;
  1392.      case POT_PARALYSIS:
  1393. diff --git c/src/priest.c w/src/priest.c
  1394. index ab20a8d..5b1cd9d 100644
  1395. --- c/src/priest.c
  1396. +++ w/src/priest.c
  1397. @@ -215,7 +215,7 @@ register struct monst *priest;
  1398.              }
  1399.              avoid = FALSE;
  1400.          }
  1401. -    } else if (Invis)
  1402. +    } else if (Invis && !perceives_you(priest->data))
  1403.          avoid = FALSE;
  1404.  
  1405.      return move_special(priest, FALSE, TRUE, FALSE, avoid, omx, omy, gx, gy);
  1406. diff --git c/src/save.c w/src/save.c
  1407. index e0af4b8..40fd0dd 100644
  1408. --- c/src/save.c
  1409. +++ w/src/save.c
  1410. @@ -602,7 +602,7 @@ boolean rlecomp;
  1411.                      && prm->flags == rgrm->flags && prm->lit == rgrm->lit
  1412.                      && prm->waslit == rgrm->waslit
  1413.                      && prm->roomno == rgrm->roomno && prm->edge == rgrm->edge
  1414. -                    && prm->candig == rgrm->candig) {
  1415. +                    && prm->buried == rgrm->buried) {
  1416.                      match++;
  1417.                      if (match > 254) {
  1418.                          match = 254; /* undo this match */
  1419. diff --git c/src/shk.c w/src/shk.c
  1420. index 6772da4..0467acb 100644
  1421. --- c/src/shk.c
  1422. +++ w/src/shk.c
  1423. @@ -580,7 +580,7 @@ char *enterstring;
  1424.      if (muteshk(shkp) || eshkp->following)
  1425.          return; /* no dialog */
  1426.  
  1427. -    if (Invis) {
  1428. +    if (Invis && !perceives_you(shkp->data)) {
  1429.          pline("%s senses your presence.", Shknam(shkp));
  1430.          if (!Deaf && !muteshk(shkp))
  1431.              verbalize("Invisible customers are not welcome!");
  1432. @@ -2203,8 +2203,7 @@ boolean unpaid_only;
  1433.              if (saleable(shkp, otmp) && !otmp->unpaid
  1434.                  && otmp->oclass != BALL_CLASS
  1435.                  && !(otmp->oclass == FOOD_CLASS && otmp->oeaten)
  1436. -                && !(Is_candle(otmp)
  1437. -                     && otmp->age < 20L * (long) objects[otmp->otyp].oc_cost))
  1438. +                && !(Is_candle(otmp) && otmp->age < candle_burn_time(otmp)))
  1439.                  price += set_cost(otmp, shkp);
  1440.          } else {
  1441.              /* no_charge is only set for floor items (including
  1442. @@ -3151,8 +3150,7 @@ xchar x, y;
  1443.      if ((!saleitem && !(container && cltmp > 0L)) || eshkp->billct == BILLSZ
  1444.          || obj->oclass == BALL_CLASS || obj->oclass == CHAIN_CLASS
  1445.          || offer == 0L || (obj->oclass == FOOD_CLASS && obj->oeaten)
  1446. -        || (Is_candle(obj)
  1447. -            && obj->age < 20L * (long) objects[obj->otyp].oc_cost)) {
  1448. +        || (Is_candle(obj) && obj->age < candle_burn_time(obj))) {
  1449.          pline("%s seems uninterested%s.", Shknam(shkp),
  1450.                cgold ? " in the rest" : "");
  1451.          if (container)
  1452. @@ -3420,8 +3418,7 @@ boolean shk_buying;
  1453.              tmp += 10L * (long) obj->spe;
  1454.          break;
  1455.      case TOOL_CLASS:
  1456. -        if (Is_candle(obj)
  1457. -            && obj->age < 20L * (long) objects[obj->otyp].oc_cost)
  1458. +        if (Is_candle(obj) && obj->age < candle_burn_time(obj))
  1459.              tmp /= 2L;
  1460.          break;
  1461.      }
  1462. @@ -3895,7 +3892,7 @@ struct monst *shkp;
  1463.          avoid = FALSE;
  1464.      } else {
  1465.  #define GDIST(x, y) (dist2(x, y, gx, gy))
  1466. -        if (Invis || u.usteed) {
  1467. +        if (Invis && !perceives_you(shkp->data) || u.usteed) {
  1468.              avoid = FALSE;
  1469.          } else {
  1470.              uondoor = (u.ux == eshkp->shd.x && u.uy == eshkp->shd.y);
  1471. @@ -4225,7 +4222,7 @@ boolean cant_mollify;
  1472.          return;
  1473.      }
  1474.  
  1475. -    if (Invis)
  1476. +    if (Invis && !perceives_you(shkp->data))
  1477.          Your("invisibility does not fool %s!", shkname(shkp));
  1478.      Sprintf(qbuf, "%sYou did %ld %s worth of damage!%s  Pay?",
  1479.              !animal ? cad(TRUE) : "", cost_of_damage,
  1480. @@ -4679,7 +4676,8 @@ register xchar x, y;
  1481.          && shkp->mcanmove && !shkp->msleeping
  1482.          && (ESHK(shkp)->debit || ESHK(shkp)->billct || ESHK(shkp)->robbed)) {
  1483.          pline("%s%s blocks your way!", Shknam(shkp),
  1484. -              Invis ? " senses your motion and" : "");
  1485. +              Invis && !perceives_you(shkp->data) ? " senses your motion and"
  1486. +                                                  : "");
  1487.          return TRUE;
  1488.      }
  1489.      return FALSE;
  1490. @@ -4713,10 +4711,11 @@ register xchar x, y;
  1491.  
  1492.      if (shkp->mx == sx && shkp->my == sy && shkp->mcanmove && !shkp->msleeping
  1493.          && (x == sx - 1 || x == sx + 1 || y == sy - 1 || y == sy + 1)
  1494. -        && (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK)
  1495. -            || u.usteed)) {
  1496. +        && (Invis && !perceives_you(shkp->data) || carrying(PICK_AXE)
  1497. +            || carrying(DWARVISH_MATTOCK) || u.usteed)) {
  1498.          pline("%s%s blocks your way!", Shknam(shkp),
  1499. -              Invis ? " senses your motion and" : "");
  1500. +              Invis && !perceives_you(shkp->data) ? " senses your motion and"
  1501. +                                                  : "");
  1502.          return TRUE;
  1503.      }
  1504.      return FALSE;
  1505. diff --git c/src/shknam.c w/src/shknam.c
  1506. index a36b67e..cb54cc7 100644
  1507. --- c/src/shknam.c
  1508. +++ w/src/shknam.c
  1509. @@ -330,8 +330,9 @@ const struct shclass shtypes[] = {
  1510.        TOOL_CLASS,
  1511.        0,
  1512.        D_SHOP,
  1513. -      { { 30, -WAX_CANDLE },
  1514. -        { 48, -TALLOW_CANDLE },
  1515. +      { { 25, -WAX_CANDLE },
  1516. +        { 38, -TALLOW_CANDLE },
  1517. +        { 15, -GUIDING_CANDLE },
  1518.          { 5, -BRASS_LANTERN },
  1519.          { 9, -OIL_LAMP },
  1520.          { 3, -MAGIC_LAMP },
  1521. diff --git c/src/timeout.c w/src/timeout.c
  1522. index f9df132..c8e136f 100644
  1523. --- c/src/timeout.c
  1524. +++ w/src/timeout.c
  1525. @@ -624,7 +624,7 @@ nh_timeout()
  1526.              case INVIS:
  1527.                  newsym(u.ux, u.uy);
  1528.                  if (!Invis && !BInvis && !Blind) {
  1529. -                    You(!See_invisible
  1530. +                    You(!See_invisible && !candetect(u.ux, u.uy)
  1531.                              ? "are no longer invisible."
  1532.                              : "can no longer see through yourself.");
  1533.                      stop_occupation();
  1534. @@ -1282,6 +1282,7 @@ long timeout;
  1535.      case CANDELABRUM_OF_INVOCATION:
  1536.      case TALLOW_CANDLE:
  1537.      case WAX_CANDLE:
  1538. +    case GUIDING_CANDLE:
  1539.          switch (obj->age) {
  1540.          case 75:
  1541.              if (canseeit)
  1542. @@ -1444,6 +1445,7 @@ boolean already_lit;
  1543.      int radius = 3;
  1544.      long turns = 0;
  1545.      boolean do_timer = TRUE;
  1546. +    boolean detect = FALSE;
  1547.  
  1548.      if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj))
  1549.          return;
  1550. @@ -1476,6 +1478,10 @@ boolean already_lit;
  1551.              turns = obj->age;
  1552.          break;
  1553.  
  1554. +    case GUIDING_CANDLE:
  1555. +        if (!obj->cursed)
  1556. +            detect = TRUE;
  1557. +        /* fall through */
  1558.      case CANDELABRUM_OF_INVOCATION:
  1559.      case TALLOW_CANDLE:
  1560.      case WAX_CANDLE:
  1561. @@ -1494,7 +1500,7 @@ boolean already_lit;
  1562.          if (artifact_light(obj)) {
  1563.              obj->lamplit = 1;
  1564.              do_timer = FALSE;
  1565. -            radius = arti_light_radius(obj);
  1566. +            radius = dynamic_light_radius(obj);
  1567.          } else {
  1568.              impossible("begin burn: unexpected %s", xname(obj));
  1569.              turns = obj->age;
  1570. @@ -1520,7 +1526,9 @@ boolean already_lit;
  1571.          xchar x, y;
  1572.  
  1573.          if (get_obj_location(obj, &x, &y, CONTAINED_TOO | BURIED_TOO))
  1574. -            new_light_source(x, y, radius, LS_OBJECT, obj_to_any(obj));
  1575. +            new_light_source(x, y, radius,
  1576. +                             detect ? LS_OBJECT | LS_DETECT : LS_OBJECT,
  1577. +                             obj_to_any(obj));
  1578.          else
  1579.              impossible("begin_burn: can't get obj position");
  1580.      }
  1581. diff --git c/src/trap.c w/src/trap.c
  1582. index b6db811..c945b3e 100644
  1583. --- c/src/trap.c
  1584. +++ w/src/trap.c
  1585. @@ -411,7 +411,8 @@ int x, y, typ;
  1586.                          && !context.mon_moving)
  1587.                             ? SHOP_HOLE_COST
  1588.                             : 0L);
  1589. -        lev->doormask = 0;     /* subsumes altarmask, icedpool... */
  1590. +        if (lev->typ != ROOM && lev->typ != CORR)
  1591. +            lev->doormask = 0; /* subsumes altarmask, icedpool... */
  1592.          if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */
  1593.              lev->typ = ROOM;
  1594.          /*
  1595. @@ -488,7 +489,7 @@ unsigned ftflags;
  1596.      if (Sokoban && Can_fall_thru(&u.uz))
  1597.          ; /* KMH -- You can't escape the Sokoban level traps */
  1598.      else if (Levitation || u.ustuck
  1599. -             || (!Can_fall_thru(&u.uz) && !levl[u.ux][u.uy].candig)
  1600. +             || !Can_fall_thru(&u.uz)
  1601.               || ((Flying || is_clinger(youmonst.data)
  1602.                    || (ceiling_hider(youmonst.data) && u.uundetected))
  1603.                   && !(ftflags & TOOKPLUNGE))
  1604. diff --git c/src/uhitm.c w/src/uhitm.c
  1605. index 2eedb18..2326d19 100644
  1606. --- c/src/uhitm.c
  1607. +++ w/src/uhitm.c
  1608. @@ -3065,7 +3065,7 @@ struct monst *mtmp;
  1609.  
  1610.          /* cloned Wiz starts out mimicking some other monster and
  1611.             might make himself invisible before being revealed */
  1612. -        if (mtmp->minvis && !See_invisible)
  1613. +        if (minvisible(mtmp) && !See_invisible)
  1614.              what = generic;
  1615.          else
  1616.              what = a_monnam(mtmp);
  1617. diff --git c/src/vision.c w/src/vision.c
  1618. index b8ce2e5..c4f968f 100644
  1619. --- c/src/vision.c
  1620. +++ w/src/vision.c
  1621. @@ -513,6 +513,7 @@ int control;
  1622.      int dx, dy;        /* one step from a lit door or lit wall (see below) */
  1623.      register int col;  /* inner loop counter */
  1624.      register struct rm *lev; /* pointer to current pos */
  1625. +    struct obj *otmp;  /* for iterating through inventory */
  1626.      struct rm *flev; /* pointer to position in "front" of current pos */
  1627.      extern unsigned char seenv_matrix[3][3]; /* from display.c */
  1628.      static unsigned char colbump[COLNO + 1]; /* cols to bump sv */
  1629. @@ -570,6 +571,18 @@ int control;
  1630.                      newsym(col, row);
  1631.          }
  1632.  
  1633. +        /* Check if the invisible hero can be seen because of their guiding
  1634. +         * candle (normally would be checked below).  We don't check for
  1635. +         * nearby candles (on the ground or held by monsters) because that's
  1636. +         * too much effort for too rare an occurence.
  1637. +         */
  1638. +        for (otmp = invent; otmp; otmp = otmp->nobj)
  1639. +            if (otmp->otyp == GUIDING_CANDLE
  1640. +                && otmp->lamplit && !otmp->cursed) {
  1641. +                viz_array[u.uy][u.ux] |= TEMP_DETECT;
  1642. +                break;
  1643. +            }
  1644. +
  1645.          /* skip the normal update loop */
  1646.          goto skip;
  1647.      } else if (Is_rogue_level(&u.uz)) {
  1648. @@ -737,8 +750,10 @@ int control;
  1649.                  lev->seenv |=
  1650.                      new_angle(lev, sv, row, col); /* update seen angle */
  1651.  
  1652. -                /* Update pos if previously not in sight or new angle. */
  1653. -                if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv)
  1654. +                /* Update pos if previously not in sight or new angle
  1655. +                 * or when entering/leaving the radius of guiding candle. */
  1656. +                if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv
  1657. +                    || (old_row[col] ^ next_row[col]) & TEMP_DETECT)
  1658.                      newsym(col, row);
  1659.  
  1660.              } else if ((next_row[col] & COULD_SEE)
  1661. @@ -766,9 +781,11 @@ int control;
  1662.                          lev->seenv |= new_angle(lev, sv, row, col);
  1663.  
  1664.                          /* Update pos if previously not in sight or new
  1665. -                         * angle.*/
  1666. +                         * angle or when entering/leaving the radius of
  1667. +                         * guiding candle. */
  1668.                          if (!(old_row[col] & IN_SIGHT)
  1669. -                            || oldseenv != lev->seenv)
  1670. +                            || oldseenv != lev->seenv
  1671. +                            || (old_row[col] ^ next_row[col]) & TEMP_DETECT)
  1672.                              newsym(col, row);
  1673.                      } else
  1674.                          goto not_in_sight; /* we don't see it */
  1675. @@ -779,8 +796,10 @@ int control;
  1676.                      oldseenv = lev->seenv;
  1677.                      lev->seenv |= new_angle(lev, sv, row, col);
  1678.  
  1679. -                    /* Update pos if previously not in sight or new angle. */
  1680. -                    if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv)
  1681. +                    /* Update pos if previously not in sight or new angle or
  1682. +                     * when entering/leaving the radius of guiding candle. */
  1683. +                    if (!(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv
  1684. +                        || (old_row[col] ^ next_row[col]) & TEMP_DETECT)
  1685.                          newsym(col, row);
  1686.                  }
  1687.              } else if ((next_row[col] & COULD_SEE) && lev->waslit) {
  1688. @@ -2806,7 +2825,7 @@ struct monst *mon;
  1689.      if (useemon && mon->minvis)
  1690.          how_seen |= MONSEEN_SEEINVIS;
  1691.      /* infravision */
  1692. -    if ((!mon->minvis || See_invisible) && see_with_infrared(mon))
  1693. +    if ((!minvisible(mon) || See_invisible) && see_with_infrared(mon))
  1694.          how_seen |= MONSEEN_INFRAVIS;
  1695.      /* telepathy */
  1696.      if (tp_sensemon(mon))
  1697. diff --git c/src/worn.c w/src/worn.c
  1698. index 1a966b7..05328b3 100644
  1699. --- c/src/worn.c
  1700. +++ w/src/worn.c
  1701. @@ -522,7 +522,7 @@ boolean racialexception;
  1702.          return; /* probably putting previous item on */
  1703.  
  1704.      /* Get a copy of monster's name before altering its visibility */
  1705. -    Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon));
  1706. +    Strcpy(nambuf, mon_nam(mon));
  1707.  
  1708.      old = which_armor(mon, flag);
  1709.      if (old && old->cursed)
  1710. @@ -640,7 +640,7 @@ outer_break:
  1711.      update_mon_intrinsics(mon, best, TRUE, creation);
  1712.      /* if couldn't see it but now can, or vice versa, */
  1713.      if (!creation && (unseen ^ !canseemon(mon))) {
  1714. -        if (mon->minvis && !See_invisible) {
  1715. +        if (minvisible(mon) && !See_invisible) {
  1716.              pline("Suddenly you cannot see %s.", nambuf);
  1717.              makeknown(best->otyp);
  1718.          } /* else if (!mon->minvis) pline("%s suddenly appears!",
  1719. diff --git c/src/zap.c w/src/zap.c
  1720. index 1c7a5de..70470c2 100644
  1721. --- c/src/zap.c
  1722. +++ w/src/zap.c
  1723. @@ -3386,7 +3386,7 @@ struct obj **pobj; /* object tossed/used, set to NULL
  1724.                     prepared for multiple hits so just get first one
  1725.                     that's either visible or could see its invisible
  1726.                     self.  [No tmp_at() cleanup is needed here.] */
  1727. -                if (!mtmp->minvis || perceives(mtmp->data)) {
  1728. +                if (!minvisible(mtmp) || perceives(mtmp->data)) {
  1729.                      result = mtmp;
  1730.                      goto bhit_done;
  1731.                  }
Add Comment
Please, Sign In to add comment