Crossfire Server, Branch 1.12
R12190
|
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 }