ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.13
Committed: Sun Dec 31 20:46:17 2006 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +11 -14 lines
Log Message:
increased various limits, strategically added cede's

File Contents

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