omega-rpg/gen2.c

496 lines
14 KiB
C

/* 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;i<Level->level_width;i++)
for(j=0;j<Level->level_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;i<Level->level_width;i++)
for (j=0;j<Level->level_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);
}
}