Guest User

NetHack guiding candle patch v1.1

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