1 /**
2  * \file cave.c
3  * \brief chunk allocation and utility functions
4  *
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of either:
9  *
10  * a) the GNU General Public License as published by the Free Software
11  *    Foundation, version 2, or
12  *
13  * b) the "Angband licence":
14  *    This software may be copied and distributed for educational, research,
15  *    and not for profit purposes provided that this copyright and statement
16  *    are included in all such copies.  Other copyrights may also apply.
17  */
18 
19 #include "angband.h"
20 #include "cave.h"
21 #include "cmds.h"
22 #include "cmd-core.h"
23 #include "game-event.h"
24 #include "game-world.h"
25 #include "init.h"
26 #include "mon-group.h"
27 #include "monster.h"
28 #include "obj-ignore.h"
29 #include "obj-pile.h"
30 #include "obj-tval.h"
31 #include "obj-util.h"
32 #include "object.h"
33 #include "player-timed.h"
34 #include "trap.h"
35 
36 struct feature *f_info;
37 struct chunk *cave = NULL;
38 
39 int FEAT_NONE;
40 int FEAT_FLOOR;
41 int FEAT_CLOSED;
42 int FEAT_OPEN;
43 int FEAT_BROKEN;
44 int FEAT_LESS;
45 int FEAT_MORE;
46 int FEAT_SECRET;
47 int FEAT_RUBBLE;
48 int FEAT_PASS_RUBBLE;
49 int FEAT_MAGMA;
50 int FEAT_QUARTZ;
51 int FEAT_MAGMA_K;
52 int FEAT_QUARTZ_K;
53 int FEAT_GRANITE;
54 int FEAT_PERM;
55 int FEAT_LAVA;
56 
57 /**
58  * Global array for looping through the "keypad directions".
59  */
60 const s16b ddd[9] =
61 { 2, 8, 6, 4, 3, 1, 9, 7, 5 };
62 
63 /**
64  * Global arrays for converting "keypad direction" into "offsets".
65  */
66 const s16b ddx[10] =
67 { 0, -1, 0, 1, -1, 0, 1, -1, 0, 1 };
68 
69 const s16b ddy[10] =
70 { 0, 1, 1, 1, 0, 0, 0, -1, -1, -1 };
71 
72 
73 const struct loc ddgrid[10] =
74 { {0, 0}, {-1, 1}, {0, 1}, {1, 1}, {-1, 0}, {0, 0}, {1, 0}, {-1, -1}, {0, -1},
75   {1, -1} };
76 
77 /**
78  * Global arrays for optimizing "ddx[ddd[i]]", "ddy[ddd[i]]" and
79  * "loc(ddx[ddd[i]], ddy[ddd[i]])".
80  *
81  * This means that each entry in this array corresponds to the direction
82  * with the same array index in ddd[].
83  */
84 const s16b ddx_ddd[9] =
85 { 0, 0, 1, -1, 1, -1, 1, -1, 0 };
86 
87 const s16b ddy_ddd[9] =
88 { 1, -1, 0, 0, 1, 1, -1, -1, 0 };
89 
90 const struct loc ddgrid_ddd[9] =
91 {{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1}, {0, 0}};
92 
93 /* Can mult these by 45 deg or 1.5 o'clock e.g. [6] -> 270 deg or 9 o'clock */
94 const s16b clockwise_ddd[9] =
95 { 8, 9, 6, 3, 2, 1, 4, 7, 5 };
96 
97 const struct loc clockwise_grid[9] =
98 {{0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {0, 0}};
99 
100 /**
101  * Hack -- Precompute a bunch of calls to distance().
102  *
103  * The pair of arrays dist_offsets_y[n] and dist_offsets_x[n] contain the
104  * offsets of all the locations with a distance of n from a central point,
105  * with an offset of (0,0) indicating no more offsets at this distance.
106  *
107  * This is, of course, fairly unreadable, but it eliminates multiple loops
108  * from the previous version.
109  *
110  * It is probably better to replace these arrays with code to compute
111  * the relevant arrays, even if the storage is pre-allocated in hard
112  * coded sizes.  At the very least, code should be included which is
113  * able to generate and dump these arrays (ala "los()").  XXX XXX XXX
114  */
115 
116 
117 static const int d_off_y_0[] =
118 { 0 };
119 
120 static const int d_off_x_0[] =
121 { 0 };
122 
123 
124 static const int d_off_y_1[] =
125 { -1, -1, -1, 0, 0, 1, 1, 1, 0 };
126 
127 static const int d_off_x_1[] =
128 { -1, 0, 1, -1, 1, -1, 0, 1, 0 };
129 
130 
131 static const int d_off_y_2[] =
132 { -1, -1, -2, -2, -2, 0, 0, 1, 1, 2, 2, 2, 0 };
133 
134 static const int d_off_x_2[] =
135 { -2, 2, -1, 0, 1, -2, 2, -2, 2, -1, 0, 1, 0 };
136 
137 
138 static const int d_off_y_3[] =
139 { -1, -1, -2, -2, -3, -3, -3, 0, 0, 1, 1, 2, 2,
140   3, 3, 3, 0 };
141 
142 static const int d_off_x_3[] =
143 { -3, 3, -2, 2, -1, 0, 1, -3, 3, -3, 3, -2, 2,
144   -1, 0, 1, 0 };
145 
146 
147 static const int d_off_y_4[] =
148 { -1, -1, -2, -2, -3, -3, -3, -3, -4, -4, -4, 0,
149   0, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 0 };
150 
151 static const int d_off_x_4[] =
152 { -4, 4, -3, 3, -2, -3, 2, 3, -1, 0, 1, -4, 4,
153   -4, 4, -3, 3, -2, -3, 2, 3, -1, 0, 1, 0 };
154 
155 
156 static const int d_off_y_5[] =
157 { -1, -1, -2, -2, -3, -3, -4, -4, -4, -4, -5, -5,
158   -5, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5,
159   5, 0 };
160 
161 static const int d_off_x_5[] =
162 { -5, 5, -4, 4, -4, 4, -2, -3, 2, 3, -1, 0, 1,
163   -5, 5, -5, 5, -4, 4, -4, 4, -2, -3, 2, 3, -1,
164   0, 1, 0 };
165 
166 
167 static const int d_off_y_6[] =
168 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -5, -5,
169   -6, -6, -6, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
170   5, 5, 6, 6, 6, 0 };
171 
172 static const int d_off_x_6[] =
173 { -6, 6, -5, 5, -5, 5, -4, 4, -2, -3, 2, 3, -1,
174   0, 1, -6, 6, -6, 6, -5, 5, -5, 5, -4, 4, -2,
175   -3, 2, 3, -1, 0, 1, 0 };
176 
177 
178 static const int d_off_y_7[] =
179 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -5, -5,
180   -6, -6, -6, -6, -7, -7, -7, 0, 0, 1, 1, 2, 2, 3,
181   3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 0 };
182 
183 static const int d_off_x_7[] =
184 { -7, 7, -6, 6, -6, 6, -5, 5, -4, -5, 4, 5, -2,
185   -3, 2, 3, -1, 0, 1, -7, 7, -7, 7, -6, 6, -6,
186   6, -5, 5, -4, -5, 4, 5, -2, -3, 2, 3, -1, 0,
187   1, 0 };
188 
189 
190 static const int d_off_y_8[] =
191 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6,
192   -6, -6, -7, -7, -7, -7, -8, -8, -8, 0, 0, 1, 1,
193   2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
194   8, 8, 8, 0 };
195 
196 static const int d_off_x_8[] =
197 { -8, 8, -7, 7, -7, 7, -6, 6, -6, 6, -4, -5, 4,
198   5, -2, -3, 2, 3, -1, 0, 1, -8, 8, -8, 8, -7,
199   7, -7, 7, -6, 6, -6, 6, -4, -5, 4, 5, -2, -3,
200   2, 3, -1, 0, 1, 0 };
201 
202 
203 static const int d_off_y_9[] =
204 { -1, -1, -2, -2, -3, -3, -4, -4, -5, -5, -6, -6,
205   -7, -7, -7, -7, -8, -8, -8, -8, -9, -9, -9, 0,
206   0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7,
207   7, 8, 8, 8, 8, 9, 9, 9, 0 };
208 
209 static const int d_off_x_9[] =
210 { -9, 9, -8, 8, -8, 8, -7, 7, -7, 7, -6, 6, -4,
211   -5, 4, 5, -2, -3, 2, 3, -1, 0, 1, -9, 9, -9,
212   9, -8, 8, -8, 8, -7, 7, -7, 7, -6, 6, -4, -5,
213   4, 5, -2, -3, 2, 3, -1, 0, 1, 0 };
214 
215 
216 const int *dist_offsets_y[10] =
217 {
218 	d_off_y_0, d_off_y_1, d_off_y_2, d_off_y_3, d_off_y_4,
219 	d_off_y_5, d_off_y_6, d_off_y_7, d_off_y_8, d_off_y_9
220 };
221 
222 const int *dist_offsets_x[10] =
223 {
224 	d_off_x_0, d_off_x_1, d_off_x_2, d_off_x_3, d_off_x_4,
225 	d_off_x_5, d_off_x_6, d_off_x_7, d_off_x_8, d_off_x_9
226 };
227 
228 
229 /**
230  * Given a central direction at position [dir #][0], return a series
231  * of directions radiating out on both sides from the central direction
232  * all the way back to its rear.
233  *
234  * Side directions come in pairs; for example, directions '1' and '3'
235  * flank direction '2'.  The code should know which side to consider
236  * first.  If the left, it must add 10 to the central direction to
237  * access the second part of the table.
238  */
239 const byte side_dirs[20][8] = {
240 	{0, 0, 0, 0, 0, 0, 0, 0},	/* bias right */
241 	{1, 4, 2, 7, 3, 8, 6, 9},
242 	{2, 1, 3, 4, 6, 7, 9, 8},
243 	{3, 2, 6, 1, 9, 4, 8, 7},
244 	{4, 7, 1, 8, 2, 9, 3, 6},
245 	{5, 5, 5, 5, 5, 5, 5, 5},
246 	{6, 3, 9, 2, 8, 1, 7, 4},
247 	{7, 8, 4, 9, 1, 6, 2, 3},
248 	{8, 9, 7, 6, 4, 3, 1, 2},
249 	{9, 6, 8, 3, 7, 2, 4, 1},
250 
251 	{0, 0, 0, 0, 0, 0, 0, 0},	/* bias left */
252 	{1, 2, 4, 3, 7, 6, 8, 9},
253 	{2, 3, 1, 6, 4, 9, 7, 8},
254 	{3, 6, 2, 9, 1, 8, 4, 7},
255 	{4, 1, 7, 2, 8, 3, 9, 6},
256 	{5, 5, 5, 5, 5, 5, 5, 5},
257 	{6, 9, 3, 8, 2, 7, 1, 4},
258 	{7, 4, 8, 1, 9, 2, 6, 3},
259 	{8, 7, 9, 4, 6, 1, 3, 2},
260 	{9, 8, 6, 7, 3, 4, 2, 1}
261 };
262 
263 /**
264  * Given a "start" and "finish" location, extract a "direction",
265  * which will move one step from the "start" towards the "finish".
266  *
267  * Note that we use "diagonal" motion whenever possible.
268  *
269  * We return DIR_NONE if no motion is needed.
270  */
motion_dir(struct loc start,struct loc finish)271 int motion_dir(struct loc start, struct loc finish)
272 {
273 	/* No movement required */
274 	if (loc_eq(start, finish)) return (DIR_NONE);
275 
276 	/* South or North */
277 	if (start.x == finish.x) return ((start.y < finish.y) ? DIR_S : DIR_N);
278 
279 	/* East or West */
280 	if (start.y == finish.y) return ((start.x < finish.x) ? DIR_E : DIR_W);
281 
282 	/* South-east or South-west */
283 	if (start.y < finish.y) return ((start.x < finish.x) ? DIR_SE : DIR_SW);
284 
285 	/* North-east or North-west */
286 	if (start.y > finish.y) return ((start.x < finish.x) ? DIR_NE : DIR_NW);
287 
288 	/* Paranoia */
289 	return (DIR_NONE);
290 }
291 
292 /**
293  * Given a grid and a direction, extract the adjacent grid in that direction
294  */
next_grid(struct loc grid,int dir)295 struct loc next_grid(struct loc grid, int dir)
296 {
297 	return loc(grid.x + ddgrid[dir].x, grid.y + ddgrid[dir].y);
298 }
299 
300 /**
301  * Find a terrain feature index by name
302  */
lookup_feat(const char * name)303 int lookup_feat(const char *name)
304 {
305 	int i;
306 
307 	/* Look for it */
308 	for (i = 0; i < z_info->f_max; i++) {
309 		struct feature *feat = &f_info[i];
310 		if (!feat->name)
311 			continue;
312 
313 		/* Test for equality */
314 		if (streq(name, feat->name))
315 			return i;
316 	}
317 
318 	/* Fail horribly */
319 	quit_fmt("Failed to find terrain feature %s", name);
320 	return -1;
321 }
322 
323 /**
324  * Set terrain constants to the indices from terrain.txt
325  */
set_terrain(void)326 void set_terrain(void)
327 {
328 	FEAT_NONE = lookup_feat("unknown grid");
329 	FEAT_FLOOR = lookup_feat("open floor");
330 	FEAT_CLOSED = lookup_feat("closed door");
331 	FEAT_OPEN = lookup_feat("open door");
332 	FEAT_BROKEN = lookup_feat("broken door");
333 	FEAT_LESS = lookup_feat("up staircase");
334 	FEAT_MORE = lookup_feat("down staircase");
335 	FEAT_SECRET = lookup_feat("secret door");
336 	FEAT_RUBBLE = lookup_feat("pile of rubble");
337 	FEAT_PASS_RUBBLE = lookup_feat("pile of passable rubble");
338 	FEAT_MAGMA = lookup_feat("magma vein");
339 	FEAT_QUARTZ = lookup_feat("quartz vein");
340 	FEAT_MAGMA_K = lookup_feat("magma vein with treasure");
341 	FEAT_QUARTZ_K = lookup_feat("quartz vein with treasure");
342 	FEAT_GRANITE = lookup_feat("granite wall");
343 	FEAT_PERM = lookup_feat("permanent wall");
344 	FEAT_LAVA = lookup_feat("lava");
345 }
346 
347 /**
348  * Allocate a new chunk of the world
349  */
cave_new(int height,int width)350 struct chunk *cave_new(int height, int width) {
351 	int y, x;
352 
353 	struct chunk *c = mem_zalloc(sizeof *c);
354 	c->height = height;
355 	c->width = width;
356 	c->feat_count = mem_zalloc((z_info->f_max + 1) * sizeof(int));
357 
358 	c->squares = mem_zalloc(c->height * sizeof(struct square*));
359 	c->noise.grids = mem_zalloc(c->height * sizeof(u16b*));
360 	c->scent.grids = mem_zalloc(c->height * sizeof(u16b*));
361 	for (y = 0; y < c->height; y++) {
362 		c->squares[y] = mem_zalloc(c->width * sizeof(struct square));
363 		for (x = 0; x < c->width; x++) {
364 			c->squares[y][x].info = mem_zalloc(SQUARE_SIZE * sizeof(bitflag));
365 		}
366 		c->noise.grids[y] = mem_zalloc(c->width * sizeof(u16b));
367 		c->scent.grids[y] = mem_zalloc(c->width * sizeof(u16b));
368 	}
369 
370 	c->objects = mem_zalloc(OBJECT_LIST_SIZE * sizeof(struct object*));
371 	c->obj_max = OBJECT_LIST_SIZE - 1;
372 
373 	c->monsters = mem_zalloc(z_info->level_monster_max *sizeof(struct monster));
374 	c->mon_max = 1;
375 	c->mon_current = -1;
376 
377 	c->monster_groups = mem_zalloc(z_info->level_monster_max *
378 								   sizeof(struct monster_group*));
379 
380 	c->turn = turn;
381 	return c;
382 }
383 
384 /**
385  * Free a chunk
386  */
cave_free(struct chunk * c)387 void cave_free(struct chunk *c) {
388 	int y, x, i;
389 
390 	while (c->join) {
391 		struct connector *current = c->join;
392 		mem_free(current->info);
393 		c->join = current->next;
394 		mem_free(current);
395 	}
396 
397 	/* Look for orphaned objects and delete them. */
398 	for (i = 1; i < c->obj_max; i++) {
399 		if (c->objects[i] && loc_is_zero(c->objects[i]->grid)) {
400 			object_delete(&c->objects[i]);
401 		}
402 	}
403 
404 	for (y = 0; y < c->height; y++) {
405 		for (x = 0; x < c->width; x++) {
406 			mem_free(c->squares[y][x].info);
407 			if (c->squares[y][x].trap)
408 				square_free_trap(c, loc(x, y));
409 			if (c->squares[y][x].obj)
410 				object_pile_free(c->squares[y][x].obj);
411 		}
412 		mem_free(c->squares[y]);
413 		mem_free(c->noise.grids[y]);
414 		mem_free(c->scent.grids[y]);
415 	}
416 	mem_free(c->squares);
417 	mem_free(c->noise.grids);
418 	mem_free(c->scent.grids);
419 
420 	mem_free(c->feat_count);
421 	mem_free(c->objects);
422 	mem_free(c->monsters);
423 	mem_free(c->monster_groups);
424 	if (c->name)
425 		string_free(c->name);
426 	mem_free(c);
427 }
428 
429 
430 /**
431  * Enter an object in the list of objects for the current level/chunk.  This
432  * function is robust against listing of duplicates or non-objects
433  */
list_object(struct chunk * c,struct object * obj)434 void list_object(struct chunk *c, struct object *obj)
435 {
436 	int i, newsize;
437 
438 	/* Check for duplicates and objects already deleted or combined */
439 	if (!obj) return;
440 	for (i = 1; i < c->obj_max; i++)
441 		if (c->objects[i] == obj)
442 			return;
443 
444 	/* Put objects in holes in the object list */
445 	for (i = 1; i < c->obj_max; i++) {
446 		/* If there is a known object, skip this slot */
447 		if ((c == cave) && player->cave && player->cave->objects[i]) {
448 			continue;
449 		}
450 
451 		/* Put the object in a hole */
452 		if (c->objects[i] == NULL) {
453 			c->objects[i] = obj;
454 			obj->oidx = i;
455 			return;
456 		}
457 	}
458 
459 	/* Extend the list */
460 	newsize = (c->obj_max + OBJECT_LIST_INCR + 1) * sizeof(struct object*);
461 	c->objects = mem_realloc(c->objects, newsize);
462 	c->objects[c->obj_max] = obj;
463 	obj->oidx = c->obj_max;
464 	for (i = c->obj_max + 1; i <= c->obj_max + OBJECT_LIST_INCR; i++)
465 		c->objects[i] = NULL;
466 	c->obj_max += OBJECT_LIST_INCR;
467 
468 	/* If we're on the current level, extend the known list */
469 	if ((c == cave) && player->cave) {
470 		player->cave->objects = mem_realloc(player->cave->objects, newsize);
471 		for (i = player->cave->obj_max; i <= c->obj_max; i++)
472 			player->cave->objects[i] = NULL;
473 		player->cave->obj_max = c->obj_max;
474 	}
475 }
476 
477 /**
478  * Remove an object from the list of objects for the current level/chunk.  This
479  * function is robust against delisting of unlisted objects.
480  */
delist_object(struct chunk * c,struct object * obj)481 void delist_object(struct chunk *c, struct object *obj)
482 {
483 	if (!obj->oidx) return;
484 	assert(c->objects[obj->oidx] == obj);
485 
486 	/* Don't delist an actual object if it still has a listed known object */
487 	if ((c == cave) && player->cave->objects[obj->oidx]) return;
488 
489 	c->objects[obj->oidx] = NULL;
490 	obj->oidx = 0;
491 }
492 
493 /**
494  * Check consistency of an object list or a pair of object lists
495  *
496  * If one list, check the listed objects relate to locations of
497  * objects correctly
498  */
object_lists_check_integrity(struct chunk * c,struct chunk * c_k)499 void object_lists_check_integrity(struct chunk *c, struct chunk *c_k)
500 {
501 	int i;
502 	if (c_k) {
503 		assert(c->obj_max == c_k->obj_max);
504 		for (i = 0; i < c->obj_max; i++) {
505 			struct object *obj = c->objects[i];
506 			struct object *known_obj = c_k->objects[i];
507 			if (obj) {
508 				assert(obj->oidx == i);
509 				if (!loc_is_zero(obj->grid))
510 					assert(pile_contains(square_object(c, obj->grid), obj));
511 			}
512 			if (known_obj) {
513 				assert (obj);
514 				if (player->upkeep->playing) {
515 					assert(known_obj == obj->known);
516 				}
517 				if (!loc_is_zero(known_obj->grid))
518 					assert (pile_contains(square_object(c_k, known_obj->grid),
519 										  known_obj));
520 				assert (known_obj->oidx == i);
521 			}
522 		}
523 	} else {
524 		for (i = 0; i < c->obj_max; i++) {
525 			struct object *obj = c->objects[i];
526 			if (obj) {
527 				assert(obj->oidx == i);
528 				if (!loc_is_zero(obj->grid))
529 					assert(pile_contains(square_object(c, obj->grid), obj));
530 			}
531 		}
532 	}
533 }
534 
535 /**
536  * Standard "find me a location" function, now with all legal outputs!
537  *
538  * Obtains a legal location within the given distance of the initial
539  * location, and with "los()" from the source to destination location.
540  *
541  * This function is often called from inside a loop which searches for
542  * locations while increasing the "d" distance.
543  *
544  * need_los determines whether line of sight is needed
545  */
scatter(struct chunk * c,struct loc * place,struct loc grid,int d,bool need_los)546 void scatter(struct chunk *c, struct loc *place, struct loc grid, int d,
547 			 bool need_los)
548 {
549 	int tries = 0;
550 
551 	/* Pick a location, try many times */
552 	while (tries < 1000) {
553 		/* Pick a new location */
554 		struct loc new_grid = rand_loc(grid, d, d);
555 		tries++;
556 
557 		/* Ignore annoying locations */
558 		if (!square_in_bounds_fully(c, new_grid)) continue;
559 
560 		/* Ignore "excessively distant" locations */
561 		if ((d > 1) && (distance(grid, new_grid) > d)) continue;
562 
563 		/* Require "line of sight" if set */
564 		if (need_los && !los(c, grid, new_grid)) continue;
565 
566 		/* Set the location and return */
567 		*place = new_grid;
568 		return;
569 	}
570 }
571 
572 
573 /**
574  * Get a monster on the current level by its index.
575  */
cave_monster(struct chunk * c,int idx)576 struct monster *cave_monster(struct chunk *c, int idx) {
577 	if (idx <= 0) return NULL;
578 	return &c->monsters[idx];
579 }
580 
581 /**
582  * The maximum number of monsters allowed in the level.
583  */
cave_monster_max(struct chunk * c)584 int cave_monster_max(struct chunk *c) {
585 	return c->mon_max;
586 }
587 
588 /**
589  * The current number of monsters present on the level.
590  */
cave_monster_count(struct chunk * c)591 int cave_monster_count(struct chunk *c) {
592 	return c->mon_cnt;
593 }
594 
595 /**
596  * Return the number of doors/traps around (or under) the character.
597  */
count_feats(struct loc * grid,bool (* test)(struct chunk * c,struct loc grid),bool under)598 int count_feats(struct loc *grid,
599 				bool (*test)(struct chunk *c, struct loc grid), bool under)
600 {
601 	int d;
602 	struct loc grid1;
603 	int count = 0; /* Count how many matches */
604 
605 	/* Check around (and under) the character */
606 	for (d = 0; d < 9; d++) {
607 		/* if not searching under player continue */
608 		if ((d == 8) && !under) continue;
609 
610 		/* Extract adjacent (legal) location */
611 		grid1 = loc_sum(player->grid, ddgrid_ddd[d]);
612 
613 		/* Paranoia */
614 		if (!square_in_bounds_fully(cave, grid1)) continue;
615 
616 		/* Must have knowledge */
617 		if (!square_isknown(cave, grid1)) continue;
618 
619 		/* Not looking for this feature */
620 		if (!((*test)(cave, grid1))) continue;
621 
622 		/* Count it */
623 		++count;
624 
625 		/* Remember the location of the last door found */
626 		if (grid) {
627 			*grid = grid1;
628 		}
629 	}
630 
631 	/* All done */
632 	return count;
633 }
634 
cave_find_decoy(struct chunk * c)635 struct loc cave_find_decoy(struct chunk *c)
636 {
637 	return c->decoy;
638 }
639