#include "cc3k.h" #include #include #include "constants.h" CC3K::CC3K(const feature enabled_features, 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); out->clear(); 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() { switch (gresult.status) { case MAIN_MENU: { auto tmp = curr_menu->run(in); if (tmp == -2) { gresult.status = TERMINATED; return TERMINATED; } if (tmp != -1) { curr_menu.reset(); curr_game = std::make_unique(static_cast(tmp), enabled_features, in, out, rng, lvls); out->clear(); curr_game->print(); out->render(); gresult.status = IN_GAME; return IN_GAME; } out->clear(); curr_menu->print(out, rng->get_init_seed()); out->render(); return MAIN_MENU; } case IN_GAME: { gresult = curr_game->run(); if (gresult.status == RESTART) { curr_game.reset(); curr_menu = std::make_unique(enabled_features); out->clear(); curr_menu->print(out, rng->get_init_seed()); out->render(); gresult.status = MAIN_MENU; return MAIN_MENU; } else if (gresult.status == IN_GAME) { out->clear(); curr_game->print(); out->render(); return IN_GAME; } else if (gresult.status == TERMINATED) { return TERMINATED; } out->clear(); gresult.print(out); out->render(); return gresult.status; } case DEAD: case WON: case ESCAPED: curr_game.reset(); gresult.run(in); if (gresult.status == RESTART) { curr_menu = std::make_unique(enabled_features); out->clear(); curr_menu->print(out, rng->get_init_seed()); out->render(); gresult.status = MAIN_MENU; return MAIN_MENU; } return TERMINATED; default: break; } 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 += '.'; }