item_ptr Item::Generate() { Die die = {1, ITEM_RANGED + 1, -1}; uint cat = DieRoll::Roll(die); item_ptr item; switch(cat) { case ITEM_ARMOUR: die.Set(1, sizeof(armourTemplates)/sizeof(armourTemplates[0]), -1); item = std::make_shared<Armour>(armourTemplates[DieRoll::Roll(die)]); break; case ITEM_WEAPON: die.Set(1, sizeof(weaponTemplates)/sizeof(weaponTemplates[0]), -1); item = std::make_shared<Weapon>(weaponTemplates[DieRoll::Roll(die)]); break; case ITEM_RANGED: die.Set(1, sizeof(rangedTemplates)/sizeof(rangedTemplates[0]), -1); item = std::make_shared<Ranged>(rangedTemplates[DieRoll::Roll(die)]); break; default: item = std::make_shared<Item>("Nothing", 255, 255, 0); } return item; }
void Level::Generate() { // allocate memory for levels Tile** new_map = new Tile* [_h]; Tile** flooded_map = new Tile* [_h]; for(uint i = 0; i < _h; i++) { new_map[i] = new Tile [_w]; flooded_map[i] = new Tile [_w]; } while(1) { // randomly fill starting level for(uint y = 1; y < _h -1; y++) { for(uint x = 1; x < _w; x++) { _map[y][x] = tiles[randpick()]; } } // fill temp level with walls for(uint y = 0; y < _h; y++) { for(uint x = 0; x < _w; x++) { new_map[y][x] = tiles[MAP_WALL]; } } // ensure the level has outer walls for(uint y = 0; y < _h; y++) { _map[y][0] = _map[y][_w-1] = tiles[MAP_WALL]; } for(uint x = 0; x < _w; x++) { _map[0][x] = _map[_h-1][x] = tiles[MAP_WALL]; } // run cellular autonoma algorithm for(uint y = 1; y < _h - 1; y++) { for(uint x = 1; x < _w - 1; x++) { int adjcount_r1 = 0, adjcount_r2 = 0; for(int i = -1; i <= 1; i++) { for(int j = -1; j <= 1; j++) { if(_map[y+i][x+j].type != MAP_FLOOR) adjcount_r1++; } } for(uint i = y - 2; i <= y + 2; i++) { for(uint j = x - 2; j <= x + 2; j++) { if(abs(i-y) == 2 && abs(j-x) == 2) continue; if(i >= _h || j >= _w) continue; if(_map[i][j].type != MAP_FLOOR) adjcount_r2++; } } // select new tile for this position if(adjcount_r1 >= _r1_cutoff || adjcount_r2 <= _r2_cutoff) { new_map[y][x] = tiles[MAP_WALL]; } else { new_map[y][x] = tiles[MAP_FLOOR]; } } } // flood map from random floor cell int rnd_x, rnd_y; while(1) { rnd_x = rand() % _w; rnd_y = rand() % _h; if(new_map[rnd_y][rnd_x].type == MAP_FLOOR) break; } for(uint y = 0; y < _h; y++) { for(uint x = 0; x < _w; x++) { flooded_map[y][x] = tiles[MAP_WALL]; } } floodmap(new_map, flooded_map, rnd_x, rnd_y); // ensure that at least 1/2 of the map is floor uint floorcount = 0; for(uint y = 0; y < _h; y++) { for(uint x = 0; x < _w; x++) { if(flooded_map[y][x].type == MAP_FLOOR) floorcount++; } } if(floorcount > (_w*_h)/2) break; } // place stairs int rnd_x, rnd_y; while(1) { rnd_x = rand() % _w; rnd_y = rand() % _h; if(flooded_map[rnd_y][rnd_x].type == MAP_FLOOR) { flooded_map[rnd_y][rnd_x] = tiles[MAP_STAIR_DOWN]; _stairDown.x = rnd_x; _stairDown.y = rnd_y; break; } } while(1) { rnd_x = rand() % _w; rnd_y = rand() % _h; if(flooded_map[rnd_y][rnd_x].type == MAP_FLOOR) { flooded_map[rnd_y][rnd_x] = tiles[MAP_STAIR_UP]; _stairUp.x = rnd_x; _stairUp.y = rnd_y; break; } } // replace map with new one for(uint y = 1; y < _h - 1; y++) { for(uint x = 1; x < _w -1; x++) { _map[y][x] = flooded_map[y][x]; } } // free memory used up by temporary maps for(uint i = 0; i < _h; i++) { delete [] new_map[i]; delete [] flooded_map[i]; } delete [] new_map; delete [] flooded_map; // scatter items around level for(uint i = 0; i < LEVEL_HEIGHT / 2; i++) { Die tmp = {1, _h-1, 0}; uint y = DieRoll::Roll(tmp); tmp.Set(1, _w-1, 0); uint x = DieRoll::Roll(tmp); if(_map[y][x].type == MAP_FLOOR) _map[y][x].items.push_back(Item::Generate()); } }