I'm trying to make a small roguelike game with a random terrain generator, which has a function called mapRefresh that currently generates a 256x256 map (although the size is variable by changing MAP_SIZE in game.h), then places a random number of lakes (10 max) and trees (10000 max). The lakes start as a single tile, and the lakes' water tiles branch out, with less chance to continue going as they get farther from the center. After this step, any tiles that are orthogonally bordered by 3+ water tiles are replaced with a water tile, to smooth out the edges of lakes.
It would seem that somewhere in the lake-generation code, some memory is addressed incorrectly and gives me a bus error. It seems to occur less with a lower number of lakes, and does not occur at all if the switch statement that branches out the water tiles are commented out. I suspect this has something to do with the tiles going off the edge of the map array and addressing -1 or +257 x/y, or something similar, but that part seems to be laid out correctly?
My source code is below; what am I doing wrong here?
/* This file contains code that:
- Changes the locale to use unicode
- Calls checkTerminal, a function found in game.cpp, to make sure the current terminal fits the criteria needed for the game to run
- Runs the basic parts of the game...
- Unless the user wants to quit
*/
#include <ctime>
#include "game.h"
int main()
{
srand(time(NULL));
// Ncurses stuff
initscr();
noecho();
cbreak();
keypad(stdscr, true);
curs_set(0);
checkTerminal();
start_color(); // use colors -- these correspond to tile number + 1
init_pair(1, COLOR_YELLOW, COLOR_BLACK);
init_pair(2, COLOR_RED, COLOR_BLACK);
init_pair(3, COLOR_RED, COLOR_BLACK);
init_pair(4, COLOR_GREEN, COLOR_BLACK);
init_pair(5, COLOR_BLUE, COLOR_BLACK);
while (true) {
mapRefresh();
draw();
getch();
// turn();
}
endwin();
return 0;
}
#ifndef _GAME_H_
#define _GAME_H_
#define MAP_SIZE 256
#define MAX_TREE 10000
#define MAX_LAKE 10
#define CHANCE_LAKE 750 // Higher numbers make lake generation less likely to stop early, causing larger lakes to be made
#include "rng.h"
#include <ncurses.h>
void checkTerminal();
void mapRefresh();
void draw();
#endif
/* This is where most of the game goes. Large functions like the random generation, AI, etc will be put in seperate source files */
#include "game.h"
#include "structures.h"
int map[MAP_SIZE][MAP_SIZE];
// Does the terminal support functions necessary for the game?
void checkTerminal()
{
if (has_colors() == false)
{
endwin();
printf("Unfortunately, your terminal doesn't support colors, which are necessary for this game. Please use a terminal with color support.\n");
exit(1);
}
int max_y, max_x;
getmaxyx(stdscr,max_y,max_x);
WINDOW* sizecheck = newwin(max_y, max_x, 0, 0);
while (max_y != 25 || max_x != 80)
{
werase(sizecheck);
wprintw(sizecheck,"This game is optimized for a terminal size of 80x25. Your terminal appears to\n\
be %ix%i instead. Please resize it to continue.",max_x,max_y);
wrefresh(sizecheck);
getmaxyx(stdscr,max_y,max_x);
}
delwin(sizecheck);
erase();
refresh();
}
void mapRefresh()
{
int x = 0, y = 0;
// Blank map
while (y < MAP_SIZE) {
while (x < MAP_SIZE) {
map[x][y] = 0;
x++;
}
x = 0;
y++;
}
int chance = CHANCE_LAKE; // chance of failure in lake tile placement
int count = 0;
int rnd1;
int rnd2;
// Place lakes
rnd1 = rand() % MAX_LAKE + 1;
while (count <= rnd1) {
x = rand() % MAP_SIZE + 1;
y = rand() % MAP_SIZE + 1;
if (map[x][y] == 0) {
// Randomly extend the initial lake tiles outward
while (true) {
rnd2 = rand() % MAP_SIZE + 1;
if (rnd2 <= chance) { // if the random number is less than 'chance'
if (map[x][y] == 0) { map[x][y] = 4; } // place another lake tile if the tile selected is blank
switch (rand() % 7 + 1)
{
case 0: if (x <= MAP_SIZE) {x++;} break;
case 1: if (y <= MAP_SIZE) {y++;} break;
case 2: if (x >= 0) {x--;} break;
case 3: if (y >= 0) {y--;} break;
case 4: if (x <= MAP_SIZE && y <= MAP_SIZE) {x++; y++;} break;
case 5: if (x <= MAP_SIZE && y >= 0) {x++; y--;} break;
case 6: if (x >= 0 && y <= MAP_SIZE) {x--; y++;} break;
case 7: if (x >= 0 && y >= 0) {x--; y--;} break;
}
chance -= 10;
}
else { break; }
}
chance = CHANCE_LAKE;
count++;
}
}
// Finalize lakes by filling tiles with water if they're orthogonal to water on 3+ sides
x = 0;
y = 0;
count = 0;
while (y < MAP_SIZE) {
while (x < MAP_SIZE) {
if (map[x+1][y] == 4) {count++;}
if (map[x-1][y] == 4) {count++;}
if (map[x][y+1] == 4) {count++;}
if (map[x][y-1] == 4) {count++;}
if (count >= 3) {
map[x][y] = 4;
}
count = 0;
x++;
}
x = 0;
y++;
}
// Make a house
// Place a random number of trees -- max is defined in game.h
count = 0;
rnd1 = rand() % MAX_TREE + 1;
while (count <= rnd1 && count <= MAX_TREE) {
x = rand() % MAP_SIZE + 1;
y = rand() % MAP_SIZE + 1;
if (map[x][y] == 0) {
map[x][y] = 3; // Place a tree
count++;
}
}
}
void draw()
{
erase();
int x = 0, y = 0;
while (y < 25) {
while (x < 25) {
if (y == 0 || y == 24 || x == 0 || x == 24 ) {mvprintw(y,x,"#");}
else {
switch (map[x][y]) {
case 0: // Floor - outside
attron(COLOR_PAIR(1)); mvprintw(y,x,"."); attroff(COLOR_PAIR(1));
break;
case 1: // Floor - inside
attron(COLOR_PAIR(2)); mvprintw(y,x,"+"); attroff(COLOR_PAIR(2));
break;
case 2: // Wall
attron(COLOR_PAIR(3)); mvprintw(y,x,"#"); attroff(COLOR_PAIR(3));
break;
case 3: // Tree
attron(COLOR_PAIR(4)); mvprintw(y,x,"7"); attroff(COLOR_PAIR(4));
break;
case 4: // Water
attron(COLOR_PAIR(5)); mvprintw(y,x,"~"); attroff(COLOR_PAIR(5));
break;
}
}
x++;
}
x = 0;
y++;
}
mvprintw(1,26," ROGUELIKE WORLD-GEN TEST");
mvprintw(2,26," This screen shows a 25x25 view of the world map");
refresh();
}
//void turn() {
//
//}
Also, I'm fairly new to C++, so if you spot some horrible convoluted code which breaks all boundaries of logic, I encourage you to notify me.