/* generate a rogue/nethack-like layout */ #include #include #include typedef struct { int x; int y; /* coordinates of room centers */ int sx; int sy; /* sizes */ int ax,ay,zx,zy; /* coordinates of extrema of the rectangle */ int rtype; /* circle or rectangular */ } Room; static int roguelike_place_room(Room *Rooms,int xsize, int ysize,int nrooms); static void roguelike_make_rooms(Room *Rooms,char **maze, int options); static void roguelike_link_rooms(Room *Rooms,char **maze,int xsize,int ysize); int surround_check(char **layout,int i,int j,int Xsize, int Ysize){ /* 1 = wall to left, 2 = wall to right, 4 = wall above 8 = wall below */ int surround_index = 0; if((i > 0) && (layout[i-1][j]!=0&&layout[i-1][j]!='.')) surround_index +=1; if((i < Xsize-1) && (layout[i+1][j]!=0&&layout[i+1][j]!='.')) surround_index +=2; if((j > 0) && (layout[i][j-1]!=0&&layout[i][j-1]!='.')) surround_index +=4; if((j < Ysize-1) && (layout[i][j+1]!=0&&layout[i][j+1]!='.')) surround_index +=8; return surround_index; } /* actually make the layout: we work by a reduction process: * first we make everything a wall, then we remove areas to make rooms */ char **roguelike_layout_gen(int xsize, int ysize, int options) { int i,j; Room * Rooms = 0; Room *walk; int nrooms=0; int tries=0; /* allocate that array, write walls everywhere up */ char **maze = (char **)malloc(sizeof(char*)*xsize); for(i=0;ix][Rooms->y] = '<'; /* get the last one */ for(walk=Rooms;walk->x!=0;walk++); /* back up one */ walk--; if (walk == Rooms) { /* In this case, there is only a single room. We don't want to * clobber are up exit (above) with a down exit, so put the * other exit one space up/down, depending which is a space * and not a wall. */ if (maze[walk->x][walk->y+1] == '.') maze[walk->x][walk->y+1] = '>'; else maze[walk->x][walk->y-1] = '>'; } else maze[walk->x][walk->y] = '>'; /* convert all the '.' to 0, we're through with the '.' */ for(i=0;i xsize - 1 || ax < 1) return 0; if(zy > ysize - 1 || ay < 1) return 0; /* no small fish */ if(sx < 3 || sy < 3) return 0; /* check overlap with existing rooms */ for(walk=Rooms;walk->x!=0;walk++) { int dx = abs(tx - walk->x); int dy = abs(ty - walk->y); if( (dx < (walk->sx + sx)/2 + 2) && (dy < (walk->sy + sy)/2 + 2)) return 0; } /* if we've got here, presumably the room is OK. */ /* get a pointer to the first free room */ for(walk=Rooms;walk->x!=0;walk++); walk->x = tx; walk->y = ty; walk->sx = sx; walk->sy = sy; walk->ax = ax; walk->ay = ay; walk->zx = zx; walk->zy = zy; return 1; /* success */ } /* write all the rooms into the maze */ static void roguelike_make_rooms(Room *Rooms,char **maze, int options) { int making_circle=0; int i,j; int R; Room *walk; for(walk=Rooms;walk->x!=0;walk++) { /* first decide what shape to make */ switch(options) { case 1: making_circle=0; break; case 2: making_circle = 1; break; default: making_circle = ((RANDOM()%3 == 0)? 1:0); break; } if(walk->sx < walk->sy) R = walk->sx/2; else R = walk->sy/2; /* enscribe a rectangle */ for(i=walk->ax;izx;i++) for(j=walk->ay;jzy;j++) { if(!making_circle || ((int)(0.5+hypot(walk->x-i,walk->y-j))) <=R) maze[i][j]='.'; } } } static void roguelike_link_rooms(Room *Rooms,char **maze,int xsize,int ysize){ Room *walk; int i,j; /* link each room to the previous room */ if(Rooms[1].x==0) return; /* only 1 room */ for(walk = Rooms +1; walk->x !=0; walk++) { int x1=walk->x; int y1=walk->y; int x2=(walk-1)->x; int y2=(walk-1)->y; int in_wall=0; if(RANDOM()%2) { /* connect in x direction first */ /* horizontal connect */ /* swap (x1,y1) (x2,y2) if necessary */ if(x2 < x1) { int tx=x2,ty=y2; x2 = x1; y2 = y1; x1 = tx; y1 = ty; } j = y1; for(i=x1;i