00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00025
00026 #include "crogue.h"
00027 #include "export.h"
00028
00029 static const schar simpledir[4][2] = {
00030 {0,-1}, {1,0}, {0,1}, {-1,0}
00031 };
00032 static const schar cornerdir[4][2] = {
00033 {-1,-1}, {1,-1},
00034
00035 {-1,1}, {1,1}
00036 };
00037 const schar dir[8][2] = {
00038 {-1,-1}, {0,-1}, {1,-1},
00039 {-1,0}, {1,0},
00040 {-1,1}, {0,1}, {1,1}
00041 };
00042
00043 void gen_map(int source, coord pos);
00044 void mkmap(map_gen_method *desc);
00045 void base_coat(void);
00046 sint place_room(room *r);
00047 void place_hole(void);
00048 void make_noise(ushort floor, ushort wall);
00049 void cave_generation(ushort floor, ushort wall);
00050 sint place_corridors(void);
00051 void fill_room(room *r);
00052
00053
00054 void place_doors(void);
00055
00056 void place_items(void);
00057 void make_connections(void);
00058 void place_player_on_map(int source, coord pos);
00059 static void connection_fill(uint x, uint y, uint s);
00060
00061
00062
00063 void gen_map(int source, coord pos)
00064 {
00065 int i;
00066 map_gen_method *desc;
00067
00068 cleanup_items();
00069 init_items();
00070
00071 desc = (map_gen_method*)deref_file_ptr(MAPDESC_CURRENT.genmethod);
00072 resize_map_store(desc->size_x, desc->size_y);
00073
00074 w->plr.score += (MAPDESC_CURRENT.difficulty - 1) * LEVEL_SCORE_FACTOR;
00075 call_genericfunc(MAPDESC_CURRENT.genfunction);
00076
00077 place_player_on_map(source, pos);
00078
00079 for(i=0; i<MAPDESC_CURRENT.initial_population; i++)
00080 addrandommonst();
00081 }
00082
00083
00084
00085 int mkmap_big_front(void)
00086 {
00087 return mkmap_big();
00088 }
00089
00090
00091
00092 void base_coat(void)
00093 {
00094 map_gen_method *desc;
00095 int xi, yi;
00096
00097 desc = (map_gen_method*)deref_file_ptr(MAPDESC_CURRENT.genmethod);
00098
00099 rle_set_source(rle_pointer, desc->data);
00100
00101 for(yi=0; yi<MAPSIZE_Y; yi++)
00102 for(xi=0; xi<MAPSIZE_X; xi++)
00103 {
00104 w->t[yi][xi].type = rlegetc();
00105
00106 if(w->t[yi][xi].type == TILE_BLANK)
00107 {
00108 w->t[yi][xi].type = TILE_WALL;
00109 w->t[yi][xi].flags = TFLAG_MUTABLE;
00110 }
00111 else
00112 {
00113 w->t[yi][xi].flags = 0;
00114 if(desc->global_light)
00115 w->t[yi][xi].flags |= TFLAG_INTRINSIC_LIGHT;
00116 }
00117
00118 w->t[yi][xi].special = 0;
00119 }
00120
00121
00122 for(yi=0; yi<MONSTERS_MAX; yi++) {
00123 w->m[yi].type = filelink_null;
00124 w->m[yi].energy = 0;
00125 }
00126
00127 }
00128
00129
00130
00131
00132
00133 sint place_room(room *r)
00134 {
00135 int retrycount=0;
00136 int x, y;
00137
00138 retry:
00139 r->left = RANGE(MAPSIZE_X-6, 1);
00140 r->right = min(r->left+RANGE(8,3), MAPSIZE_X-2);
00141 r->top = RANGE(MAPSIZE_Y-4, 1);
00142 r->bottom = min(r->top+RANGE(6,3), MAPSIZE_Y-2);
00143
00144
00145 for(y=r->top-1; y<=r->bottom+1; y++)
00146 for(x=r->left-1; x<=r->right+1; x++)
00147 if( !(w->t[y][x].flags & TFLAG_MUTABLE) )
00148 {
00149 retrycount++;
00150 if( retrycount>200 )
00151 return 0;
00152 else
00153 goto retry;
00154 }
00155
00156 for(y=r->top; y<=r->bottom; y++)
00157 for(x=r->left; x<=r->right; x++)
00158 {
00159 w->t[y][x].flags &= ~TFLAG_MUTABLE;
00160 w->t[y][x].type=TILE_FLOOR;
00161 }
00162
00163 return 1;
00164 }
00165
00166
00167 void place_hole(void)
00168 {
00169 int x, y;
00170
00171 do
00172 {
00173 x = RANGE(MAPSIZE_X-2, 1);
00174 y = RANGE(MAPSIZE_Y-2, 1);
00175 } while(!(w->t[y][x].flags & TFLAG_MUTABLE));
00176
00177 w->t[y][x].type = TILE_FLOOR;
00178 w->t[y][x].flags &= ~TFLAG_MUTABLE;
00179 }
00180
00181
00182 void make_noise(ushort floor, ushort wall)
00183 {
00184 int x, y;
00185
00186 for(y=0; y<MAPSIZE_Y; y++)
00187 for(x=0; x<MAPSIZE_X; x++)
00188 if(w->t[y][x].flags & TFLAG_MUTABLE)
00189 {
00190 if(RANGE(100, 0) >= 45)
00191 w->t[y][x].type = floor;
00192 else
00193 w->t[y][x].type = wall;
00194 }
00195 }
00196
00197
00198 void cave_pass(ushort floor, ushort wall, void (*effect)(ushort floor, ushort wall, int x, int y, int neighbors))
00199 {
00200 int adjcount;
00201 int i, ii;
00202 int x, y;
00203
00204 for(y=1; y<MAPSIZE_Y-1; y++)
00205 for(x=1; x<MAPSIZE_X-1; x++)
00206 {
00207 if( !(w->t[y][x].flags & TFLAG_MUTABLE) )
00208 continue;
00209
00210 adjcount=0;
00211 for(i=-1; i<=1; i++)
00212 for(ii=-1; ii<=1; ii++)
00213 if( w->t[y+i][x+ii].type != floor )
00214 adjcount++;
00215
00216 effect(floor, wall, x, y, adjcount);
00217 }
00218 }
00219
00220
00221 void cb_cave_partial(ushort floor, ushort wall, int x, int y, int neighbors)
00222 {
00223 if(neighbors >= nrandom(9,0))
00224 w->t[y][x].type = wall;
00225 else
00226 w->t[y][x].type = floor;
00227 }
00228
00229
00230 void cave_partial_gen(ushort floor, ushort wall)
00231 {
00232 cave_pass(floor, wall, cb_cave_partial);
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 }
00255
00256
00257 void cb_cave(ushort floor, ushort wall, int x, int y, int neighbors)
00258 {
00259 if(neighbors >= 5)
00260 w->t[y][x].type = wall;
00261 else
00262 w->t[y][x].type = floor;
00263 }
00264
00265
00266 void cave_generation(ushort floor, ushort wall)
00267 {
00268 cave_pass(floor, wall, cb_cave);
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 }
00291
00292 static void replace(int from, int into);
00293
00294 sint place_corridors(void)
00295 {
00296 int num_areas=0;
00297 int state=0;
00298 int x, y;
00299 int type, otype;
00300 int tries=0;
00301
00302
00303 for(y=0; y<MAPSIZE_Y; y++)
00304 {
00305 for(x=0; x<MAPSIZE_X; x++)
00306 {
00307 if(state) {
00308 if( !TILEDESC(w->t[y][x]).passable ) {
00309 state=0;
00310 } else {
00311 w->t[y][x].special = num_areas;
00312 }
00313 } else {
00314 if( TILEDESC(w->t[y][x]).passable ) {
00315 state=1;
00316 num_areas++;
00317 w->t[y][x].special = num_areas;
00318 }
00319 }
00320 }
00321 state=0;
00322 }
00323
00324
00325 for(y=1; y<MAPSIZE_Y-1; y++)
00326 for(x=1; x<MAPSIZE_X-1; x++) {
00327 type = w->t[y][x].special;
00328 otype = w->t[y+1][x].special;
00329 if( type!=0 && otype!=0 && type!=otype ) {
00330 num_areas--;
00331 replace(otype, type);
00332 }
00333 otype = w->t[y][x+1].special;
00334 if( type!=0 && otype!=0 && type!=otype ) {
00335 num_areas--;
00336 replace(otype, type);
00337 }
00338 }
00339
00340
00341 do {
00342
00343 y = RANGE(MAPSIZE_Y-2, 1);
00344 type = otype = 0;
00345 for(x=1; x<MAPSIZE_X-1; x++) {
00346 if( w->t[y][x].special) {
00347 if(!otype)
00348 otype = w->t[y][x].special;
00349 else {
00350 type = w->t[y][x].special;
00351 if(type==otype) continue;
00352
00353 for(;;x--) {
00354 if(w->t[y][x].special == otype) break;
00355 w->t[y][x].type = TILE_FLOOR;
00356
00357 w->t[y][x].special = type;
00358 }
00359 replace(type, otype);
00360 num_areas--;
00361 break;
00362 }
00363 }
00364 }
00365
00366
00367 x = RANGE( MAPSIZE_X-2, 1);
00368 type = otype = 0;
00369 for(y=1; y<MAPSIZE_Y-1; y++) {
00370 if( w->t[y][x].special ) {
00371 if(!otype)
00372 otype = w->t[y][x].special;
00373 else {
00374 type = w->t[y][x].special;
00375 if(type==otype) continue;
00376
00377 for(;;y--) {
00378 if(w->t[y][x].special == otype) break;
00379 w->t[y][x].type = TILE_FLOOR;
00380
00381 w->t[y][x].special = type;
00382 }
00383 replace(type, otype);
00384 num_areas--;
00385 break;
00386 }
00387 }
00388 }
00389
00390 tries++;
00391 if(tries>750) {
00392 return 0;
00393 }
00394
00395 } while(num_areas>1);
00396
00397 for(y=0; y<MAPSIZE_Y; y++)
00398 for(x=0; x<MAPSIZE_X; x++)
00399 {
00400 w->t[y][x].special = 0;
00401 }
00402
00403 return 1;
00404 }
00405
00406 static void replace(int from, int into)
00407 {
00408 int x, y;
00409
00410 for(y=0; y<MAPSIZE_Y; y++)
00411 for(x=0; x<MAPSIZE_X; x++)
00412 if(w->t[y][x].special == from)
00413 w->t[y][x].special = into;
00414 }
00415
00416
00417 void fill_room(room *r)
00418 {
00419 dll_fill_room(r);
00420 }
00421
00422
00423 void place_doors(void)
00424 {
00425 int x, y;
00426
00427
00428
00429
00430
00431
00432
00433 for(y=1; y<MAPSIZE_Y-1; y++)
00434 for(x=1; x<MAPSIZE_X-1; x++)
00435 {
00436 if( !(w->t[y][x].flags & TFLAG_MUTABLE) )
00437 continue;
00438
00439 if(make_door(x, y)) {
00440 if(RANGE(7,0)==0)
00441 w->t[y][x].type = TILE_SDOOR;
00442 else
00443 w->t[y][x].type = TILE_CDOOR;
00444 }
00445 }
00446 }
00447
00448
00449 int make_door(int x, int y)
00450 {
00451 int i;
00452 int result;
00453 tile *type, *otype;
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464 otype = &w->t[y+simpledir[0][1]][x+simpledir[0][0]];
00465 if(TILEDESC(*otype).is_door) return 0;
00466
00467 for(i=1; i<4; i++) {
00468 type = &w->t[y+simpledir[i][1]][x+simpledir[i][0]];
00469 if(TILEDESC(*type).is_wall == TILEDESC(*otype).is_wall || TILEDESC(*type).is_door)
00470 return 0;
00471 otype = type;
00472 }
00473
00474 result=0;
00475 for(i=0; i<3; i++)
00476 {
00477 type = &w->t[y+cornerdir[i][1]][x+cornerdir[i][0]];
00478 if( TILEDESC(*type).passable )
00479 result|=1;
00480 if( TILEDESC(*type).is_wall )
00481 result|=2;
00482 }
00483
00484 if(result==3)
00485 return 1;
00486 else
00487 return 0;
00488 }
00489
00490
00491 void place_items(void)
00492 {
00493 int yi=0, xi=0;
00494 int ii;
00495 int num_items = rrandom(MAPDESC_CURRENT.num_items);
00496 item itm;
00497
00498 for(ii=0; ii<num_items; ii++)
00499 {
00500 do {
00501 xi = nrandom(MAPSIZE_X-2, 1);
00502 yi = nrandom(MAPSIZE_Y-2, 1);
00503 } while( !w->tiledescs[ w->t[yi][xi].type ].allow_item
00504 || w->t[yi][xi].flags & TFLAG_ITEM );
00505
00506 itm = randitem(w->desc.generate_item);
00507 place_item(&itm, xi, yi);
00508 }
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 }
00521
00522
00523 void make_connections(void)
00524 {
00525 int x, y, i;
00526 const spec_descriptor *specs;
00527 item itm;
00528
00529
00530 specs = MAPDESC_CURRENT.ext;
00531
00532
00533 for( i=0; i < MAPDESC_CURRENT.numspecial; i++ )
00534 {
00535 if( specs[i].location.x==0 && specs[i].location.y == 0 ) {
00536 do {
00537 x = RANGE(MAPSIZE_X-2, 2);
00538 y = RANGE(MAPSIZE_Y-2, 2);
00539 } while(w->t[y][x].type != TILE_FLOOR);
00540 } else {
00541 x = specs[i].location.x;
00542 y = specs[i].location.y;
00543 }
00544 if( specs[i].type >= 0 )
00545 {
00546 w->t[y][x].type = specs[i].type;
00547 w->t[y][x].special = i;
00548 } else if( specs[i].type == MAPSPEC_ITEM ) {
00549 itm = randitem(specs[i].ext.spec_item);
00550 place_item(&itm, x, y);
00551 } else if( specs[i].type == MAPSPEC_MONSTER ) {
00552 addmonster(x, y, specs[i].ext.spec_monster);
00553 } else if( specs[i].type == MAPSPEC_CONNECT ) {
00554 connection_fill(x, y, i);
00555 }
00556 }
00557 }
00558
00559
00560 void place_player_on_map(int source, coord pos)
00561 {
00562 int x, y;
00563 const spec_descriptor *connections;
00564
00565 connections = MAPDESC_CURRENT.ext;
00566
00567
00568 if( pos.x || pos.y )
00569 {
00570 w->plr.x = pos.x;
00571 w->plr.y = pos.y;
00572 w->t[w->plr.y][w->plr.x].flags |= TFLAG_OCCUPIED;
00573 return;
00574 }
00575 else
00576 {
00577 for(x=0; x<MAPSIZE_X; x++)
00578 for(y=0; y<MAPSIZE_Y; y++) {
00579 if( TILEDESC(w->t[y][x]).is_connection &&
00580 ((mapdesc*)deref_file_ptr(MAPDESC_CURRENT.ext[w->t[y][x].special].ext.lvl.destmap))->mapindex == source )
00581 {
00582 w->plr.x = x;
00583 w->plr.y = y;
00584 w->t[y][x].flags |= TFLAG_OCCUPIED;
00585 return;
00586 }
00587 }
00588 }
00589
00590 place_player_randomly();
00591 }
00592
00593
00594
00595 static void connection_fill(uint x, uint y, uint s)
00596 {
00597 int xi, yi;
00598 int left, right, top, bottom;
00599 w->t[y][x].special = s;
00600 w->t[y][x].flags |= TFLAG_TEMP;
00601
00602 left = x-1;
00603 if(left<0) left=0;
00604 right = x+1;
00605 if(right>=MAPSIZE_X) right=MAPSIZE_X-1;
00606 top = y-1;
00607 if(top<0) top=0;
00608 bottom = y+1;
00609 if(bottom>=MAPSIZE_Y) bottom=MAPSIZE_Y-1;
00610
00611 for(yi=top; yi<=bottom; yi++)
00612 for(xi=left; xi<=right; xi++)
00613 {
00614 if(TILEDESC(w->t[yi][xi]).is_connection &&
00615 !(w->t[yi][xi].flags & TFLAG_TEMP) )
00616 connection_fill(xi, yi, s);
00617 }
00618 }
00619