00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00022
00023 #include "crogue.h"
00024 #include "dll.h"
00025
00026 #define ROOMCONN_RETRIES 2
00027 #define CORRIDOREND_RETRIES 10
00028 #define CORRIDORBRANCH_RETRIES 2
00029 #define ROOMSIZE_MAX_X 8
00030 #define ROOMSIZE_MIN_X 4
00031 #define ROOMSIZE_MAX_Y 8
00032 #define ROOMSIZE_MIN_Y 4
00033 #define CORRIDOR_MAX_LEN 10
00034 #define CORRIDOR_MIN_LEN 4
00035
00036 #define TFLAG_CLEAN 1
00037 #define TFLAG_RECEPTACLE 2
00038 #define TFLAG_JUNCTION 4
00039
00040 typedef struct mark
00041 {
00042 scoord pos;
00043 unsigned char direction;
00044 unsigned char retries;
00045 } mark;
00046
00047
00048 typedef union feature_info
00049 {
00050 short length;
00051
00052 struct {
00053 scoord size;
00054 short offset;
00055 } room;
00056
00057 struct {
00058 short vaultid;
00059 } vault;
00060 } feature_info;
00061
00062
00063 typedef struct feature
00064 {
00065 scoord pos;
00066 feature_info ext;
00067 short type;
00068 short direction;
00069 } feature;
00070
00071 #define NUM_TYPES 2
00072 #define FEATURE_ROOM 0
00073 #define FEATURE_CORRIDOR 1
00074 #define FEATURE_VAULT 2
00075
00076 typedef struct vaultdesc
00077 {
00078 scoord size;
00079 scoord offset;
00080 const char *content;
00081 } vaultdesc;
00082
00083
00084 #define NUM_VAULT_TYPES 12
00085
00086 #define VAULTCHAR_BLANK '/'
00087 #define VAULTCHAR_WALL_HARD '#'
00088 #define VAULTCHAR_WALL_SOFT '$'
00089
00090 #define VAULTCHAR_DOOR '+'
00091 #define VAULTCHAR_MARK_DOWN '2'
00092 #define VAULTCHAR_MARK_LEFT '4'
00093 #define VAULTCHAR_MARK_RIGHT '6'
00094 #define VAULTCHAR_MARK_UP '8'
00095
00096 const vaultdesc vaults[] =
00097 {
00098
00099 { {7,7}, {4,0},
00100 "/## ##/"
00101 "## ##"
00102 "# #"
00103 "4 6"
00104 "# #"
00105 "## ##"
00106 "/##2##/"
00107 },
00108
00109
00110 { {9,9}, {4,0},
00111 "//## ##//"
00112 "/## ##/"
00113 "## ##"
00114 "# #"
00115 "4 6"
00116 "# #"
00117 "## ##"
00118 "/## ##/"
00119 "//##2##//"
00120 },
00121
00122
00123 { {11,11}, {5,0},
00124 "//### ###//"
00125 "/## ##/"
00126 "## ##"
00127 "# #"
00128 "# #"
00129 "4 6"
00130 "# #"
00131 "# #"
00132 "## ##"
00133 "/## ##/"
00134 "//###2###//"
00135 },
00136
00137
00138 { {9,9}, {4,0},
00139 "//## ##//"
00140 "//# #//"
00141 "### ###"
00142 "# #"
00143 "4 6"
00144 "# #"
00145 "### ###"
00146 "//# #//"
00147 "//##2##//"
00148 },
00149
00150
00151 { {13,13}, {8,0},
00152 "
00153 "
00154 "
00155 "
00156 "/### ###/"
00157 "## ##"
00158 "4 6"
00159 "## ##"
00160 "/### ###/"
00161 "
00162 "
00163 "
00164 "
00165 },
00166
00167
00168 { {15,15}, {8,0},
00169 "
00170 "
00171 "
00172 "
00173 "
00174 "/#### ####/"
00175 "## ##"
00176 "4 6"
00177 "## ##"
00178 "/#### ####/"
00179 "
00180 "
00181 "
00182 "
00183 "
00184 },
00185
00186
00187 { {9,9}, {4,0},
00188 "//## ##//"
00189 "/## ##/"
00190 "## ##"
00191 "# ### #"
00192 "4 ### 6"
00193 "# ### #"
00194 "## ##"
00195 "/## ##/"
00196 "//##2##//"
00197 },
00198
00199
00200 { {11,11}, {5,0},
00201 "//### ###//"
00202 "/## ##/"
00203 "## ### ##"
00204 "# ##### #"
00205 "# ####### #"
00206 "4 ####### 6"
00207 "# ####### #"
00208 "# ##### #"
00209 "## ### ##"
00210 "/## ##/"
00211 "//###2###//"
00212 },
00213
00214
00215 { {13,13}, {8,0},
00216 "
00217 "
00218 "/## ##/"
00219 "## ### ##"
00220 "# ##### #"
00221 "# ####### #"
00222 "4 ####### 6"
00223 "# ####### #"
00224 "# ##### #"
00225 "## ### ##"
00226 "/## ##/"
00227 "//## ##//"
00228 "
00229 },
00230 //}}}
00231 //{{{
00232 { {17,17}, {8,0},// 15x15 rotary
00233 "
00234 "
00235 "
00236 "/## ### ##/"
00237 "/# ####### #/"
00238 "## ######### ##"
00239 "# ######### #"
00240 "# ########### #"
00241 "4 ########### 6"
00242 "# ########### #"
00243 "# ######### #"
00244 "## ######### ##"
00245 "/# ####### #/"
00246 "/## ### ##/"
00247 "//## ##//"
00248 "
00249 "
00250 },
00251
00252
00253 { {15,15}, {3,0},
00254 "### ###########"
00255 "# #"
00256 "# #"
00257 "4 6"
00258 "# #"
00259 "# ### #"
00260 "# ## ## #"
00261 "4 # # 6"
00262 "# ## ## #"
00263 "# ### #"
00264 "# #"
00265 "4 6"
00266 "# #"
00267 "# #"
00268 "###2###2###2###"
00269 },
00270
00271
00272 { {13,11}, {6,0},
00273 "###### ######"
00274 "# #"
00275 "# ######### #"
00276 "# + # + #"
00277 "# # # # #"
00278 "4 ######### 6"
00279 "# # # # #"
00280 "# + # + #"
00281 "# ######### #"
00282 "# #"
00283 "######2######"
00284 },
00285
00286 };
00287
00288
00289 scoord directions[4] =
00290 {
00291 { 1, 0 },
00292 { 0, -1 },
00293 { -1, 0 },
00294 { 0, 1 }
00295 };
00296
00297 #define DIR_RIGHT 0
00298 #define DIR_UP 1
00299 #define DIR_LEFT 2
00300 #define DIR_DOWN 3
00301
00302 static void bigmap_prepass(void);
00303 static int bigmap_postpass(void);
00304 static void bigmap_fill(void);
00305 static int bigmap_place_feature(feature *feature, mark *marks, int *marks_pending);
00306 static int bigmap_place_corridor(feature *feature, int dry, mark *marks, int *marks_pending);
00307 static int bigmap_place_room(feature *feature, int dry, mark *marks, int *pending);
00308 static int bigmap_place_vault(feature *feature, int dry, mark *marks, int *pending);
00309 static void rand_feature(feature *feature, mark *m);
00310 static void add_mark(int x, int y, int dir, mark *marks, int *pending, int retries);
00311
00312
00313 int mkmap_big(void)
00314 {
00315 bigmap_prepass();
00316 bigmap_fill();
00317 return bigmap_postpass();
00318 }
00319
00320
00321 static int is_in_bounds(scoord pos)
00322 {
00323 if(pos.x<=0 || pos.y<=0 || pos.x>=MAPSIZE_X-1 || pos.y>=MAPSIZE_Y-1)
00324 return 0;
00325 else
00326 return 1;
00327 }
00328
00329
00330 static void bigmap_prepass(void)
00331 {
00332 int xi, yi;
00333 for(yi=0; yi<MAPSIZE_Y; yi++)
00334 for(xi=0; xi<MAPSIZE_X; xi++)
00335 w->t[yi][xi].flags = TFLAG_CLEAN;
00336 }
00337
00338
00339 static int bigmap_postpass(void)
00340 {
00341 int xi, yi;
00342 unsigned filled=0, empty=0;
00343 for(yi=1; yi<MAPSIZE_Y-1; yi++)
00344 for(xi=1; xi<MAPSIZE_X-1; xi++)
00345 {
00346 if(w->t[yi][xi].type == TILE_FLOOR)
00347 empty++;
00348 else
00349 filled++;
00350 if(w->t[yi][xi].flags & TFLAG_JUNCTION && make_door(xi, yi))
00351 {
00352 if(nrandom(15,0)==0)
00353 w->t[yi][xi].type = TILE_SDOOR;
00354 else
00355 w->t[yi][xi].type = TILE_CDOOR;
00356 }
00357 }
00358
00359 for(yi=0; yi<MAPSIZE_Y; yi++)
00360 for(xi=0; xi<MAPSIZE_X; xi++)
00361 w->t[yi][xi].flags = 0;
00362
00363 if(empty < 100)
00364 return 0;
00365 else
00366 return 1;
00367 }
00368
00369
00370 static void bigmap_fill(void)
00371 {
00372 mark marks[512];
00373 int marks_pending = 0;
00374 int current_mark;
00375 feature current_feature;
00376
00377 add_mark(MAPSIZE_X/2, MAPSIZE_Y/2, nrandom(3,0), marks, &marks_pending,255);
00378
00379 while(marks_pending > 0)
00380 {
00381
00382 current_mark = nrandom(marks_pending-1, 0);
00383
00384
00385 rand_feature(¤t_feature, &marks[current_mark]);
00386
00387
00388 if( bigmap_place_feature(¤t_feature, marks, &marks_pending) ) {
00389 marks[current_mark] = marks[--marks_pending];
00390 } else {
00391 marks[current_mark].retries --;
00392 if(marks[current_mark].retries == 0)
00393 marks[current_mark] = marks[--marks_pending];
00394 }
00395 }
00396 }
00397
00398
00399 static int bigmap_place_feature(feature *feature, mark *marks, int *pending)
00400 {
00401 switch(feature->type)
00402 {
00403 case FEATURE_CORRIDOR:
00404
00405 if(bigmap_place_corridor(feature, 1, marks, pending))
00406 return bigmap_place_corridor(feature, 0, marks, pending);
00407 else return 0;
00408 default:
00409 case FEATURE_ROOM:
00410
00411 if(bigmap_place_room(feature, 1, marks, pending))
00412 return bigmap_place_room(feature, 0, marks, pending);
00413 else return 0;
00414 case FEATURE_VAULT:
00415 if(bigmap_place_vault(feature, 1, marks, pending))
00416 return bigmap_place_vault(feature, 0, marks, pending);
00417 else return 0;
00418 }
00419 }
00420
00421
00422 static int bigmap_place_corridor(feature *feature, int dry,
00423 mark *marks, int *marks_pending)
00424 {
00425 int ii;
00426 scoord pos = feature->pos;
00427 scoord delta = directions[feature->direction];
00428 scoord perpendicular = directions[ (feature->direction+1)%4 ];
00429 scoord tmp;
00430 int branch_direction = (feature->direction+1)%4;
00431
00432 for(ii=0; ii<feature->ext.length; ii++)
00433 {
00434
00435 if(!is_in_bounds(pos)) return 0;
00436
00437 if(dry)
00438 {
00439 if(w->t[pos.y][pos.x].flags & TFLAG_RECEPTACLE)
00440
00441
00442 return 1;
00443 if(w->t[pos.y][pos.x].flags & TFLAG_CLEAN)
00444
00445 continue;
00446 return 0;
00447 }
00448 else
00449 {
00450 if(w->t[pos.y][pos.x].flags & TFLAG_CLEAN)
00451 {
00452 w->t[pos.y][pos.x].type = TILE_FLOOR;
00453 w->t[pos.y][pos.x].flags &= ~TFLAG_CLEAN;
00454
00455
00456 if(nrandom(8,0)==0)
00457 {
00458 if(nrandom(1,0))
00459 {
00460 perpendicular.x = -perpendicular.x;
00461 perpendicular.y = -perpendicular.y;
00462 branch_direction = (branch_direction+2)%4;
00463 }
00464 tmp.x = pos.x + perpendicular.x;
00465 tmp.y = pos.y + perpendicular.y;
00466 add_mark(tmp.x, tmp.y, branch_direction,
00467 marks, marks_pending, CORRIDORBRANCH_RETRIES);
00468 }
00469 }
00470 else if(w->t[pos.y][pos.x].flags & TFLAG_RECEPTACLE)
00471 {
00472 w->t[pos.y][pos.x].type = TILE_FLOOR;
00473 return 1;
00474 }
00475 else
00476 {
00477 pos.x -= delta.x;
00478 pos.y -= delta.y;
00479 w->t[pos.y][pos.x].flags |= TFLAG_JUNCTION;
00480 return 1;
00481 }
00482 }
00483
00484 pos.x += delta.x;
00485 pos.y += delta.y;
00486 }
00487
00488 if(!dry) {
00489 add_mark(pos.x, pos.y, feature->direction,
00490 marks, marks_pending, CORRIDOREND_RETRIES);
00491 }
00492
00493
00494 return 1;
00495 }
00496
00497
00498 static int bigmap_place_room(feature *feature, int dry,
00499 mark *marks, int *pending)
00500 {
00501 scoord next_cell, next_row;
00502 scoord pos;
00503 int xi, yi;
00504 int min_x, max_x, min_y, max_y;
00505 int intersections = 0;
00506
00507 next_cell.x = directions[(feature->direction+1)%4].x;
00508 next_cell.y = directions[(feature->direction+1)%4].y;
00509 next_row.x = directions[feature->direction].x
00510 - next_cell.x*feature->ext.room.size.x;
00511 next_row.y = directions[feature->direction].y
00512 - next_cell.y*feature->ext.room.size.x;
00513
00514 if(dry) {
00515 if(!(w->t[feature->pos.y][feature->pos.x].flags & TFLAG_CLEAN))
00516 return 0;
00517 } else {
00518 w->t[feature->pos.y][feature->pos.x].flags &= ~TFLAG_CLEAN;
00519 w->t[feature->pos.y][feature->pos.x].type = TILE_FLOOR;
00520 }
00521
00522 pos.x = feature->pos.x + directions[feature->direction].x;
00523 pos.y = feature->pos.y + directions[feature->direction].y;
00524 pos.x -= next_cell.x * feature->ext.room.offset;
00525 pos.y -= next_cell.y * feature->ext.room.offset;
00526 min_x = max_x = pos.x;
00527 min_y = max_y = pos.y;
00528
00529 for(yi=0; yi<feature->ext.room.size.y; yi++)
00530 {
00531 for(xi=0; xi<feature->ext.room.size.x; xi++)
00532 {
00533
00534 if(!is_in_bounds(pos)) return 0;
00535
00536 if(dry) {
00537 if(!(w->t[pos.y][pos.x].flags & TFLAG_CLEAN))
00538 return 0;
00539 } else {
00540 w->t[pos.y][pos.x].type = TILE_FLOOR;
00541 w->t[pos.y][pos.x].flags &= ~TFLAG_CLEAN;
00542 }
00543
00544 if(pos.x < min_x) min_x = pos.x;
00545 if(pos.x > max_x) max_x = pos.x;
00546 if(pos.y < min_y) min_y = pos.y;
00547 if(pos.y > max_y) max_y = pos.y;
00548 pos.x += next_cell.x;
00549 pos.y += next_cell.y;
00550 }
00551 pos.x += next_row.x;
00552 pos.y += next_row.y;
00553 }
00554
00555 if(dry)
00556 {
00557
00558
00559
00560
00561 min_x --; max_x ++;
00562 min_y --; max_y ++;
00563
00564
00565
00566 for(xi=min_x; xi<=max_x; xi++) {
00567 if(min_y>0 && w->t[min_y][xi].type != TILE_WALL)
00568 intersections++;
00569 if(max_y<MAPSIZE_Y-1 && w->t[max_y][xi].type != TILE_WALL)
00570 intersections++;
00571 }
00572 for(yi=min_y; yi<=max_y; yi++) {
00573 if(min_x>0 && w->t[yi][min_x].type != TILE_WALL)
00574 intersections++;
00575 if(max_x<MAPSIZE_X-1 && w->t[yi][max_x].type != TILE_WALL)
00576 intersections++;
00577 }
00578 if(intersections>1)
00579 return 0;
00580 }
00581 else
00582 {
00583 add_mark(nrandom(max_x, min_x), max_y+1, DIR_DOWN,
00584 marks, pending, ROOMCONN_RETRIES);
00585 add_mark(nrandom(max_x, min_x), min_y-1, DIR_UP,
00586 marks, pending, ROOMCONN_RETRIES);
00587 add_mark(min_x-1, nrandom(max_y, min_y), DIR_LEFT,
00588 marks, pending, ROOMCONN_RETRIES);
00589 add_mark(max_x+1, nrandom(max_y, min_y), DIR_RIGHT,
00590 marks, pending, ROOMCONN_RETRIES);
00591 }
00592
00593 return 1;
00594 }
00595
00596
00597 static int bigmap_place_vault(feature *feature, int dry,
00598 mark *marks, int *pending)
00599 {
00600 scoord next_cell, next_row;
00601 scoord perpendicular_cell;
00602 scoord pos;
00603 int xi, yi;
00604 int direction = feature->direction;
00605 const vaultdesc *desc = &vaults[feature->ext.vault.vaultid];
00606
00607 next_cell.x = directions[(feature->direction+1)%4].x;
00608 next_cell.y = directions[(feature->direction+1)%4].y;
00609 next_row.x = directions[feature->direction].x
00610 - next_cell.x*desc->size.x;
00611 next_row.y = directions[feature->direction].y
00612 - next_cell.y*desc->size.x;
00613 perpendicular_cell.x = directions[feature->direction].x;
00614 perpendicular_cell.y = directions[feature->direction].y;
00615
00616 pos.x = feature->pos.x + directions[feature->direction].x;
00617 pos.y = feature->pos.y + directions[feature->direction].y;
00618 pos.x -= next_cell.x * desc->offset.x;
00619 pos.y -= next_cell.y * desc->offset.x;
00620 pos.x -= perpendicular_cell.x * desc->offset.y;
00621 pos.y -= perpendicular_cell.y * desc->offset.y;
00622
00623 for(yi=0; yi<desc->size.y; yi++)
00624 {
00625 for(xi=0; xi<desc->size.x; xi++)
00626 {
00627
00628 if(!is_in_bounds(pos)) return 0;
00629
00630 if(dry) {
00631 if(desc->content[yi*desc->size.x + xi] != '/')
00632 {
00633 if(w->t[pos.y][pos.x].type != TILE_WALL)
00634 return 0;
00635 }
00636 } else {
00637 switch(desc->content[ yi*desc->size.x + xi ])
00638 {
00639 case '/':
00640 break;
00641 case '2':
00642 add_mark(pos.x, pos.y, (DIR_DOWN+direction+1)%4,
00643 marks, pending, ROOMCONN_RETRIES);
00644 break;
00645 case '4':
00646 add_mark(pos.x, pos.y, (DIR_LEFT+direction+1)%4,
00647 marks, pending, ROOMCONN_RETRIES);
00648 break;
00649 case '6':
00650 add_mark(pos.x, pos.y, (DIR_RIGHT+direction+1)%4,
00651 marks, pending, ROOMCONN_RETRIES);
00652 break;
00653 case '8':
00654 add_mark(pos.x, pos.y, (DIR_UP+direction+1)%4,
00655 marks, pending, ROOMCONN_RETRIES);
00656 break;
00657 case '#':
00658 w->t[pos.y][pos.x].flags &= ~TFLAG_CLEAN;
00659 break;
00660 case ' ':
00661 w->t[pos.y][pos.x].type = TILE_FLOOR;
00662 w->t[pos.y][pos.x].flags &= ~TFLAG_CLEAN;
00663 break;
00664 case '+':
00665 w->t[pos.y][pos.x].type = TILE_CDOOR;
00666 w->t[pos.y][pos.x].flags &= ~TFLAG_CLEAN;
00667 }
00668 }
00669 pos.x += next_cell.x;
00670 pos.y += next_cell.y;
00671 }
00672 pos.x += next_row.x;
00673 pos.y += next_row.y;
00674 }
00675 return 1;
00676 }
00677
00678
00679 static void rand_feature(feature *feature, mark *m)
00680 {
00681 const vaultdesc *vault_desc;
00682
00683 feature->pos = m->pos;
00684 feature->direction = m->direction;
00685 if(nrandom(5,1)==1)
00686 feature->type = FEATURE_CORRIDOR;
00687 else if(nrandom(2,1)==1)
00688 feature->type = FEATURE_ROOM;
00689 else
00690 feature->type = FEATURE_VAULT;
00691
00692 switch(feature->type)
00693 {
00694 case FEATURE_CORRIDOR:
00695 feature->ext.length = nrandom(CORRIDOR_MAX_LEN, CORRIDOR_MIN_LEN);
00696 break;
00697 case FEATURE_ROOM:
00698 feature->ext.room.size.x = nrandom(ROOMSIZE_MAX_X, ROOMSIZE_MIN_Y);
00699 feature->ext.room.size.y = nrandom(ROOMSIZE_MAX_X, ROOMSIZE_MIN_Y);
00700 feature->ext.room.offset = nrandom(feature->ext.room.size.x-1, 0);
00701 break;
00702 case FEATURE_VAULT:
00703 feature->ext.vault.vaultid = nrandom(NUM_VAULT_TYPES-1, 0);
00704 vault_desc = &vaults[feature->ext.vault.vaultid];
00705 break;
00706 }
00707 }
00708
00709
00710 static void add_mark(int x, int y, int dir, mark *marks, int *pending,
00711 int retries)
00712 {
00713 if(*pending >= 512) return;
00714 marks[*pending].pos.x = x;
00715 marks[*pending].pos.y = y;
00716 marks[*pending].direction = dir;
00717 marks[*pending].retries = retries;
00718 w->t[y][x].flags |= TFLAG_JUNCTION;
00719 (*pending)++;
00720 }
00721
00722