ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.19
Committed: Wed Jan 17 12:36:31 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.18: +47 -33 lines
Log Message:
fix possibly uninitialised kx,ky because find_free_spot does not seem to guarentee a result

File Contents

# Content
1 /*
2 <<<<<<< treasure.C
3 * CrossFire, A Multiplayer game
4 *
5 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
6 * Copyright (C) 2001 Mark Wedel & Crossfire Development Team
7 * Copyright (C) 1992 Frank Tore Johansen
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * The authors can be reached via e-mail at <crossfire@schmorp.de>
24 */
25 =======
26 * CrossFire, A Multiplayer game for X-windows
27 *
28 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
29 * Copyright (C) 2001 Mark Wedel & Crossfire Development Team
30 * Copyright (C) 1992 Frank Tore Johansen
31 *
32 * This program is free software; you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation; either version 2 of the License, or
35 * (at your option) any later version.
36 *
37 * This program is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 * GNU General Public License for more details.
41 *
42 * You should have received a copy of the GNU General Public License
43 * along with this program; if not, write to the Free Software
44 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
45 *
46 * The authors can be reached via e-mail at <crossfire@schmorp.de>
47 */
48 >>>>>>> 1.18
49
50 /* placing treasure in maps, where appropriate. */
51
52 #include <global.h>
53 #include <random_map.h>
54 #include <rproto.h>
55
56 /* some defines for various options which can be set. */
57
58 #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */
59 #define HIDDEN 2 /* doors to treasure are hidden. */
60 #define KEYREQUIRED 4 /* chest has a key, which is placed randomly in the map. */
61 #define DOORED 8 /* treasure has doors around it. */
62 #define TRAPPED 16 /* trap dropped in same location as chest. */
63 #define SPARSE 32 /* 1/2 as much treasure as default */
64 #define RICH 64 /* 2x as much treasure as default */
65 #define FILLED 128 /* Fill/tile the entire map with treasure */
66 #define LAST_OPTION 64 /* set this to the last real option, for random */
67
68 #define NO_PASS_DOORS 0
69 #define PASS_DOORS 1
70
71
72 /* returns true if square x,y has P_NO_PASS set, which is true for walls
73 * and doors but not monsters.
74 * This function is not map tile aware.
75 */
76 int
77 wall_blocked (maptile *m, int x, int y)
78 {
79 if (OUT_OF_REAL_MAP (m, x, y))
80 return 1;
81
82 int r = GET_MAP_MOVE_BLOCK (m, x, y) & ~MOVE_BLOCK_DEFAULT;
83 return r;
84 }
85
86 /* place treasures in the map, given the
87 map, (required)
88 layout, (required)
89 treasure style (may be empty or NULL, or "none" to cause no treasure.)
90 treasureoptions (may be 0 for random choices or positive)
91 */
92 void
93 place_treasure (maptile *map, char **layout, char *treasure_style, int treasureoptions, random_map_params *RP)
94 {
95 char styledirname[1024];
96 char stylefilepath[1024];
97 maptile *style_map = 0;
98 int num_treasures;
99
100 /* bail out if treasure isn't wanted. */
101 if (treasure_style)
102 if (!strcmp (treasure_style, "none"))
103 return;
104 if (treasureoptions <= 0)
105 treasureoptions = RANDOM () % (2 * LAST_OPTION);
106
107 /* filter out the mutually exclusive options */
108 if ((treasureoptions & RICH) && (treasureoptions & SPARSE))
109 {
110 if (RANDOM () % 2)
111 treasureoptions -= 1;
112 else
113 treasureoptions -= 2;
114 }
115
116 /* pick the number of treasures */
117 if (treasureoptions & SPARSE)
118 num_treasures = BC_RANDOM (RP->total_map_hp / 600 + RP->difficulty / 2 + 1);
119 else if (treasureoptions & RICH)
120 num_treasures = BC_RANDOM (RP->total_map_hp / 150 + 2 * RP->difficulty + 1);
121 else
122 num_treasures = BC_RANDOM (RP->total_map_hp / 300 + RP->difficulty + 1);
123
124 if (num_treasures <= 0)
125 return;
126
127 /* get the style map */
128 sprintf (styledirname, "%s", "/styles/treasurestyles");
129 sprintf (stylefilepath, "%s/%s", styledirname, treasure_style);
130 style_map = find_style (styledirname, treasure_style, -1);
131
132 /* all the treasure at one spot in the map. */
133 if (treasureoptions & CONCENTRATED)
134 {
135
136 /* map_layout_style global, and is previously set */
137 switch (RP->map_layout_style)
138 {
139 case LAYOUT_ONION:
140 case LAYOUT_SPIRAL:
141 case LAYOUT_SQUARE_SPIRAL:
142 {
143 int i, j;
144
145 /* search the onion for C's or '>', and put treasure there. */
146 for (i = 0; i < RP->Xsize; i++)
147 {
148 for (j = 0; j < RP->Ysize; j++)
149 {
150 if (layout[i][j] == 'C' || layout[i][j] == '>')
151 {
152 int tdiv = RP->symmetry_used;
153 object **doorlist;
154 object *chest;
155
156 if (tdiv == 3)
157 tdiv = 2; /* this symmetry uses a divisor of 2 */
158 /* don't put a chest on an exit. */
159 chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures / tdiv, RP);
160 if (!chest)
161 continue; /* if no chest was placed NEXT */
162 if (treasureoptions & (DOORED | HIDDEN))
163 {
164 doorlist = find_doors_in_room (map, i, j, RP);
165 lock_and_hide_doors (doorlist, map, treasureoptions, RP);
166 free (doorlist);
167 }
168 }
169 }
170 }
171 break;
172 }
173 default:
174 {
175 int i, j, tries;
176 object *chest;
177 object **doorlist;
178
179 i = j = -1;
180 tries = 0;
181 while (i == -1 && tries < 100)
182 {
183 i = RANDOM () % (RP->Xsize - 2) + 1;
184 j = RANDOM () % (RP->Ysize - 2) + 1;
185 find_enclosed_spot (map, &i, &j, RP);
186 if (wall_blocked (map, i, j))
187 i = -1;
188 tries++;
189 }
190 chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures, RP);
191 if (!chest)
192 return;
193 i = chest->x;
194 j = chest->y;
195 if (treasureoptions & (DOORED | HIDDEN))
196 {
197 doorlist = surround_by_doors (map, layout, i, j, treasureoptions);
198 lock_and_hide_doors (doorlist, map, treasureoptions, RP);
199 free (doorlist);
200 }
201 }
202 }
203 }
204 else
205 { /* DIFFUSE treasure layout */
206 int ti, i, j;
207
208 for (ti = 0; ti < num_treasures; ti++)
209 {
210 i = RANDOM () % (RP->Xsize - 2) + 1;
211 j = RANDOM () % (RP->Ysize - 2) + 1;
212 place_chest (treasureoptions, i, j, map, style_map, 1, RP);
213 }
214 }
215 }
216
217 /* put a chest into the map, near x and y, with the treasure style
218 determined (may be null, or may be a treasure list from lib/treasures,
219 if the global variable "treasurestyle" is set to that treasure list's name */
220
221 object *
222 place_chest (int treasureoptions, int x, int y, maptile *map, maptile *style_map, int n_treasures, random_map_params *RP)
223 {
224 object *the_chest;
225 int i, xl, yl;
226
227 the_chest = get_archetype ("chest"); /* was "chest_2" */
228
229 /* first, find a place to put the chest. */
230 i = find_first_free_spot (the_chest, map, x, y);
231 if (i == -1)
232 {
233 the_chest->destroy ();
234 return NULL;
235 }
236
237 xl = x + freearr_x[i];
238 yl = y + freearr_y[i];
239
240 /* if the placement is blocked, return a fail. */
241 if (wall_blocked (map, xl, yl))
242 return 0;
243
244 /* put the treasures in the chest. */
245 /* if(style_map) { */
246 #if 0 /* don't use treasure style maps for now! */
247 int ti;
248
249 /* if treasurestyle lists a treasure list, use it. */
250 treasurelist *tlist = find_treasurelist (RP->treasurestyle);
251
252 if (tlist != NULL)
253 for (ti = 0; ti < n_treasures; ti++)
254 { /* use the treasure list */
255 object *new_treasure = pick_random_object (style_map);
256
257 insert_ob_in_ob (arch_to_object (new_treasure->arch), the_chest);
258 }
259 else
260 { /* use the style map */
261 the_chest->randomitems = tlist;
262 the_chest->stats.hp = n_treasures;
263 }
264 #endif
265 { /* neither style_map no treasure list given */
266 treasurelist *tlist = find_treasurelist ("chest");
267
268 the_chest->randomitems = tlist;
269 the_chest->stats.hp = n_treasures;
270 }
271
272 /* stick a trap in the chest if required */
273 if (treasureoptions & TRAPPED)
274 {
275 maptile *trap_map = find_style ("/styles/trapstyles", "traps", -1);
276 object *the_trap;
277
278 if (trap_map)
279 {
280 the_trap = pick_random_object (trap_map);
281 the_trap->stats.Cha = 10 + RP->difficulty;
282 the_trap->level = BC_RANDOM ((3 * RP->difficulty) / 2);
283 if (the_trap)
284 {
285 object *new_trap;
286
287 new_trap = arch_to_object (the_trap->arch);
288 new_trap->copy_to (the_trap);
289 new_trap->x = x;
290 new_trap->y = y;
291 insert_ob_in_ob (new_trap, the_chest);
292 }
293 }
294 }
295
296 /* set the chest lock code, and call the keyplacer routine with
297 the lockcode. It's not worth bothering to lock the chest if
298 there's only 1 treasure.... */
299
300 if ((treasureoptions & KEYREQUIRED) && n_treasures > 1)
301 {
302 char keybuf[1024];
303
304 sprintf (keybuf, "%d", (int) RANDOM ());
305 the_chest->slaying = keybuf;
306 keyplace (map, x, y, keybuf, PASS_DOORS, 1, RP);
307 }
308
309 /* actually place the chest. */
310 the_chest->x = xl;
311 the_chest->y = yl;
312 insert_ob_in_map (the_chest, map, NULL, 0);
313 return the_chest;
314 }
315
316
317 /* finds the closest monster and returns him, regardless of doors
318 or walls */
319 object *
320 find_closest_monster (maptile *map, int x, int y, random_map_params *RP)
321 {
322 int i;
323
324 for (i = 0; i < SIZEOFFREE; i++)
325 {
326 int lx, ly;
327
328 lx = x + freearr_x[i];
329 ly = y + freearr_y[i];
330 /* boundscheck */
331 if (lx >= 0 && ly >= 0 && lx < RP->Xsize && ly < RP->Ysize)
332 /* don't bother searching this square unless the map says life exists. */
333 if (GET_MAP_FLAGS (map, lx, ly) & P_IS_ALIVE)
334 {
335 object *the_monster = GET_MAP_OB (map, lx, ly);
336
337 for (; the_monster != NULL && (!QUERY_FLAG (the_monster, FLAG_MONSTER)); the_monster = the_monster->above);
338 if (the_monster && QUERY_FLAG (the_monster, FLAG_MONSTER))
339 return the_monster;
340 }
341 }
342 return NULL;
343 }
344
345
346
347 /* places keys in the map, preferably in something alive.
348 keycode is the key's code,
349 door_flag is either PASS_DOORS or NO_PASS_DOORS.
350 NO_PASS_DOORS won't cross doors or walls to keyplace, PASS_DOORS will.
351 if n_keys is 1, it will place 1 key. if n_keys >1, it will place 2-4 keys:
352 it will place 2-4 keys regardless of what nkeys is provided nkeys > 1.
353
354 The idea is that you call keyplace on x,y where a door is, and it'll make
355 sure a key is placed on both sides of the door.
356 */
357 int
358 keyplace (maptile *map, int x, int y, char *keycode, int door_flag, int n_keys, random_map_params *RP)
359 {
360 int i, j;
361 int kx = 0, ky = 0;
362 object *the_keymaster; /* the monster that gets the key. */
363 object *the_key;
364
365 /* get a key and set its keycode */
366 the_key = get_archetype ("key2");
367 the_key->slaying = keycode;
368
369 if (door_flag == PASS_DOORS)
370 {
371 int tries = 0;
372
373 the_keymaster = 0;
374 while (tries < 15 && !the_keymaster)
375 {
376 i = (RANDOM () % (RP->Xsize - 2)) + 1;
377 j = (RANDOM () % (RP->Ysize - 2)) + 1;
378 tries++;
379 the_keymaster = find_closest_monster (map, i, j, RP);
380 }
381
382 /* if we don't find a good keymaster, drop the key on the ground. */
383 if (!the_keymaster)
384 {
385 int freeindex;
386
387 freeindex = -1;
388 for (tries = 0; tries < 15 && freeindex == -1; tries++)
389 {
390 kx = (RANDOM () % (RP->Xsize - 2)) + 1;
391 ky = (RANDOM () % (RP->Ysize - 2)) + 1;
392 freeindex = find_free_spot (the_key, map, kx, ky, 1, SIZEOFFREE1 + 1);
393 }
394
395 // can freeindex ever be < 0?
396 if (freeindex >= 0)
397 {
398 kx += freearr_x [freeindex];
399 ky += freearr_y [freeindex];
400 }
401 }
402 }
403 else
404 { /* NO_PASS_DOORS --we have to work harder. */
405 /* don't try to keyplace if we're sitting on a blocked square and
406 NO_PASS_DOORS is set. */
407 if (n_keys == 1)
408 {
409 if (wall_blocked (map, x, y))
410 return 0;
411
412 the_keymaster = find_monster_in_room (map, x, y, RP);
413 if (!the_keymaster) /* if fail, find a spot to drop the key. */
414 find_spot_in_room (map, x, y, &kx, &ky, RP);
415 }
416 else
417 {
418 int sum = 0; /* count how many keys we actually place */
419
420 /* I'm lazy, so just try to place in all 4 directions. */
421 sum += keyplace (map, x + 1, y, keycode, NO_PASS_DOORS, 1, RP);
422 sum += keyplace (map, x, y + 1, keycode, NO_PASS_DOORS, 1, RP);
423 sum += keyplace (map, x - 1, y, keycode, NO_PASS_DOORS, 1, RP);
424 sum += keyplace (map, x, y - 1, keycode, NO_PASS_DOORS, 1, RP);
425
426 if (sum < 2) /* we might have made a disconnected map-place more keys. */
427 { /* diagonally this time. */
428 keyplace (map, x + 1, y + 1, keycode, NO_PASS_DOORS, 1, RP);
429 keyplace (map, x + 1, y - 1, keycode, NO_PASS_DOORS, 1, RP);
430 keyplace (map, x - 1, y + 1, keycode, NO_PASS_DOORS, 1, RP);
431 keyplace (map, x - 1, y - 1, keycode, NO_PASS_DOORS, 1, RP);
432 }
433
434 return 1;
435 }
436 }
437
438 if (!the_keymaster)
439 {
440 the_key->x = kx;
441 the_key->y = ky;
442 insert_ob_in_map (the_key, map, NULL, 0);
443 return 1;
444 }
445
446 insert_ob_in_ob (the_key, the_keymaster);
447 return 1;
448 }
449
450
451
452 /* both find_monster_in_room routines need to have access to this. */
453
454 object *theMonsterToFind;
455
456 /* a recursive routine which will return a monster, eventually,if there is one.
457 it does a check-off on the layout, converting 0's to 1's */
458
459 object *
460 find_monster_in_room_recursive (char **layout, maptile *map, int x, int y, random_map_params *RP)
461 {
462 int i, j;
463
464 /* if we've found a monster already, leave */
465 if (theMonsterToFind != NULL)
466 return theMonsterToFind;
467
468 /* bounds check x and y */
469 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
470 return theMonsterToFind;
471
472 /* if the square is blocked or searched already, leave */
473 if (layout[x][y] != 0)
474 return theMonsterToFind; /* might be NULL, that's fine. */
475
476 /* check the current square for a monster. If there is one,
477 set theMonsterToFind and return it. */
478 layout[x][y] = 1;
479 if (GET_MAP_FLAGS (map, x, y) & P_IS_ALIVE)
480 {
481 object *the_monster = GET_MAP_OB (map, x, y);
482
483 /* check off this point */
484 for (; the_monster != NULL && (!QUERY_FLAG (the_monster, FLAG_ALIVE)); the_monster = the_monster->above);
485 if (the_monster && QUERY_FLAG (the_monster, FLAG_ALIVE))
486 {
487 theMonsterToFind = the_monster;
488 return theMonsterToFind;
489 }
490 }
491
492 /* now search all the 8 squares around recursively for a monster,in random order */
493 for (i = RANDOM () % 8, j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
494 {
495 theMonsterToFind = find_monster_in_room_recursive (layout, map, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], RP);
496 if (theMonsterToFind != NULL)
497 return theMonsterToFind;
498 }
499 return theMonsterToFind;
500 }
501
502
503 /* sets up some data structures: the _recursive form does the
504 real work. */
505
506 object *
507 find_monster_in_room (maptile *map, int x, int y, random_map_params *RP)
508 {
509 char **layout2;
510 int i, j;
511
512 theMonsterToFind = 0;
513 layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
514 /* allocate and copy the layout, converting C to 0. */
515 for (i = 0; i < RP->Xsize; i++)
516 {
517 layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
518 for (j = 0; j < RP->Ysize; j++)
519 {
520 if (wall_blocked (map, i, j))
521 layout2[i][j] = '#';
522 }
523 }
524 theMonsterToFind = find_monster_in_room_recursive (layout2, map, x, y, RP);
525
526 /* deallocate the temp. layout */
527 for (i = 0; i < RP->Xsize; i++)
528 {
529 free (layout2[i]);
530 }
531 free (layout2);
532
533 return theMonsterToFind;
534 }
535
536 /* a datastructure needed by find_spot_in_room and find_spot_in_room_recursive */
537 int *room_free_spots_x;
538 int *room_free_spots_y;
539 int number_of_free_spots_in_room;
540
541 /* the workhorse routine, which finds the free spots in a room:
542 a datastructure of free points is set up, and a position chosen from
543 that datastructure. */
544 void
545 find_spot_in_room_recursive (char **layout, int x, int y, random_map_params *RP)
546 {
547 int i, j;
548
549 /* bounds check x and y */
550 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
551 return;
552
553 /* if the square is blocked or searched already, leave */
554 if (layout[x][y] != 0)
555 return;
556
557 /* set the current square as checked, and add it to the list.
558 set theMonsterToFind and return it. */
559 /* check off this point */
560 layout[x][y] = 1;
561 room_free_spots_x[number_of_free_spots_in_room] = x;
562 room_free_spots_y[number_of_free_spots_in_room] = y;
563 number_of_free_spots_in_room++;
564
565 /* now search all the 8 squares around recursively for free spots,in random order */
566 for (i = RANDOM () % 8, j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
567 find_spot_in_room_recursive (layout, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], RP);
568
569 }
570
571 /* find a random non-blocked spot in this room to drop a key. */
572 void
573 find_spot_in_room (maptile *map, int x, int y, int *kx, int *ky, random_map_params *RP)
574 {
575 char **layout2;
576 int i, j;
577
578 number_of_free_spots_in_room = 0;
579 room_free_spots_x = (int *) calloc (sizeof (int), RP->Xsize * RP->Ysize);
580 room_free_spots_y = (int *) calloc (sizeof (int), RP->Xsize * RP->Ysize);
581
582 layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
583 /* allocate and copy the layout, converting C to 0. */
584 for (i = 0; i < RP->Xsize; i++)
585 {
586 layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
587 for (j = 0; j < RP->Ysize; j++)
588 if (wall_blocked (map, i, j))
589 layout2[i][j] = '#';
590 }
591
592 /* setup num_free_spots and room_free_spots */
593 find_spot_in_room_recursive (layout2, x, y, RP);
594
595 if (number_of_free_spots_in_room > 0)
596 {
597 i = RANDOM () % number_of_free_spots_in_room;
598 *kx = room_free_spots_x[i];
599 *ky = room_free_spots_y[i];
600 }
601
602 /* deallocate the temp. layout */
603 for (i = 0; i < RP->Xsize; i++)
604 free (layout2[i]);
605
606 free (layout2);
607 free (room_free_spots_x);
608 free (room_free_spots_y);
609 }
610
611
612 /* searches the map for a spot with walls around it. The more
613 walls the better, but it'll settle for 1 wall, or even 0, but
614 it'll return 0 if no FREE spots are found.*/
615 void
616 find_enclosed_spot (maptile *map, int *cx, int *cy, random_map_params *RP)
617 {
618 int x, y;
619 int i;
620
621 x = *cx;
622 y = *cy;
623
624 for (i = 0; i <= SIZEOFFREE1; i++)
625 {
626 int lx, ly, sindex;
627
628 lx = x + freearr_x[i];
629 ly = y + freearr_y[i];
630 sindex = surround_flag3 (map, lx, ly, RP);
631 /* if it's blocked on 3 sides, it's enclosed */
632 if (sindex == 7 || sindex == 11 || sindex == 13 || sindex == 14)
633 {
634 *cx = lx;
635 *cy = ly;
636 return;
637 }
638 }
639
640 /* OK, if we got here, we're obviously someplace where there's no enclosed
641 spots--try to find someplace which is 2x enclosed. */
642 for (i = 0; i <= SIZEOFFREE1; i++)
643 {
644 int lx, ly, sindex;
645
646 lx = x + freearr_x[i];
647 ly = y + freearr_y[i];
648 sindex = surround_flag3 (map, lx, ly, RP);
649 /* if it's blocked on 3 sides, it's enclosed */
650 if (sindex == 3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex == 10 || sindex == 12)
651 {
652 *cx = lx;
653 *cy = ly;
654 return;
655 }
656 }
657
658 /* settle for one surround point */
659 for (i = 0; i <= SIZEOFFREE1; i++)
660 {
661 int lx, ly, sindex;
662
663 lx = x + freearr_x[i];
664 ly = y + freearr_y[i];
665 sindex = surround_flag3 (map, lx, ly, RP);
666 /* if it's blocked on 3 sides, it's enclosed */
667 if (sindex)
668 {
669 *cx = lx;
670 *cy = ly;
671 return;
672 }
673 }
674 /* give up and return the closest free spot. */
675 i = find_free_spot (&archetype::find ("chest")->clone, map, x, y, 1, SIZEOFFREE1 + 1);
676
677 if (i != -1)
678 {
679 *cx = x + freearr_x[i];
680 *cy = y + freearr_y[i];
681 }
682 else
683 {
684 /* indicate failure */
685 *cx = -1;
686 *cy = -1;
687 }
688 }
689
690
691 void
692 remove_monsters (int x, int y, maptile *map)
693 {
694 object *tmp;
695
696 for (tmp = GET_MAP_OB (map, x, y); tmp != NULL; tmp = tmp->above)
697 if (QUERY_FLAG (tmp, FLAG_ALIVE))
698 {
699 if (tmp->head)
700 tmp = tmp->head;
701 tmp->remove ();
702 tmp->destroy ();
703 tmp = GET_MAP_OB (map, x, y);
704 if (tmp == NULL)
705 break;
706 };
707 }
708
709
710 /* surrounds the point x,y by doors, so as to enclose something, like
711 a chest. It only goes as far as the 8 squares surrounding, and
712 it'll remove any monsters it finds.*/
713
714 object **
715 surround_by_doors (maptile *map, char **layout, int x, int y, int opts)
716 {
717 int i;
718 char *doors[2];
719 object **doorlist;
720 int ndoors_made = 0;
721 doorlist = (object **) calloc (9, sizeof (object *)); /* 9 doors so we can hold termination null */
722
723 /* this is a list we pick from, for horizontal and vertical doors */
724 if (opts & DOORED)
725 {
726 doors[0] = "locked_door2";
727 doors[1] = "locked_door1";
728 }
729 else
730 {
731 doors[0] = "door_1";
732 doors[1] = "door_2";
733 }
734
735 /* place doors in all the 8 adjacent unblocked squares. */
736 for (i = 1; i < 9; i++)
737 {
738 int x1 = x + freearr_x[i], y1 = y + freearr_y[i];
739
740 if (!wall_blocked (map, x1, y1) || layout[x1][y1] == '>')
741 { /* place a door */
742 object *new_door = get_archetype ((freearr_x[i] == 0) ? doors[1] : doors[0]);
743
744 new_door->x = x + freearr_x[i];
745 new_door->y = y + freearr_y[i];
746 remove_monsters (new_door->x, new_door->y, map);
747 insert_ob_in_map (new_door, map, NULL, 0);
748 doorlist[ndoors_made] = new_door;
749 ndoors_made++;
750 }
751 }
752 return doorlist;
753 }
754
755
756 /* returns the first door in this square, or NULL if there isn't a door. */
757 object *
758 door_in_square (maptile *map, int x, int y)
759 {
760 object *tmp;
761
762 for (tmp = GET_MAP_OB (map, x, y); tmp != NULL; tmp = tmp->above)
763 if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
764 return tmp;
765 return NULL;
766 }
767
768
769 /* the workhorse routine, which finds the doors in a room */
770 void
771 find_doors_in_room_recursive (char **layout, maptile *map, int x, int y, object **doorlist, int *ndoors, random_map_params *RP)
772 {
773 int i, j;
774 object *door;
775
776 /* bounds check x and y */
777 if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
778 return;
779
780 /* if the square is blocked or searched already, leave */
781 if (layout[x][y] == 1)
782 return;
783
784 /* check off this point */
785 if (layout[x][y] == '#')
786 { /* there could be a door here */
787 layout[x][y] = 1;
788 door = door_in_square (map, x, y);
789 if (door)
790 {
791 doorlist[*ndoors] = door;
792 if (*ndoors > 1022) /* eek! out of memory */
793 {
794 LOG (llevError, "find_doors_in_room_recursive:Too many doors for memory allocated!\n");
795 return;
796 }
797
798 *ndoors = *ndoors + 1;
799 }
800 }
801 else
802 {
803 layout[x][y] = 1;
804 /* now search all the 8 squares around recursively for free spots,in random order */
805 for (i = RANDOM () % 8, j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
806 find_doors_in_room_recursive (layout, map, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], doorlist, ndoors, RP);
807 }
808 }
809
810 /* find a random non-blocked spot in this room to drop a key. */
811 object **
812 find_doors_in_room (maptile *map, int x, int y, random_map_params *RP)
813 {
814 char **layout2;
815 object **doorlist;
816 int i, j;
817 int ndoors = 0;
818
819 doorlist = (object **) calloc (sizeof (int), 1024);
820
821 layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
822 /* allocate and copy the layout, converting C to 0. */
823 for (i = 0; i < RP->Xsize; i++)
824 {
825 layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
826 for (j = 0; j < RP->Ysize; j++)
827 {
828 if (wall_blocked (map, i, j))
829 layout2[i][j] = '#';
830 }
831 }
832
833 /* setup num_free_spots and room_free_spots */
834 find_doors_in_room_recursive (layout2, map, x, y, doorlist, &ndoors, RP);
835
836 /* deallocate the temp. layout */
837 for (i = 0; i < RP->Xsize; i++)
838 free (layout2[i]);
839
840 free (layout2);
841 return doorlist;
842 }
843
844
845
846 /* locks and/or hides all the doors in doorlist, or does nothing if
847 opts doesn't say to lock/hide doors. */
848
849 void
850 lock_and_hide_doors (object **doorlist, maptile *map, int opts, random_map_params *RP)
851 {
852 object *door;
853 int i;
854
855 /* lock the doors and hide the keys. */
856
857 if (opts & DOORED)
858 {
859 for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
860 {
861 object *new_door = get_archetype ("locked_door1");
862 char keybuf[1024];
863
864 door = doorlist[i];
865 new_door->face = door->face;
866 new_door->x = door->x;
867 new_door->y = door->y;
868 door->remove ();
869 door->destroy ();
870 doorlist[i] = new_door;
871 insert_ob_in_map (new_door, map, NULL, 0);
872 sprintf (keybuf, "%d", (int) RANDOM ());
873 new_door->slaying = keybuf;
874 keyplace (map, new_door->x, new_door->y, keybuf, NO_PASS_DOORS, 2, RP);
875 }
876 }
877
878 /* change the faces of the doors and surrounding walls to hide them. */
879 if (opts & HIDDEN)
880 {
881 for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
882 {
883 object *wallface;
884
885 door = doorlist[i];
886 wallface = retrofit_joined_wall (map, door->x, door->y, 1, RP);
887 if (wallface != NULL)
888 {
889 retrofit_joined_wall (map, door->x - 1, door->y, 0, RP);
890 retrofit_joined_wall (map, door->x + 1, door->y, 0, RP);
891 retrofit_joined_wall (map, door->x, door->y - 1, 0, RP);
892 retrofit_joined_wall (map, door->x, door->y + 1, 0, RP);
893 door->face = wallface->face;
894 if (!QUERY_FLAG (wallface, FLAG_REMOVED))
895 wallface->remove ();
896 wallface->destroy ();
897 }
898 }
899 }
900 }