/* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */ /* gen2.c */ /* level generator functions */ #include "glob.h" /* For each level, there should be one stairway going up and one down. fromlevel determines whether the player is placed on the up or the down staircase. The aux value is currently unused elsewhere, but is set to the destination level. */ void make_stairs(int fromlevel) { int i,j; /* no stairway out of astral */ if (Current_Environment != E_ASTRAL) { findspace(&i,&j,-1); Level->site[i][j].locchar = STAIRS_UP; Level->site[i][j].aux = Level->depth-1; lset(i,j,STOPS); if (fromlevel >= 0 && fromlevel < Level->depth) { Player.x = i; Player.y = j; } } if (Level->depth < MaxDungeonLevels) { findspace(&i,&j,-1); Level->site[i][j].locchar = STAIRS_DOWN; Level->site[i][j].aux = Level->depth+1; lset(i,j,STOPS); if (fromlevel > Level->depth) { Player.x = i; Player.y = j; } } } /* tactical map generating functions */ void make_country_screen(Symbol terrain) { int i,j; TempLevel = Level; if (ok_to_free(TempLevel)) { #ifndef SAVE_LEVELS free_level(TempLevel); #endif TempLevel = NULL; } #ifndef SAVE_LEVELS Level = ((plv) checkmalloc(sizeof(levtype))); #else msdos_changelevel(TempLevel,0,-1); Level = &TheLevel; #endif clear_level(Level); Level->environment = E_TACTICAL_MAP; Level->generated = TRUE; Level->level_length = TACTICAL_LENGTH; Level->level_width = TACTICAL_WIDTH; switch(terrain) { case FOREST: make_forest(); break; case JUNGLE: make_jungle(); break; case SWAMP: make_swamp(); break; case RIVER: make_river(); break; case MOUNTAINS: case PASS: make_mountains(); break; case ROAD: make_road(); break; default: make_plains(); break; } if (nighttime()) { print3("Night's gloom shrouds your sight."); for(i=0;ilevel_width;i++) for(j=0;jlevel_length;j++) { Level->site[i][j].showchar = SPACE; Level->site[i][j].lstatus = 0; } } } void make_general_map(char *terrain) { int i, j; int size = strlen(terrain); char curr; for (i=0;ilevel_width;i++) for (j=0;jlevel_length;j++) { if ((i == 0 && j == 0) || !random_range(5)) curr = terrain[random_range(size)]; else if (j == 0 || (random_range(2) && i > 0)) curr = Level->site[i - 1][j].locchar&0xff; else curr = Level->site[i][j - 1].locchar&0xff; switch (curr) { case (FLOOR&0xff): Level->site[i][j].locchar = Level->site[i][j].showchar = FLOOR; Level->site[i][j].p_locf = L_NO_OP; break; case (HEDGE&0xff): Level->site[i][j].locchar = Level->site[i][j].showchar = HEDGE; Level->site[i][j].p_locf = L_HEDGE; break; case (WATER&0xff): Level->site[i][j].locchar = Level->site[i][j].showchar = WATER; Level->site[i][j].p_locf = L_WATER; break; case (RUBBLE&0xff): Level->site[i][j].locchar = Level->site[i][j].showchar = RUBBLE; Level->site[i][j].p_locf = L_RUBBLE; break; } Level->site[i][j].lstatus = SEEN+LIT; Level->site[i][j].roomnumber = RS_COUNTRYSIDE; if ((i == 0) || (j == 0) || (i == (Level->level_width)-1) || (j == (Level->level_length)-1)) Level->site[i][j].p_locf = L_TACTICAL_EXIT; } } void make_plains(void) { make_general_map("."); } void make_road(void) { int x, y; make_general_map("\"\"~4...."); for (x = (Level->level_width)/2 - 3; x <= (Level->level_width)/2 + 3; x++) for (y = 0; y < Level->level_length; y++) { Level->site[x][y].locchar = Level->site[x][y].showchar = FLOOR; if (y != 0 && y != ((Level->level_length) - 1)) Level->site[x][y].p_locf = L_NO_OP; } } void make_forest(void) { make_general_map("\"."); straggle_corridor(0,random_range(Level->level_length),Level->level_width,random_range(Level->level_length), WATER,RS_COUNTRYSIDE); } void make_jungle(void) { make_general_map("\"\"."); } void make_river(void) { int i,y,y1; make_general_map("\"......."); y = random_range(Level->level_length); y1 = random_range(Level->level_length); straggle_corridor(0,y,Level->level_width,y1,WATER,RS_COUNTRYSIDE); for(i=0;i<7;i++) { if (y > (Level->level_length)/2) y--; else y++; if (y1 > (Level->level_length)/2) y1--; else y1++; straggle_corridor(0,y,Level->level_width,y1,WATER,RS_COUNTRYSIDE); } } void make_mountains(void) { int i,x,y,x1,y1; make_general_map("4..."); x = 0; y = random_range(Level->level_length); x1 = Level->level_width; y1 = random_range(Level->level_length); straggle_corridor(x,y,x1,y1,WATER,RS_COUNTRYSIDE); for(i=0;i<7;i++) { x = random_range(Level->level_width); x1 = random_range(Level->level_width); y = 0; y1 = Level->level_length; straggle_corridor(x,y,x1,y1,WATER,RS_COUNTRYSIDE); } } void make_swamp(void) { make_general_map("~~\"."); } /* builds a room. Then, for each successive room, sends off at least one corridor which is guaranteed to connect up to another room, thus guaranteeing fully connected level. */ void room_level(void) { int i,fx,fy,tx,ty,t,l,e; char rsi; Level->numrooms = random_range(8)+9; do { t = random_range((Level->level_length)-10)+1; l = random_range((Level->level_width)-10)+1; e = 4+random_range(5); } while ((Level->site[l][t].roomnumber != RS_WALLSPACE) || (Level->site[l+e][t].roomnumber != RS_WALLSPACE) || (Level->site[l][t+e].roomnumber != RS_WALLSPACE) || (Level->site[l+e][t+e].roomnumber != RS_WALLSPACE)); if (Current_Dungeon == E_SEWERS) { if (random_range(2)) rsi = RS_SEWER_CONTROL; else rsi = ROOMBASE+random_range(NUMROOMNAMES); } else rsi = ROOMBASE+random_range(NUMROOMNAMES); build_room(l,t,e,rsi,1); for (i=2;i<=Level->numrooms;i++) { do { t = random_range((Level->level_length)-10)+1; l = random_range((Level->level_width)-10)+1; e = 4+random_range(5); } while ((Level->site[l][t].roomnumber != RS_WALLSPACE) || (Level->site[l+e][t].roomnumber != RS_WALLSPACE) || (Level->site[l][t+e].roomnumber != RS_WALLSPACE) || (Level->site[l+e][t+e].roomnumber != RS_WALLSPACE)); if (Current_Dungeon == E_SEWERS) { if (random_range(2)) rsi = RS_SEWER_CONTROL; else rsi = ROOMBASE+random_range(NUMROOMNAMES); } else rsi = ROOMBASE+random_range(NUMROOMNAMES); build_room(l,t,e,rsi,i); /* corridor which is guaranteed to connect */ findspace(&tx,&ty,i); /* figure out where to start corridor from */ if ((ty <= t) && (tx <= l+e)) { fx = l+1+random_range(e-1); fy = t; } else if ((tx >= l+e) && (ty <= t+e)) { fx = l+e; fy = t+1+random_range(e-1); } else if ((ty >= t+e) && (tx >= l)) { fx = l+1+random_range(e-1); fy = t+e; } else { fx = l; fy = t+1+random_range(e-1); } room_corridor(fx,fy,tx,ty,i); /* corridor which may not go anywhere */ if (random_range(2)) { findspace(&tx,&ty,i); if ((ty <= t) && (tx <= l+e)) { fx = l+1+random_range(e-1); fy = t; } else if ((tx >= l+e) && (ty <= t+e)) { fx = l+e; fy = t+1+random_range(e-1); } else if ((ty >= t+e) && (tx >= l)) { fx = l+1+random_range(e-1); fy = t+e; } else { fx = l; fy = t+1+random_range(e-1); } room_corridor(fx,fy,tx,ty,i); } } if (Current_Dungeon == E_SEWERS) { if (Level->depth == SEWERLEVELS) { findspace(&tx,&ty,-1); Level->mlist = ((pml) checkmalloc(sizeof(mltype))); Level->mlist->next = NULL; Level->mlist->m = Level->site[tx][ty].creature = ((pmt) make_creature(GREAT_WYRM)); /* The Great Wyrm */ Level->mlist->m->x = tx; Level->mlist->m->y = ty; } } if (Current_Dungeon == E_PALACE) { /* PGM TODO */ if (Level->depth == PALACELEVELS) { findspace(&tx,&ty,-1); Level->mlist = ((pml) checkmalloc(sizeof(mltype))); Level->mlist->next = NULL; Level->mlist->m = Level->site[tx][ty].creature = ((pmt) make_creature(MAHARAJA)); /* The Maharaja */ Level->mlist->m->x = tx; Level->mlist->m->y = ty; } } else if (Current_Environment == E_CASTLE) { if (Level->depth == CASTLELEVELS) { findspace(&tx,&ty,-1); Level->site[tx][ty].locchar = STAIRS_DOWN; Level->site[tx][ty].p_locf = L_ENTER_COURT; } } else if (Current_Environment == E_VOLCANO) { if (Level->depth == VOLCANOLEVELS && !gamestatusp(COMPLETED_VOLCANO)) { findspace(&tx,&ty,-1); Level->mlist = ((pml) checkmalloc(sizeof(mltype))); Level->mlist->next = NULL; Level->mlist->m = Level->site[tx][ty].creature = ((pmt) make_creature(DEMON_EMP)); /* The demon emp */ Level->mlist->m->x = tx; Level->mlist->m->y = ty; } } } /* goes from f to t unless it hits a site which is not a wall and doesn't have buildaux field == baux */ void room_corridor(int fx, int fy, int tx, int ty, int baux) { int dx,dy,continuing = TRUE; dx = sign(tx-fx); dy = sign(ty-fy); makedoor(fx,fy); fx+=dx; fy+=dy; while(continuing) { Level->site[fx][fy].locchar = FLOOR; Level->site[fx][fy].roomnumber = RS_CORRIDOR; Level->site[fx][fy].buildaux = baux; dx = sign(tx-fx); dy = sign(ty-fy); if ((dx != 0) && (dy != 0)) { if (random_range(2)) dx = 0; else if (random_range(2)) dy = 0; } fx+=dx; fy+=dy; continuing = (((fx != tx) || (fy != ty)) && ((Level->site[fx][fy].buildaux == 0) || (Level->site[fx][fy].buildaux == baux))); } makedoor(fx,fy); } void maze_level (void) { int mid; int y_idx; int x_idx; int tx, ty; char rsi = RS_VOLCANO; if (E_ASTRAL == Current_Environment) { switch (Level->depth) { case 1: rsi = RS_EARTHPLANE; break; case 2: rsi = RS_AIRPLANE; break; case 3: rsi = RS_WATERPLANE; break; case 4: rsi = RS_FIREPLANE; break; case 5: rsi = RS_HIGHASTRAL; break; } maze_corridor(1 + random_range(Level->level_width - 1), 1 + random_range(Level->level_length - 1), 1 + random_range(Level->level_width - 1), 1 + random_range(Level->level_length - 1), rsi, 0); if (E_ASTRAL == Current_Dungeon) { for (x_idx = 0; x_idx < Level->level_width; ++x_idx) { for (y_idx = 0; y_idx < Level->level_length; ++y_idx) { if (WALL == Level->site[x_idx][y_idx].locchar) { switch (Level->depth) { case 1: Level->site[x_idx][y_idx].aux = 500; break; case 2: Level->site[x_idx][y_idx].locchar = WHIRLWIND; Level->site[x_idx][y_idx].p_locf = L_WHIRLWIND; break; case 3: Level->site[x_idx][y_idx].locchar = WATER; Level->site[x_idx][y_idx].p_locf = L_WATER; break; case 4: Level->site[x_idx][y_idx].locchar = FIRE; Level->site[x_idx][y_idx].p_locf = L_FIRE; break; case 5: Level->site[x_idx][y_idx].locchar = ABYSS; Level->site[x_idx][y_idx].p_locf = L_ABYSS; break; } } } switch (Level->depth) { case 1: mid = LORD_EARTH; break; /* Elemental Lord of Earth */ case 2: mid = LORD_AIR; break; /* Elemental Lord of Air */ case 3: mid = LORD_WATER; break; /* Elemental Lord of Water */ case 4: mid = LORD_FIRE; break; /* Elemental Lord of Fire */ case 5: mid = ELEM_MASTER; break; /* Elemental Master */ default: mid = ELEM_MASTER; assert(FALSE); /* bomb if this happens */ } if (5 == Level->depth) { findspace(&tx, &ty, -1); Level->site[tx][ty].p_locf = L_ENTER_CIRCLE; Level->site[tx][ty].locchar = STAIRS_DOWN; } if (!gamestatusp(COMPLETED_ASTRAL)) { findspace(&tx, &ty, -1); Level->mlist = checkmalloc(sizeof(mltype)); Level->mlist->next = NULL; Level->mlist->m = make_creature(mid); Level->mlist->m->x = tx; Level->mlist->m->y = ty; Level->site[tx][ty].creature = Level->mlist->m; } } } } else if (E_VOLCANO == Current_Environment) { if (VOLCANOLEVELS == Level->depth && !gamestatusp(COMPLETED_VOLCANO)) { findspace(&tx, &ty, -1); Level->mlist = checkmalloc(sizeof(mltype)); Level->mlist->next = NULL; Level->mlist->m = make_creature(DEMON_EMP); Level->mlist->m->x = tx; Level->mlist->m->y = ty; Level->site[tx][ty].creature = Level->mlist->m; } } } /* keep drawing corridors recursively for 2^5 endpoints */ void maze_corridor(int fx, int fy, int tx, int ty, char rsi, char num) { if (num < 6) { straggle_corridor(fx,fy,tx,ty,FLOOR,rsi); maze_corridor(tx,ty, random_range((Level->level_width)-1)+1, random_range((Level->level_length)-1)+1, rsi,num+1); } }