211 lines
6.2 KiB
C++
211 lines
6.2 KiB
C++
#include "game.h"
|
|
|
|
#include "constants.h"
|
|
#include "pc.h"
|
|
|
|
game::game(const enum race starting_race,
|
|
const feature enabled_features,
|
|
input *new_in,
|
|
output *new_out,
|
|
RNG *new_rng):
|
|
enabled_features{enabled_features},
|
|
in{new_in}, out{new_out}, rng{new_rng},
|
|
curr_turn{0} {
|
|
const position nil{0, 0};
|
|
the_world = false;
|
|
|
|
// TODO: add the other races
|
|
init_player(rng, player, enabled_features, starting_race);
|
|
|
|
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<level>(player.get(),
|
|
rng, enabled_features));
|
|
else
|
|
levels.push_back(std::make_unique<level>(default_map, player.get(),
|
|
rng, enabled_features));
|
|
}
|
|
|
|
enemy_list game::sort_enemies(const enemy_list &elist) {
|
|
enemy_list result;
|
|
result.reserve(elist.size());
|
|
|
|
for (auto enemy : elist) {
|
|
result.push_back(enemy);
|
|
|
|
for (int i = result.size() - 1; i > 0 &&
|
|
enemy->get_pos() < result[i - 1]->get_pos(); --i)
|
|
std::swap(result[i], result[i - 1]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
character *game::move_enemies() {
|
|
if (the_world)
|
|
return nullptr;
|
|
|
|
auto enemies = sort_enemies(levels[curr_level]->get_elist());
|
|
|
|
for (auto ch : enemies) {
|
|
bool hostile = ch->get_race() == rmerchant ?
|
|
hostile_merchants : true;
|
|
ch->start_turn();
|
|
ch->calc_effects();
|
|
auto res =
|
|
ch->act(levels[curr_level].get(), player.get(), hostile);
|
|
|
|
if (player->is_dead())
|
|
return ch;
|
|
|
|
if (ch->is_dead()) {
|
|
int g = ch->dies(levels[curr_level].get());
|
|
|
|
if (g)
|
|
levels[curr_level]->add_gold({g, ch->get_pos()});
|
|
}
|
|
|
|
msg += res.msg;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
game_result game::run() {
|
|
auto res = player->interpret_command(levels[curr_level].get(),
|
|
in->get_command());
|
|
msg = res.msg;
|
|
|
|
if (res.msg.find('M') != std::string::npos)
|
|
hostile_merchants = true;
|
|
|
|
switch (res.res) {
|
|
case result::terminate:
|
|
return {terminated, ""};
|
|
|
|
case result::died:
|
|
return {dead, "You died: killed by your own stupidity!"};
|
|
|
|
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!"};
|
|
|
|
player->discard_level_effects();
|
|
|
|
++curr_level;
|
|
|
|
if (curr_level == levels.size())
|
|
new_level();
|
|
|
|
if (enabled_features & FEATURE_REVISIT)
|
|
player->set_pos(levels[curr_level]->get_up_stairs());
|
|
|
|
break;
|
|
}
|
|
|
|
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!"};
|
|
|
|
player->discard_level_effects();
|
|
|
|
--curr_level;
|
|
|
|
player->set_pos(levels[curr_level]->get_down_stairs());
|
|
|
|
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 {in_game, ""};
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
player->calc_effects();
|
|
|
|
if (player->is_dead())
|
|
return {dead, "You died: killed by your own stupidity!"};
|
|
|
|
auto killer = move_enemies();
|
|
|
|
if (player->is_dead()) {
|
|
if (killer == nullptr)
|
|
return {dead, "You died: killed by your own stupidity!"};
|
|
|
|
return {dead, (std::string)"You died: killed by a(n) " +
|
|
killer->get_race_name()};
|
|
}
|
|
|
|
++curr_turn;
|
|
return {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 std::string BLANK(DISPLAY_BUFFER_SIZE, ' ');
|
|
|
|
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 += "...";
|
|
}
|
|
|
|
out->print_str({0, 0}, BLANK);
|
|
|
|
levels[curr_level]->print(out);
|
|
player->print(out);
|
|
|
|
std::string tmp = "Race: ";
|
|
tmp += player->get_race_name();
|
|
tmp += " Gold: " + std::to_string(player->get_gold());
|
|
out->print_str(STATUS_RACE, tmp);
|
|
out->print_str(STATUS_FLOOR, "Floor " + std::to_string(curr_level + 1));
|
|
out->print_str(STATUS_HP, "HP: " + std::to_string(player->get_HP()));
|
|
out->print_str(STATUS_ATK, "Atk: " + std::to_string(player->get_ATK()));
|
|
out->print_str(STATUS_DEF, "Def: " + std::to_string(player->get_DEF()));
|
|
out->print_str(STATUS_ACTION, "Action: " + msg);
|
|
}
|