A WIP Roguelike game by Adekto, VonBednat, Trelemar and Wuuff made for CGAJam in spring 2017
Dependencies: PokittoLib
Fork of Arcade by
Diff: mapgen.c
- Revision:
- 10:590a26231903
- Child:
- 15:67fb7b0c1149
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mapgen.c Thu Oct 19 08:43:47 2017 +0000 @@ -0,0 +1,363 @@ +#include <stdio.h> +#include <stdlib.h> + +#define MAPSIZE 64 + +#define ID_FLOOR 0 +#define ID_WALL_TOP 1 +#define ID_WALL 2 +#define ID_WALL_SKULL 3 +#define ID_WALL_FLAME 4 +#define ID_WALL_HOLE 5 +#define ID_WALL_SHIELD 6 +#define ID_COLUMN_TOP_SQUARE_1 7 +#define ID_COLUMN_TOP_SQUARE_2 9 +#define ID_COLUMN_TOP_SQUARE_3 10 +#define ID_COLUMN_TOP_ROUND_1 11 +#define ID_COLUMN_TOP_ROUND_2 13 +#define ID_COLUMN_BOTTOM_SQUARE_1 8 +#define ID_COLUMN_BOTTOM_ROUND_1 12 +#define ID_COLUMN_BOTTOM_ROUND_2 14 +#define ID_COFFIN_CLOSED_TOP 15 +#define ID_COFFIN_CLOSED_BOTTOM 16 +#define ID_COFFIN_OPEN_TOP 17 +#define ID_COFFIN_OPEN_BOTTOM 18 +#define ID_COBWEB 33 + +void mapinit(char map[][MAPSIZE], int width, int height); +void mapgen(char map[][MAPSIZE], int mapwidth, int mapheight, int startx, int starty, int endx, int endy); +void mapprint(char map[][MAPSIZE], int width, int height); + +void mapinit(char map[][MAPSIZE], int width, int height){ + int i,j; + + //Fill with empty space + for( i = 0; i < width; i++ ){ + for( j = 0; j < height; j++ ){ + map[j][i] = 0; + } + } + //Generate walls around the edges + for( i = 0; i < width; i++ ){ + map[0][i] = 1; + map[height-1][i] = 1; + } + for( j = 0; j < height; j++ ){ + map[j][0] = 1; + map[j][width-1] = 1; + } +} + +#define HORIZONTAL 0 +#define VERTICAL 1 +#define MIN_WIDTH 6 +#define MIN_HEIGHT 8 +#define HALL_CHANCE 40 +#define MIN_HALL_WIDTH 8 +#define MIN_HALL_HEIGHT 10 +#define MAX_HALL_WIDTH 18 +#define MAX_HALL_HEIGHT 20 +#define EXTRA_DOOR 10 +#define REM_WALL_CHANCE 25 +#define MAX_REM_WALL 10 +void mapgen(char map[][MAPSIZE], int mapwidth, int mapheight, int startx, int starty, int endx, int endy){ + int i,j,orientation,position,door,door2,doorcount,hall,colspacex,colspacey,remwall; + int width = endx-startx; + int height = endy-starty; + + if( width < MIN_WIDTH && height < MIN_HEIGHT ){ + return; + } + + //Determine whether to generate a big hall with pillars or not. + //The size of the room determines the column spacing for now + if( width >= MIN_HALL_WIDTH && height >= MIN_HALL_HEIGHT && width < MAX_HALL_WIDTH && height < MAX_HALL_HEIGHT ){ + hall = rand()%100;//Percent chance out of 100 + if( HALL_CHANCE > hall ){ + hall = rand()%3;//Choose type of hall; square columns, round columns, or coffins + //Place room columns as densely as the room supports + //IF you can divide the room into columns evenly + //but make sure there is greater than one space between columns + colspacex = width; + if( colspacex%2 != 0 ){ + colspacex--; + } + while( colspacex%2 == 0 && colspacex > 4 ) colspacex /= 2; + colspacey = height; + if( colspacey%4 != 0 ) + { + while( colspacey%4 != 0 ) colspacey++; + } + while( colspacey%4 == 0 && colspacey > 4 ) colspacey /= 4; + + for( i = startx+colspacex; i < startx + width - 1; i+=colspacex ){ + for( j = starty+colspacey; j < starty + height - 2; j+=colspacey ){ + if( hall == 0 ){//Square columns + switch( rand()%3 ){ + case 0: + map[j][i] = ID_COLUMN_TOP_SQUARE_1; + break; + case 1: + map[j][i] = ID_COLUMN_TOP_SQUARE_2; + break; + case 2: + map[j][i] = ID_COLUMN_TOP_SQUARE_3; + break; + } + map[j+1][i] = ID_COLUMN_BOTTOM_SQUARE_1; + }else if( hall == 1 ){//Round columns + switch( rand()%2 ){ + case 0: + map[j][i] = ID_COLUMN_TOP_ROUND_1; + break; + case 1: + map[j][i] = ID_COLUMN_TOP_ROUND_2; + break; + } + switch( rand()%2 ){ + case 0: + map[j+1][i] = ID_COLUMN_BOTTOM_ROUND_1; + break; + case 1: + map[j+1][i] = ID_COLUMN_BOTTOM_ROUND_2; + break; + } + }else{//Coffins + switch( rand()%2 ){ + case 0: + map[j][i] = ID_COFFIN_CLOSED_TOP; + map[j+1][i] = ID_COFFIN_CLOSED_BOTTOM; + break; + case 1: + map[j][i] = ID_COFFIN_OPEN_TOP; + map[j+1][i] = ID_COFFIN_OPEN_BOTTOM; + break; + } + } + + } + } + return;//Do not subdivide; return immediately + } + } + + //Determine whether we will split the space + //horizontally or vertically by choosing whichever + //orientation is larger (this avoids extremely long rooms) + if( width >= height ){ + //If there is a door (or more than one door!) into a small room, + //we may not be able to generate a wall in any location! + //so abort if room is min + number of horiz door tiles + doorcount = 0; + for( i = startx; i < endx; i++ ){ + if( map[starty][i] == 0 ) doorcount++; + if( map[endy][i] == 0 ) doorcount++; + } + if( width < MIN_WIDTH + doorcount ){ + return; + } + orientation = VERTICAL; + //puts("Trying vertical"); + }else{ + //If there is a door (or more than one door!) into a small room, + //we may not be able to generate a wall in any location! + //so abort if room is min + number of vert door tiles + doorcount = 0; + for( i = starty; i < endy; i++ ){ + if( map[i][startx] == 0 ) doorcount++; + if( map[i][endx] == 0 ) doorcount++; + } + if( height < MIN_HEIGHT + doorcount ){ + return; + } + orientation = HORIZONTAL; + //puts("Trying horizontal"); + } + //printf("startx %d, starty %d\n",startx,starty); + //mapprint(map,MAPSIZE,MAPSIZE); + position = -1; + if( orientation == HORIZONTAL ){ + //Make sure the position is valid: + //1. It must have generated at least one number + //2. It must not be too close to existing walls + //3. It must not be over a door + while( position == -1 || position < starty + (MIN_HEIGHT/2) || position > endy - (MIN_HEIGHT/2) || map[position][startx] == 0 || map[position][endx] == 0 ){ + position = starty + (rand()%height); + } + //Generate a door at a random position + door = startx + 1 + (rand()%(width-1)); + //Generate an extra door if wall is long enough. + //Doors may overlap or be next to each other because such + //doors shouldn't be a problem and it might result in interesting maps. + //If it is not long enough set to -1 so it won't interfere + door2 = width >= EXTRA_DOOR ? startx + 1 + (rand()%(width-1)) : -1; + //printf("HORIZ %d\n",position); + for( i = startx+1; i < startx + width; i++ ){ + if( i != door && i != door2 ) + map[position][i] = 1; + } + //Determine whether or not we will remove a wall. + //We can't remove bottom and right walls because the regions beyond them + //haven't been generated yet, so we only try to remove top and left walls. + //If we are not on the map edges + if( startx > 0 && endx < mapwidth-1 ){ + //If the new space is taller than it is wide + //and the wall is short enough + if( /*position - starty > width &&*/ position - starty < MAX_REM_WALL ){ + remwall = 1; + //Check if there is no wall touching the wall we want to remove. + //If not, we can remove the wall + for( i = starty+1; i < position; i++ ){ + if( map[i][startx-1] != 0 ){ + remwall = 0; + break; + } + } + if( remwall && REM_WALL_CHANCE > (rand()%100) ){ + for( i = starty+1; i < position; i++ ){ + map[i][startx] = 0;//2;//Clear left side of upper half + } + } + } + //If the new space is taller than it is wide + //and the wall is short enough + if( /*endy - position > width &&*/ endy - position < MAX_REM_WALL ){ + remwall = 1; + //Check if there is no wall touching the wall we want to remove. + //If not, we can remove the wall + for( i = position+1; i < endy; i++ ){ + if( map[i][startx+1] != 0 ){ + remwall = 0; + break; + } + } + if( remwall && REM_WALL_CHANCE > (rand()%100) ){ + for( i = position+1; i < endy; i++ ){ + map[i][startx] = 0;//4;//Clear left side of lower half + } + } + } + } + //Recursively call to fill the two new spaces we generated + mapgen(map, mapwidth, mapheight, startx, starty, endx,position); + mapgen(map, mapwidth, mapheight, startx, position, endx, endy); + }else if( orientation == VERTICAL ){ + //Make sure the position is valid: + //1. It must have generated at least one number + //2. It must not be too close to existing walls + //3. It must not be over a door + while( position == -1 || position < startx + (MIN_WIDTH/2) || position > endx - (MIN_WIDTH/2) || map[starty][position] == 0 || map[endy][position] == 0 ){ + position = startx + (rand()%width); + } + //Generate a door at a random position + //(allocating space for it to be 2 high) + door = starty + 1 + (rand()%(height-2)); + //Generate an extra door if wall is long enough. + //Doors may overlap or be next to each other because such + //doors shouldn't be a problem and it might result in interesting maps. + //If it is not long enough set to -1 so it won't interfere + door2 = height >= EXTRA_DOOR ? starty + 1 + (rand()%(height-2)) : -1; + //printf("VERT %d\n",position); + for( i = starty+1; i < starty + height; i++ ){ + if( i != door && i != door+1 && i != door2 && i != door2+1 ) + map[i][position] = 1; + } + //Determine whether or not we will remove a wall. + //We can't remove bottom and right walls because the regions beyond them + //haven't been generated yet, so we only try to remove top and left walls. + //If we are not on the map edges + if( starty > 0 && endy < mapheight-1 ){ + //If the new space is wider than it is tall + //and the wall is short enough + if( /*position - startx > height &&*/ position - startx < MAX_REM_WALL ){ + remwall = 1; + //Check if there is no wall touching the wall we want to remove. + //If not, we can remove the wall + for( i = startx+1; i < position; i++ ){ + if( map[starty-1][i] != 0 ){ + remwall = 0; + break; + } + } + if( remwall && REM_WALL_CHANCE > (rand()%100) ){ + for( i = startx+1; i < position; i++ ){ + map[starty][i] = 0;//3;//Clear top side of left half + } + } + } + //If the new space is wider than it is tall + //and the wall is short enough + if( /*endx - position > height &&*/ endx - position < MAX_REM_WALL ){ + remwall = 1; + //Check if there is no wall touching the wall we want to remove. + //If not, we can remove the wall + for( i = position+1; i < endx; i++ ){ + if( map[starty-1][i] != 0 ){ + remwall = 0; + break; + } + } + if( remwall && REM_WALL_CHANCE > (rand()%100) ){ + for( i = position+1; i < endx; i++ ){ + map[starty][i] = 0;//5;//Clear top side of right half + } + } + } + } + //Recursively call to fill the two new spaces we generated + mapgen(map, mapwidth, mapheight, startx, starty, position,endy); + mapgen(map, mapwidth, mapheight, position, starty, endx, endy); + } +} + +void mapprint(char map[][MAPSIZE], int width, int height){ + int i,j; + + for( i = 0; i < height; i++ ){ + for( j = 0; j < width; j++ ){ + if( map[i][j] == 0 ){ + printf("0"); + }else if( map[i][j] == 1 ){ + printf("1"); + } + } + puts(""); + } +} + +void mappretty(char map[][MAPSIZE],int width, int height){ + int i,j,v; + for (i=0; i < height-1; i++) { + for (j=0;j<width-1;j++){ + if (map[i][j]==1 && map[i+1][j]==0){ + v = rand()%25 + 3; + //If v is any of the random wall variations + if( v <= ID_WALL_SHIELD ){ + map[i+1][j] = v; + }else { + map[i+1][j]=ID_WALL; + } + } + + if (map[i][j]==0 && map[i+1][j]==1 && map[i][j-1]==1 && rand()%10 <=1) { + map[i][j]=ID_COBWEB; + } + } + } +} + + +//char map[MAPSIZE][MAPSIZE]; + +/* +int main(int argc, char** argv){ + srand(42);//Can choose the seed to get the same map every time + + mapinit(map,MAPSIZE,MAPSIZE); + mapgen(map,MAPSIZE,MAPSIZE,0,0,MAPSIZE-1,MAPSIZE-1); + + mapprint(map,MAPSIZE,MAPSIZE); +} +*/ + +