#include "game.h" #include "races.h" game::game(const enum race starting_race, const feature enabled_features, input *new_in, display *new_out, logger *new_log, RNG *new_rng): enabled_features{enabled_features}, in{new_in}, out{new_out}, log{new_log}, rng{new_rng}, curr_turn{0} { const position nil{0, 0}; the_world = false; // TODO: add the other races switch (starting_race) { case race::rshade: player = std::make_unique(rng, nil); break; } if (enabled_features & FEATURE_EXTRA_LEVELS) max_level = rng->rand_between(MIN_LEVEL_CNT, MAX_LEVEL_CNT + 1); else max_level = DEFAULT_MAX_LEVEL; levels.reserve(max_level); curr_level = 0; hostile_merchants = false; new_level(); msg += "Player character has spawned. "; print(); } void game::new_level() { if (enabled_features & FEATURE_RAND_MAP) levels.push_back(std::make_unique(player.get(), rng, enabled_features)); else levels.push_back(std::make_unique(default_map, player.get(), rng, enabled_features)); } result game::player_moves(game_command cmd) { if (cmd == game_command_terminate) { return result::terminate; } else if (cmd >= move_north && cmd <= move_southwest) { // Tried to move if (enabled_features & FEATURE_NCURSES) return player_move_or_attack((direction)(cmd - move_north)); return player->move((direction)(cmd - move_north), levels[curr_level]->get_available_around( player->get_position())); } else if (cmd >= apply_north && cmd <= apply_southwest) { auto res = player->apply((direction)(cmd - apply_north), levels[curr_level]->get_plist()); if (res.res == applied) { msg += "PC used potion "; msg += POTION_REAL_NAME[res.which->get_type()]; msg += ". "; } else { msg += "PC tried to drink thin air. "; } return res.res; } else if (cmd == apply_panic) { msg += "PC tried to use in some non-existent direction. "; return fine; } else if (cmd >= attack_north && cmd <= attack_southwest) { auto res = player->attack((direction)(cmd - attack_north), levels[curr_level]->get_chlist()); if (res.res == hit) { msg += "PC deals " + std::to_string(res.dmg_dealt) + " damage to " + CHARACTER_REP[res.which->get_race()] + " (" + std::to_string(res.remaining_HP) + " HP). "; } else if (res.res == miss) { msg += "PC missed "; msg += CHARACTER_REP[res.which->get_race()]; msg += ". "; } else { msg += "PC tried to attack thin air. "; } if (res.which->get_race() == rmerchant) hostile_merchants = true; return res.res; } else if (cmd == up_stairs) { if (player->get_position() == levels[curr_level]->get_up_stairs()) return go_up; msg += "PC tried to fly through the ceiling. "; return fine; } else if (cmd == down_stairs) { if (player->get_position() == levels[curr_level]->get_down_stairs()) return go_down; msg += "PC tried to dig through the floor. "; return fine; } else if (cmd == the_world) { msg += "PC toggled Stand: The World! "; return toggle_the_world; } else if (cmd == game_restart) { return restart_game; } else if (cmd == game_command_pass) { return fine; } else if (cmd == game_command_panic) { msg += "PC tried to produce some undefined behaviour. "; return unknown; } msg += "PC tried to produce some undefined behaviour. "; return unknown; } #include bool compare_characters(character *&a, character *&b) { return a->get_position() < b->get_position(); } void game::move_enemies() { if (the_world) return; character_list enemies = levels[curr_level]->get_chlist(); std::sort(enemies.begin(), enemies.end(), &game::compare_characters); for (auto ch : enemies) { } } game_status game::run() { msg = ""; auto res = player_moves(in->get_command()); if (!(enabled_features & FEATURE_NCURSES) && res == result::moved && (player->get_position() == levels[curr_level]->get_down_stairs())) res = go_down; if (!(enabled_features & FEATURE_NCURSES) && res == result::moved && (player->get_position() == levels[curr_level]->get_up_stairs())) res = go_up; switch (res) { case result::terminate: return terminated; case result::died: return game_status::dead; case result::go_down: { if (curr_level == max_level - 1) return game_status::won; player->discard_level_effects(); ++curr_level; new_level(); msg += "PC went down a floor. "; break; } case result::go_up: { if (curr_level == 0) return game_status::escaped; player->discard_level_effects(); --curr_level; player->set_position(levels[curr_level]->get_down_stairs()); msg += "PC went up a floor. "; break; } case toggle_the_world: the_world = !the_world; break; case restart_game: return restart; case unknown: case fine: case applied_nothing: ++curr_turn; return game_status::in_game; default: break; } player->start_turn(); player->apply_effects(); if (player->get_HP() <= 0) return game_status::dead; move_enemies(); if (player->get_HP() <= 0) return game_status::dead; ++curr_turn; return game_status::in_game; } const position STATUS_RACE{0, 25}; const position STATUS_FLOOR{69, 25}; const position STATUS_HP{0, 26}; const position STATUS_ATK{0, 27}; const position STATUS_DEF{0, 28}; const position STATUS_ACTION{0, 29}; const char *ASK_ATK_MERCHANT = "Action: Do you really want to attack the peaceful merchant? [Y/N]"; size_t game::get_curr_turn() const { return curr_turn; } void game::print() { if (msg.length() > MAX_MSG_LENGTH) { msg.resize(MAX_MSG_LENGTH); msg += "..."; } levels[curr_level]->print(out); player->print(out, true); std::string tmp = "Race: "; tmp += RACE_NAME[player->get_race()]; tmp += " Gold: " + std::to_string(player->get_gold()); out->print_str(STATUS_RACE, tmp); tmp = "Floor " + std::to_string(curr_level + 1); out->print_str(STATUS_FLOOR, tmp); tmp = "Atk: " + std::to_string(player->get_ATK()); out->print_str(STATUS_ATK, tmp); tmp = "Def: " + std::to_string(player->get_DEF()); out->print_str(STATUS_DEF, tmp); tmp = "Action: " + msg; out->print_str(STATUS_ACTION, tmp); } result game::player_move_or_attack(const direction &dir) { auto avlbl = levels[curr_level]->get_available_around( player->get_position()); if (find(avlbl, player->get_position() + MOVE[dir]) != avlbl.size()) { player->set_position(player->get_position() + MOVE[dir]); return result::moved; } auto tmp = player->get_position() + MOVE[dir]; character *target; for (auto ch : levels[curr_level]->get_chlist()) if (tmp == ch->get_position()) { target = ch; } auto res = player->attack(dir, target); if (target->get_race() == rmerchant) hostile_merchants = true; if (res.res == hit) { msg += "PC deals " + std::to_string(res.dmg_dealt) + " damage to " + CHARACTER_REP[res.which->get_race()] + " (" + std::to_string(res.remaining_HP) + " HP). "; } else if (res.res == miss) { msg += "PC missed "; msg += CHARACTER_REP[res.which->get_race()]; msg += ". "; } else { msg += "PC tried to attack thin air. "; } return res.res; }