]> granicus.if.org Git - nethack/commitdiff
implement #986 - camera flash 'tweak'
authorPatR <rankin@nethack.org>
Sat, 9 May 2020 20:07:35 +0000 (13:07 -0700)
committerPatR <rankin@nethack.org>
Sat, 9 May 2020 20:07:35 +0000 (13:07 -0700)
Implement the suggested feature that a camera's flash actually update
hero's memory of the map as it traverses across the level.  Turned
out to be more work than anticipated despite having the code for a
thrown or kicked lit candle or lamp to build upon.

Among other things it needed to update the circle code to handle
previously unused radius 0 to operate on the center point only.  I've
never touched that before and hope this hasn't introduced any bugs.

Also removes several instances of vision code operating on column #0.
(At least one is still present.)

doc/fixes37.0
include/vision.h
src/apply.c
src/light.c
src/uhitm.c
src/vision.c
src/zap.c

index 7a5d84997595fafdf24f6ed3810ff3291514efd3..72c20003f811657d7d752a07b1c1b0fe970f595e 100644 (file)
@@ -324,6 +324,8 @@ extended achievement and conduct fields for xlogfile
 record amount of gold in hero's possession in xlogfile
 new objects:  amulets of flying and guarding
 new monsters:  displacer beast ('f') and genetic engineer ('Q')
+make camera flash which reveals previously unseen map features or objects or
+       monsters record those on the hero's map; monsters revert to 'unseen'
 
 
 Platform- and/or Interface-Specific New Features
index f0ccd6f054f727197121e47b7f902bdbf1cc8775..8b2b0090c06d64e5da43f5018ddea5f8c2b1abcb 100644 (file)
@@ -52,7 +52,7 @@
 /*
  *  Circle information
  */
-#define MAX_RADIUS 15 /* this is in points from the source */
+#define MAX_RADIUS 16 /* this is in points from the source */
 
 /* Use this macro to get a list of distances of the edges (see vision.c). */
 #define circle_ptr(z) (&circle_data[(int) circle_start[z]])
index 45c2c7b54e0163e919f54488f7e815af52f3356b..856b54ee5fc415b3f0c1d5600b56934e43c37d82 100644 (file)
@@ -75,11 +75,16 @@ struct obj *obj;
             (u.dz > 0) ? surface(u.ux, u.uy) : ceiling(u.ux, u.uy));
     } else if (!u.dx && !u.dy) {
         (void) zapyourself(obj, TRUE);
-    } else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT,
-                            (int FDECL((*), (MONST_P, OBJ_P))) 0,
-                            (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj)) != 0) {
-        obj->ox = u.ux, obj->oy = u.uy;
-        (void) flash_hits_mon(mtmp, obj);
+    } else {
+        mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT,
+                    (int FDECL((*), (MONST_P, OBJ_P))) 0,
+                    (int FDECL((*), (OBJ_P, OBJ_P))) 0, &obj);
+        obj->ox = u.ux, obj->oy = u.uy; /* flash_hits_mon() wants this */
+        if (mtmp)
+            (void) flash_hits_mon(mtmp, obj);
+        /* normally bhit() would do this but for FLASHED_LIGHT we want it
+           to be deferred until after flash_hits_mon() */
+        transient_light_cleanup();
     }
     return 1;
 }
index c34acfcdc580e7db063ccd0dcc4f4fe3a5498e30..26932b40bbf8720b9687b6a4dc75fd860f067504 100644 (file)
@@ -41,6 +41,9 @@
 #define LSF_SHOW 0x1        /* display the light source */
 #define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */
 
+static light_source *FDECL(new_light_core, (XCHAR_P, XCHAR_P, int, int,
+                                            anything *));
+static void NDECL(discard_flashes);
 static void FDECL(write_ls, (NHFILE *, light_source *));
 static int FDECL(maybe_write_ls, (NHFILE *, int, BOOLEAN_P));
 
@@ -49,18 +52,31 @@ extern char circle_data[];
 extern char circle_start[];
 
 
-/* Create a new light source.  */
+/* Create a new light source.  Caller (and extern.h) doesn't need to know
+   anything about type 'light_source'. */
 void
 new_light_source(x, y, range, type, id)
     xchar x, y;
     int range, type;
     anything *id;
+{
+    (void) new_light_core(x, y, range, type, id);
+}
+
+/* Create a new light source and return it.  Only used within this file. */
+static light_source *
+new_light_core(x, y, range, type, id)
+    xchar x, y;
+    int range, type;
+    anything *id;
 {
     light_source *ls;
 
-    if (range > MAX_RADIUS || range < 1) {
-       impossible("new_light_source:  illegal range %d", range);
-       return;
+    if (range > MAX_RADIUS || range < 0
+        /* camera flash uses radius 0 and passes Null object */
+        || (range == 0 && (type != LS_OBJECT || id->a_obj != 0))) {
+        impossible("new_light_source:  illegal range %d", range);
+       return (light_source *) 0;
     }
 
     ls = (light_source *) alloc(sizeof *ls);
@@ -75,6 +91,7 @@ new_light_source(x, y, range, type, id)
     g.light_base = ls;
 
     g.vision_full_recalc = 1; /* make the source show up */
+    return ls;
 }
 
 /*
@@ -95,7 +112,7 @@ anything *id;
        (in particular: chameleon vs prot. from shape changers) */
     switch (type) {
     case LS_OBJECT:
-        tmp_id.a_uint = id->a_obj->o_id;
+        tmp_id.a_uint = id->a_obj ? id->a_obj->o_id : 0;
         break;
     case LS_MONSTER:
         tmp_id.a_uint = id->a_monst->m_id;
@@ -145,7 +162,8 @@ char **cs_rows;
          * vision recalc.
          */
         if (ls->type == LS_OBJECT) {
-            if (get_obj_location(ls->id.a_obj, &ls->x, &ls->y, 0))
+            if (ls->range == 0 /* camera flash; caller has set ls->{x,y} */
+                || get_obj_location(ls->id.a_obj, &ls->x, &ls->y, 0))
                 ls->flags |= LSF_SHOW;
         } else if (ls->type == LS_MONSTER) {
             if (get_mon_location(ls->id.a_monst, &ls->x, &ls->y, 0))
@@ -177,8 +195,8 @@ char **cs_rows;
             for (; y <= max_y; y++) {
                 row = cs_rows[y];
                 offset = limits[abs(y - ls->y)];
-                if ((min_x = (ls->x - offset)) < 0)
-                    min_x = 0;
+                if ((min_x = (ls->x - offset)) < 1)
+                    min_x = 1;
                 if ((max_x = (ls->x + offset)) >= COLNO)
                     max_x = COLNO - 1;
 
@@ -210,62 +228,94 @@ char **cs_rows;
 
 /* lit 'obj' has been thrown or kicked and is passing through x,y on the
    way to its destination; show its light so that hero has a chance to
-   remember terrain, objects, and monsters being revealed */
+   remember terrain, objects, and monsters being revealed;
+   if 'obj' is Null, <x,y> is being hit by a camera's light flash */
 void
 show_transient_light(obj, x, y)
 struct obj *obj;
 int x, y;
 {
-    light_source *ls;
+    light_source *ls = 0;
+    anything cameraflash;
     struct monst *mon;
     int radius_squared;
 
-    /* caller has verified obj->lamplit and that hero is not Blind;
-       validate light source and obtain its radius (for monster sightings) */
-    for (ls = g.light_base; ls; ls = ls->next) {
-        if (ls->type != LS_OBJECT)
-            continue;
-        if (ls->id.a_obj == obj)
-            break;
+    /* Null object indicates camera flash */
+    if (!obj) {
+        /* no need to temporarily light an already lit spot */
+        if (levl[x][y].lit)
+            return;
+
+        cameraflash = cg.zeroany;
+        /* radius 0 will just light <x,y>; cameraflash.a_obj is Null */
+        ls = new_light_core(x, y, 0, LS_OBJECT, &cameraflash);
+    } else {
+        /* thrown or kicked object which is emitting light; validate its
+           light source to obtain its radius (for monster sightings) */
+        for (ls = g.light_base; ls; ls = ls->next) {
+            if (ls->type != LS_OBJECT)
+                continue;
+            if (ls->id.a_obj == obj)
+                break;
+        }
     }
-    if (!ls || obj->where != OBJ_FREE) {
+    if (!ls || (obj && obj->where != OBJ_FREE)) {
         impossible("transient light %s %s is not %s?",
                    obj->lamplit ? "lit" : "unlit", xname(obj),
                    !ls ? "a light source" : "free");
-    } else {
-        /* "expensive" but rare */
-        place_object(obj, g.bhitpos.x, g.bhitpos.y); /* temporarily put on map */
-        vision_recalc(0);
-        flush_screen(0);
-        delay_output();
-        remove_object(obj); /* take back off of map */
+        return;
+    }
 
-        radius_squared = ls->range * ls->range;
-        for (mon = fmon; mon; mon = mon->nmon) {
-            if (DEADMONSTER(mon))
-                continue;
-            /* light range is the radius of a circle and we're limiting
-               canseemon() to a square exclosing that circle, but setting
-               mtemplit 'erroneously' for a seen monster is not a problem;
-               it just flags monsters for another canseemon() check when
-               'obj' has reached its destination after missile traversal */
-            if (dist2(mon->mx, mon->my, x, y) <= radius_squared
-                && canseemon(mon))
+    if (obj) /* put lit candle or lamp temporarily on the map */
+        place_object(obj, g.bhitpos.x, g.bhitpos.y);
+    else /* camera flash:  no object; directly set light source's location */
+        ls->x = x, ls->y = y;
+
+    /* full recalc; runs do_light_sources() */
+    vision_recalc(0);
+    flush_screen(0);
+
+    radius_squared = ls->range * ls->range;
+    for (mon = fmon; mon; mon = mon->nmon) {
+        if (DEADMONSTER(mon) || (mon->isgd && !mon->mx))
+            continue;
+        /* light range is the radius of a circle and we're limiting
+           canseemon() to a square exclosing that circle, but setting
+           mtemplit 'erroneously' for a seen monster is not a problem;
+           it just flags monsters for another canseemon() check when
+           'obj' has reached its destination after missile traversal */
+        if (dist2(mon->mx, mon->my, x, y) <= radius_squared) {
+            if (canseemon(mon))
                 mon->mtemplit = 1;
-            /* [what about worm tails?] */
         }
+        /* [what about worm tails?] */
+    }
+
+    if (obj) { /* take thrown/kicked candle or lamp off the map */
+        delay_output();
+        remove_object(obj);
     }
 }
 
-/* draw "remembered, unseen monster" glyph at locations where a monster
-   was flagged for being visible during transient light movement but can't
-   be seen now */
+/* delete any camera flash light sources and draw "remembered, unseen
+   monster" glyph at locations where a monster was flagged for being
+   visible during transient light movement but can't be seen now */
 void
 transient_light_cleanup()
 {
     struct monst *mon;
-    int mtempcount = 0;
+    int mtempcount;
+
+    /* in case we're cleaning up a camera flash, remove all object light
+       sources which aren't associated with a specific object */
+    discard_flashes();
+    if (g.vision_full_recalc) /* set by del_light_source() */
+        vision_recalc(0);
 
+    /* for thrown/kicked candle or lamp or for camera flash, some
+       monsters may have been mapped in light which has now gone away
+       so need to be replaced by "remembered, unseen monster" glyph */
+    mtempcount = 0;
     for (mon = fmon; mon; mon = mon->nmon) {
         if (DEADMONSTER(mon))
             continue;
@@ -276,9 +326,22 @@ transient_light_cleanup()
                 map_invisible(mon->mx, mon->my);
         }
     }
-    if (mtempcount) {
-        vision_recalc(0);
+    if (mtempcount)
         flush_screen(0);
+}
+
+/* camera flashes have Null object; caller wants to get rid of them now */
+static void
+discard_flashes()
+{
+    light_source *ls, *nxt_ls;
+
+    for (ls = g.light_base; ls; ls = nxt_ls) {
+        nxt_ls = ls->next;
+        if (ls->type != LS_OBJECT)
+            continue;
+        if (!ls->id.a_obj)
+            del_light_source(LS_OBJECT, &ls->id);
     }
 }
 
@@ -318,6 +381,13 @@ int range;
     int count, actual, is_global;
     light_source **prev, *curr;
 
+    /* camera flash light sources have Null object and would trigger
+       impossible("no id!") below; they can only happen here if we're
+       in the midst of a panic save and they wouldn't be useful after
+       restore so just throw any that are present away */
+    discard_flashes();
+    g.vision_full_recalc = 0;
+
     if (perform_bwrite(nhfp)) {
         count = maybe_write_ls(nhfp, range, FALSE);
         if (nhfp->structlevel) {
@@ -330,7 +400,7 @@ int range;
     }
     
      if (release_data(nhfp)) {
-        for (prev = &g.light_base; (curr = *prev) != 0;) {
+        for (prev = &g.light_base; (curr = *prev) != 0; ) {
             if (!curr->id.a_monst) {
                 impossible("save_light_sources: no id! [range=%d]", range);
                 is_global = 0;
index 0b9b22c47ee399c1caa18b11883d17a66162e5f2..74a48641b610596c30ec3ef5b810521f51cf3656 100644 (file)
@@ -3110,14 +3110,21 @@ struct monst *mon;
     u.umconf--;
 }
 
+/* returns 1 if light flash has noticeable effect on 'mtmp', 0 otherwise */
 int
 flash_hits_mon(mtmp, otmp)
 struct monst *mtmp;
 struct obj *otmp; /* source of flash */
 {
-    int tmp, amt, res = 0, useeit = canseemon(mtmp);
+    struct rm *lev;
+    int tmp, amt, useeit, res = 0;
 
-    if (mtmp->msleeping) {
+    if (g.notonhead)
+        return 0;
+    lev = &levl[mtmp->mx][mtmp->my];
+    useeit = canseemon(mtmp);
+
+    if (mtmp->msleeping && haseyes(mtmp->data)) {
         mtmp->msleeping = 0;
         if (useeit) {
             pline_The("flash awakens %s.", mon_nam(mtmp));
@@ -3144,8 +3151,19 @@ struct obj *otmp; /* source of flash */
                 mtmp->mcansee = 0;
                 mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50 / tmp);
             }
+        } else if (flags.verbose && useeit) {
+            if (lev->lit)
+                pline("The flash of light shines on %s.", mon_nam(mtmp));
+            else
+                pline("%s is illuminated.", Monnam(mtmp));
+            res = 2; /* 'message has been given' temporary value */
         }
     }
+    if (res) {
+        if (!lev->lit)
+            display_nhwindow(WIN_MESSAGE, TRUE);
+        res &= 1; /* change temporary 2 back to 0 */
+    }
     return res;
 }
 
index fb3c589beed14ddd70c61a162eea4951ae834f94..2d9f8bd2461810b5c7bc567f1c9d4c587c4e8033 100644 (file)
  *
  */
 const char circle_data[] = {
-    /*  0*/ 1,  1,
-    /*  2*/ 2,  2,  1,
-    /*  5*/ 3,  3,  2,  1,
-    /*  9*/ 4,  4,  4,  3,  2,
-    /* 14*/ 5,  5,  5,  4,  3,  2,
-    /* 20*/ 6,  6,  6,  5,  5,  4,  2,
-    /* 27*/ 7,  7,  7,  6,  6,  5,  4,  2,
-    /* 35*/ 8,  8,  8,  7,  7,  6,  6,  4,  2,
-    /* 44*/ 9,  9,  9,  9,  8,  8,  7,  6,  5,  3,
-    /* 54*/ 10, 10, 10, 10, 9,  9,  8,  7,  6,  5,  3,
-    /* 65*/ 11, 11, 11, 11, 10, 10, 9,  9,  8,  7,  5,  3,
-    /* 77*/ 12, 12, 12, 12, 11, 11, 10, 10, 9,  8,  7,  5,  3,
-    /* 90*/ 13, 13, 13, 13, 12, 12, 12, 11, 10, 10, 9,  7,  6, 3,
-    /*104*/ 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 10, 9,  8, 6, 3,
-    /*119*/ 15, 15, 15, 15, 14, 14, 14, 13, 13, 12, 11, 10, 9, 8, 6, 3,
-    /*135*/ 16 /* MAX_RADIUS+1; used to terminate range loops -dlc */
+    /*  0*/ 0,
+    /*  1*/ 1,  1,
+    /*  3*/ 2,  2,  1,
+    /*  6*/ 3,  3,  2,  1,
+    /* 10*/ 4,  4,  4,  3,  2,
+    /* 15*/ 5,  5,  5,  4,  3,  2,
+    /* 21*/ 6,  6,  6,  5,  5,  4,  2,
+    /* 28*/ 7,  7,  7,  6,  6,  5,  4,  2,
+    /* 36*/ 8,  8,  8,  7,  7,  6,  6,  4,  2,
+    /* 45*/ 9,  9,  9,  9,  8,  8,  7,  6,  5,  3,
+    /* 55*/ 10, 10, 10, 10, 9,  9,  8,  7,  6,  5,  3,
+    /* 66*/ 11, 11, 11, 11, 10, 10, 9,  9,  8,  7,  5,  3,
+    /* 78*/ 12, 12, 12, 12, 11, 11, 10, 10, 9,  8,  7,  5,  3,
+    /* 91*/ 13, 13, 13, 13, 12, 12, 12, 11, 10, 10, 9,  7,  6, 3,
+    /*105*/ 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 10, 9,  8, 6, 3,
+    /*120*/ 15, 15, 15, 15, 14, 14, 14, 13, 13, 12, 11, 10, 9, 8, 6, 3,
+    /*136*/ 16 /* MAX_RADIUS+1; used to terminate range loops -dlc */
 };
 
 /*
  * These are the starting indexes into the circle_data[] array for a
- * circle of a given radius.
+ * circle of a given radius.  Radius 0 used to be unused, but is now
+ * used for a single point:  temporary light source of a camera flash
+ * as it traverses its path.
  */
 const char circle_start[] = {
-    /*  */ 0, /* circles of radius zero are not used */
-    /* 1*/ 0,
-    /* 2*/ 2,
-    /* 3*/ 5,
-    /* 4*/ 9,
-    /* 5*/ 14,
-    /* 6*/ 20,
-    /* 7*/ 27,
-    /* 8*/ 35,
-    /* 9*/ 44,
-    /*10*/ 54,
-    /*11*/ 65,
-    /*12*/ 77,
-    /*13*/ 90,
-    /*14*/ 104,
-    /*15*/ 119,
+    /* 0*/ 0,
+    /* 1*/ 1,
+    /* 2*/ 3,
+    /* 3*/ 6,
+    /* 4*/ 10,
+    /* 5*/ 15,
+    /* 6*/ 21,
+    /* 7*/ 38,
+    /* 8*/ 36,
+    /* 9*/ 45,
+    /*10*/ 55,
+    /*11*/ 66,
+    /*12*/ 78,
+    /*13*/ 91,
+    /*14*/ 105,
+    /*15*/ 120,
 };
 
 /*==========================================================================*/
@@ -263,11 +266,10 @@ char **rmin, **rmax;
     nrmin = *rmin;
     nrmax = *rmax;
 
-    (void) memset((genericptr_t) * *rows, 0,
-                  ROWNO * COLNO);       /* we see nothing */
+    (void) memset((genericptr_t) **rows, 0, ROWNO * COLNO); /* see nothing */
     for (row = 0; row < ROWNO; row++) { /* set row min & max */
         *nrmin++ = COLNO - 1;
-        *nrmax++ = 0;
+        *nrmax++ = 1;
     }
 }
 
@@ -490,23 +492,23 @@ void
 vision_recalc(control)
 int control;
 {
+    extern unsigned char seenv_matrix[3][3]; /* from display.c */
+    static unsigned char colbump[COLNO + 1]; /* cols to bump sv */
     char **temp_array; /* points to the old vision array */
     char **next_array; /* points to the new vision array */
     char *next_row;    /* row pointer for the new array */
     char *old_row;     /* row pointer for the old array */
     char *next_rmin;   /* min pointer for the new array */
     char *next_rmax;   /* max pointer for the new array */
-    const char *ranges;      /* circle ranges -- used for xray & night vision */
+    const char *ranges; /* circle ranges -- used for xray & night vision */
     int row = 0;       /* row counter (outer loop)  */
     int start, stop;   /* inner loop starting/stopping index */
     int dx, dy;        /* one step from a lit door or lit wall (see below) */
     register int col;  /* inner loop counter */
     register struct rm *lev; /* pointer to current pos */
-    struct rm *flev; /* pointer to position in "front" of current pos */
-    extern unsigned char seenv_matrix[3][3]; /* from display.c */
-    static unsigned char colbump[COLNO + 1]; /* cols to bump sv */
-    unsigned char *sv;                       /* ptr to seen angle bits */
-    int oldseenv;                            /* previous seenv value */
+    struct rm *flev;   /* pointer to position in "front" of current pos */
+    unsigned char *sv; /* ptr to seen angle bits */
+    int oldseenv;      /* previous seenv value */
 
     g.vision_full_recalc = 0; /* reset flag */
     if (g.in_mklev || !iflags.vision_inited)
@@ -532,7 +534,6 @@ int control;
          *
          *      + Monsters to see with the "new" vision, even on the rogue
          *        level.
-         *
          *      + Monsters can see you even when you're in a pit.
          */
         view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, 0,
@@ -564,7 +565,7 @@ int control;
     } else if (Is_rogue_level(&u.uz)) {
         rogue_vision(next_array, next_rmin, next_rmax);
     } else {
-        int has_night_vision = 1; /* hero has night vision */
+        int lo_col, has_night_vision = 1; /* hero has night vision */
 
         if (Underwater && !Is_waterlevel(&u.uz)) {
             /*
@@ -574,8 +575,9 @@ int control;
              */
             has_night_vision = 0;
 
+            lo_col = max(u.ux - 1, 1);
             for (row = u.uy - 1; row <= u.uy + 1; row++)
-                for (col = u.ux - 1; col <= u.ux + 1; col++) {
+                for (col = lo_col; col <= u.ux + 1; col++) {
                     if (!isok(col, row) || !is_pool(col, row))
                         continue;
 
@@ -592,7 +594,7 @@ int control;
                 if (row >= ROWNO)
                     break;
 
-                next_rmin[row] = max(0, u.ux - 1);
+                next_rmin[row] = max(1, u.ux - 1);
                 next_rmax[row] = min(COLNO - 1, u.ux + 1);
                 next_row = next_array[row];
 
@@ -620,11 +622,12 @@ int control;
                     dy = v_abs(u.uy - row);
                     next_row = next_array[row];
 
-                    start = max(0, u.ux - ranges[dy]);
+                    start = max(1, u.ux - ranges[dy]);
                     stop = min(COLNO - 1, u.ux + ranges[dy]);
 
                     for (col = start; col <= stop; col++) {
                         char old_row_val = next_row[col];
+
                         next_row[col] |= IN_SIGHT;
                         oldseenv = levl[col][row].seenv;
                         levl[col][row].seenv = SVALL; /* see all! */
@@ -663,7 +666,7 @@ int control;
                     dy = v_abs(u.uy - row);
                     next_row = next_array[row];
 
-                    start = max(0, u.ux - ranges[dy]);
+                    start = max(1, u.ux - ranges[dy]);
                     stop = min(COLNO - 1, u.ux + ranges[dy]);
 
                     for (col = start; col <= stop; col++)
index 64e642e16fca5c0f17399b5a2f78aa86b9dc58d4..158f542c2dc0e2bb3963905da5997d3d1bab418e 100644 (file)
--- a/src/zap.c
+++ b/src/zap.c
@@ -3320,6 +3320,8 @@ struct obj **pobj; /* object tossed/used, set to NULL
 
         /* iron bars will block anything big enough and break some things */
         if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) {
+            if (obj->lamplit && !Blind)
+                show_transient_light(obj, g.bhitpos.x, g.bhitpos.y);
             if (typ == IRONBARS
                 && hits_bars(pobj, x - ddx, y - ddy, g.bhitpos.x, g.bhitpos.y,
                              point_blank ? 0 : !rn2(5), 1)) {
@@ -3328,9 +3330,11 @@ struct obj **pobj; /* object tossed/used, set to NULL
                 g.bhitpos.x -= ddx;
                 g.bhitpos.y -= ddy;
                 break;
-            } else if (obj->lamplit && !Blind) {
-                show_transient_light(obj, g.bhitpos.x, g.bhitpos.y);
             }
+        } else if (weapon == FLASHED_LIGHT) {
+            if (!Blind)
+                show_transient_light((struct obj *) 0,
+                                     g.bhitpos.x, g.bhitpos.y);
         }
 
         if (weapon == ZAPPED_WAND && find_drawbridge(&x, &y)) {
@@ -3546,6 +3550,8 @@ struct obj **pobj; /* object tossed/used, set to NULL
         pay_for_damage("destroy", FALSE);
 
  bhit_done:
+    /* note: for FLASHED_LIGHT, _caller_ must call transient_light_cleanup()
+       after possibly calling flash_hits_mon() */
     if (weapon == THROWN_WEAPON || weapon == KICKED_WEAPON)
         transient_light_cleanup();