Crossfire Server, Branch 1.12  R12190
treasure.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_treasure_c =
00003  *   "$Id: treasure.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 /*
00007     CrossFire, A Multiplayer game for X-windows
00008 
00009     Copyright (C) 2001 Mark Wedel & Crossfire Development Team
00010     Copyright (C) 1992 Frank Tore Johansen
00011 
00012     This program is free software; you can redistribute it and/or modify
00013     it under the terms of the GNU General Public License as published by
00014     the Free Software Foundation; either version 2 of the License, or
00015     (at your option) any later version.
00016 
00017     This program is distributed in the hope that it will be useful,
00018     but WITHOUT ANY WARRANTY; without even the implied warranty of
00019     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020     GNU General Public License for more details.
00021 
00022     You should have received a copy of the GNU General Public License
00023     along with this program; if not, write to the Free Software
00024     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 
00026     The authors can be reached via e-mail at crossfire-devel@real-time.com
00027 */
00028 
00029 /*  placing treasure in maps, where appropriate.  */
00030 
00036 #include <global.h>
00037 #include <random_map.h>
00038 #include <rproto.h>
00039 
00046 #define CONCENTRATED 1 /* all the treasure is at the C's for onions. */
00047 #define HIDDEN 2   /* doors to treasure are hidden. */
00048 #define KEYREQUIRED 4 /* chest has a key, which is placed randomly in the map. */
00049 #define DOORED 8   /* treasure has doors around it. */
00050 #define TRAPPED 16 /* trap dropped in same location as chest. */
00051 #define SPARSE 32  /* 1/2 as much treasure as default */
00052 #define RICH 64   /* 2x as much treasure as default */
00053 #define FILLED 128  /* Fill/tile the entire map with treasure */
00054 #define LAST_OPTION 64  /* set this to the last real option, for random */
00055 
00057 #define NO_PASS_DOORS 0
00058 #define PASS_DOORS 1
00059 
00060 static object **surround_by_doors(mapstruct *map, char **layout, int x, int y, int opts);
00061 
00073 int wall_blocked(mapstruct *m, int x, int y) {
00074     int r;
00075 
00076     if (OUT_OF_REAL_MAP(m, x, y))
00077         return 1;
00078     r = GET_MAP_MOVE_BLOCK(m, x, y)&~MOVE_BLOCK_DEFAULT;
00079     return r;
00080 }
00081 
00101 void place_treasure(mapstruct *map, char **layout, char *treasure_style, int treasureoptions, RMParms *RP) {
00102     char styledirname[256];
00103     char stylefilepath[256];
00104     mapstruct *style_map = NULL;
00105     int num_treasures;
00106 
00107     /* bail out if treasure isn't wanted. */
00108     if (treasure_style)
00109         if (!strcmp(treasure_style, "none"))
00110             return;
00111     if (treasureoptions <= 0)
00112         treasureoptions = RANDOM()%(2*LAST_OPTION);
00113 
00114     /* filter out the mutually exclusive options */
00115     if ((treasureoptions&RICH) && (treasureoptions&SPARSE)) {
00116         if (RANDOM()%2)
00117             treasureoptions -= 1;
00118         else
00119             treasureoptions -= 2;
00120     }
00121 
00122     /* pick the number of treasures */
00123     if (treasureoptions&SPARSE)
00124         num_treasures = BC_RANDOM(RP->total_map_hp/600+RP->difficulty/2+1);
00125     else if (treasureoptions&RICH)
00126         num_treasures = BC_RANDOM(RP->total_map_hp/150+2*RP->difficulty+1);
00127     else
00128         num_treasures = BC_RANDOM(RP->total_map_hp/300+RP->difficulty+1);
00129 
00130     if (num_treasures <= 0)
00131         return;
00132 
00133     /* get the style map */
00134     snprintf(styledirname, sizeof(styledirname), "%s", "/styles/treasurestyles");
00135     snprintf(stylefilepath, sizeof(stylefilepath), "%s/%s", styledirname, treasure_style);
00136     style_map = find_style(styledirname, treasure_style, -1);
00137 
00138     /* all the treasure at one spot in the map. */
00139     if (treasureoptions&CONCENTRATED) {
00140         /* map_layout_style global, and is previously set */
00141         switch (RP->map_layout_style) {
00142         case ONION_LAYOUT:
00143         case SPIRAL_LAYOUT:
00144         case SQUARE_SPIRAL_LAYOUT: {
00145                 int i, j;
00146 
00147                 /* search the onion for C's or '>', and put treasure there. */
00148                 for (i = 0; i < RP->Xsize; i++) {
00149                     for (j = 0; j < RP->Ysize; j++) {
00150                         if (layout[i][j] == 'C' || layout[i][j] == '>') {
00151                             int tdiv = RP->symmetry_used;
00152                             object **doorlist;
00153                             object *chest;
00154 
00155                             if (tdiv == 3)
00156                                 tdiv = 2; /* this symmetry uses a divisor of 2*/
00157                             /* don't put a chest on an exit. */
00158                             chest = place_chest(treasureoptions, i, j, map, style_map, num_treasures/tdiv, RP);
00159                             if (!chest)
00160                                 continue; /* if no chest was placed NEXT */
00161                             if (treasureoptions&(DOORED|HIDDEN)) {
00162                                 doorlist = find_doors_in_room(map, i, j, RP);
00163                                 lock_and_hide_doors(doorlist, map, treasureoptions, RP);
00164                                 free(doorlist);
00165                             }
00166                         }
00167                     }
00168                 }
00169                 break;
00170         }
00171         default: {
00172                 int i, j, tries;
00173                 object *chest;
00174                 object **doorlist;
00175 
00176                 i = j = -1;
00177                 tries = 0;
00178                 while (i == -1 && tries < 100) {
00179                     i = RANDOM()%(RP->Xsize-2)+1;
00180                     j = RANDOM()%(RP->Ysize-2)+1;
00181                     find_enclosed_spot(map, &i, &j, RP);
00182                     if (wall_blocked(map, i, j))
00183                         i = -1;
00184                     tries++;
00185                 }
00186                 chest = place_chest(treasureoptions, i, j, map, style_map, num_treasures, RP);
00187                 if (!chest)
00188                     return;
00189                 i = chest->x;
00190                 j = chest->y;
00191                 if (treasureoptions&(DOORED|HIDDEN)) {
00192                     doorlist = surround_by_doors(map, layout, i, j, treasureoptions);
00193                     lock_and_hide_doors(doorlist, map, treasureoptions, RP);
00194                     free(doorlist);
00195                 }
00196             }
00197         }
00198     } else { /* DIFFUSE treasure layout */
00199         int ti, i, j;
00200 
00201         for (ti = 0; ti < num_treasures; ti++) {
00202             i = RANDOM()%(RP->Xsize-2)+1;
00203             j = RANDOM()%(RP->Ysize-2)+1;
00204             place_chest(treasureoptions, i, j, map, style_map, 1, RP);
00205         }
00206     }
00207 }
00208 
00232 object *place_chest(int treasureoptions, int x, int y, mapstruct *map, mapstruct *style_map, int n_treasures, RMParms *RP) {
00233     object *the_chest;
00234     int i, xl, yl;
00235     treasurelist *tlist;
00236 
00237     the_chest = create_archetype("chest");  /* was "chest_2" */
00238 
00239     /* first, find a place to put the chest. */
00240     i = find_first_free_spot(the_chest, map, x, y);
00241     if (i == -1) {
00242         free_object(the_chest);
00243         return NULL;
00244     }
00245     xl = x+freearr_x[i];
00246     yl = y+freearr_y[i];
00247 
00248     /* if the placement is blocked, return a fail. */
00249     if (wall_blocked(map, xl, yl)) {
00250         free_object(the_chest);
00251         return NULL;
00252     }
00253 
00254     tlist = find_treasurelist("chest");
00255     the_chest->randomitems = tlist;
00256     the_chest->stats.hp = n_treasures;
00257 
00258     /* stick a trap in the chest if required  */
00259     if (treasureoptions&TRAPPED) {
00260         mapstruct *trap_map = find_style("/styles/trapstyles", "traps", -1);
00261         object *the_trap;
00262 
00263         if (trap_map) {
00264             the_trap = pick_random_object(trap_map);
00265             the_trap->stats.Cha = 10+RP->difficulty;
00266             the_trap->level = BC_RANDOM((3*RP->difficulty)/2);
00267             if (the_trap) {
00268                 object *new_trap;
00269 
00270                 new_trap = arch_to_object(the_trap->arch);
00271                 copy_object(new_trap, the_trap);
00272                 new_trap->x = x;
00273                 new_trap->y = y;
00274                 insert_ob_in_ob(new_trap, the_chest);
00275             }
00276         }
00277     }
00278 
00279     /* set the chest lock code, and call the keyplacer routine with
00280      the lockcode.  It's not worth bothering to lock the chest if
00281      there's only 1 treasure....*/
00282     if ((treasureoptions&KEYREQUIRED) && n_treasures > 1) {
00283         char keybuf[256];
00284 
00285         snprintf(keybuf, sizeof(keybuf), "%d", (int)RANDOM());
00286         if (keyplace(map, x, y, keybuf, PASS_DOORS, 1, RP))
00287             the_chest->slaying = add_string(keybuf);
00288     }
00289 
00290     /* actually place the chest. */
00291     the_chest->x = xl;
00292     the_chest->y = yl;
00293     insert_ob_in_map(the_chest, map, NULL, 0);
00294     return the_chest;
00295 }
00296 
00311 object *find_closest_monster(mapstruct *map, int x, int y, RMParms *RP) {
00312     int i;
00313 
00314     for (i = 0; i < SIZEOFFREE; i++) {
00315         int lx, ly;
00316 
00317         lx = x+freearr_x[i];
00318         ly = y+freearr_y[i];
00319         /* boundscheck */
00320         if (lx >= 0 && ly >= 0 && lx < RP->Xsize && ly < RP->Ysize)
00321             /* don't bother searching this square unless the map says life exists.*/
00322             if (GET_MAP_FLAGS(map, lx, ly)&P_IS_ALIVE) {
00323                 object *the_monster = GET_MAP_OB(map, lx, ly);
00324 
00325                 for (; the_monster != NULL && (!QUERY_FLAG(the_monster, FLAG_MONSTER)); the_monster = the_monster->above)
00326                     ;
00327                 if (the_monster && QUERY_FLAG(the_monster, FLAG_MONSTER))
00328                     return the_monster;
00329             }
00330     }
00331     return NULL;
00332 }
00333 
00361 int keyplace(mapstruct *map, int x, int y, char *keycode, int door_flag, int n_keys, RMParms *RP) {
00362     int i, j;
00363     int kx, ky;
00364     object *the_keymaster; /* the monster that gets the key. */
00365     object *the_key;
00366     char keybuf[256];
00367 
00368     /* get a key and set its keycode */
00369     the_key = create_archetype("key2");
00370     the_key->slaying = add_string(keycode);
00371     free_string(the_key->name);
00372     snprintf(keybuf, 256, "key from level %d of %s", RP->dungeon_level, RP->dungeon_name[0] != '\0' ? RP->dungeon_name : "a random map");
00373     the_key->name = add_string(keybuf);
00374 
00375     if (door_flag == PASS_DOORS) {
00376         int tries = 0;
00377 
00378         the_keymaster = NULL;
00379         while (tries < 15 && the_keymaster == NULL) {
00380             i = (RANDOM()%(RP->Xsize-2))+1;
00381             j = (RANDOM()%(RP->Ysize-2))+1;
00382             tries++;
00383             the_keymaster = find_closest_monster(map, i, j, RP);
00384         }
00385         /* if we don't find a good keymaster, drop the key on the ground. */
00386         if (the_keymaster == NULL) {
00387             int freeindex;
00388 
00389             freeindex = -1;
00390             for (tries = 0; tries < 15 && freeindex == -1; tries++) {
00391                 kx = (RANDOM()%(RP->Xsize-2))+1;
00392                 ky = (RANDOM()%(RP->Ysize-2))+1;
00393                 freeindex = find_first_free_spot(the_key, map, kx, ky);
00394             }
00395             if (freeindex != -1) {
00396                 kx += freearr_x[freeindex];
00397                 ky += freearr_y[freeindex];
00398             }
00399         }
00400     } else { /* NO_PASS_DOORS --we have to work harder.*/
00401         /* don't try to keyplace if we're sitting on a blocked square and
00402          * NO_PASS_DOORS is set.
00403         */
00404         if (n_keys == 1) {
00405             if (wall_blocked(map, x, y))
00406                 return 0;
00407             the_keymaster = find_monster_in_room(map, x, y, RP);
00408             if (the_keymaster == NULL) /* if fail, find a spot to drop the key. */
00409                 if (!find_spot_in_room(map, x, y, &kx, &ky, RP))
00410                     return 0;
00411         } else {
00412             /* It can happen that spots around that point are all blocked, so
00413             * try to look farther away if needed
00414             */
00415             int sum = 0; /* count how many keys we actually place */
00416             int distance = 1;
00417 
00418             while (distance < 5) {
00419                 /* I'm lazy, so just try to place in all 4 directions. */
00420                 sum += keyplace(map, x+distance, y, keycode, NO_PASS_DOORS, 1, RP);
00421                 sum += keyplace(map, x, y+distance, keycode, NO_PASS_DOORS, 1, RP);
00422                 sum += keyplace(map, x-distance, y, keycode, NO_PASS_DOORS, 1, RP);
00423                 sum += keyplace(map, x, y-distance, keycode, NO_PASS_DOORS, 1, RP);
00424                 if (sum < 2) {  /* we might have made a disconnected map-place more keys. */
00425                     /* diagonally this time. */
00426                     keyplace(map, x+distance, y+distance, keycode, NO_PASS_DOORS, 1, RP);
00427                     keyplace(map, x+distance, y-distance, keycode, NO_PASS_DOORS, 1, RP);
00428                     keyplace(map, x-distance, y+distance, keycode, NO_PASS_DOORS, 1, RP);
00429                     keyplace(map, x-distance, y-distance, keycode, NO_PASS_DOORS, 1, RP);
00430                 }
00431                 if (sum > 0)
00432                     return 1;
00433                 distance++;
00434             }
00435             return 0;
00436         }
00437     }
00438 
00439     if (the_keymaster == NULL) {
00440         the_key->x = kx;
00441         the_key->y = ky;
00442         insert_ob_in_map(the_key, map, NULL, 0);
00443         return 1;
00444     }
00445 
00446     insert_ob_in_ob(the_key, the_keymaster);
00447     return 1;
00448 }
00449 
00465 object *find_monster_in_room_recursive(char **layout, mapstruct *map, int x, int y, RMParms *RP) {
00466     int i, j;
00467     object *the_monster;
00468 
00469     /* bounds check x and y */
00470     if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
00471         return NULL;
00472 
00473     /* if the square is blocked or searched already, leave */
00474     if (layout[x][y] != 0)
00475         return NULL;
00476 
00477     /* check the current square for a monster.  If there is one,
00478        set theMonsterToFind and return it. */
00479     layout[x][y] = 1;
00480     if (GET_MAP_FLAGS(map, x, y)&P_IS_ALIVE) {
00481         the_monster = GET_MAP_OB(map, x, y);
00482         /* check off this point */
00483         for (; the_monster != NULL && (!QUERY_FLAG(the_monster, FLAG_ALIVE)); the_monster = the_monster->above)
00484             ;
00485         if (the_monster && QUERY_FLAG(the_monster, FLAG_ALIVE)) {
00486             return the_monster;
00487         }
00488     }
00489 
00490     /* now search all the 8 squares around recursively for a monster, in random order */
00491     for (i = RANDOM()%8, j = 0; j < 8; i++, j++) {
00492         the_monster = find_monster_in_room_recursive(layout, map, x+freearr_x[i%8+1], y+freearr_y[i%8+1], RP);
00493         if (the_monster != NULL)
00494             return the_monster;
00495     }
00496     return NULL;
00497 }
00498 
00513 object *find_monster_in_room(mapstruct *map, int x, int y, RMParms *RP) {
00514     char **layout2;
00515     int i, j;
00516     object *theMonsterToFind;
00517 
00518     layout2 = (char **)calloc(sizeof(char *), RP->Xsize);
00519     /* allocate and copy the layout, converting C to 0. */
00520     for (i = 0; i < RP->Xsize; i++) {
00521         layout2[i] = (char *)calloc(sizeof(char), RP->Ysize);
00522         for (j = 0; j < RP->Ysize; j++) {
00523             if (wall_blocked(map, i, j))
00524                 layout2[i][j] = '#';
00525         }
00526     }
00527     theMonsterToFind = find_monster_in_room_recursive(layout2, map, x, y, RP);
00528 
00529     /* deallocate the temp. layout */
00530     for (i = 0; i < RP->Xsize; i++) {
00531         free(layout2[i]);
00532     }
00533     free(layout2);
00534 
00535     return theMonsterToFind;
00536 }
00537 
00539 typedef struct free_spots_struct {
00540     int *room_free_spots_x;             
00541     int *room_free_spots_y;             
00542     int number_of_free_spots_in_room;   
00543 } free_spots_struct;
00544 
00559 static void find_spot_in_room_recursive(char **layout, int x, int y, RMParms *RP, free_spots_struct *spots) {
00560     int i, j;
00561 
00562     /* bounds check x and y */
00563     if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
00564         return;
00565 
00566     /* if the square is blocked or searched already, leave */
00567     if (layout[x][y] != 0)
00568         return;
00569 
00570     /* set the current square as checked, and add it to the list.
00571       check off this point */
00572     layout[x][y] = 1;
00573     spots->room_free_spots_x[spots->number_of_free_spots_in_room] = x;
00574     spots->room_free_spots_y[spots->number_of_free_spots_in_room] = y;
00575     spots->number_of_free_spots_in_room++;
00576     /* now search all the 8 squares around recursively for free spots, in random order */
00577     for (i = RANDOM()%8, j = 0; j < 8; i++, j++) {
00578         find_spot_in_room_recursive(layout, x+freearr_x[i%8+1], y+freearr_y[i%8+1], RP, spots);
00579     }
00580 }
00581 
00600 int find_spot_in_room(mapstruct *map, int x, int y, int *kx, int *ky, RMParms *RP) {
00601     char **layout2;
00602     int i, j;
00603     free_spots_struct spots;
00604 
00605     spots.number_of_free_spots_in_room = 0;
00606     spots.room_free_spots_x = (int *)calloc(sizeof(int), RP->Xsize*RP->Ysize);
00607     spots.room_free_spots_y = (int *)calloc(sizeof(int), RP->Xsize*RP->Ysize);
00608 
00609     layout2 = (char **)calloc(sizeof(char *), RP->Xsize);
00610     /* allocate and copy the layout, converting C to 0. */
00611     for (i = 0; i < RP->Xsize; i++) {
00612         layout2[i] = (char *)calloc(sizeof(char), RP->Ysize);
00613         for (j = 0; j < RP->Ysize; j++) {
00614             if (wall_blocked(map, i, j))
00615                 layout2[i][j] = '#';
00616         }
00617     }
00618 
00619     /* setup num_free_spots and room_free_spots */
00620     find_spot_in_room_recursive(layout2, x, y, RP, &spots);
00621 
00622     if (spots.number_of_free_spots_in_room > 0) {
00623         i = RANDOM()%spots.number_of_free_spots_in_room;
00624         *kx = spots.room_free_spots_x[i];
00625         *ky = spots.room_free_spots_y[i];
00626     }
00627 
00628     /* deallocate the temp. layout */
00629     for (i = 0; i < RP->Xsize; i++) {
00630         free(layout2[i]);
00631     }
00632     free(layout2);
00633     free(spots.room_free_spots_x);
00634     free(spots.room_free_spots_y);
00635 
00636     if (spots.number_of_free_spots_in_room > 0)
00637         return 1;
00638     return 0;
00639 }
00640 
00653 void find_enclosed_spot(mapstruct *map, int *cx, int *cy, RMParms *RP) {
00654     int x, y;
00655     int i;
00656 
00657     x = *cx;
00658     y = *cy;
00659 
00660     for (i = 0; i <= SIZEOFFREE1; i++) {
00661         int lx, ly, sindex;
00662         lx = x+freearr_x[i];
00663         ly = y+freearr_y[i];
00664         sindex = surround_flag3(map, lx, ly, RP);
00665         /* if it's blocked on 3 sides, it's enclosed */
00666         if (sindex == 7 || sindex == 11 || sindex == 13 || sindex == 14) {
00667             *cx = lx;
00668             *cy = ly;
00669             return;
00670         }
00671     }
00672 
00673     /* OK, if we got here, we're obviously someplace where there's no enclosed
00674        spots--try to find someplace which is 2x enclosed.  */
00675     for (i = 0; i <= SIZEOFFREE1; i++) {
00676         int lx, ly, sindex;
00677 
00678         lx = x+freearr_x[i];
00679         ly = y+freearr_y[i];
00680         sindex = surround_flag3(map, lx, ly, RP);
00681         /* if it's blocked on 3 sides, it's enclosed */
00682         if (sindex == 3 || sindex == 5 || sindex == 9 || sindex == 6 || sindex == 10 || sindex == 12) {
00683             *cx = lx;
00684             *cy = ly;
00685             return;
00686         }
00687     }
00688 
00689     /* settle for one surround point */
00690     for (i = 0; i <= SIZEOFFREE1; i++) {
00691         int lx, ly, sindex;
00692 
00693         lx = x+freearr_x[i];
00694         ly = y+freearr_y[i];
00695         sindex = surround_flag3(map, lx, ly, RP);
00696         /* if it's blocked on 3 sides, it's enclosed */
00697         if (sindex) {
00698             *cx = lx;
00699             *cy = ly;
00700             return;
00701         }
00702     }
00703 
00704     /* give up and return the closest free spot. */
00705     i = find_first_free_spot(&find_archetype("chest")->clone, map, x, y);
00706     if (i != -1 && i <= SIZEOFFREE1) {
00707         *cx = x+freearr_x[i];
00708         *cy = y+freearr_y[i];
00709         return;
00710     }
00711     /* indicate failure */
00712     *cx = *cy = -1;
00713 }
00714 
00722 void remove_monsters(int x, int y, mapstruct *map) {
00723     object *tmp;
00724 
00725     for (tmp = GET_MAP_OB(map, x, y); tmp != NULL; tmp = tmp->above)
00726         if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
00727             if (tmp->head)
00728                 tmp = tmp->head;
00729             remove_ob(tmp);
00730             free_object(tmp);
00731             tmp = GET_MAP_OB(map, x, y);
00732             if (tmp == NULL)
00733                 break;
00734         };
00735 }
00736 
00755 static object **surround_by_doors(mapstruct *map, char **layout, int x, int y, int opts) {
00756     int i;
00757     const char *doors[2];
00758     object **doorlist;
00759     int ndoors_made = 0;
00760     doorlist = (object **)calloc(9, sizeof(object *)); /* 9 doors so we can hold termination null */
00761 
00762     /* this is a list we pick from, for horizontal and vertical doors */
00763     if (opts&DOORED) {
00764         doors[0] = "locked_door2";
00765         doors[1] = "locked_door1";
00766     } else {
00767         doors[0] = "door_1";
00768         doors[1] = "door_2";
00769     }
00770 
00771     /* place doors in all the 8 adjacent unblocked squares. */
00772     for (i = 1; i < 9; i++) {
00773         int x1 = x+freearr_x[i], y1 = y+freearr_y[i];
00774 
00775         if (!wall_blocked(map, x1, y1)
00776         || layout[x1][y1] == '>') {/* place a door */
00777             object *new_door = create_archetype((freearr_x[i] == 0) ? doors[1] : doors[0]);
00778 
00779             new_door->x = x+freearr_x[i];
00780             new_door->y = y+freearr_y[i];
00781             remove_monsters(new_door->x, new_door->y, map);
00782             insert_ob_in_map(new_door, map, NULL, 0);
00783             doorlist[ndoors_made] = new_door;
00784             ndoors_made++;
00785         }
00786     }
00787     return doorlist;
00788 }
00789 
00801 static object *door_in_square(mapstruct *map, int x, int y) {
00802     object *tmp;
00803 
00804     for (tmp = GET_MAP_OB(map, x, y); tmp != NULL; tmp = tmp->above)
00805         if (tmp->type == DOOR || tmp->type == LOCKED_DOOR)
00806             return tmp;
00807     return NULL;
00808 }
00809 
00824 void find_doors_in_room_recursive(char **layout, mapstruct *map, int x, int y, object **doorlist, int *ndoors, RMParms *RP) {
00825     int i, j;
00826     object *door;
00827 
00828     /* bounds check x and y */
00829     if (!(x >= 0 && y >= 0 && x < RP->Xsize && y < RP->Ysize))
00830         return;
00831 
00832     /* if the square is blocked or searched already, leave */
00833     if (layout[x][y] == 1)
00834         return;
00835 
00836     /* check off this point */
00837     if (layout[x][y] == '#') { /* there could be a door here */
00838         layout[x][y] = 1;
00839         door = door_in_square(map, x, y);
00840         if (door != NULL) {
00841             doorlist[*ndoors] = door;
00842             if (*ndoors > 254) { /* eek!  out of memory */
00843                 LOG(llevError, "find_doors_in_room_recursive:Too many doors for memory allocated!\n");
00844                 return;
00845             }
00846             *ndoors = *ndoors+1;
00847         }
00848     } else {
00849         layout[x][y] = 1;
00850         /* now search all the 8 squares around recursively for free spots, in random order */
00851         for (i = RANDOM()%8, j = 0; j < 8; i++, j++) {
00852             find_doors_in_room_recursive(layout, map, x+freearr_x[i%8+1], y+freearr_y[i%8+1], doorlist, ndoors, RP);
00853         }
00854     }
00855 }
00856 
00871 object **find_doors_in_room(mapstruct *map, int x, int y, RMParms *RP) {
00872     char **layout2;
00873     object **doorlist;
00874     int i, j;
00875     int ndoors = 0;
00876 
00877     doorlist = (object **)calloc(sizeof(int), 256);
00878 
00879 
00880     layout2 = (char **)calloc(sizeof(char *), RP->Xsize);
00881     /* allocate and copy the layout, converting C to 0. */
00882     for (i = 0; i < RP->Xsize; i++) {
00883         layout2[i] = (char *)calloc(sizeof(char), RP->Ysize);
00884         for (j = 0; j < RP->Ysize; j++) {
00885             if (wall_blocked(map, i, j))
00886                 layout2[i][j] = '#';
00887         }
00888     }
00889 
00890     /* setup num_free_spots and room_free_spots */
00891     find_doors_in_room_recursive(layout2, map, x, y, doorlist, &ndoors, RP);
00892 
00893     /* deallocate the temp. layout */
00894     for (i = 0; i < RP->Xsize; i++) {
00895         free(layout2[i]);
00896     }
00897     free(layout2);
00898     return doorlist;
00899 }
00900 
00910 static void remove_adjacent_doors(object *door) {
00911     mapstruct *m = door->map;
00912     int x = door->x;
00913     int y = door->y;
00914     int i, flags;
00915     object *tmp;
00916 
00917     for (i = 1; i <= 8; i++) {
00918         flags = get_map_flags(m, NULL, x+freearr_x[i], y+freearr_y[i], NULL, NULL);
00919         if (flags&P_OUT_OF_MAP)
00920             continue;
00921 
00922         /* Old style doors are living objects.  So if P_IS_ALIVE is not
00923          * set, can not be a door on this space.
00924          */
00925         if (flags&P_IS_ALIVE) {
00926             for (tmp = GET_MAP_OB(m, x+freearr_x[i], y+freearr_y[i]); tmp; tmp = tmp->above) {
00927                 if (tmp->type == DOOR) {
00928                     remove_ob(tmp);
00929                     free_object(tmp);
00930                     break;
00931                 }
00932             }
00933         }
00934     }
00935 }
00936 
00952 void lock_and_hide_doors(object **doorlist, mapstruct *map, int opts, RMParms *RP) {
00953     object *door;
00954     int i;
00955 
00956     /* lock the doors and hide the keys. */
00957     if (opts&DOORED) {
00958         for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++) {
00959             object *new_door = create_archetype("locked_door1");
00960             char keybuf[256];
00961 
00962             door = doorlist[i];
00963             new_door->face = door->face;
00964             new_door->x = door->x;
00965             new_door->y = door->y;
00966             remove_ob(door);
00967             free_object(door);
00968             doorlist[i] = new_door;
00969             insert_ob_in_map(new_door, map, NULL, 0);
00970 
00971             snprintf(keybuf, 256, "%d", (int)RANDOM());
00972             if (keyplace(map, new_door->x, new_door->y, keybuf, NO_PASS_DOORS, 2, RP))
00973                 new_door->slaying = add_string(keybuf);
00974         }
00975         for (i = 0; doorlist[i] != NULL; i++)
00976             remove_adjacent_doors(doorlist[i]);
00977     }
00978 
00979     /* change the faces of the doors and surrounding walls to hide them. */
00980     if (opts&HIDDEN) {
00981         for (i = 0, door = doorlist[0]; doorlist[i] != NULL; i++) {
00982             object *wallface;
00983 
00984             door = doorlist[i];
00985             wallface = retrofit_joined_wall(map, door->x, door->y, 1, RP);
00986             if (wallface != NULL) {
00987                 retrofit_joined_wall(map, door->x-1, door->y, 0, RP);
00988                 retrofit_joined_wall(map, door->x+1, door->y, 0, RP);
00989                 retrofit_joined_wall(map, door->x, door->y-1, 0, RP);
00990                 retrofit_joined_wall(map, door->x, door->y+1, 0, RP);
00991                 door->face = wallface->face;
00992                 if (!QUERY_FLAG(wallface, FLAG_REMOVED))
00993                     remove_ob(wallface);
00994                 free_object(wallface);
00995             }
00996         }
00997     }
00998 }