ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.8
Committed: Tue Dec 12 20:53:03 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +7 -7 lines
Log Message:
replace some function- by method-calls

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4     Copyright (C) 2001 Mark Wedel & Crossfire Development Team
5     Copyright (C) 1992 Frank Tore Johansen
6    
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11    
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     GNU General Public License for more details.
16    
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20    
21 root 1.6 The authors can be reached via e-mail at <crossfire@schmorp.de>
22 elmex 1.1 */
23    
24     /* placing treasure in maps, where appropriate. */
25    
26    
27    
28     #include <global.h>
29     #include <random_map.h>
30     #include <rproto.h>
31    
32     /* some defines for various options which can be set. */
33    
34 root 1.4 #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */
35     #define HIDDEN 2 /* doors to treasure are hidden. */
36     #define KEYREQUIRED 4 /* chest has a key, which is placed randomly in the map. */
37     #define DOORED 8 /* treasure has doors around it. */
38     #define TRAPPED 16 /* trap dropped in same location as chest. */
39     #define SPARSE 32 /* 1/2 as much treasure as default */
40     #define RICH 64 /* 2x as much treasure as default */
41     #define FILLED 128 /* Fill/tile the entire map with treasure */
42     #define LAST_OPTION 64 /* set this to the last real option, for random */
43 elmex 1.1
44     #define NO_PASS_DOORS 0
45     #define PASS_DOORS 1
46    
47    
48     /* returns true if square x,y has P_NO_PASS set, which is true for walls
49     * and doors but not monsters.
50     * This function is not map tile aware.
51     */
52    
53 root 1.4 int
54 root 1.7 wall_blocked (maptile *m, int x, int y)
55 root 1.4 {
56     int r;
57 elmex 1.1
58 root 1.4 if (OUT_OF_REAL_MAP (m, x, y))
59     return 1;
60     r = GET_MAP_MOVE_BLOCK (m, x, y) & ~MOVE_BLOCK_DEFAULT;
61     return r;
62 elmex 1.1 }
63    
64     /* place treasures in the map, given the
65     map, (required)
66     layout, (required)
67     treasure style (may be empty or NULL, or "none" to cause no treasure.)
68     treasureoptions (may be 0 for random choices or positive)
69     */
70    
71 root 1.4 void
72 root 1.7 place_treasure (maptile *map, char **layout, char *treasure_style, int treasureoptions, RMParms * RP)
73 root 1.4 {
74 elmex 1.1 char styledirname[256];
75     char stylefilepath[256];
76 root 1.7 maptile *style_map = 0;
77 elmex 1.1 int num_treasures;
78    
79     /* bail out if treasure isn't wanted. */
80 root 1.4 if (treasure_style)
81     if (!strcmp (treasure_style, "none"))
82     return;
83     if (treasureoptions <= 0)
84     treasureoptions = RANDOM () % (2 * LAST_OPTION);
85 elmex 1.1
86     /* filter out the mutually exclusive options */
87 root 1.4 if ((treasureoptions & RICH) && (treasureoptions & SPARSE))
88     {
89     if (RANDOM () % 2)
90     treasureoptions -= 1;
91     else
92     treasureoptions -= 2;
93     }
94 elmex 1.1
95     /* pick the number of treasures */
96 root 1.4 if (treasureoptions & SPARSE)
97     num_treasures = BC_RANDOM (RP->total_map_hp / 600 + RP->difficulty / 2 + 1);
98     else if (treasureoptions & RICH)
99     num_treasures = BC_RANDOM (RP->total_map_hp / 150 + 2 * RP->difficulty + 1);
100     else
101     num_treasures = BC_RANDOM (RP->total_map_hp / 300 + RP->difficulty + 1);
102    
103     if (num_treasures <= 0)
104     return;
105 elmex 1.1
106     /* get the style map */
107 root 1.4 sprintf (styledirname, "%s", "/styles/treasurestyles");
108     sprintf (stylefilepath, "%s/%s", styledirname, treasure_style);
109     style_map = find_style (styledirname, treasure_style, -1);
110 elmex 1.1
111     /* all the treasure at one spot in the map. */
112 root 1.4 if (treasureoptions & CONCENTRATED)
113     {
114 elmex 1.1
115 root 1.4 /* map_layout_style global, and is previously set */
116     switch (RP->map_layout_style)
117     {
118     case ONION_LAYOUT:
119     case SPIRAL_LAYOUT:
120     case SQUARE_SPIRAL_LAYOUT:
121     {
122     int i, j;
123    
124     /* search the onion for C's or '>', and put treasure there. */
125     for (i = 0; i < RP->Xsize; i++)
126     {
127     for (j = 0; j < RP->Ysize; j++)
128     {
129     if (layout[i][j] == 'C' || layout[i][j] == '>')
130     {
131     int tdiv = RP->symmetry_used;
132     object **doorlist;
133     object *chest;
134    
135     if (tdiv == 3)
136     tdiv = 2; /* this symmetry uses a divisor of 2 */
137     /* don't put a chest on an exit. */
138     chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures / tdiv, RP);
139     if (!chest)
140     continue; /* if no chest was placed NEXT */
141     if (treasureoptions & (DOORED | HIDDEN))
142     {
143     doorlist = find_doors_in_room (map, i, j, RP);
144     lock_and_hide_doors (doorlist, map, treasureoptions, RP);
145     free (doorlist);
146     }
147     }
148     }
149     }
150     break;
151     }
152     default:
153     {
154     int i, j, tries;
155     object *chest;
156     object **doorlist;
157    
158     i = j = -1;
159     tries = 0;
160     while (i == -1 && tries < 100)
161     {
162     i = RANDOM () % (RP->Xsize - 2) + 1;
163     j = RANDOM () % (RP->Ysize - 2) + 1;
164     find_enclosed_spot (map, &i, &j, RP);
165     if (wall_blocked (map, i, j))
166     i = -1;
167     tries++;
168     }
169     chest = place_chest (treasureoptions, i, j, map, style_map, num_treasures, RP);
170     if (!chest)
171     return;
172     i = chest->x;
173     j = chest->y;
174     if (treasureoptions & (DOORED | HIDDEN))
175     {
176     doorlist = surround_by_doors (map, layout, i, j, treasureoptions);
177     lock_and_hide_doors (doorlist, map, treasureoptions, RP);
178     free (doorlist);
179     }
180 elmex 1.1 }
181     }
182 root 1.4 }
183     else
184     { /* DIFFUSE treasure layout */
185     int ti, i, j;
186    
187     for (ti = 0; ti < num_treasures; ti++)
188     {
189     i = RANDOM () % (RP->Xsize - 2) + 1;
190     j = RANDOM () % (RP->Ysize - 2) + 1;
191     place_chest (treasureoptions, i, j, map, style_map, 1, RP);
192 elmex 1.1 }
193     }
194     }
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.7 place_chest (int treasureoptions, int x, int y, maptile *map, maptile *style_map, int n_treasures, RMParms * 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.8 the_chest->destroy (0);
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    
225 elmex 1.1 /* put the treasures in the chest. */
226     /* if(style_map) { */
227 root 1.4 #if 0 /* don't use treasure style maps for now! */
228 elmex 1.1 int ti;
229 root 1.4
230 elmex 1.1 /* if treasurestyle lists a treasure list, use it. */
231 root 1.4 treasurelist *tlist = find_treasurelist (RP->treasurestyle);
232    
233     if (tlist != NULL)
234     for (ti = 0; ti < n_treasures; ti++)
235     { /* use the treasure list */
236     object *new_treasure = pick_random_object (style_map);
237    
238     insert_ob_in_ob (arch_to_object (new_treasure->arch), the_chest);
239     }
240     else
241     { /* use the style map */
242     the_chest->randomitems = tlist;
243     the_chest->stats.hp = n_treasures;
244 elmex 1.1 }
245     #endif
246 root 1.4 else
247     { /* neither style_map no treasure list given */
248     treasurelist *tlist = find_treasurelist ("chest");
249    
250     the_chest->randomitems = tlist;
251 elmex 1.1 the_chest->stats.hp = n_treasures;
252     }
253    
254     /* stick a trap in the chest if required */
255 root 1.4 if (treasureoptions & TRAPPED)
256     {
257 root 1.7 maptile *trap_map = find_style ("/styles/trapstyles", "traps", -1);
258 root 1.4 object *the_trap;
259    
260     if (trap_map)
261     {
262     the_trap = pick_random_object (trap_map);
263     the_trap->stats.Cha = 10 + RP->difficulty;
264     the_trap->level = BC_RANDOM ((3 * RP->difficulty) / 2);
265     if (the_trap)
266     {
267     object *new_trap;
268    
269     new_trap = arch_to_object (the_trap->arch);
270     copy_object (new_trap, the_trap);
271     new_trap->x = x;
272     new_trap->y = y;
273     insert_ob_in_ob (new_trap, the_chest);
274     }
275     }
276 elmex 1.1 }
277    
278     /* set the chest lock code, and call the keyplacer routine with
279     the lockcode. It's not worth bothering to lock the chest if
280 root 1.4 there's only 1 treasure.... */
281 elmex 1.1
282 root 1.4 if ((treasureoptions & KEYREQUIRED) && n_treasures > 1)
283     {
284     char keybuf[256];
285    
286     sprintf (keybuf, "%d", (int) RANDOM ());
287     the_chest->slaying = keybuf;
288     keyplace (map, x, y, keybuf, PASS_DOORS, 1, RP);
289     }
290 elmex 1.1
291     /* actually place the chest. */
292 root 1.4 the_chest->x = xl;
293     the_chest->y = yl;
294     insert_ob_in_map (the_chest, map, NULL, 0);
295 elmex 1.1 return the_chest;
296     }
297    
298    
299     /* finds the closest monster and returns him, regardless of doors
300 root 1.2 or walls */
301 root 1.4 object *
302 root 1.7 find_closest_monster (maptile *map, int x, int y, RMParms * RP)
303 root 1.4 {
304 elmex 1.1 int i;
305 root 1.4
306     for (i = 0; i < SIZEOFFREE; i++)
307     {
308     int lx, ly;
309    
310     lx = x + freearr_x[i];
311     ly = y + freearr_y[i];
312     /* boundscheck */
313     if (lx >= 0 && ly >= 0 && lx < RP->Xsize && ly < RP->Ysize)
314     /* don't bother searching this square unless the map says life exists. */
315     if (GET_MAP_FLAGS (map, lx, ly) & P_IS_ALIVE)
316     {
317     object *the_monster = get_map_ob (map, lx, ly);
318    
319     for (; the_monster != NULL && (!QUERY_FLAG (the_monster, FLAG_MONSTER)); the_monster = the_monster->above);
320     if (the_monster && QUERY_FLAG (the_monster, FLAG_MONSTER))
321     return the_monster;
322     }
323     }
324 elmex 1.1 return NULL;
325     }
326 root 1.4
327 elmex 1.1
328    
329     /* places keys in the map, preferably in something alive.
330 root 1.2 keycode is the key's code,
331     door_flag is either PASS_DOORS or NO_PASS_DOORS.
332     NO_PASS_DOORS won't cross doors or walls to keyplace, PASS_DOORS will.
333     if n_keys is 1, it will place 1 key. if n_keys >1, it will place 2-4 keys:
334     it will place 2-4 keys regardless of what nkeys is provided nkeys > 1.
335 elmex 1.1
336 root 1.2 The idea is that you call keyplace on x,y where a door is, and it'll make
337     sure a key is placed on both sides of the door.
338 elmex 1.1 */
339 root 1.4
340     int
341 root 1.7 keyplace (maptile *map, int x, int y, char *keycode, int door_flag, int n_keys, RMParms * RP)
342 root 1.4 {
343     int i, j;
344     int kx, ky;
345     object *the_keymaster; /* the monster that gets the key. */
346 elmex 1.1 object *the_key;
347    
348     /* get a key and set its keycode */
349 root 1.4 the_key = get_archetype ("key2");
350 root 1.3 the_key->slaying = keycode;
351 elmex 1.1
352 root 1.4 if (door_flag == PASS_DOORS)
353     {
354     int tries = 0;
355    
356     the_keymaster = NULL;
357     while (tries < 15 && the_keymaster == NULL)
358     {
359     i = (RANDOM () % (RP->Xsize - 2)) + 1;
360     j = (RANDOM () % (RP->Ysize - 2)) + 1;
361     tries++;
362     the_keymaster = find_closest_monster (map, i, j, RP);
363     }
364     /* if we don't find a good keymaster, drop the key on the ground. */
365     if (the_keymaster == NULL)
366     {
367     int freeindex;
368    
369     freeindex = -1;
370     for (tries = 0; tries < 15 && freeindex == -1; tries++)
371     {
372     kx = (RANDOM () % (RP->Xsize - 2)) + 1;
373     ky = (RANDOM () % (RP->Ysize - 2)) + 1;
374     freeindex = find_first_free_spot (the_key, map, kx, ky);
375     }
376     if (freeindex != -1)
377     {
378     kx += freearr_x[freeindex];
379     ky += freearr_y[freeindex];
380     }
381     }
382 elmex 1.1 }
383 root 1.4 else
384     { /* NO_PASS_DOORS --we have to work harder. */
385     /* don't try to keyplace if we're sitting on a blocked square and
386     NO_PASS_DOORS is set. */
387     if (n_keys == 1)
388     {
389     if (wall_blocked (map, x, y))
390     return 0;
391     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.7 find_monster_in_room_recursive (char **layout, maptile *map, int x, int y, RMParms * 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     object *the_monster = get_map_ob (map, x, y);
459    
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.7 find_monster_in_room (maptile *map, int x, int y, RMParms * 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     find_spot_in_room_recursive (char **layout, int x, int y, RMParms * RP)
527     {
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.7 find_spot_in_room (maptile *map, int x, int y, int *kx, int *ky, RMParms * 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.7 find_enclosed_spot (maptile *map, int *cx, int *cy, RMParms * 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.4 for (tmp = get_map_ob (map, x, y); tmp != NULL; tmp = tmp->above)
679     if (QUERY_FLAG (tmp, FLAG_ALIVE))
680     {
681     if (tmp->head)
682     tmp = tmp->head;
683 root 1.8 tmp->remove ();
684     tmp->destroy (0);
685 root 1.4 tmp = get_map_ob (map, x, y);
686     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     for (tmp = get_map_ob (map, x, y); tmp != NULL; tmp = tmp->above)
745     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.7 find_doors_in_room_recursive (char **layout, maptile *map, int x, int y, object **doorlist, int *ndoors, RMParms * 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     if (door != NULL)
772 elmex 1.1 {
773 root 1.4 doorlist[*ndoors] = door;
774     if (*ndoors > 254) /* eek! out of memory */
775     {
776     LOG (llevError, "find_doors_in_room_recursive:Too many doors for memory allocated!\n");
777     return;
778     }
779     *ndoors = *ndoors + 1;
780 elmex 1.1 }
781     }
782 root 1.4 else
783     {
784     layout[x][y] = 1;
785     /* now search all the 8 squares around recursively for free spots,in random order */
786     for (i = RANDOM () % 8, j = 0; j < 8 && theMonsterToFind == NULL; i++, j++)
787     {
788     find_doors_in_room_recursive (layout, map, x + freearr_x[i % 8 + 1], y + freearr_y[i % 8 + 1], doorlist, ndoors, RP);
789     }
790 elmex 1.1 }
791     }
792    
793     /* find a random non-blocked spot in this room to drop a key. */
794 root 1.4 object **
795 root 1.7 find_doors_in_room (maptile *map, int x, int y, RMParms * RP)
796 root 1.4 {
797 elmex 1.1 char **layout2;
798     object **doorlist;
799 root 1.4 int i, j;
800     int ndoors = 0;
801 elmex 1.1
802 root 1.4 doorlist = (object **) calloc (sizeof (int), 256);
803 elmex 1.1
804    
805 root 1.4 layout2 = (char **) calloc (sizeof (char *), RP->Xsize);
806 elmex 1.1 /* allocate and copy the layout, converting C to 0. */
807 root 1.4 for (i = 0; i < RP->Xsize; i++)
808     {
809     layout2[i] = (char *) calloc (sizeof (char), RP->Ysize);
810     for (j = 0; j < RP->Ysize; j++)
811     {
812     if (wall_blocked (map, i, j))
813     layout2[i][j] = '#';
814     }
815 elmex 1.1 }
816 root 1.4
817     /* setup num_free_spots and room_free_spots */
818     find_doors_in_room_recursive (layout2, map, x, y, doorlist, &ndoors, RP);
819 elmex 1.1
820     /* deallocate the temp. layout */
821 root 1.4 for (i = 0; i < RP->Xsize; i++)
822     {
823     free (layout2[i]);
824     }
825     free (layout2);
826 elmex 1.1 return doorlist;
827     }
828    
829    
830    
831     /* locks and/or hides all the doors in doorlist, or does nothing if
832 root 1.2 opts doesn't say to lock/hide doors. */
833 elmex 1.1
834 root 1.4 void
835 root 1.7 lock_and_hide_doors (object **doorlist, maptile *map, int opts, RMParms * RP)
836 root 1.4 {
837 elmex 1.1 object *door;
838     int i;
839 root 1.4
840 elmex 1.1 /* lock the doors and hide the keys. */
841 root 1.4
842     if (opts & DOORED)
843     {
844     for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
845     {
846     object *new_door = get_archetype ("locked_door1");
847     char keybuf[256];
848    
849     door = doorlist[i];
850     new_door->face = door->face;
851     new_door->x = door->x;
852     new_door->y = door->y;
853 root 1.8 door->remove ();
854     door->destroy (0);
855 root 1.4 doorlist[i] = new_door;
856     insert_ob_in_map (new_door, map, NULL, 0);
857     sprintf (keybuf, "%d", (int) RANDOM ());
858     new_door->slaying = keybuf;
859     keyplace (map, new_door->x, new_door->y, keybuf, NO_PASS_DOORS, 2, RP);
860     }
861 elmex 1.1 }
862    
863     /* change the faces of the doors and surrounding walls to hide them. */
864 root 1.4 if (opts & HIDDEN)
865     {
866     for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++)
867     {
868     object *wallface;
869    
870     door = doorlist[i];
871     wallface = retrofit_joined_wall (map, door->x, door->y, 1, RP);
872     if (wallface != NULL)
873     {
874     retrofit_joined_wall (map, door->x - 1, door->y, 0, RP);
875     retrofit_joined_wall (map, door->x + 1, door->y, 0, RP);
876     retrofit_joined_wall (map, door->x, door->y - 1, 0, RP);
877     retrofit_joined_wall (map, door->x, door->y + 1, 0, RP);
878     door->face = wallface->face;
879     if (!QUERY_FLAG (wallface, FLAG_REMOVED))
880 root 1.8 wallface->remove ();
881     wallface->destroy (0);
882 root 1.4 }
883     }
884 elmex 1.1 }
885     }