ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/random_maps/treasure.C
Revision: 1.3
Committed: Sun Sep 3 00:18:41 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.2: +4 -5 lines
Log Message:
THIS CODE WILL NOT COMPILE
use the STABLE tag instead.

- major changes in object lifetime and memory management
- replaced manual refcounting by shstr class
- removed quest system
- many optimisations
- major changes

File Contents

# User Rev Content
1 elmex 1.1 /*
2     * static char *rcsid_treasure_c =
3 root 1.3 * "$Id: treasure.C,v 1.2 2006-08-29 08:01:36 root Exp $";
4 elmex 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 root 1.2 return 1;
63 elmex 1.1 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 root 1.2 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 elmex 1.1
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 root 1.3 the_chest->slaying = keybuf;
241 elmex 1.1 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 root 1.2 or walls */
253 elmex 1.1 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 root 1.2 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 elmex 1.1
281 root 1.2 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 elmex 1.1 */
284 root 1.2
285 elmex 1.1 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 root 1.3 the_key->slaying = keycode;
294 elmex 1.1
295     if(door_flag==PASS_DOORS) {
296     int tries=0;
297     the_keymaster=NULL;
298     while(tries<15&&the_keymaster==NULL) {
299     i = (RANDOM()%(RP->Xsize-2))+1;
300     j = (RANDOM()%(RP->Ysize-2))+1;
301     tries++;
302     the_keymaster=find_closest_monster(map,i,j,RP);
303     }
304     /* if we don't find a good keymaster, drop the key on the ground. */
305     if(the_keymaster==NULL) {
306     int freeindex;
307    
308     freeindex = -1;
309     for(tries = 0; tries < 15 && freeindex == -1; tries++) {
310 root 1.2 kx = (RANDOM()%(RP->Xsize-2))+1;
311     ky = (RANDOM()%(RP->Ysize-2))+1;
312     freeindex = find_first_free_spot(the_key,map,kx,ky);
313 elmex 1.1 }
314     if(freeindex != -1) {
315 root 1.2 kx += freearr_x[freeindex];
316     ky += freearr_y[freeindex];
317 elmex 1.1 }
318     }
319     }
320     else { /* NO_PASS_DOORS --we have to work harder.*/
321     /* don't try to keyplace if we're sitting on a blocked square and
322     NO_PASS_DOORS is set. */
323     if(n_keys==1) {
324     if(wall_blocked(map,x,y)) return 0;
325     the_keymaster=find_monster_in_room(map,x,y,RP);
326     if(the_keymaster==NULL) /* if fail, find a spot to drop the key. */
327     find_spot_in_room(map,x,y,&kx,&ky,RP);
328     }
329     else {
330     int sum=0; /* count how many keys we actually place */
331     /* I'm lazy, so just try to place in all 4 directions. */
332     sum +=keyplace(map,x+1,y,keycode,NO_PASS_DOORS,1,RP);
333     sum +=keyplace(map,x,y+1,keycode,NO_PASS_DOORS,1,RP);
334     sum +=keyplace(map,x-1,y,keycode,NO_PASS_DOORS,1,RP);
335     sum +=keyplace(map,x,y-1,keycode,NO_PASS_DOORS,1,RP);
336     if(sum < 2) /* we might have made a disconnected map-place more keys. */
337     { /* diagnoally this time. */
338     keyplace(map,x+1,y+1,keycode,NO_PASS_DOORS,1,RP);
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     }
343     return 1;
344     }
345     }
346    
347     if(the_keymaster==NULL) {
348     the_key->x = kx;
349     the_key->y = ky;
350     insert_ob_in_map(the_key,map,NULL,0);
351     return 1;
352     }
353    
354     insert_ob_in_ob(the_key,the_keymaster);
355     return 1;
356     }
357    
358    
359    
360     /* both find_monster_in_room routines need to have access to this. */
361    
362     object *theMonsterToFind;
363    
364     /* a recursive routine which will return a monster, eventually,if there is one.
365     it does a check-off on the layout, converting 0's to 1's */
366    
367     object *find_monster_in_room_recursive(char **layout, mapstruct *map, int x, int y, RMParms *RP) {
368     int i,j;
369     /* if we've found a monster already, leave */
370     if(theMonsterToFind!=NULL) return theMonsterToFind;
371    
372     /* bounds check x and y */
373     if(!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize)) return theMonsterToFind;
374    
375     /* if the square is blocked or searched already, leave */
376     if(layout[x][y]!=0) return theMonsterToFind; /* might be NULL, that's fine.*/
377    
378     /* check the current square for a monster. If there is one,
379     set theMonsterToFind and return it. */
380     layout[x][y]=1;
381     if(GET_MAP_FLAGS(map,x,y) & P_IS_ALIVE) {
382     object *the_monster = get_map_ob(map,x,y);
383     /* check off this point */
384     for(;the_monster!=NULL&&(!QUERY_FLAG(the_monster,FLAG_ALIVE));the_monster=the_monster->above);
385     if(the_monster && QUERY_FLAG(the_monster,FLAG_ALIVE)) {
386     theMonsterToFind=the_monster;
387     return theMonsterToFind;
388     }
389     }
390    
391     /* now search all the 8 squares around recursively for a monster,in random order */
392     for(i=RANDOM()%8,j=0; j<8 && theMonsterToFind==NULL;i++,j++) {
393     theMonsterToFind = find_monster_in_room_recursive(layout,map,x+freearr_x[i%8+1],y+freearr_y[i%8+1],RP);
394     if(theMonsterToFind!=NULL) return theMonsterToFind;
395     }
396     return theMonsterToFind;
397     }
398    
399    
400     /* sets up some data structures: the _recursive form does the
401     real work. */
402    
403     object *find_monster_in_room(mapstruct *map,int x,int y,RMParms *RP) {
404     char **layout2;
405     int i,j;
406     theMonsterToFind=0;
407     layout2 = (char **) calloc(sizeof(char *),RP->Xsize);
408     /* allocate and copy the layout, converting C to 0. */
409     for(i=0;i<RP->Xsize;i++) {
410     layout2[i]=(char *)calloc(sizeof(char),RP->Ysize);
411     for(j=0;j<RP->Ysize;j++) {
412     if(wall_blocked(map,i,j)) layout2[i][j] = '#';
413     }
414     }
415     theMonsterToFind = find_monster_in_room_recursive(layout2,map,x,y,RP);
416    
417     /* deallocate the temp. layout */
418     for(i=0;i<RP->Xsize;i++) {
419     free(layout2[i]);
420     }
421     free(layout2);
422    
423     return theMonsterToFind;
424     }
425    
426    
427    
428    
429     /* a datastructure needed by find_spot_in_room and find_spot_in_room_recursive */
430     int *room_free_spots_x;
431     int *room_free_spots_y;
432     int number_of_free_spots_in_room;
433    
434     /* the workhorse routine, which finds the free spots in a room:
435     a datastructure of free points is set up, and a position chosen from
436     that datastructure. */
437    
438     void find_spot_in_room_recursive(char **layout,int x,int y,RMParms *RP) {
439     int i,j;
440    
441     /* bounds check x and y */
442     if(!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize)) return;
443    
444     /* if the square is blocked or searched already, leave */
445     if(layout[x][y]!=0) return;
446    
447     /* set the current square as checked, and add it to the list.
448     set theMonsterToFind and return it. */
449     /* check off this point */
450     layout[x][y]=1;
451     room_free_spots_x[number_of_free_spots_in_room]=x;
452     room_free_spots_y[number_of_free_spots_in_room]=y;
453     number_of_free_spots_in_room++;
454     /* now search all the 8 squares around recursively for free spots,in random order */
455     for(i=RANDOM()%8,j=0; j<8 && theMonsterToFind==NULL;i++,j++) {
456     find_spot_in_room_recursive(layout,x+freearr_x[i%8+1],y+freearr_y[i%8+1],RP);
457     }
458    
459     }
460    
461     /* find a random non-blocked spot in this room to drop a key. */
462     void find_spot_in_room(mapstruct *map,int x,int y,int *kx,int *ky,RMParms *RP) {
463     char **layout2;
464     int i,j;
465     number_of_free_spots_in_room=0;
466     room_free_spots_x = (int *)calloc(sizeof(int),RP->Xsize * RP->Ysize);
467     room_free_spots_y = (int *)calloc(sizeof(int),RP->Xsize * RP->Ysize);
468    
469     layout2 = (char **) calloc(sizeof(char *),RP->Xsize);
470     /* allocate and copy the layout, converting C to 0. */
471     for(i=0;i<RP->Xsize;i++) {
472     layout2[i]=(char *)calloc(sizeof(char),RP->Ysize);
473     for(j=0;j<RP->Ysize;j++) {
474     if(wall_blocked(map,i,j)) layout2[i][j] = '#';
475     }
476     }
477    
478     /* setup num_free_spots and room_free_spots */
479     find_spot_in_room_recursive(layout2,x,y,RP);
480    
481     if(number_of_free_spots_in_room > 0) {
482     i = RANDOM()%number_of_free_spots_in_room;
483     *kx = room_free_spots_x[i];
484     *ky = room_free_spots_y[i];
485     }
486    
487     /* deallocate the temp. layout */
488     for(i=0;i<RP->Xsize;i++) {
489     free(layout2[i]);
490     }
491     free(layout2);
492     free(room_free_spots_x);
493     free(room_free_spots_y);
494     }
495    
496    
497     /* searches the map for a spot with walls around it. The more
498 root 1.2 walls the better, but it'll settle for 1 wall, or even 0, but
499     it'll return 0 if no FREE spots are found.*/
500 elmex 1.1
501     void find_enclosed_spot(mapstruct *map, int *cx, int *cy,RMParms *RP) {
502     int x,y;
503     int i;
504     x = *cx;y=*cy;
505    
506     for(i=0;i<=SIZEOFFREE1;i++) {
507     int lx,ly,sindex;
508     lx = x +freearr_x[i];
509     ly = y +freearr_y[i];
510     sindex = surround_flag3(map,lx,ly,RP);
511     /* if it's blocked on 3 sides, it's enclosed */
512     if(sindex==7 || sindex == 11 || sindex == 13 || sindex == 14) {
513     *cx= lx;*cy= ly;
514     return;
515     }
516     }
517    
518     /* OK, if we got here, we're obviously someplace where there's no enclosed
519     spots--try to find someplace which is 2x enclosed. */
520     for(i=0;i<=SIZEOFFREE1;i++) {
521     int lx,ly,sindex;
522     lx = x +freearr_x[i];
523     ly = y +freearr_y[i];
524     sindex = surround_flag3(map,lx,ly,RP);
525     /* if it's blocked on 3 sides, it's enclosed */
526     if(sindex==3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex==10 || sindex==12) {
527     *cx= lx;*cy= ly;
528     return;
529     }
530     }
531    
532     /* settle for one surround point */
533     for(i=0;i<=SIZEOFFREE1;i++) {
534     int lx,ly,sindex;
535     lx = x +freearr_x[i];
536     ly = y +freearr_y[i];
537     sindex = surround_flag3(map,lx,ly,RP);
538     /* if it's blocked on 3 sides, it's enclosed */
539     if(sindex) {
540     *cx= lx;*cy= ly;
541     return;
542     }
543     }
544     /* give up and return the closest free spot. */
545     i = find_first_free_spot(&find_archetype("chest")->clone,map,x,y);
546     if(i!=-1&&i<=SIZEOFFREE1) {
547     *cx = x +freearr_x[i];
548     *cy = y +freearr_y[i];
549     return;
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 root 1.2 a chest. It only goes as far as the 8 squares surrounding, and
572     it'll remove any monsters it finds.*/
573 elmex 1.1
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 root 1.2 opts doesn't say to lock/hide doors. */
687 elmex 1.1
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 root 1.3 new_door->slaying = keybuf;
707 elmex 1.1 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     }