ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.c
Revision: 1.2
Committed: Sat Feb 25 23:03:47 2006 UTC (18 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.1: +7 -7 lines
Log Message:
Use SIZEOFFREE1 not SIZEOFFREE, as the former was obviously the intent of
the various callers.

File Contents

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