245 lines
6.9 KiB
C++
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 += '.';
|
|
}
|