ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.15
Committed: Mon Jan 15 01:50:33 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.14: +2 -0 lines
Log Message:
testing helps

File Contents

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