SHARE
TWEET

NetHack guiding candle patch v1.1

a guest Sep 25th, 2019 19 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top