diff --git a/src/cc3k.h b/src/cc3k.h new file mode 100644 index 0000000..e702d1a --- /dev/null +++ b/src/cc3k.h @@ -0,0 +1,6 @@ +#ifndef __CC3K_H__ +#define __CC3K_H__ + +class CC3K; + +#endif diff --git a/src/characters.cc b/src/characters.cc index 48a0931..13602db 100644 --- a/src/characters.cc +++ b/src/characters.cc @@ -110,24 +110,6 @@ result character::apply(direction &dir, const potion_list &potions) { return result::fine; } -position_list remove_from_list(const position_list &sorted_positions, - position_list excluded) { - std::sort(excluded.begin(), excluded.end()); - - position_list result{sorted_positions.size() - excluded.size()}; - - auto exc = excluded.begin(); - - for (auto src : sorted_positions) { - if (exc != excluded.end() && src == *exc) - ++exc; - else - result.push_back(src); - } - - return result; -} - // IMPORTANT: remember to check if player is on the stairs result character::move(const direction dir, const position_list &available_positions) { diff --git a/src/characters.h b/src/characters.h index 4c5a04c..d4f6bb3 100644 --- a/src/characters.h +++ b/src/characters.h @@ -14,6 +14,7 @@ #include "constants.h" #include "position.h" #include "potion.h" +#include "gold.h" #include "rng.h" // #include "inventory.h" // Reserved for later @@ -85,11 +86,6 @@ protected: bool hostile; }; -// requires: all elements of excluded are in sorted_positions -position_list remove_from_list(const position_list &sorted_positions, - position_list excluded); - - int calc_dmg(const int ATK, const int DEF); #endif diff --git a/src/constants.h b/src/constants.h index f4316de..d9c7962 100644 --- a/src/constants.h +++ b/src/constants.h @@ -106,6 +106,5 @@ const int COLOR_BLACK_ON_WHITE = 8; typedef std::vector position_list; typedef std::vector direction_list; -typedef std::vector gold_list; #endif diff --git a/src/game.h b/src/game.h index e7318ec..f79aa5d 100644 --- a/src/game.h +++ b/src/game.h @@ -17,6 +17,8 @@ private: display &out; logger &log; RNG &rng; + + // IMPORTANT: during player generation, std::unique_ptr player; public: game(const feature enabled_features, diff --git a/src/gold.h b/src/gold.h new file mode 100644 index 0000000..738f066 --- /dev/null +++ b/src/gold.h @@ -0,0 +1,14 @@ +#ifndef __GOLD_H__ +#define __GOLD_H__ + +#include +#include "position.h" + +struct gold { + int amount; + position pos; +}; + +typedef std::vector gold_list; + +#endif diff --git a/src/level.h b/src/level.h index dff3881..4488d5f 100644 --- a/src/level.h +++ b/src/level.h @@ -1,6 +1,31 @@ #ifndef __LEVEL_H__ #define __LEVEL_H__ -class level; +#include +#include "display.h" +#include "characters.h" +#include "potion.h" +#include "constants.h" +#include "gold.h" +#include "map.h" + +class level { +private: + game_map map; + const character &player; + character_list chlist; + potion_list plist; + gold_list glist; +public: + // randomly generate a map + level(const character &player); + // read map from a string + level(const std::string &map_data, const character &player); + void print(display &out) const; + void run(); + position_list get_available_positions() const; + position get_up_stairs() const; + position get_down_stairs() const; +}; #endif diff --git a/src/main.cc b/src/main.cc index dec8057..30069a2 100644 --- a/src/main.cc +++ b/src/main.cc @@ -1,4 +1,4 @@ -#include "game.h" +#include "cc3k.h" #include "arguments.h" int main(int argc, char **argv) { @@ -19,10 +19,12 @@ int main(int argc, char **argv) { return RETURN_PANICKED; } - game game_proc(enabled_features, *in, *out, *log, *rng); + CC3K game_proc(enabled_features, *in, *out, *log, *rng); - while (game_proc.run() != game_status::terminated) + while (game_proc.run() != game_status::terminated) { out->render(); + out->clear(); + } return RETURN_FINE; } diff --git a/src/map.cc b/src/map.cc index d9827cd..5a9a787 100644 --- a/src/map.cc +++ b/src/map.cc @@ -1,68 +1,82 @@ #include "map.h" -#include -#include -#include -#include +game_map::game_map(RNG &rng, const feature enabled_features): + enabled_features{enabled_features} { -game_map::game_map(int lvl) { - level = lvl; - // TODO: randomly generate a map } -game_map::game_map(const std::string &map_data, int lvl) { - level = lvl; - std::istringstream iss{map_data}; +game_map::game_map(const std::string &map_data, + RNG &rng, const feature enabled_features): + enabled_features{enabled_features} { + int map_size = MAP_HEIGHT * MAP_WIDTH; + map.reserve(map_size); - std::string line; + for (int i = 0; i < map_size; ++i) { + if (map_data[i] >= '0' && map_data[i] <= '9') + map.push_back(map_data[i] - '0'); + else + map.push_back(map_data[i]); - for (int i = 0; i < MAP_HEIGHT; ++i) { - getline(iss, line); - map[i] = line; + if ((map_data[i] >= '0' && map_data[i] <= '9') || + map_data[i] == '+' || map_data[i] == '#') + empty_spots.push_back(remap_index(i)); + } + + down_stairs = rng.get_rand_in_vector(empty_spots); + + + if (enabled_features | FEATURE_REVISIT) { + up_stairs = rng.get_rand_in_vector( + remove_from_list(empty_spots, {down_stairs})); + map[remap_position(up_stairs)] = '<'; + map[remap_position(down_stairs)] = '>'; + } else { + map[remap_position(down_stairs)] = '\\'; } } -game_map::~game_map() {} - -int game_map::get_level() const { - return this->level; +const position_list game_map::get_available_positions() const { + return empty_spots; } -std::vector game_map::get_available_positions() const { - std::vector result; +void game_map::print(display &out) const { + for (std::size_t i = 0; i < map.size(); ++i) + out.print_char(remap_index(i), map[i] <= 9 ? '.' : map[i], + map[i] == '\\' || map[i] == '>' || + map[i] == '<' ? COLOR_PAIR(COLOR_BLUE) : A_NORMAL); +} + +position game_map::get_up_stairs() const { + return up_stairs; +} + +position game_map::get_down_stairs() const { + return down_stairs; +} + +int game_map::get_up_stairs_room() const { + return map[remap_position(up_stairs)]; +} + +int game_map::get_down_stairs_room() const { + return map[remap_position(down_stairs)]; +} + +const std::vectorgame_map::get_room_list() const { + std::vector result; + result.reserve(10); + + for (int i = 0; i < 10; ++i) + result.push_back({}); + + for (std::size_t i = 0; i < map.size(); ++i) + if (map[i] <= 9) + result[map[i]].push_back(remap_index(i)); + + result.shrink_to_fit(); + + for (std::size_t i = 0; i < result.size(); ++i) + result[i].shrink_to_fit(); - for (int line = 0; line < MAP_HEIGHT; ++line) - for (int x = 0; x < MAP_WIDTH; ++x) - if (map[line][x] == '.' || - map[line][x] == '#' || - map[line][x] == '+') - result.push_back(position{x, line}); return result; } - -void game_map::print() const { - - // TODO: write a print function using ncurses -} - -void game_map::print(display &display) const { - for (int i = 0; i < MAP_HEIGHT; ++i) - display.print_str(position{0, i}, map[i]); -} - -void game_map::apply_potion(character *who, const stat_name statn, - const int amount) { - effects.push_back(effect{who, statn, amount}); - who->apply_buff(statn, amount); -} - -void game_map::enter_level(character *who) { - for (auto eff : effects) - if (eff.who == who) - who->apply_buff(eff.statn, eff.amount); -} - -void game_map::leave_level(character *who) { - who->set_ATK(STARTING_ATK[who->get_race()]); - who->set_DEF(STARTING_DEF[who->get_race()]); -} diff --git a/src/map.cc.bak b/src/map.cc.bak new file mode 100644 index 0000000..d9827cd --- /dev/null +++ b/src/map.cc.bak @@ -0,0 +1,68 @@ +#include "map.h" + +#include +#include +#include +#include + +game_map::game_map(int lvl) { + level = lvl; + // TODO: randomly generate a map +} + +game_map::game_map(const std::string &map_data, int lvl) { + level = lvl; + std::istringstream iss{map_data}; + + std::string line; + + for (int i = 0; i < MAP_HEIGHT; ++i) { + getline(iss, line); + map[i] = line; + } +} + +game_map::~game_map() {} + +int game_map::get_level() const { + return this->level; +} + +std::vector game_map::get_available_positions() const { + std::vector result; + + for (int line = 0; line < MAP_HEIGHT; ++line) + for (int x = 0; x < MAP_WIDTH; ++x) + if (map[line][x] == '.' || + map[line][x] == '#' || + map[line][x] == '+') + result.push_back(position{x, line}); + return result; +} + +void game_map::print() const { + + // TODO: write a print function using ncurses +} + +void game_map::print(display &display) const { + for (int i = 0; i < MAP_HEIGHT; ++i) + display.print_str(position{0, i}, map[i]); +} + +void game_map::apply_potion(character *who, const stat_name statn, + const int amount) { + effects.push_back(effect{who, statn, amount}); + who->apply_buff(statn, amount); +} + +void game_map::enter_level(character *who) { + for (auto eff : effects) + if (eff.who == who) + who->apply_buff(eff.statn, eff.amount); +} + +void game_map::leave_level(character *who) { + who->set_ATK(STARTING_ATK[who->get_race()]); + who->set_DEF(STARTING_DEF[who->get_race()]); +} diff --git a/src/map.h b/src/map.h index 58fe7c2..2255d64 100644 --- a/src/map.h +++ b/src/map.h @@ -12,49 +12,70 @@ #include "display.h" #include "position.h" #include "characters.h" +#include "rng.h" class game_map final { +private: + const feature enabled_features; + std::vector map; + // IMPORTANT: keep empty_spots ordered + position_list empty_spots; + position up_stairs; + position down_stairs; + int room_cnt; public: - game_map(int lvl = 0); // randomly generate one - // initialize using stored data - game_map(const std::string &map_data, int lvl); - ~game_map(); // placeholder + // randomly generate a map + game_map(RNG &rng, const feature enabled_features); + // read map from a string + game_map(const std::string &map_data, RNG &rng, + const feature enabled_features); - int get_level() const; - - position_list get_available_positions() const; + const position_list get_available_positions() const; + const std::vector get_room_list() const; // IMPORTANT: always print a map before anything else + void print(display &out) const; - // prints using ncurses - void print() const; + position get_up_stairs() const; + position get_down_stairs() const; - // prints to a string - void print(display &display) const; + int get_up_stairs_room() const; + int get_down_stairs_room() const; +private: + position remap_index(const int idx) const { + return {idx % MAP_WIDTH, idx / MAP_HEIGHT}; + } - // This is implemented this way to do two things: - // 1. avoid directly accessing heap memory (bonus points) - // 2. make a level revisitable - void apply_potion(character *who, const stat_name statn, const int amount); - - // just in case you want to retain the potion effects - void enter_level(character *who); - void leave_level(character *who); -public: - struct effect { - character *who; - stat_name statn; - int amount; - }; - - std::string map[MAP_HEIGHT]; - int level; - - // use this to remember every applied potion - std::vector effects; + int remap_position(const position &pos) const { + return pos.y * MAP_WIDTH + pos.x; + } }; const std::string default_map = - "|-----------------------------------------------------------------------------|\n| |\n| |--------------------------| |-----------------------| |\n| |..........................| |.......................| |\n| |..........................+########+.......................|-------| |\n| |..........................| # |...............................|--| |\n| |..........................| # |..................................|--| |\n| |----------+---------------| # |----+----------------|...............| |\n| # ############# |...............| |\n| # # |-----+------| |...............| |\n| # # |............| |...............| |\n| ################### |............| ######+...............| |\n| # # |............| # |...............| |\n| # # |-----+------| # |--------+------| |\n| |---------+-----------| # # # # |\n| |.....................| # # # |----+------| |\n| |.....................| ######################## |...........| |\n| |.....................| # # |...........| |\n| |.....................| # |------+--------------------|...........| |\n| |.....................| # |.......................................| |\n| |.....................+##########+.......................................| |\n| |.....................| |.......................................| |\n| |---------------------| |---------------------------------------| |\n| |\n|-----------------------------------------------------------------------------|"; + "|-----------------------------------------------------------------------------|\ +| |\ +| |--------------------------| |-----------------------| |\ +| |11111111111111111111111111| |33333333333333333333333| |\ +| |11111111111111111111111111+########+33333333333333333333333|-------| |\ +| |11111111111111111111111111| # |3333333333333333333333333333333|--| |\ +| |11111111111111111111111111| # |3333333333333333333333333333333333|--| |\ +| |----------+---------------| # |----+----------------|333333333333333| |\ +| # ############# |333333333333333| |\ +| # # |-----+------| |333333333333333| |\ +| # # |444444444444| |333333333333333| |\ +| ################### |444444444444| ######+333333333333333| |\ +| # # |444444444444| # |333333333333333| |\ +| # # |-----+------| # |--------+------| |\ +| |---------+-----------| # # # # |\ +| |222222222222222222222| # # # |----+------| |\ +| |222222222222222222222| ######################## |00000000000| |\ +| |222222222222222222222| # # |00000000000| |\ +| |222222222222222222222| # |------+--------------------|00000000000| |\ +| |222222222222222222222| # |000000000000000000000000000000000000000| |\ +| |222222222222222222222+##########+000000000000000000000000000000000000000| |\ +| |222222222222222222222| |000000000000000000000000000000000000000| |\ +| |---------------------| |---------------------------------------| |\ +| |\ +|-----------------------------------------------------------------------------|"; #endif diff --git a/src/position.cc b/src/position.cc index 63609e5..478b57d 100644 --- a/src/position.cc +++ b/src/position.cc @@ -43,3 +43,24 @@ size_t find(const std::vector &sorted_list, return sorted_list.size(); } + +#include + +std::vector remove_from_list(const std::vector + &sorted_positions, + std::vector excluded) { + std::sort(excluded.begin(), excluded.end()); + + std::vector result{sorted_positions.size() - excluded.size()}; + + auto exc = excluded.begin(); + + for (auto src : sorted_positions) { + if (exc != excluded.end() && src == *exc) + ++exc; + else + result.push_back(src); + } + + return result; +} diff --git a/src/position.h b/src/position.h index 6d794a5..ea9535e 100644 --- a/src/position.h +++ b/src/position.h @@ -26,4 +26,9 @@ typedef struct position { std::size_t find(const std::vector &sorted_list, const position &target); +// requires: all elements of excluded are in sorted_positions +std::vector remove_from_list(const std::vector + &sorted_positions, + std::vector excluded); + #endif