OSDN Git Service

[Refactor] #38997 clear_mon_lite() に floor_type * 引数を追加.
[hengband/hengband.git] / src / floor-events.c
index f1d2687..8ecb563 100644 (file)
@@ -1,5 +1,24 @@
 #include "angband.h"
+#include "util.h"
+
+#include "dungeon.h"
+#include "floor.h"
+#include "floor-events.h"
 #include "grid.h"
+#include "monster.h"
+#include "monster-status.h"
+#include "quest.h"
+#include "object-hook.h"
+#include "player-move.h"
+#include "world.h"
+#include "player-effects.h"
+#include "objectkind.h"
+#include "object-ego.h"
+#include "cmd-dump.h"
+#include "view-mainwindow.h"
+
+static bool mon_invis;
+static POSITION mon_fy, mon_fx;
 
 void day_break()
 {
@@ -9,11 +28,11 @@ void day_break()
        if (!p_ptr->wild_mode)
        {
                /* Hack -- Scan the town */
-               for (y = 0; y < cur_hgt; y++)
+               for (y = 0; y < current_floor_ptr->height; y++)
                {
-                       for (x = 0; x < cur_wid; x++)
+                       for (x = 0; x < current_floor_ptr->width; x++)
                        {
-                               grid_type *g_ptr = &grid_array[y][x];
+                               grid_type *g_ptr = &current_floor_ptr->grid_array[y][x];
 
                                /* Assume lit */
                                g_ptr->info |= (CAVE_GLOW);
@@ -21,7 +40,6 @@ void day_break()
                                /* Hack -- Memorize lit grids if allowed */
                                if (view_perma_grids) g_ptr->info |= (CAVE_MARK);
 
-                               /* Hack -- Notice spot */
                                note_spot(y, x);
                        }
                }
@@ -33,7 +51,7 @@ void day_break()
 
        if (p_ptr->special_defense & NINJA_S_STEALTH)
        {
-               if (grid_array[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE);
+               if (current_floor_ptr->grid_array[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(p_ptr, FALSE);
        }
 
 }
@@ -46,11 +64,11 @@ void night_falls(void)
        if (!p_ptr->wild_mode)
        {
                /* Hack -- Scan the town */
-               for (y = 0; y < cur_hgt; y++)
+               for (y = 0; y < current_floor_ptr->height; y++)
                {
-                       for (x = 0; x < cur_wid; x++)
+                       for (x = 0; x < current_floor_ptr->width; x++)
                        {
-                               grid_type *g_ptr = &grid_array[y][x];
+                               grid_type *g_ptr = &current_floor_ptr->grid_array[y][x];
 
                                /* Feature code (applying "mimic" field) */
                                feature_type *f_ptr = &f_info[get_feat_mimic(g_ptr)];
@@ -66,14 +84,12 @@ void night_falls(void)
                                                /* Forget the normal floor grid */
                                                g_ptr->info &= ~(CAVE_MARK);
 
-                                               /* Hack -- Notice spot */
                                                note_spot(y, x);
                                        }
                                }
                        }
 
-                       /* Glow deep lava and building entrances */
-                       glow_deep_lava_and_bldg();
+                       glow_deep_lava_and_bldg(current_floor_ptr);
                }
        }
 
@@ -83,7 +99,7 @@ void night_falls(void)
 
        if (p_ptr->special_defense & NINJA_S_STEALTH)
        {
-               if (grid_array[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(FALSE);
+               if (current_floor_ptr->grid_array[p_ptr->y][p_ptr->x].info & CAVE_GLOW) set_superstealth(p_ptr, FALSE);
        }
 
 }
@@ -92,18 +108,18 @@ void night_falls(void)
  * @brief 現在フロアに残っている敵モンスターの数を返す /
  * @return 現在の敵モンスターの数
  */
-MONSTER_NUMBER count_all_hostile_monsters(void)
+MONSTER_NUMBER count_all_hostile_monsters(floor_type *floor_ptr)
 {
        POSITION x, y;
        MONSTER_NUMBER number_mon = 0;
 
-       for (x = 0; x < cur_wid; ++x)
+       for (x = 0; x < floor_ptr->width; ++x)
        {
-               for (y = 0; y < cur_hgt; ++y)
+               for (y = 0; y < floor_ptr->height; ++y)
                {
-                       MONSTER_IDX m_idx = grid_array[y][x].m_idx;
+                       MONSTER_IDX m_idx = floor_ptr->grid_array[y][x].m_idx;
 
-                       if (m_idx > 0 && is_hostile(&m_list[m_idx]))
+                       if (m_idx > 0 && is_hostile(&floor_ptr->m_list[m_idx]))
                        {
                                ++number_mon;
                        }
@@ -113,3 +129,1700 @@ MONSTER_NUMBER count_all_hostile_monsters(void)
        return number_mon;
 }
 
+
+
+/*!
+ * ダンジョンの雰囲気を計算するための非線形基準値 / Dungeon rating is no longer linear
+ */
+#define RATING_BOOST(delta) (delta * delta + 50 * delta)
+
+ /*!
+  * @brief ダンジョンの雰囲気を算出する。
+  * / Examine all monsters and unidentified objects, and get the feeling of current dungeon floor
+  * @return 算出されたダンジョンの雰囲気ランク
+  */
+byte get_dungeon_feeling(floor_type *floor_ptr)
+{
+       const int base = 10;
+       int rating = 0;
+       MONSTER_IDX i;
+
+       /* Hack -- no feeling in the town */
+       if (!floor_ptr->dun_level) return 0;
+
+       /* Examine each monster */
+       for (i = 1; i < floor_ptr->m_max; i++)
+       {
+               monster_type *m_ptr = &floor_ptr->m_list[i];
+               monster_race *r_ptr;
+               int delta = 0;
+               if (!monster_is_valid(m_ptr)) continue;
+
+               if (is_pet(m_ptr)) continue;
+
+               r_ptr = &r_info[m_ptr->r_idx];
+
+               if (r_ptr->flags1 & (RF1_UNIQUE))
+               {
+                       /* Nearly out-of-depth unique monsters */
+                       if (r_ptr->level + 10 > floor_ptr->dun_level)
+                       {
+                               /* Boost rating by twice delta-depth */
+                               delta += (r_ptr->level + 10 - floor_ptr->dun_level) * 2 * base;
+                       }
+               }
+               else
+               {
+                       /* Out-of-depth monsters */
+                       if (r_ptr->level > floor_ptr->dun_level)
+                       {
+                               /* Boost rating by delta-depth */
+                               delta += (r_ptr->level - floor_ptr->dun_level) * base;
+                       }
+               }
+
+               /* Unusually crowded monsters get a little bit of rating boost */
+               if (r_ptr->flags1 & RF1_FRIENDS)
+               {
+                       if (5 <= get_monster_crowd_number(i)) delta += 1;
+               }
+               else
+               {
+                       if (2 <= get_monster_crowd_number(i)) delta += 1;
+               }
+
+
+               rating += RATING_BOOST(delta);
+       }
+
+       /* Examine each unidentified object */
+       for (i = 1; i < floor_ptr->o_max; i++)
+       {
+               object_type *o_ptr = &floor_ptr->o_list[i];
+               object_kind *k_ptr = &k_info[o_ptr->k_idx];
+               int delta = 0;
+
+               if (!OBJECT_IS_VALID(o_ptr)) continue;
+
+               /* Skip known objects */
+               if (object_is_known(o_ptr))
+               {
+                       /* Touched? */
+                       if (o_ptr->marked & OM_TOUCHED) continue;
+               }
+
+               /* Skip pseudo-known objects */
+               if (o_ptr->ident & IDENT_SENSE) continue;
+
+               /* Ego objects */
+               if (object_is_ego(o_ptr))
+               {
+                       ego_item_type *e_ptr = &e_info[o_ptr->name2];
+
+                       delta += e_ptr->rating * base;
+               }
+
+               /* Artifacts */
+               if (object_is_artifact(o_ptr))
+               {
+                       PRICE cost = object_value_real(o_ptr);
+
+                       delta += 10 * base;
+                       if (cost > 10000L) delta += 10 * base;
+                       if (cost > 50000L) delta += 10 * base;
+                       if (cost > 100000L) delta += 10 * base;
+
+                       /* Special feeling */
+                       if (!preserve_mode) return 1;
+               }
+
+               if (o_ptr->tval == TV_DRAG_ARMOR) delta += 30 * base;
+               if (o_ptr->tval == TV_SHIELD && o_ptr->sval == SV_DRAGON_SHIELD) delta += 5 * base;
+               if (o_ptr->tval == TV_GLOVES && o_ptr->sval == SV_SET_OF_DRAGON_GLOVES) delta += 5 * base;
+               if (o_ptr->tval == TV_BOOTS && o_ptr->sval == SV_PAIR_OF_DRAGON_GREAVE) delta += 5 * base;
+               if (o_ptr->tval == TV_HELM && o_ptr->sval == SV_DRAGON_HELM) delta += 5 * base;
+               if (o_ptr->tval == TV_RING && o_ptr->sval == SV_RING_SPEED && !object_is_cursed(o_ptr)) delta += 25 * base;
+               if (o_ptr->tval == TV_RING && o_ptr->sval == SV_RING_LORDLY && !object_is_cursed(o_ptr)) delta += 15 * base;
+               if (o_ptr->tval == TV_AMULET && o_ptr->sval == SV_AMULET_THE_MAGI && !object_is_cursed(o_ptr)) delta += 15 * base;
+
+               /* Out-of-depth objects */
+               if (!object_is_cursed(o_ptr) && !object_is_broken(o_ptr) && k_ptr->level > floor_ptr->dun_level)
+               {
+                       /* Rating increase */
+                       delta += (k_ptr->level - floor_ptr->dun_level) * base;
+               }
+
+               rating += RATING_BOOST(delta);
+       }
+
+
+       if (rating > RATING_BOOST(1000)) return 2;
+       if (rating > RATING_BOOST(800)) return 3;
+       if (rating > RATING_BOOST(600)) return 4;
+       if (rating > RATING_BOOST(400)) return 5;
+       if (rating > RATING_BOOST(300)) return 6;
+       if (rating > RATING_BOOST(200)) return 7;
+       if (rating > RATING_BOOST(100)) return 8;
+       if (rating > RATING_BOOST(0)) return 9;
+
+       return 10;
+}
+
+/*!
+ * @brief ダンジョンの雰囲気を更新し、変化があった場合メッセージを表示する
+ * / Update dungeon feeling, and announce it if changed
+ * @return なし
+ */
+void update_dungeon_feeling(floor_type *floor_ptr)
+{
+       byte new_feeling;
+       int quest_num;
+       int delay;
+
+       /* No feeling on the surface */
+       if (!floor_ptr->dun_level) return;
+
+       /* No feeling in the arena */
+       if (p_ptr->phase_out) return;
+
+       /* Extract delay time */
+       delay = MAX(10, 150 - p_ptr->skill_fos) * (150 - floor_ptr->dun_level) * TURNS_PER_TICK / 100;
+
+       /* Not yet felt anything */
+       if (current_world_ptr->game_turn < p_ptr->feeling_turn + delay && !cheat_xtra) return;
+
+       /* Extract quest number (if any) */
+       quest_num = quest_number(floor_ptr->dun_level);
+
+       /* No feeling in a quest */
+       if (quest_num &&
+               (is_fixed_quest_idx(quest_num) &&
+                       !((quest_num == QUEST_OBERON) || (quest_num == QUEST_SERPENT) ||
+                               !(quest[quest_num].flags & QUEST_FLAG_PRESET)))) return;
+
+
+       /* Get new dungeon feeling */
+       new_feeling = get_dungeon_feeling(floor_ptr);
+
+       /* Remember last time updated */
+       p_ptr->feeling_turn = current_world_ptr->game_turn;
+
+       /* No change */
+       if (p_ptr->feeling == new_feeling) return;
+
+       /* Dungeon feeling is changed */
+       p_ptr->feeling = new_feeling;
+
+       /* Announce feeling */
+       do_cmd_feeling(p_ptr);
+
+       select_floor_music();
+
+       /* Update the level indicator */
+       p_ptr->redraw |= (PR_DEPTH);
+
+       if (disturb_minor) disturb(FALSE, FALSE);
+}
+
+
+/*
+ * Glow deep lava and building entrances in the floor
+ */
+void glow_deep_lava_and_bldg(floor_type *floor_ptr)
+{
+       POSITION y, x, yy, xx;
+       DIRECTION i;
+       grid_type *g_ptr;
+
+       /* Not in the darkness dungeon */
+       if (d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS) return;
+
+       for (y = 0; y < floor_ptr->height; y++)
+       {
+               for (x = 0; x < floor_ptr->width; x++)
+               {
+                       g_ptr = &floor_ptr->grid_array[y][x];
+
+                       /* Feature code (applying "mimic" field) */
+
+                       if (have_flag(f_info[get_feat_mimic(g_ptr)].flags, FF_GLOW))
+                       {
+                               for (i = 0; i < 9; i++)
+                               {
+                                       yy = y + ddy_ddd[i];
+                                       xx = x + ddx_ddd[i];
+                                       if (!in_bounds2(yy, xx)) continue;
+                                       floor_ptr->grid_array[yy][xx].info |= CAVE_GLOW;
+                               }
+                       }
+               }
+       }
+
+       /* Update the view and lite */
+       p_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE);
+
+       p_ptr->redraw |= (PR_MAP);
+}
+
+/*
+ * Actually erase the entire "lite" array, redrawing every grid
+ */
+void forget_lite(void)
+{
+       int i;
+       POSITION x, y;
+
+       /* None to forget */
+       if (!current_floor_ptr->lite_n) return;
+
+       /* Clear them all */
+       for (i = 0; i < current_floor_ptr->lite_n; i++)
+       {
+               y = current_floor_ptr->lite_y[i];
+               x = current_floor_ptr->lite_x[i];
+
+               /* Forget "LITE" flag */
+               current_floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE);
+
+               /* lite_spot(y, x); Perhaps don't need? */
+       }
+
+       /* None left */
+       current_floor_ptr->lite_n = 0;
+}
+
+
+
+/*
+ * Update the set of grids "illuminated" by the player's lite.
+ *
+ * This routine needs to use the results of "update_view()"
+ *
+ * Note that "blindness" does NOT affect "torch lite".  Be careful!
+ *
+ * We optimize most lites (all non-artifact lites) by using "obvious"
+ * facts about the results of "small" lite radius, and we attempt to
+ * list the "nearby" grids before the more "distant" ones in the
+ * array of torch-lit grids.
+ *
+ * We assume that "radius zero" lite is in fact no lite at all.
+ *
+ *     Torch     Lantern     Artifacts
+ *     (etc)
+ *                              ***
+ *                 ***         *****
+ *      ***       *****       *******
+ *      *@*       **@**       ***@***
+ *      ***       *****       *******
+ *                 ***         *****
+ *                              ***
+ */
+void update_lite(void)
+{
+       int i;
+       POSITION x, y, min_x, max_x, min_y, max_y;
+       POSITION p = p_ptr->cur_lite;
+       grid_type *g_ptr;
+
+       /*** Special case ***/
+
+#if 0
+       /* Hack -- Player has no lite */
+       if (p <= 0)
+       {
+               /* Forget the old lite */
+               /* forget_lite(); Perhaps don't need? */
+
+               /* Add it to later visual update */
+               cave_redraw_later(&current_floor_ptr->grid_array[p_ptr->y][p_ptr->x], p_ptr->y, p_ptr->x);
+       }
+#endif
+
+       /*** Save the old "lite" grids for later ***/
+
+       /* Clear them all */
+       for (i = 0; i < current_floor_ptr->lite_n; i++)
+       {
+               y = current_floor_ptr->lite_y[i];
+               x = current_floor_ptr->lite_x[i];
+
+               /* Mark the grid as not "lite" */
+               current_floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE);
+
+               /* Mark the grid as "seen" */
+               current_floor_ptr->grid_array[y][x].info |= (CAVE_TEMP);
+
+               /* Add it to the "seen" set */
+               tmp_pos.y[tmp_pos.n] = y;
+               tmp_pos.x[tmp_pos.n] = x;
+               tmp_pos.n++;
+       }
+
+       /* None left */
+       current_floor_ptr->lite_n = 0;
+
+
+       /*** Collect the new "lite" grids ***/
+
+       /* Radius 1 -- torch radius */
+       if (p >= 1)
+       {
+               /* Player grid */
+               cave_lite_hack(p_ptr->y, p_ptr->x);
+
+               /* Adjacent grid */
+               cave_lite_hack(p_ptr->y + 1, p_ptr->x);
+               cave_lite_hack(p_ptr->y - 1, p_ptr->x);
+               cave_lite_hack(p_ptr->y, p_ptr->x + 1);
+               cave_lite_hack(p_ptr->y, p_ptr->x - 1);
+
+               /* Diagonal grids */
+               cave_lite_hack(p_ptr->y + 1, p_ptr->x + 1);
+               cave_lite_hack(p_ptr->y + 1, p_ptr->x - 1);
+               cave_lite_hack(p_ptr->y - 1, p_ptr->x + 1);
+               cave_lite_hack(p_ptr->y - 1, p_ptr->x - 1);
+       }
+
+       /* Radius 2 -- lantern radius */
+       if (p >= 2)
+       {
+               /* South of the player */
+               if (cave_los_bold(p_ptr->y + 1, p_ptr->x))
+               {
+                       cave_lite_hack(p_ptr->y + 2, p_ptr->x);
+                       cave_lite_hack(p_ptr->y + 2, p_ptr->x + 1);
+                       cave_lite_hack(p_ptr->y + 2, p_ptr->x - 1);
+               }
+
+               /* North of the player */
+               if (cave_los_bold(p_ptr->y - 1, p_ptr->x))
+               {
+                       cave_lite_hack(p_ptr->y - 2, p_ptr->x);
+                       cave_lite_hack(p_ptr->y - 2, p_ptr->x + 1);
+                       cave_lite_hack(p_ptr->y - 2, p_ptr->x - 1);
+               }
+
+               /* East of the player */
+               if (cave_los_bold(p_ptr->y, p_ptr->x + 1))
+               {
+                       cave_lite_hack(p_ptr->y, p_ptr->x + 2);
+                       cave_lite_hack(p_ptr->y + 1, p_ptr->x + 2);
+                       cave_lite_hack(p_ptr->y - 1, p_ptr->x + 2);
+               }
+
+               /* West of the player */
+               if (cave_los_bold(p_ptr->y, p_ptr->x - 1))
+               {
+                       cave_lite_hack(p_ptr->y, p_ptr->x - 2);
+                       cave_lite_hack(p_ptr->y + 1, p_ptr->x - 2);
+                       cave_lite_hack(p_ptr->y - 1, p_ptr->x - 2);
+               }
+       }
+
+       /* Radius 3+ -- artifact radius */
+       if (p >= 3)
+       {
+               int d;
+
+               /* Paranoia -- see "LITE_MAX" */
+               if (p > 14) p = 14;
+
+               /* South-East of the player */
+               if (cave_los_bold(p_ptr->y + 1, p_ptr->x + 1))
+               {
+                       cave_lite_hack(p_ptr->y + 2, p_ptr->x + 2);
+               }
+
+               /* South-West of the player */
+               if (cave_los_bold(p_ptr->y + 1, p_ptr->x - 1))
+               {
+                       cave_lite_hack(p_ptr->y + 2, p_ptr->x - 2);
+               }
+
+               /* North-East of the player */
+               if (cave_los_bold(p_ptr->y - 1, p_ptr->x + 1))
+               {
+                       cave_lite_hack(p_ptr->y - 2, p_ptr->x + 2);
+               }
+
+               /* North-West of the player */
+               if (cave_los_bold(p_ptr->y - 1, p_ptr->x - 1))
+               {
+                       cave_lite_hack(p_ptr->y - 2, p_ptr->x - 2);
+               }
+
+               /* Maximal north */
+               min_y = p_ptr->y - p;
+               if (min_y < 0) min_y = 0;
+
+               /* Maximal south */
+               max_y = p_ptr->y + p;
+               if (max_y > current_floor_ptr->height - 1) max_y = current_floor_ptr->height - 1;
+
+               /* Maximal west */
+               min_x = p_ptr->x - p;
+               if (min_x < 0) min_x = 0;
+
+               /* Maximal east */
+               max_x = p_ptr->x + p;
+               if (max_x > current_floor_ptr->width - 1) max_x = current_floor_ptr->width - 1;
+
+               /* Scan the maximal box */
+               for (y = min_y; y <= max_y; y++)
+               {
+                       for (x = min_x; x <= max_x; x++)
+                       {
+                               int dy = (p_ptr->y > y) ? (p_ptr->y - y) : (y - p_ptr->y);
+                               int dx = (p_ptr->x > x) ? (p_ptr->x - x) : (x - p_ptr->x);
+
+                               /* Skip the "central" grids (above) */
+                               if ((dy <= 2) && (dx <= 2)) continue;
+
+                               /* Hack -- approximate the distance */
+                               d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
+
+                               /* Skip distant grids */
+                               if (d > p) continue;
+
+                               /* Viewable, nearby, grids get "torch lit" */
+                               if (current_floor_ptr->grid_array[y][x].info & CAVE_VIEW)
+                               {
+                                       /* This grid is "torch lit" */
+                                       cave_lite_hack(y, x);
+                               }
+                       }
+               }
+       }
+
+
+       /*** Complete the algorithm ***/
+
+       /* Draw the new grids */
+       for (i = 0; i < current_floor_ptr->lite_n; i++)
+       {
+               y = current_floor_ptr->lite_y[i];
+               x = current_floor_ptr->lite_x[i];
+
+               g_ptr = &current_floor_ptr->grid_array[y][x];
+
+               /* Update fresh grids */
+               if (g_ptr->info & (CAVE_TEMP)) continue;
+
+               /* Add it to later visual update */
+               cave_note_and_redraw_later(g_ptr, y, x);
+       }
+
+       /* Clear them all */
+       for (i = 0; i < tmp_pos.n; i++)
+       {
+               y = tmp_pos.y[i];
+               x = tmp_pos.x[i];
+
+               g_ptr = &current_floor_ptr->grid_array[y][x];
+
+               /* No longer in the array */
+               g_ptr->info &= ~(CAVE_TEMP);
+
+               /* Update stale grids */
+               if (g_ptr->info & (CAVE_LITE)) continue;
+
+               /* Add it to later visual update */
+               cave_redraw_later(g_ptr, y, x);
+       }
+
+       /* None left */
+       tmp_pos.n = 0;
+
+       /* Mega-Hack -- Visual update later */
+       p_ptr->update |= (PU_DELAY_VIS);
+}
+
+
+/*
+ * Clear the viewable space
+ */
+void forget_view(void)
+{
+       int i;
+
+       grid_type *g_ptr;
+
+       /* None to forget */
+       if (!current_floor_ptr->view_n) return;
+
+       /* Clear them all */
+       for (i = 0; i < current_floor_ptr->view_n; i++)
+       {
+               POSITION y = current_floor_ptr->view_y[i];
+               POSITION x = current_floor_ptr->view_x[i];
+               g_ptr = &current_floor_ptr->grid_array[y][x];
+
+               /* Forget that the grid is viewable */
+               g_ptr->info &= ~(CAVE_VIEW);
+
+               /* if (!panel_contains(y, x)) continue; */
+
+               /* Update the screen */
+               /* lite_spot(y, x); Perhaps don't need? */
+       }
+
+       /* None left */
+       current_floor_ptr->view_n = 0;
+}
+
+
+
+/*
+ * Helper function for "update_view()" below
+ *
+ * We are checking the "viewability" of grid (y,x) by the player.
+ *
+ * This function assumes that (y,x) is legal (i.e. on the map).
+ *
+ * Grid (y1,x1) is on the "diagonal" between (p_ptr->y,p_ptr->x) and (y,x)
+ * Grid (y2,x2) is "adjacent", also between (p_ptr->y,p_ptr->x) and (y,x).
+ *
+ * Note that we are using the "CAVE_XTRA" field for marking grids as
+ * "easily viewable".  This bit is cleared at the end of "update_view()".
+ *
+ * This function adds (y,x) to the "viewable set" if necessary.
+ *
+ * This function now returns "TRUE" if vision is "blocked" by grid (y,x).
+ */
+static bool update_view_aux(POSITION y, POSITION x, POSITION y1, POSITION x1, POSITION y2, POSITION x2)
+{
+       bool f1, f2, v1, v2, z1, z2, wall;
+
+       grid_type *g_ptr;
+
+       grid_type *g1_c_ptr;
+       grid_type *g2_c_ptr;
+
+       /* Access the grids */
+       g1_c_ptr = &current_floor_ptr->grid_array[y1][x1];
+       g2_c_ptr = &current_floor_ptr->grid_array[y2][x2];
+
+
+       /* Check for walls */
+       f1 = (cave_los_grid(g1_c_ptr));
+       f2 = (cave_los_grid(g2_c_ptr));
+
+       /* Totally blocked by physical walls */
+       if (!f1 && !f2) return (TRUE);
+
+
+       /* Check for visibility */
+       v1 = (f1 && (g1_c_ptr->info & (CAVE_VIEW)));
+       v2 = (f2 && (g2_c_ptr->info & (CAVE_VIEW)));
+
+       /* Totally blocked by "unviewable neighbors" */
+       if (!v1 && !v2) return (TRUE);
+
+       g_ptr = &current_floor_ptr->grid_array[y][x];
+
+
+       /* Check for walls */
+       wall = (!cave_los_grid(g_ptr));
+
+
+       /* Check the "ease" of visibility */
+       z1 = (v1 && (g1_c_ptr->info & (CAVE_XTRA)));
+       z2 = (v2 && (g2_c_ptr->info & (CAVE_XTRA)));
+
+       /* Hack -- "easy" plus "easy" yields "easy" */
+       if (z1 && z2)
+       {
+               g_ptr->info |= (CAVE_XTRA);
+
+               cave_view_hack(g_ptr, y, x);
+
+               return (wall);
+       }
+
+       /* Hack -- primary "easy" yields "viewed" */
+       if (z1)
+       {
+               cave_view_hack(g_ptr, y, x);
+
+               return (wall);
+       }
+
+       /* Hack -- "view" plus "view" yields "view" */
+       if (v1 && v2)
+       {
+               /* g_ptr->info |= (CAVE_XTRA); */
+
+               cave_view_hack(g_ptr, y, x);
+
+               return (wall);
+       }
+
+
+       /* Mega-Hack -- the "los()" function works poorly on walls */
+       if (wall)
+       {
+               cave_view_hack(g_ptr, y, x);
+
+               return (wall);
+       }
+
+
+       /* Hack -- check line of sight */
+       if (los(p_ptr->y, p_ptr->x, y, x))
+       {
+               cave_view_hack(g_ptr, y, x);
+
+               return (wall);
+       }
+
+
+       /* Assume no line of sight. */
+       return (TRUE);
+}
+
+
+/*
+ * Calculate the viewable space
+ *
+ *  1: Process the player
+ *  1a: The player is always (easily) viewable
+ *  2: Process the diagonals
+ *  2a: The diagonals are (easily) viewable up to the first wall
+ *  2b: But never go more than 2/3 of the "full" distance
+ *  3: Process the main axes
+ *  3a: The main axes are (easily) viewable up to the first wall
+ *  3b: But never go more than the "full" distance
+ *  4: Process sequential "strips" in each of the eight octants
+ *  4a: Each strip runs along the previous strip
+ *  4b: The main axes are "previous" to the first strip
+ *  4c: Process both "sides" of each "direction" of each strip
+ *  4c1: Each side aborts as soon as possible
+ *  4c2: Each side tells the next strip how far it has to check
+ *
+ * Note that the octant processing involves some pretty interesting
+ * observations involving when a grid might possibly be viewable from
+ * a given grid, and on the order in which the strips are processed.
+ *
+ * Note the use of the mathematical facts shown below, which derive
+ * from the fact that (1 < sqrt(2) < 1.5), and that the length of the
+ * hypotenuse of a right triangle is primarily determined by the length
+ * of the longest side, when one side is small, and is strictly less
+ * than one-and-a-half times as long as the longest side when both of
+ * the sides are large.
+ *
+ *   if (manhatten(dy,dx) < R) then (hypot(dy,dx) < R)
+ *   if (manhatten(dy,dx) > R*3/2) then (hypot(dy,dx) > R)
+ *
+ *   hypot(dy,dx) is approximated by (dx+dy+MAX(dx,dy)) / 2
+ *
+ * These observations are important because the calculation of the actual
+ * value of "hypot(dx,dy)" is extremely expensive, involving square roots,
+ * while for small values (up to about 20 or so), the approximations above
+ * are correct to within an error of at most one grid or so.
+ *
+ * Observe the use of "full" and "over" in the code below, and the use of
+ * the specialized calculation involving "limit", all of which derive from
+ * the observations given above.  Basically, we note that the "circle" of
+ * view is completely contained in an "octagon" whose bounds are easy to
+ * determine, and that only a few steps are needed to derive the actual
+ * bounds of the circle given the bounds of the octagon.
+ *
+ * Note that by skipping all the grids in the corners of the octagon, we
+ * place an upper limit on the number of grids in the field of view, given
+ * that "full" is never more than 20.  Of the 1681 grids in the "square" of
+ * view, only about 1475 of these are in the "octagon" of view, and even
+ * fewer are in the "circle" of view, so 1500 or 1536 is more than enough
+ * entries to completely contain the actual field of view.
+ *
+ * Note also the care taken to prevent "running off the map".  The use of
+ * explicit checks on the "validity" of the "diagonal", and the fact that
+ * the loops are never allowed to "leave" the map, lets "update_view_aux()"
+ * use the optimized "cave_los_bold()" macro, and to avoid the overhead
+ * of multiple checks on the validity of grids.
+ *
+ * Note the "optimizations" involving the "se","sw","ne","nw","es","en",
+ * "ws","wn" variables.  They work like this: While travelling down the
+ * south-bound strip just to the east of the main south axis, as soon as
+ * we get to a grid which does not "transmit" viewing, if all of the strips
+ * preceding us (in this case, just the main axis) had terminated at or before
+ * the same point, then we can stop, and reset the "max distance" to ourself.
+ * So, each strip (named by major axis plus offset, thus "se" in this case)
+ * maintains a "blockage" variable, initialized during the main axis step,
+ * and checks it whenever a blockage is observed.  After processing each
+ * strip as far as the previous strip told us to process, the next strip is
+ * told not to go farther than the current strip's farthest viewable grid,
+ * unless open space is still available.  This uses the "k" variable.
+ *
+ * Note the use of "inline" macros for efficiency.  The "cave_los_grid()"
+ * macro is a replacement for "cave_los_bold()" which takes a pointer to
+ * a grid instead of its location.  The "cave_view_hack()" macro is a
+ * chunk of code which adds the given location to the "view" array if it
+ * is not already there, using both the actual location and a pointer to
+ * the grid.  See above.
+ *
+ * By the way, the purpose of this code is to reduce the dependancy on the
+ * "los()" function which is slow, and, in some cases, not very accurate.
+ *
+ * It is very possible that I am the only person who fully understands this
+ * function, and for that I am truly sorry, but efficiency was very important
+ * and the "simple" version of this function was just not fast enough.  I am
+ * more than willing to replace this function with a simpler one, if it is
+ * equally efficient, and especially willing if the new function happens to
+ * derive "reverse-line-of-sight" at the same time, since currently monsters
+ * just use an optimized hack of "you see me, so I see you", and then use the
+ * actual "projectable()" function to check spell attacks.
+ */
+void update_view(void)
+{
+       int n, m, d, k, z;
+       POSITION y, x;
+
+       int se, sw, ne, nw, es, en, ws, wn;
+
+       int full, over;
+
+       POSITION y_max = current_floor_ptr->height - 1;
+       POSITION x_max = current_floor_ptr->width - 1;
+
+       grid_type *g_ptr;
+
+       /*** Initialize ***/
+
+       /* Optimize */
+       if (view_reduce_view && !current_floor_ptr->dun_level)
+       {
+               /* Full radius (10) */
+               full = MAX_SIGHT / 2;
+
+               /* Octagon factor (15) */
+               over = MAX_SIGHT * 3 / 4;
+       }
+
+       /* Normal */
+       else
+       {
+               /* Full radius (20) */
+               full = MAX_SIGHT;
+
+               /* Octagon factor (30) */
+               over = MAX_SIGHT * 3 / 2;
+       }
+
+
+       /*** Step 0 -- Begin ***/
+
+       /* Save the old "view" grids for later */
+       for (n = 0; n < current_floor_ptr->view_n; n++)
+       {
+               y = current_floor_ptr->view_y[n];
+               x = current_floor_ptr->view_x[n];
+               g_ptr = &current_floor_ptr->grid_array[y][x];
+
+               /* Mark the grid as not in "view" */
+               g_ptr->info &= ~(CAVE_VIEW);
+
+               /* Mark the grid as "seen" */
+               g_ptr->info |= (CAVE_TEMP);
+
+               /* Add it to the "seen" set */
+               tmp_pos.y[tmp_pos.n] = y;
+               tmp_pos.x[tmp_pos.n] = x;
+               tmp_pos.n++;
+       }
+
+       /* Start over with the "view" array */
+       current_floor_ptr->view_n = 0;
+
+       /*** Step 1 -- adjacent grids ***/
+
+       /* Now start on the player */
+       y = p_ptr->y;
+       x = p_ptr->x;
+       g_ptr = &current_floor_ptr->grid_array[y][x];
+
+       /* Assume the player grid is easily viewable */
+       g_ptr->info |= (CAVE_XTRA);
+
+       /* Assume the player grid is viewable */
+       cave_view_hack(g_ptr, y, x);
+
+
+       /*** Step 2 -- Major Diagonals ***/
+
+       /* Hack -- Limit */
+       z = full * 2 / 3;
+
+       /* Scan south-east */
+       for (d = 1; d <= z; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y + d][x + d];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y + d, x + d);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /* Scan south-west */
+       for (d = 1; d <= z; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y + d][x - d];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y + d, x - d);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /* Scan north-east */
+       for (d = 1; d <= z; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y - d][x + d];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y - d, x + d);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /* Scan north-west */
+       for (d = 1; d <= z; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y - d][x - d];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y - d, x - d);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /*** Step 3 -- major axes ***/
+
+       /* Scan south */
+       for (d = 1; d <= full; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y + d][x];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y + d, x);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /* Initialize the "south strips" */
+       se = sw = d;
+
+       /* Scan north */
+       for (d = 1; d <= full; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y - d][x];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y - d, x);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /* Initialize the "north strips" */
+       ne = nw = d;
+
+       /* Scan east */
+       for (d = 1; d <= full; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y][x + d];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y, x + d);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /* Initialize the "east strips" */
+       es = en = d;
+
+       /* Scan west */
+       for (d = 1; d <= full; d++)
+       {
+               g_ptr = &current_floor_ptr->grid_array[y][x - d];
+               g_ptr->info |= (CAVE_XTRA);
+               cave_view_hack(g_ptr, y, x - d);
+               if (!cave_los_grid(g_ptr)) break;
+       }
+
+       /* Initialize the "west strips" */
+       ws = wn = d;
+
+
+       /*** Step 4 -- Divide each "octant" into "strips" ***/
+
+       /* Now check each "diagonal" (in parallel) */
+       for (n = 1; n <= over / 2; n++)
+       {
+               POSITION ypn, ymn, xpn, xmn;
+
+               /* Acquire the "bounds" of the maximal circle */
+               z = over - n - n;
+               if (z > full - n) z = full - n;
+               while ((z + n + (n >> 1)) > full) z--;
+
+
+               /* Access the four diagonal grids */
+               ypn = y + n;
+               ymn = y - n;
+               xpn = x + n;
+               xmn = x - n;
+
+
+               /* South strip */
+               if (ypn < y_max)
+               {
+                       /* Maximum distance */
+                       m = MIN(z, y_max - ypn);
+
+                       /* East side */
+                       if ((xpn <= x_max) && (n < se))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ypn + d, xpn, ypn + d - 1, xpn - 1, ypn + d - 1, xpn))
+                                       {
+                                               if (n + d >= se) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               se = k + 1;
+                       }
+
+                       /* West side */
+                       if ((xmn >= 0) && (n < sw))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ypn + d, xmn, ypn + d - 1, xmn + 1, ypn + d - 1, xmn))
+                                       {
+                                               if (n + d >= sw) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               sw = k + 1;
+                       }
+               }
+
+
+               /* North strip */
+               if (ymn > 0)
+               {
+                       /* Maximum distance */
+                       m = MIN(z, ymn);
+
+                       /* East side */
+                       if ((xpn <= x_max) && (n < ne))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ymn - d, xpn, ymn - d + 1, xpn - 1, ymn - d + 1, xpn))
+                                       {
+                                               if (n + d >= ne) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               ne = k + 1;
+                       }
+
+                       /* West side */
+                       if ((xmn >= 0) && (n < nw))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ymn - d, xmn, ymn - d + 1, xmn + 1, ymn - d + 1, xmn))
+                                       {
+                                               if (n + d >= nw) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               nw = k + 1;
+                       }
+               }
+
+
+               /* East strip */
+               if (xpn < x_max)
+               {
+                       /* Maximum distance */
+                       m = MIN(z, x_max - xpn);
+
+                       /* South side */
+                       if ((ypn <= x_max) && (n < es))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ypn, xpn + d, ypn - 1, xpn + d - 1, ypn, xpn + d - 1))
+                                       {
+                                               if (n + d >= es) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               es = k + 1;
+                       }
+
+                       /* North side */
+                       if ((ymn >= 0) && (n < en))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ymn, xpn + d, ymn + 1, xpn + d - 1, ymn, xpn + d - 1))
+                                       {
+                                               if (n + d >= en) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               en = k + 1;
+                       }
+               }
+
+
+               /* West strip */
+               if (xmn > 0)
+               {
+                       /* Maximum distance */
+                       m = MIN(z, xmn);
+
+                       /* South side */
+                       if ((ypn <= y_max) && (n < ws))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ypn, xmn - d, ypn - 1, xmn - d + 1, ypn, xmn - d + 1))
+                                       {
+                                               if (n + d >= ws) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               ws = k + 1;
+                       }
+
+                       /* North side */
+                       if ((ymn >= 0) && (n < wn))
+                       {
+                               /* Scan */
+                               for (k = n, d = 1; d <= m; d++)
+                               {
+                                       /* Check grid "d" in strip "n", notice "blockage" */
+                                       if (update_view_aux(ymn, xmn - d, ymn + 1, xmn - d + 1, ymn, xmn - d + 1))
+                                       {
+                                               if (n + d >= wn) break;
+                                       }
+
+                                       /* Track most distant "non-blockage" */
+                                       else
+                                       {
+                                               k = n + d;
+                                       }
+                               }
+
+                               /* Limit the next strip */
+                               wn = k + 1;
+                       }
+               }
+       }
+
+
+       /*** Step 5 -- Complete the algorithm ***/
+
+       /* Update all the new grids */
+       for (n = 0; n < current_floor_ptr->view_n; n++)
+       {
+               y = current_floor_ptr->view_y[n];
+               x = current_floor_ptr->view_x[n];
+               g_ptr = &current_floor_ptr->grid_array[y][x];
+
+               /* Clear the "CAVE_XTRA" flag */
+               g_ptr->info &= ~(CAVE_XTRA);
+
+               /* Update only newly viewed grids */
+               if (g_ptr->info & (CAVE_TEMP)) continue;
+
+               /* Add it to later visual update */
+               cave_note_and_redraw_later(g_ptr, y, x);
+       }
+
+       /* Wipe the old grids, update as needed */
+       for (n = 0; n < tmp_pos.n; n++)
+       {
+               y = tmp_pos.y[n];
+               x = tmp_pos.x[n];
+               g_ptr = &current_floor_ptr->grid_array[y][x];
+
+               /* No longer in the array */
+               g_ptr->info &= ~(CAVE_TEMP);
+
+               /* Update only non-viewable grids */
+               if (g_ptr->info & (CAVE_VIEW)) continue;
+
+               /* Add it to later visual update */
+               cave_redraw_later(g_ptr, y, x);
+       }
+
+       /* None left */
+       tmp_pos.n = 0;
+
+       /* Mega-Hack -- Visual update later */
+       p_ptr->update |= (PU_DELAY_VIS);
+}
+
+
+/*
+ * Add a square to the changes array
+ */
+static void mon_lite_hack(POSITION y, POSITION x)
+{
+       grid_type *g_ptr;
+       int dpf, d;
+       POSITION midpoint;
+
+       /* We trust this grid is in bounds */
+       /* if (!in_bounds2(y, x)) return; */
+
+       g_ptr = &current_floor_ptr->grid_array[y][x];
+
+       /* Want a unlit square in view of the player */
+       if ((g_ptr->info & (CAVE_MNLT | CAVE_VIEW)) != CAVE_VIEW) return;
+
+       if (!cave_los_grid(g_ptr))
+       {
+               /* Hack -- Prevent monster lite leakage in walls */
+
+               /* Horizontal walls between player and a monster */
+               if (((y < p_ptr->y) && (y > mon_fy)) || ((y > p_ptr->y) && (y < mon_fy)))
+               {
+                       dpf = p_ptr->y - mon_fy;
+                       d = y - mon_fy;
+                       midpoint = mon_fx + ((p_ptr->x - mon_fx) * ABS(d)) / ABS(dpf);
+
+                       /* Only first wall viewed from mid-x is lit */
+                       if (x < midpoint)
+                       {
+                               if (!cave_los_bold(y, x + 1)) return;
+                       }
+                       else if (x > midpoint)
+                       {
+                               if (!cave_los_bold(y, x - 1)) return;
+                       }
+
+                       /* Hack XXX XXX - Is it a wall and monster not in LOS? */
+                       else if (mon_invis) return;
+               }
+
+               /* Vertical walls between player and a monster */
+               if (((x < p_ptr->x) && (x > mon_fx)) || ((x > p_ptr->x) && (x < mon_fx)))
+               {
+                       dpf = p_ptr->x - mon_fx;
+                       d = x - mon_fx;
+                       midpoint = mon_fy + ((p_ptr->y - mon_fy) * ABS(d)) / ABS(dpf);
+
+                       /* Only first wall viewed from mid-y is lit */
+                       if (y < midpoint)
+                       {
+                               if (!cave_los_bold(y + 1, x)) return;
+                       }
+                       else if (y > midpoint)
+                       {
+                               if (!cave_los_bold(y - 1, x)) return;
+                       }
+
+                       /* Hack XXX XXX - Is it a wall and monster not in LOS? */
+                       else if (mon_invis) return;
+               }
+       }
+
+       /* We trust tmp_pos.n does not exceed TEMP_MAX */
+
+       /* New grid */
+       if (!(g_ptr->info & CAVE_MNDK))
+       {
+               /* Save this square */
+               tmp_pos.x[tmp_pos.n] = x;
+               tmp_pos.y[tmp_pos.n] = y;
+               tmp_pos.n++;
+       }
+
+       /* Darkened grid */
+       else
+       {
+               /* No longer dark */
+               g_ptr->info &= ~(CAVE_MNDK);
+       }
+
+       /* Light it */
+       g_ptr->info |= CAVE_MNLT;
+}
+
+
+/*
+ * Add a square to the changes array
+ */
+static void mon_dark_hack(POSITION y, POSITION x)
+{
+       grid_type *g_ptr;
+       int       midpoint, dpf, d;
+
+       /* We trust this grid is in bounds */
+       /* if (!in_bounds2(y, x)) return; */
+
+       g_ptr = &current_floor_ptr->grid_array[y][x];
+
+       /* Want a unlit and undarkened square in view of the player */
+       if ((g_ptr->info & (CAVE_LITE | CAVE_MNLT | CAVE_MNDK | CAVE_VIEW)) != CAVE_VIEW) return;
+
+       if (!cave_los_grid(g_ptr) && !cave_have_flag_grid(g_ptr, FF_PROJECT))
+       {
+               /* Hack -- Prevent monster dark lite leakage in walls */
+
+               /* Horizontal walls between player and a monster */
+               if (((y < p_ptr->y) && (y > mon_fy)) || ((y > p_ptr->y) && (y < mon_fy)))
+               {
+                       dpf = p_ptr->y - mon_fy;
+                       d = y - mon_fy;
+                       midpoint = mon_fx + ((p_ptr->x - mon_fx) * ABS(d)) / ABS(dpf);
+
+                       /* Only first wall viewed from mid-x is lit */
+                       if (x < midpoint)
+                       {
+                               if (!cave_los_bold(y, x + 1) && !cave_have_flag_bold(y, x + 1, FF_PROJECT)) return;
+                       }
+                       else if (x > midpoint)
+                       {
+                               if (!cave_los_bold(y, x - 1) && !cave_have_flag_bold(y, x - 1, FF_PROJECT)) return;
+                       }
+
+                       /* Hack XXX XXX - Is it a wall and monster not in LOS? */
+                       else if (mon_invis) return;
+               }
+
+               /* Vertical walls between player and a monster */
+               if (((x < p_ptr->x) && (x > mon_fx)) || ((x > p_ptr->x) && (x < mon_fx)))
+               {
+                       dpf = p_ptr->x - mon_fx;
+                       d = x - mon_fx;
+                       midpoint = mon_fy + ((p_ptr->y - mon_fy) * ABS(d)) / ABS(dpf);
+
+                       /* Only first wall viewed from mid-y is lit */
+                       if (y < midpoint)
+                       {
+                               if (!cave_los_bold(y + 1, x) && !cave_have_flag_bold(y + 1, x, FF_PROJECT)) return;
+                       }
+                       else if (y > midpoint)
+                       {
+                               if (!cave_los_bold(y - 1, x) && !cave_have_flag_bold(y - 1, x, FF_PROJECT)) return;
+                       }
+
+                       /* Hack XXX XXX - Is it a wall and monster not in LOS? */
+                       else if (mon_invis) return;
+               }
+       }
+
+       /* We trust tmp_pos.n does not exceed TEMP_MAX */
+
+       /* Save this square */
+       tmp_pos.x[tmp_pos.n] = x;
+       tmp_pos.y[tmp_pos.n] = y;
+       tmp_pos.n++;
+
+       /* Darken it */
+       g_ptr->info |= CAVE_MNDK;
+}
+
+/*
+ * Update squares illuminated or darkened by monsters.
+ *
+ * Hack - use the CAVE_ROOM flag (renamed to be CAVE_MNLT) to
+ * denote squares illuminated by monsters.
+ *
+ * The CAVE_TEMP and CAVE_XTRA flag are used to store the state during the
+ * updating.  Only squares in view of the player, whos state
+ * changes are drawn via lite_spot().
+ */
+void update_mon_lite(floor_type *floor_ptr)
+{
+       int i, rad;
+       grid_type *g_ptr;
+
+       POSITION fx, fy;
+       void(*add_mon_lite)(POSITION, POSITION);
+       int f_flag;
+
+       s16b end_temp;
+
+       /* Non-Ninja player in the darkness */
+       int dis_lim = ((d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS) && !p_ptr->see_nocto) ?
+               (MAX_SIGHT / 2 + 1) : (MAX_SIGHT + 3);
+
+       /* Clear all monster lit squares */
+       for (i = 0; i < floor_ptr->mon_lite_n; i++)
+       {
+               /* Point to grid */
+               g_ptr = &floor_ptr->grid_array[floor_ptr->mon_lite_y[i]][floor_ptr->mon_lite_x[i]];
+
+               /* Set temp or xtra flag */
+               g_ptr->info |= (g_ptr->info & CAVE_MNLT) ? CAVE_TEMP : CAVE_XTRA;
+
+               /* Clear monster illumination flag */
+               g_ptr->info &= ~(CAVE_MNLT | CAVE_MNDK);
+       }
+
+       /* Empty temp list of new squares to lite up */
+       tmp_pos.n = 0;
+
+       /* If a monster stops time, don't process */
+       if (!current_world_ptr->timewalk_m_idx)
+       {
+               monster_type *m_ptr;
+               monster_race *r_ptr;
+
+               /* Loop through monsters, adding newly lit squares to changes list */
+               for (i = 1; i < floor_ptr->m_max; i++)
+               {
+                       m_ptr = &floor_ptr->m_list[i];
+                       r_ptr = &r_info[m_ptr->r_idx];
+                       if (!monster_is_valid(m_ptr)) continue;
+
+                       /* Is it too far away? */
+                       if (m_ptr->cdis > dis_lim) continue;
+
+                       /* Get lite radius */
+                       rad = 0;
+
+                       /* Note the radii are cumulative */
+                       if (r_ptr->flags7 & (RF7_HAS_LITE_1 | RF7_SELF_LITE_1)) rad++;
+                       if (r_ptr->flags7 & (RF7_HAS_LITE_2 | RF7_SELF_LITE_2)) rad += 2;
+                       if (r_ptr->flags7 & (RF7_HAS_DARK_1 | RF7_SELF_DARK_1)) rad--;
+                       if (r_ptr->flags7 & (RF7_HAS_DARK_2 | RF7_SELF_DARK_2)) rad -= 2;
+
+                       /* Exit if has no light */
+                       if (!rad) continue;
+                       else if (rad > 0)
+                       {
+                               if (!(r_ptr->flags7 & (RF7_SELF_LITE_1 | RF7_SELF_LITE_2)) && (MON_CSLEEP(m_ptr) || (!floor_ptr->dun_level && is_daytime()) || p_ptr->phase_out)) continue;
+                               if (d_info[p_ptr->dungeon_idx].flags1 & DF1_DARKNESS) rad = 1;
+                               add_mon_lite = mon_lite_hack;
+                               f_flag = FF_LOS;
+                       }
+                       else
+                       {
+                               if (!(r_ptr->flags7 & (RF7_SELF_DARK_1 | RF7_SELF_DARK_2)) && (MON_CSLEEP(m_ptr) || (!floor_ptr->dun_level && !is_daytime()))) continue;
+                               add_mon_lite = mon_dark_hack;
+                               f_flag = FF_PROJECT;
+                               rad = -rad; /* Use absolute value */
+                       }
+
+                       mon_fx = m_ptr->fx;
+                       mon_fy = m_ptr->fy;
+
+                       /* Is the monster visible? */
+                       mon_invis = !(floor_ptr->grid_array[mon_fy][mon_fx].info & CAVE_VIEW);
+
+                       /* The square it is on */
+                       add_mon_lite(mon_fy, mon_fx);
+
+                       /* Adjacent squares */
+                       add_mon_lite(mon_fy + 1, mon_fx);
+                       add_mon_lite(mon_fy - 1, mon_fx);
+                       add_mon_lite(mon_fy, mon_fx + 1);
+                       add_mon_lite(mon_fy, mon_fx - 1);
+                       add_mon_lite(mon_fy + 1, mon_fx + 1);
+                       add_mon_lite(mon_fy + 1, mon_fx - 1);
+                       add_mon_lite(mon_fy - 1, mon_fx + 1);
+                       add_mon_lite(mon_fy - 1, mon_fx - 1);
+
+                       /* Radius 2 */
+                       if (rad >= 2)
+                       {
+                               /* South of the monster */
+                               if (cave_have_flag_bold(mon_fy + 1, mon_fx, f_flag))
+                               {
+                                       add_mon_lite(mon_fy + 2, mon_fx + 1);
+                                       add_mon_lite(mon_fy + 2, mon_fx);
+                                       add_mon_lite(mon_fy + 2, mon_fx - 1);
+
+                                       g_ptr = &floor_ptr->grid_array[mon_fy + 2][mon_fx];
+
+                                       /* Radius 3 */
+                                       if ((rad == 3) && cave_have_flag_grid(g_ptr, f_flag))
+                                       {
+                                               add_mon_lite(mon_fy + 3, mon_fx + 1);
+                                               add_mon_lite(mon_fy + 3, mon_fx);
+                                               add_mon_lite(mon_fy + 3, mon_fx - 1);
+                                       }
+                               }
+
+                               /* North of the monster */
+                               if (cave_have_flag_bold(mon_fy - 1, mon_fx, f_flag))
+                               {
+                                       add_mon_lite(mon_fy - 2, mon_fx + 1);
+                                       add_mon_lite(mon_fy - 2, mon_fx);
+                                       add_mon_lite(mon_fy - 2, mon_fx - 1);
+
+                                       g_ptr = &floor_ptr->grid_array[mon_fy - 2][mon_fx];
+
+                                       /* Radius 3 */
+                                       if ((rad == 3) && cave_have_flag_grid(g_ptr, f_flag))
+                                       {
+                                               add_mon_lite(mon_fy - 3, mon_fx + 1);
+                                               add_mon_lite(mon_fy - 3, mon_fx);
+                                               add_mon_lite(mon_fy - 3, mon_fx - 1);
+                                       }
+                               }
+
+                               /* East of the monster */
+                               if (cave_have_flag_bold(mon_fy, mon_fx + 1, f_flag))
+                               {
+                                       add_mon_lite(mon_fy + 1, mon_fx + 2);
+                                       add_mon_lite(mon_fy, mon_fx + 2);
+                                       add_mon_lite(mon_fy - 1, mon_fx + 2);
+
+                                       g_ptr = &floor_ptr->grid_array[mon_fy][mon_fx + 2];
+
+                                       /* Radius 3 */
+                                       if ((rad == 3) && cave_have_flag_grid(g_ptr, f_flag))
+                                       {
+                                               add_mon_lite(mon_fy + 1, mon_fx + 3);
+                                               add_mon_lite(mon_fy, mon_fx + 3);
+                                               add_mon_lite(mon_fy - 1, mon_fx + 3);
+                                       }
+                               }
+
+                               /* West of the monster */
+                               if (cave_have_flag_bold(mon_fy, mon_fx - 1, f_flag))
+                               {
+                                       add_mon_lite(mon_fy + 1, mon_fx - 2);
+                                       add_mon_lite(mon_fy, mon_fx - 2);
+                                       add_mon_lite(mon_fy - 1, mon_fx - 2);
+
+                                       g_ptr = &floor_ptr->grid_array[mon_fy][mon_fx - 2];
+
+                                       /* Radius 3 */
+                                       if ((rad == 3) && cave_have_flag_grid(g_ptr, f_flag))
+                                       {
+                                               add_mon_lite(mon_fy + 1, mon_fx - 3);
+                                               add_mon_lite(mon_fy, mon_fx - 3);
+                                               add_mon_lite(mon_fy - 1, mon_fx - 3);
+                                       }
+                               }
+                       }
+
+                       /* Radius 3 */
+                       if (rad == 3)
+                       {
+                               /* South-East of the monster */
+                               if (cave_have_flag_bold(mon_fy + 1, mon_fx + 1, f_flag))
+                               {
+                                       add_mon_lite(mon_fy + 2, mon_fx + 2);
+                               }
+
+                               /* South-West of the monster */
+                               if (cave_have_flag_bold(mon_fy + 1, mon_fx - 1, f_flag))
+                               {
+                                       add_mon_lite(mon_fy + 2, mon_fx - 2);
+                               }
+
+                               /* North-East of the monster */
+                               if (cave_have_flag_bold(mon_fy - 1, mon_fx + 1, f_flag))
+                               {
+                                       add_mon_lite(mon_fy - 2, mon_fx + 2);
+                               }
+
+                               /* North-West of the monster */
+                               if (cave_have_flag_bold(mon_fy - 1, mon_fx - 1, f_flag))
+                               {
+                                       add_mon_lite(mon_fy - 2, mon_fx - 2);
+                               }
+                       }
+               }
+       }
+
+       /* Save end of list of new squares */
+       end_temp = tmp_pos.n;
+
+       /*
+        * Look at old set flags to see if there are any changes.
+        */
+       for (i = 0; i < floor_ptr->mon_lite_n; i++)
+       {
+               fx = floor_ptr->mon_lite_x[i];
+               fy = floor_ptr->mon_lite_y[i];
+
+               /* We trust this grid is in bounds */
+
+               /* Point to grid */
+               g_ptr = &floor_ptr->grid_array[fy][fx];
+
+               if (g_ptr->info & CAVE_TEMP) /* Pervious lit */
+               {
+                       /* It it no longer lit? */
+                       if ((g_ptr->info & (CAVE_VIEW | CAVE_MNLT)) == CAVE_VIEW)
+                       {
+                               /* It is now unlit */
+                               /* Add it to later visual update */
+                               cave_note_and_redraw_later(g_ptr, fy, fx);
+                       }
+               }
+               else /* Pervious darkened */
+               {
+                       /* It it no longer darken? */
+                       if ((g_ptr->info & (CAVE_VIEW | CAVE_MNDK)) == CAVE_VIEW)
+                       {
+                               /* It is now undarken */
+                               /* Add it to later visual update */
+                               cave_note_and_redraw_later(g_ptr, fy, fx);
+                       }
+               }
+
+               /* Add to end of temp array */
+               tmp_pos.x[tmp_pos.n] = fx;
+               tmp_pos.y[tmp_pos.n] = fy;
+               tmp_pos.n++;
+       }
+
+       /* Clear the lite array */
+       floor_ptr->mon_lite_n = 0;
+
+       /* Copy the temp array into the lit array lighting the new squares. */
+       for (i = 0; i < end_temp; i++)
+       {
+               fx = tmp_pos.x[i];
+               fy = tmp_pos.y[i];
+
+               /* We trust this grid is in bounds */
+
+               /* Point to grid */
+               g_ptr = &floor_ptr->grid_array[fy][fx];
+
+               if (g_ptr->info & CAVE_MNLT) /* Lit */
+               {
+                       /* The is the square newly lit and visible? */
+                       if ((g_ptr->info & (CAVE_VIEW | CAVE_TEMP)) == CAVE_VIEW)
+                       {
+                               /* It is now lit */
+                               /* Add it to later visual update */
+                               cave_note_and_redraw_later(g_ptr, fy, fx);
+                       }
+               }
+               else /* Darkened */
+               {
+                       /* The is the square newly darkened and visible? */
+                       if ((g_ptr->info & (CAVE_VIEW | CAVE_XTRA)) == CAVE_VIEW)
+                       {
+                               /* It is now darkened */
+                               /* Add it to later visual update */
+                               cave_note_and_redraw_later(g_ptr, fy, fx);
+                       }
+               }
+
+               /* Save in the monster lit or darkened array */
+               floor_ptr->mon_lite_x[floor_ptr->mon_lite_n] = fx;
+               floor_ptr->mon_lite_y[floor_ptr->mon_lite_n] = fy;
+               floor_ptr->mon_lite_n++;
+       }
+
+       /* Clear the temp flag for the old lit or darken grids */
+       for (i = end_temp; i < tmp_pos.n; i++)
+       {
+               /* We trust this grid is in bounds */
+
+               floor_ptr->grid_array[tmp_pos.y[i]][tmp_pos.x[i]].info &= ~(CAVE_TEMP | CAVE_XTRA);
+       }
+
+       /* Finished with tmp_pos.n */
+       tmp_pos.n = 0;
+
+       /* Mega-Hack -- Visual update later */
+       p_ptr->update |= (PU_DELAY_VIS);
+
+       p_ptr->monlite = (floor_ptr->grid_array[p_ptr->y][p_ptr->x].info & CAVE_MNLT) ? TRUE : FALSE;
+
+       if (p_ptr->special_defense & NINJA_S_STEALTH)
+       {
+               if (p_ptr->old_monlite != p_ptr->monlite)
+               {
+                       if (p_ptr->monlite)
+                       {
+                               msg_print(_("影の覆いが薄れた気がする。", "Your mantle of shadow become thin."));
+                       }
+                       else
+                       {
+                               msg_print(_("影の覆いが濃くなった!", "Your mantle of shadow restored its original darkness."));
+                       }
+               }
+       }
+       p_ptr->old_monlite = p_ptr->monlite;
+}
+
+void clear_mon_lite(floor_type *floor_ptr)
+{
+       int i;
+       grid_type *g_ptr;
+
+       /* Clear all monster lit squares */
+       for (i = 0; i < floor_ptr->mon_lite_n; i++)
+       {
+               /* Point to grid */
+               g_ptr = &floor_ptr->grid_array[floor_ptr->mon_lite_y[i]][floor_ptr->mon_lite_x[i]];
+
+               /* Clear monster illumination flag */
+               g_ptr->info &= ~(CAVE_MNLT | CAVE_MNDK);
+       }
+
+       /* Empty the array */
+       floor_ptr->mon_lite_n = 0;
+}
+
+