Files
cc3k/src/cc3k.cc

245 lines
6.9 KiB
C++

#include "cc3k.h"
#include <iostream>
#include <fstream>
#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<menu>(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<game>(static_cast<race>(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<menu>(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<menu>(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 += '.';
}