diff --git a/src/arguments.cc b/src/arguments.cc index bad9016..396a7ff 100644 --- a/src/arguments.cc +++ b/src/arguments.cc @@ -19,7 +19,8 @@ feature proc_args(int argc, char **argv, std::unique_ptr &curse, std::unique_ptr &in, std::unique_ptr &out, - std::unique_ptr &rng) { + std::unique_ptr &rng, + std::ifstream &data) { feature result = 0; std::string str; std::string fn_fin; @@ -37,6 +38,9 @@ feature proc_args(int argc, char **argv, result |= FEATURE_NCURSES; } else if (str == "-r") { + if (result & FEATURE_READ_MAP) + return FEATURE_CONFLICT | i; + result |= FEATURE_RAND_MAP; } else if (str == "-c") { result |= FEATURE_ENEMIES_CHASE; @@ -56,6 +60,14 @@ feature proc_args(int argc, char **argv, result |= FEATURE_EXTRA_LEVELS; } else if (str == "-o") { result |= FEATURE_WALK_OVER; + } else if (str == "-m") { + if (result & FEATURE_RAND_MAP) + return FEATURE_CONFLICT | i; + + result |= FEATURE_READ_MAP; + ++i; + str = argv[i]; + data.open(str); } else if (str == "-s") { ++i; str = argv[i]; @@ -172,7 +184,7 @@ void panic_args(feature panic) { } const char *ARGS_LIST = "\ --n : Use ncurses for I/O\n\ +-n : Use ncurses for I/O\n\ -r : Randomly generate maps\n\ -c : Enemies chase the player (CAUTION: THEY CAN REALLY CHASE!!!)\n\ -d : Enemies can go through doors (CAUTION: DO NOT ENABLE WITH CHASING!)\n\ @@ -182,6 +194,7 @@ const char *ARGS_LIST = "\ -e : Enable extra potions and races\n\ -E : Enable extra levels\n\ -o : Allows characters to go over gold and potions\n\ +-m [file] : Reads map data from file. CANNOT BE USED WITH -r. DOES NOT PANIC!\n\ -s [seed] : Sets initial seed to seed\n\ -I [file] : Reads commands from file. CANNOT BE USED WITH -n.\n\ -O [file] : Outputs to file. CANNOT BE USED WITH -n.\n\ diff --git a/src/arguments.h b/src/arguments.h index 1e483d0..c11ddfe 100644 --- a/src/arguments.h +++ b/src/arguments.h @@ -12,8 +12,9 @@ typedef unsigned int feature; feature proc_args(int argc, char **argv, std::unique_ptr &curse, std::unique_ptr &in, - std::unique_ptr &out, - std::unique_ptr &rng); + std::unique_ptr &out, + std::unique_ptr &rng, + std::ifstream &data); void panic_args(feature panic); diff --git a/src/cc3k.cc b/src/cc3k.cc index 52536d4..80524a8 100644 --- a/src/cc3k.cc +++ b/src/cc3k.cc @@ -1,9 +1,11 @@ #include "cc3k.h" +#include +#include #include "constants.h" CC3K::CC3K(const feature enabled_features, - input *in, output *out, RNG *rng): + input *in, output *out, RNG *rng, std::ifstream &data): enabled_features{enabled_features}, in{in}, out{out}, rng{rng} { curr_menu = std::make_unique(enabled_features); @@ -11,6 +13,9 @@ CC3K::CC3K(const feature enabled_features, curr_menu->print(out, rng->get_init_seed()); out->render(); gresult.status = game_status::MAIN_MENU; + + if (enabled_features & FEATURE_READ_MAP) + proc_lvls(data); } game_status CC3K::run() { @@ -28,7 +33,8 @@ game_status CC3K::run() { curr_game = std::make_unique(static_cast(tmp), enabled_features, - in, out, rng); + in, out, rng, + lvls); out->clear(); curr_game->print(); out->render(); @@ -91,3 +97,148 @@ game_status CC3K::run() { return TERMINATED; } + +void CC3K::proc_lvls(std::ifstream &data) { + lvls.reserve(DEFAULT_LVL_CNT); + + for (int i = 0; i < DEFAULT_LVL_CNT; ++i) { + level_data tmp = {POS_NIL, {}, {}, {}, {}, POS_NIL}; + std::string buffer; + + for (int y = 0; y < MAP_HEIGHT; ++y) { + getline(data, buffer); + + for (int x = 0; x < MAP_WIDTH; ++x) + push_tile(buffer[x], {x, y}, tmp); + } + + number_rooms(tmp); + + lvls.push_back(tmp); + } +} + +size_t CC3K::remap_pos(const position &pos) { + return pos.x + pos.y * MAP_WIDTH; +} + +void CC3K::number_rooms(level_data &lvl) { + int curr_room_cnt = 0; + + for (int y = 0; y < MAP_HEIGHT; ++y) + for (int x = 0; x < MAP_WIDTH; ++x) + if (lvl.map_data[remap_pos({x, y})] == '.') { + number_block(lvl.map_data, {x, y}, curr_room_cnt); + ++curr_room_cnt; + } +} + +bool CC3K::in_bounds(const position &pos) { + return pos.x >= 0 && pos.x < MAP_WIDTH && + pos.y >= 0 && pos.y < MAP_HEIGHT; +} + +void CC3K::number_block(std::string &map_data, const position &pos, int num) { + if (map_data[remap_pos(pos)] != '.') + return; + + map_data[remap_pos(pos)] = num + '0'; + + for (int i = 0; i < DIRECTION_CNT; ++i) + if (in_bounds(pos + MOVE[i]) && + map_data[remap_pos(pos + MOVE[i])] == '.') + number_block(map_data, pos + MOVE[i], num); +} + +void CC3K::push_tile(const char ch, const position &pos, level_data &lvl) { + switch (ch) { + case '-': + case '|': + case ' ': + case '+': + case '#': + lvl.map_data += ch; + return; + + case '@': + lvl.pc_pos = pos; + break; + + case '\\': + lvl.stairs = pos; + break; + + case '0': + lvl.potions.push_back({RESTORE_HEALTH, pos}); + break; + + case '1': + lvl.potions.push_back({BOOST_ATK, pos}); + break; + + case '2': + lvl.potions.push_back({BOOST_DEF, pos}); + break; + + case '3': + lvl.potions.push_back({POISON_HEALTH, pos}); + break; + + case '4': + lvl.potions.push_back({WOUND_ATK, pos}); + break; + + case '5': + lvl.potions.push_back({WOUND_DEF, pos}); + break; + + case '6': + lvl.gold_piles.push_back({pos, GOLD_NORMAL}); + break; + + case '7': + lvl.gold_piles.push_back({pos, GOLD_SMALL}); + break; + + case '8': + lvl.gold_piles.push_back({pos, GOLD_MERCHANT}); + break; + + case '9': + lvl.gold_piles.push_back({pos, GOLD_DRAGON}); + break; + + case 'H': + lvl.enemies.push_back({HUMAN, pos}); + break; + + case 'W': + lvl.enemies.push_back({DWARF, pos}); + break; + + case 'E': + lvl.enemies.push_back({ELF, pos}); + break; + + case 'O': + lvl.enemies.push_back({ORC, pos}); + break; + + case 'M': + lvl.enemies.push_back({MERCHANT, pos}); + break; + + case 'D': + lvl.enemies.push_back({DRAGON, pos}); + break; + + case 'L': + lvl.enemies.push_back({HALFLING, pos}); + break; + + default: + break; + } + + lvl.map_data += '.'; +} diff --git a/src/cc3k.h b/src/cc3k.h index 5948248..ea74f3e 100644 --- a/src/cc3k.h +++ b/src/cc3k.h @@ -1,6 +1,7 @@ #ifndef __CC3K_H__ #define __CC3K_H__ +#include #include "input.h" #include "output.h" #include "game.h" @@ -9,6 +10,7 @@ class CC3K final { private: + static const int DEFAULT_LVL_CNT = 5; const feature enabled_features; input *in; output *out; @@ -17,9 +19,17 @@ private: game_result gresult; std::unique_ptr curr_game; std::unique_ptr curr_menu; + + std::vector lvls; + void proc_lvls(std::ifstream &data); + void push_tile(const char ch, const position &pos, level_data &lvl); + void number_rooms(level_data &lvl); + size_t remap_pos(const position &pos); + void number_block(std::string &map_data, const position &pos, int num); + bool in_bounds(const position &pos); public: CC3K(const feature enabled_features, - input *in, output *out, RNG *rng); + input *in, output *out, RNG *rng, std::ifstream &data); game_status run(); }; diff --git a/src/constants.h b/src/constants.h index ee4671e..d437be2 100644 --- a/src/constants.h +++ b/src/constants.h @@ -145,6 +145,7 @@ static const feature FEATURE_OUT_FILE = 1 << 9; static const feature FEATURE_EXTRA_STUFF = 1 << 10; static const feature FEATURE_EXTRA_LEVELS = 1 << 11; static const feature FEATURE_DOORS = 1 << 12; +static const feature FEATURE_READ_MAP = 1 << 13; static const feature FEATURE_LIST_COMMANDS = 1 << 23; static const feature FEATURE_LIST_RACES = 1 << 24; @@ -170,4 +171,6 @@ static const size_t WHAT_ENEMY = 1 << 29; static const size_t WHAT_WALL = 1 << 30; static const size_t WHAT_SPACE = 1 << 31; +static const position POS_NIL = {0, 0}; + #endif diff --git a/src/enemies.cc b/src/enemies.cc index 762c9b1..aa320ff 100644 --- a/src/enemies.cc +++ b/src/enemies.cc @@ -55,8 +55,6 @@ enum race get_normal_race(RNG *rng) { std::unique_ptr new_enemy(RNG *rng, const position &pos, const feature enabled_features, int which_room) { - using std::make_unique; - enum race r; if (enabled_features & FEATURE_EXTRA_STUFF) @@ -64,7 +62,15 @@ std::unique_ptr new_enemy(RNG *rng, const position &pos, else r = get_normal_race(rng); - switch (r) { + return new_enemy(r, pos, enabled_features, which_room, rng); +} + +std::unique_ptr new_enemy(const race &race, const position &pos, + const feature enabled_features, + int which_room, RNG *rng) { + using std::make_unique; + + switch (race) { case DWARF: return make_unique(rng, enabled_features, pos, which_room); @@ -113,6 +119,10 @@ std::unique_ptr new_enemy(RNG *rng, const position &pos, return make_unique(rng, enabled_features, pos, which_room); + case DRAGON: + return make_unique(rng, enabled_features, + pos, which_room); + default: break; } diff --git a/src/enemies.h b/src/enemies.h index 14183c8..3604019 100644 --- a/src/enemies.h +++ b/src/enemies.h @@ -4,6 +4,8 @@ #include #include "enemy.h" +enum race : int; + std::unique_ptr new_dragon(RNG *rng, const position &pos, const position &fallback, const feature enabled_features, @@ -13,4 +15,8 @@ std::unique_ptr new_enemy(RNG *rng, const position &pos, const feature enabled_features, int which_room); +std::unique_ptr new_enemy(const race &race, const position &pos, + const feature enabled_features, + int which_room, RNG *rng); + #endif diff --git a/src/game.cc b/src/game.cc index 4cf5210..2d80423 100644 --- a/src/game.cc +++ b/src/game.cc @@ -7,8 +7,9 @@ game::game(const enum race starting_race, const feature enabled_features, input *new_in, output *new_out, - RNG *new_rng): - enabled_features{enabled_features}, + RNG *new_rng, + const std::vector &lvls): + enabled_features{enabled_features}, lvls{lvls}, in{new_in}, out{new_out}, rng{new_rng}, curr_turn{0} { const position nil{0, 0}; @@ -33,12 +34,19 @@ game::game(const enum race starting_race, } void game::new_level() { + if (enabled_features & FEATURE_RAND_MAP) levels.push_back(std::make_unique(player.get(), rng, enabled_features)); + else if (enabled_features & FEATURE_READ_MAP) + levels.push_back(std::make_unique(lvls[curr_level], + player.get(), rng, enabled_features)); else - levels.push_back(std::make_unique(DEFAULT_MAP, player.get(), - rng, enabled_features)); + levels.push_back(std::make_unique( + level_data{POS_NIL, {}, {}, {}, + DEFAULT_MAP, POS_NIL}, + player.get(), rng, + enabled_features)); } enemy_list game::sort_enemies(const enemy_list &elist) { @@ -115,11 +123,8 @@ game_result game::run() { case result::GO_DOWN: { if (curr_level == max_level - 1) - return {WON, "You won! You collected " + - std::to_string(player->get_gold()) + - " pieces of gold after " + - std::to_string(curr_turn + 1) + - " turns!"}; + return {WON, "You won! Your final score is: " + + str_score() + ". "}; player->start_turn(); @@ -138,11 +143,9 @@ game_result game::run() { case result::GO_UP: { if (curr_level == 0) - return {ESCAPED, "You escaped the dungeon with " + - std::to_string(player->get_gold()) + - " pieces of gold after " + - std::to_string(curr_turn + 1) + - " turns! Coward!"}; + return {ESCAPED, + "You escaped the dungeon with a score of" + + str_score() + ". Coward!"}; player->start_turn(); @@ -185,10 +188,11 @@ game_result game::run() { if (player->is_dead()) { if (killer == nullptr) - return {DEAD, "You died: killed by your own stupidity!"}; + return {DEAD, + "You died: killed by your own stupidity!"}; return {DEAD, std::string{"You died: killed by a(n) "} + - killer->get_race_name()}; + killer->get_race_name() + ". "}; } return {IN_GAME, ""}; @@ -227,3 +231,11 @@ void game::print() { out->print_str(STATUS_DEF, "Def: " + std::to_string(player->get_DEF())); out->print_str(STATUS_ACTION, "Action: " + msg); } + +std::string game::str_score() const { + if (player->get_race() == SHADE) + return std::to_string(static_cast(player->get_gold() * + SHADE_SCORE_MUL)); + + return std::to_string(player->get_gold()); +} diff --git a/src/game.h b/src/game.h index 4b3a5ad..c358d5d 100644 --- a/src/game.h +++ b/src/game.h @@ -18,8 +18,10 @@ private: static const size_t MIN_LEVEL_CNT = 30; static const size_t DEFAULT_MAX_LEVEL = 5; static const size_t MAX_MSG_LENGTH = 300; + inline static const float SHADE_SCORE_MUL = 1.5f; const feature enabled_features; + const std::vector &lvls; input *in; output *out; @@ -43,7 +45,8 @@ public: const feature enabled_features, input *new_in, output *new_out, - RNG *new_rng); + RNG *new_rng, + const std::vector &lvls); game_result run(); size_t get_curr_level() const; size_t get_curr_turn() const; @@ -53,6 +56,7 @@ private: void new_level(); character *move_enemies(); enemy_list sort_enemies(const enemy_list &elist); + std::string str_score() const; }; #endif diff --git a/src/level.cc b/src/level.cc index ae2a3ab..9d14fa4 100644 --- a/src/level.cc +++ b/src/level.cc @@ -19,13 +19,13 @@ level::level(character *player, RNG *rng, const feature enabled_features): gen_potions(rng, tiles); gen_gold(rng, tiles); - gen_enemies(rng, tiles); + gen_enemies({}, rng, tiles); } -level::level(const std::string &map_data, character *player, RNG *rng, +level::level(const level_data &lvl, character *player, RNG *rng, const feature enabled_features): enabled_features{enabled_features}, - map{player, map_data, rng, enabled_features}, player{player} { + map{lvl, player, rng, enabled_features}, player{player} { auto tiles = map.get_room_list(); for (size_t i = 0; i < tiles.size(); ++i) @@ -38,23 +38,63 @@ level::level(const std::string &map_data, character *player, RNG *rng, for (size_t i = 0; i < tiles.size(); ++i) remove_from_list(tiles[i], map.get_up_stairs()); + if (enabled_features & FEATURE_READ_MAP) + fill(lvl, tiles, rng); + gen_potions(rng, tiles); gen_gold(rng, tiles); - gen_enemies(rng, tiles); + gen_enemies(lvl, rng, tiles); } -gold_list level::dragon_hoard() { +void level::fill(const level_data &lvl, std::vector &tiles, + RNG *rng) { + for (auto [type, pos] : lvl.enemies) { + for (size_t i = 0; i < tiles.size(); ++i) + remove_from_list(tiles[i], pos); + + pelist.push_back(new_enemy(type, pos, enabled_features, + map.which_room(pos), rng)); + elist.push_back(pelist[pelist.size() - 1].get()); + } + + for (auto [type, pos] : lvl.potions) { + for (size_t i = 0; i < tiles.size(); ++i) + remove_from_list(tiles[i], pos); + + pplist.push_back(new_potion(type, pos)); + plist.push_back(pplist[pplist.size() - 1].get()); + } + + for (auto g : lvl.gold_piles) { + for (size_t i = 0; i < tiles.size(); ++i) + remove_from_list(tiles[i], g.get_pos()); + + glist.push_back(g); + } +} + +gold_list level::dragon_hoard(const level_data &lvl) { gold_list result; for (auto g : glist) - if (g.get_amount() == GOLD_DRAGON) + if (g.get_amount() == GOLD_DRAGON && + !is_in_glist(g, lvl.gold_piles)) result.push_back(g); return result; } -void level::gen_enemies(RNG *rng, std::vector &tiles) { - auto dhoard = dragon_hoard(); +bool level::is_in_glist(gold &g, const gold_list &gl) { + for (auto tmp : gl) + if (tmp.get_pos() == g.get_pos()) + return true; + + return false; +} + +void level::gen_enemies(const level_data &lvl, RNG *rng, + std::vector &tiles) { + auto dhoard = dragon_hoard(lvl); int cnt = enabled_features & FEATURE_EXTRA_STUFF ? rng->rand_between(MIN_ENEMIE_CNT, MAX_ENEMIE_CNT + 1) : MIN_ENEMIE_CNT + dhoard.size(); @@ -87,7 +127,7 @@ void level::gen_enemies(RNG *rng, std::vector &tiles) { } - for (int i = dhoard.size(); i < cnt; ++i) { + for (int i = elist.size(); i < cnt; ++i) { auto p = get_rand_pos(rng, tiles); pelist.push_back(new_enemy(rng, p, enabled_features, map.which_room(p))); @@ -116,7 +156,7 @@ void level::add_gold(gold g) { void level::gen_gold(RNG *rng, std::vector &tiles) { glist.reserve(GOLD_CNT); - for (int i = 0; i < GOLD_CNT; ++i) + for (int i = glist.size(); i < GOLD_CNT; ++i) glist.push_back(gold{get_rand_pos(rng, tiles), rand_gold_pile(rng)}); } @@ -135,7 +175,7 @@ void level::gen_potions(RNG *rng, std::vector &tiles) { plist.reserve(cnt); pplist.reserve(cnt); - for (int i = 0; i < cnt; ++i) { + for (int i = pplist.size(); i < cnt; ++i) { pplist.push_back(new_potion(static_cast (rng->rand_under(max_type)), get_rand_pos(rng, tiles))); diff --git a/src/level.h b/src/level.h index d8a3a78..4ba3a90 100644 --- a/src/level.h +++ b/src/level.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "output.h" #include "gold.h" #include "enemies.h" @@ -11,6 +12,17 @@ #include "potions.h" #include "map.h" +enum race : int; + +struct level_data { + position pc_pos; + std::vector> enemies; + std::vector> potions; + gold_list gold_piles; + std::string map_data; + position stairs; +}; + class level { private: static const int MAX_POTION_CNT = 15; @@ -30,8 +42,8 @@ private: public: // randomly generate a map level(character *player, RNG *rng, const feature enabled_features); - // read map from a string - level(const std::string &map_data, character *player, RNG *rng, + // read map from data + level(const level_data &lvl_data, character *player, RNG *rng, const feature enabled_features); void print(output *out) const; @@ -59,10 +71,13 @@ private: // every gen will delete the positions in tiles void gen_potions(RNG *rng, std::vector &tiles); void gen_gold(RNG *rng, std::vector &tiles); - void gen_enemies(RNG *rng, std::vector &tiles); + void gen_enemies(const level_data &lvl, RNG *rng, + std::vector &tiles); position get_rand_pos(RNG *rng, std::vector &tiles); - gold_list dragon_hoard(); + gold_list dragon_hoard(const level_data &lvl); + bool is_in_glist(gold &g, const gold_list &gl); + void fill(const level_data &lvl, std::vector &tiles, RNG *rng); }; #endif diff --git a/src/main.cc b/src/main.cc index d1c71a6..3172d54 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,4 +1,5 @@ #include +#include #include "cc3k.h" #include "arguments.h" @@ -9,8 +10,9 @@ int main(int argc, char **argv) { std::unique_ptr in; std::unique_ptr out; std::unique_ptr rng; + std::ifstream data; - feature enabled_features = proc_args(argc, argv, curse, in, out, rng); + feature enabled_features = proc_args(argc, argv, curse, in, out, rng, data); if (enabled_features & (FEATURE_PANIC | FEATURE_PANIC_FILE | @@ -25,7 +27,7 @@ int main(int argc, char **argv) { return RETURN_FINE; } - CC3K game_proc(enabled_features, in.get(), out.get(), rng.get()); + CC3K game_proc(enabled_features, in.get(), out.get(), rng.get(), data); while (1) if (game_proc.run() == game_status::TERMINATED) diff --git a/src/map.cc b/src/map.cc index 7aff8e4..22eb154 100644 --- a/src/map.cc +++ b/src/map.cc @@ -4,6 +4,7 @@ #include #include "constants.h" +#include "level.h" game_map::game_map(character *player, RNG *rng, const feature enabled_features): enabled_features{enabled_features} { @@ -44,10 +45,18 @@ game_map::game_map(character *player, RNG *rng, const feature enabled_features): int player_room = rng->rand_under(room_data.size()); player->set_pos(rng->get_rand_in_vector(rooms_tile_list[player_room])); - gen_stairs(player_room, rng); + gen_stairs({}, player_room, rng); } -void game_map::gen_stairs(int player_room, RNG *rng) { +void game_map::gen_stairs(const level_data &lvl, int player_room, + RNG *rng) { + if (enabled_features & FEATURE_READ_MAP) { + int stairs_room = rng->exclude_middle(0, room_data.size(), + player_room); + down_stairs = get_available_spot(lvl, stairs_room, rng); + return; + } + down_stairs = rng->get_rand_in_vector(rooms_tile_list[ rng->exclude_middle(0, room_data.size(), player_room)]); @@ -69,7 +78,7 @@ position game_map::random_size(int min_width, int min_height, rng->rand_between(min_height, max_height + 1)}; } -game_map::game_map(character *player, const std::string &map_data, +game_map::game_map(const level_data &lvl, character *player, RNG *rng, const feature enabled_features): enabled_features{enabled_features} { int map_size = MAP_HEIGHT * MAP_WIDTH; @@ -82,15 +91,17 @@ game_map::game_map(character *player, const std::string &map_data, int max_room_num = 0; for (int i = 0; i < map_size; ++i) { - if (map_data[i] >= '0' && map_data[i] <= '9') { - map.push_back(map_data[i] - '0'); - max_room_num = std::max(max_room_num, map_data[i] - '0'); + if (lvl.map_data[i] >= '0' && lvl.map_data[i] <= '9') { + map.push_back(lvl.map_data[i] - '0'); + max_room_num = std::max(max_room_num, + lvl.map_data[i] - '0'); } else { - map.push_back(map_data[i]); + map.push_back(lvl.map_data[i]); } - if (map_data[i] >= '0' && map_data[i] <= '9') - rooms_tile_list[map_data[i] - '0'].push_back(remap_index(i)); + if (lvl.map_data[i] >= '0' && lvl.map_data[i] <= '9') + rooms_tile_list[lvl.map_data[i] - '0'].push_back( + remap_index(i)); } while (rooms_tile_list[rooms_tile_list.size() - 1].size() == 0) @@ -98,11 +109,38 @@ game_map::game_map(character *player, const std::string &map_data, for (int i = 0; i <= max_room_num; ++i) room_data.push_back({0, 0, 0, 0}); + int player_room; - int player_room = rng->rand_under(room_data.size()); - player->set_pos(rng->get_rand_in_vector(rooms_tile_list[player_room])); + if (lvl.pc_pos != POS_NIL) { + player->set_pos(lvl.pc_pos); + player_room = which_room(lvl.pc_pos); + } else { + player_room = rng->rand_under(room_data.size()); + player->set_pos(get_available_spot(lvl, player_room, rng)); + } - gen_stairs(player_room, rng); + if (lvl.stairs == POS_NIL) { + gen_stairs(lvl, player_room, rng); + } else { + down_stairs = lvl.stairs; + map[remap_position(down_stairs)] = '\\'; + } +} + +position game_map::get_available_spot(const level_data &lvl, int room, + RNG *rng) { + position_list spots = rooms_tile_list[room]; + + for (auto [type, pos] : lvl.enemies) + remove_from_list(spots, pos); + + for (auto [type, pos] : lvl.potions) + remove_from_list(spots, pos); + + for (auto g : lvl.gold_piles) + remove_from_list(spots, g.get_pos()); + + return rng->get_rand_in_vector(spots); } bool game_map::is_available(const position &pos) const { diff --git a/src/map.h b/src/map.h index 570e036..d042799 100644 --- a/src/map.h +++ b/src/map.h @@ -11,6 +11,8 @@ #include "player.h" #include "characters.h" +struct level_data; + class game_map final { private: static const int MAX_ROOM_CNT = 20; @@ -54,7 +56,7 @@ public: // randomly generate a map game_map(character *player, RNG *rng, const feature enabled_features); // read map from a string - game_map(character *player, const std::string &map_data, RNG *rng, + game_map(const level_data &lvl, character *player, RNG *rng, const feature enabled_features); bool is_available(const position &pos) const; @@ -74,6 +76,7 @@ public: int get_room_cnt() const; private: + position get_available_spot(const level_data &lvl, int room, RNG *rng); std::vector room_data; position remap_index(const int idx) const; int remap_position(const position &pos) const; @@ -107,7 +110,7 @@ private: room hit_room(const position &a); bool hit_room(const position &a, const room &r); - void gen_stairs(int player_room, RNG *rng); + void gen_stairs(const level_data &lvl, int player_room, RNG *rng); room get_room(std::size_t idx) const; };