ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.1
Committed: Sun Aug 13 17:16:03 2006 UTC (17 years, 9 months ago) by elmex
Content type: text/plain
Branch: MAIN
Log Message:
Made server compile with C++.
Removed cfanim plugin and crossedit.
C++ here we come.

File Contents

# User Rev Content
1 elmex 1.1 /*
2     * static char *rcsid_treasure_c =
3     * "$Id$";
4     */
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     if(treasureoptions & (DOORED|HIDDEN)) {
151     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     for(i=0;i<SIZEOFFREE;i++) {
256     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     for(i=0;i<=SIZEOFFREE1;i++) {
508     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     for(i=0;i<=SIZEOFFREE1;i++) {
522     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     for(i=0;i<=SIZEOFFREE1;i++) {
535     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     if(i!=-1&&i<=SIZEOFFREE1) {
548     *cx = x +freearr_x[i];
549     *cy = y +freearr_y[i];
550     return;
551     }
552     /* indicate failure */
553     *cx=*cy=-1;
554     }
555    
556    
557     void remove_monsters(int x,int y,mapstruct *map) {
558     object *tmp;
559    
560     for(tmp=get_map_ob(map,x,y);tmp!=NULL;tmp=tmp->above)
561     if(QUERY_FLAG(tmp,FLAG_ALIVE)) {
562     if(tmp->head) tmp=tmp->head;
563     remove_ob(tmp);
564     free_object(tmp);
565     tmp=get_map_ob(map,x,y);
566     if(tmp==NULL) break;
567     };
568     }
569    
570    
571     /* surrounds the point x,y by doors, so as to enclose something, like
572     a chest. It only goes as far as the 8 squares surrounding, and
573     it'll remove any monsters it finds.*/
574    
575     object ** surround_by_doors(mapstruct *map,char **layout,int x,int y,int opts) {
576     int i;
577     char *doors[2];
578     object **doorlist;
579     int ndoors_made=0;
580     doorlist = (object **) calloc(9, sizeof(object *)); /* 9 doors so we can hold termination null */
581    
582     /* this is a list we pick from, for horizontal and vertical doors */
583     if(opts&DOORED) {
584     doors[0]="locked_door2";
585     doors[1]="locked_door1";
586     }
587     else {
588     doors[0]="door_1";
589     doors[1]="door_2";
590     }
591    
592     /* place doors in all the 8 adjacent unblocked squares. */
593     for(i=1;i<9;i++) {
594     int x1 = x + freearr_x[i], y1 = y+freearr_y[i];
595    
596     if(!wall_blocked(map,x1,y1)
597     || layout[x1][y1]=='>') {/* place a door */
598     object * new_door=get_archetype( (freearr_x[i]==0)?doors[1]:doors[0]);
599     new_door->x = x + freearr_x[i];
600     new_door->y = y + freearr_y[i];
601     remove_monsters(new_door->x,new_door->y,map);
602     insert_ob_in_map(new_door,map,NULL,0);
603     doorlist[ndoors_made]=new_door;
604     ndoors_made++;
605     }
606     }
607     return doorlist;
608     }
609    
610    
611     /* returns the first door in this square, or NULL if there isn't a door. */
612     object *door_in_square(mapstruct *map,int x,int y) {
613     object *tmp;
614     for(tmp=get_map_ob(map,x,y);tmp!=NULL;tmp=tmp->above)
615     if(tmp->type == DOOR || tmp->type== LOCKED_DOOR) return tmp;
616     return NULL;
617     }
618    
619    
620     /* the workhorse routine, which finds the doors in a room */
621     void find_doors_in_room_recursive(char **layout,mapstruct *map,int x,int y,object **doorlist,int *ndoors,RMParms *RP) {
622     int i,j;
623     object *door;
624    
625     /* bounds check x and y */
626     if(!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize)) return;
627    
628     /* if the square is blocked or searched already, leave */
629     if(layout[x][y]==1) return;
630    
631     /* check off this point */
632     if(layout[x][y]=='#') { /* there could be a door here */
633     layout[x][y]=1;
634     door=door_in_square(map,x,y);
635     if(door!=NULL) {
636     doorlist[*ndoors]=door;
637     if(*ndoors>254) /* eek! out of memory */
638     {
639     LOG(llevError, "find_doors_in_room_recursive:Too many doors for memory allocated!\n");
640     return;
641     }
642     *ndoors=*ndoors+1;
643     }
644     }
645     else {
646     layout[x][y]=1;
647     /* now search all the 8 squares around recursively for free spots,in random order */
648     for(i=RANDOM()%8,j=0; j<8 && theMonsterToFind==NULL;i++,j++) {
649     find_doors_in_room_recursive(layout,map,x+freearr_x[i%8+1],y+freearr_y[i%8+1],doorlist,ndoors,RP);
650     }
651     }
652     }
653    
654     /* find a random non-blocked spot in this room to drop a key. */
655     object** find_doors_in_room(mapstruct *map,int x,int y,RMParms *RP) {
656     char **layout2;
657     object **doorlist;
658     int i,j;
659     int ndoors=0;
660    
661     doorlist = (object **)calloc(sizeof(int),256);
662    
663    
664     layout2 = (char **) calloc(sizeof(char *),RP->Xsize);
665     /* allocate and copy the layout, converting C to 0. */
666     for(i=0;i<RP->Xsize;i++) {
667     layout2[i]=(char *)calloc(sizeof(char),RP->Ysize);
668     for(j=0;j<RP->Ysize;j++) {
669     if(wall_blocked(map,i,j)) layout2[i][j] = '#';
670     }
671     }
672    
673     /* setup num_free_spots and room_free_spots */
674     find_doors_in_room_recursive(layout2,map,x,y,doorlist,&ndoors,RP);
675    
676     /* deallocate the temp. layout */
677     for(i=0;i<RP->Xsize;i++) {
678     free(layout2[i]);
679     }
680     free(layout2);
681     return doorlist;
682     }
683    
684    
685    
686     /* locks and/or hides all the doors in doorlist, or does nothing if
687     opts doesn't say to lock/hide doors. */
688    
689     void lock_and_hide_doors(object **doorlist,mapstruct *map,int opts,RMParms *RP) {
690     object *door;
691     int i;
692     /* lock the doors and hide the keys. */
693    
694     if(opts & DOORED) {
695     for(i=0,door=doorlist[0];doorlist[i]!=NULL;i++) {
696     object *new_door=get_archetype("locked_door1");
697     char keybuf[256];
698     door=doorlist[i];
699     new_door->face = door->face;
700     new_door->x = door->x;
701     new_door->y = door->y;
702     remove_ob(door);
703     free_object(door);
704     doorlist[i]=new_door;
705     insert_ob_in_map(new_door,map,NULL,0);
706     sprintf(keybuf,"%d",(int)RANDOM());
707     new_door->slaying = add_string(keybuf);
708     keyplace(map,new_door->x,new_door->y,keybuf,NO_PASS_DOORS,2,RP);
709     }
710     }
711    
712     /* change the faces of the doors and surrounding walls to hide them. */
713     if(opts & HIDDEN) {
714     for(i=0,door=doorlist[0];doorlist[i]!=NULL;i++) {
715     object *wallface;
716     door=doorlist[i];
717     wallface=retrofit_joined_wall(map,door->x,door->y,1,RP);
718     if(wallface!=NULL) {
719     retrofit_joined_wall(map,door->x-1,door->y,0,RP);
720     retrofit_joined_wall(map,door->x+1,door->y,0,RP);
721     retrofit_joined_wall(map,door->x,door->y-1,0,RP);
722     retrofit_joined_wall(map,door->x,door->y+1,0,RP);
723     door->face = wallface->face;
724     if(!QUERY_FLAG(wallface,FLAG_REMOVED)) remove_ob(wallface);
725     free_object(wallface);
726     }
727     }
728     }
729     }