full implementation!

bug: level generation will generate nullptrs
This commit is contained in:
2024-07-15 00:09:14 -04:00
parent c3b974c83c
commit 6768d73d16
13 changed files with 407 additions and 46 deletions

76
src/cc3k.cc Normal file
View File

@ -0,0 +1,76 @@
#include "cc3k.h"
#include "constants.h"
CC3K::CC3K(const feature enabled_features,
input *in, display *out, RNG *rng):
enabled_features{enabled_features},
in{in}, out{out}, rng{rng} {
curr_menu = std::make_unique<menu>(enabled_features);
out->clear();
curr_menu->print(out);
out->render();
gresult.status = game_status::main_menu;
}
game_status CC3K::run() {
switch (gresult.status) {
case main_menu: {
auto tmp = curr_menu->run(in);
if (tmp == -2)
return terminated;
if (tmp != -1) {
curr_menu = nullptr;
curr_game = std::make_unique<game>((race)tmp,
enabled_features,
in, out, rng);
out->clear();
curr_game->print();
out->render();
gresult.status = in_game;
return in_game;
}
out->clear();
curr_menu->print(out);
out->render();
return main_menu;
}
case in_game: {
gresult = curr_game->run();
if (gresult.status == restart) {
curr_game = nullptr;
curr_menu = std::make_unique<menu>(enabled_features);
out->clear();
curr_menu->print(out);
out->render();
return main_menu;
} else if (gresult.status == in_game) {
out->clear();
curr_game->print();
out->render();
return in_game;
}
out->clear();
gresult.print(out);
out->render();
return gresult.status;
}
case dead:
case won:
case escaped:
gresult.run(in);
return terminated;
default:
break;
}
return terminated;
}

View File

@ -1,8 +1,26 @@
#ifndef __CC3K_H__
#define __CC3K_H__
class CC3K;
#include "input.h"
#include "display.h"
#include "game.h"
#include "menu.h"
#include "result.h"
// every time it runs, clear first
class CC3K final {
private:
const feature enabled_features;
input *in;
display *out;
RNG *rng;
game_result gresult;
std::unique_ptr<game> curr_game;
std::unique_ptr<menu> curr_menu;
public:
CC3K(const feature enabled_features,
input *in, display *out, RNG *rng);
game_status run();
};
#endif

View File

@ -20,7 +20,7 @@ struct long_result {
};
enum game_status : int {terminated, main_menu, in_game, options,
dead, won, escaped, restart, skip_turn
dead, won, escaped, restart
};
enum game_command : int {game_command_terminate = 0,

View File

@ -46,9 +46,9 @@ bool compare_characters(const character *a, const character *b) {
return a->get_pos() < b->get_pos();
}
void game::move_enemies() {
character *game::move_enemies() {
if (the_world)
return;
return nullptr;
auto enemies = levels[curr_level]->get_elist();
std::sort(enemies.begin(), enemies.end(), ::compare_characters);
@ -62,16 +62,18 @@ void game::move_enemies() {
ch->act(levels[curr_level].get(), player.get(), hostile);
if (player->is_dead())
return;
return ch;
if (ch->is_dead())
ch->dies(levels[curr_level].get(), player.get());
msg += res.msg;
}
return nullptr;
}
game_status game::run() {
game_result game::run() {
player->start_turn();
auto res = player->interpret_command(levels[curr_level].get(),
in->get_command());
@ -79,28 +81,40 @@ game_status game::run() {
switch (res.res) {
case result::terminate:
return terminated;
return {terminated, ""};
case result::died:
return game_status::dead;
return {dead, "You died: killed by your own stupidity!"};
case result::go_down: {
if (curr_level == max_level - 1)
return game_status::won;
return {won, "You won! You collected " +
std::to_string(player->get_gold()) +
" after " + std::to_string(curr_turn + 1) +
" turns!"};
player->discard_level_effects();
++curr_level;
new_level();
break;
}
case result::go_up: {
if (curr_level == 0)
return game_status::escaped;
return {escaped, "You escaped the dungeon with " +
std::to_string(player->get_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;
}
@ -109,13 +123,13 @@ game_status game::run() {
break;
case restart_game:
return restart;
return {restart, ""};
case unknown:
case fine:
case applied_nothing:
++curr_turn;
return game_status::in_game;
return {in_game, ""};
default:
break;
@ -125,15 +139,20 @@ game_status game::run() {
player->calc_effects();
if (player->is_dead())
return game_status::dead;
return {dead, "You died: killed by your own stupidity!"};
move_enemies();
auto killer = move_enemies();
if (player->is_dead())
return game_status::dead;
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 game_status::in_game;
return {in_game, ""};
}
const position STATUS_RACE{0, 25};

View File

@ -8,6 +8,7 @@
#include "characters.h"
#include "level.h"
#include "player.h"
#include "result.h"
enum game_status : int;
@ -43,14 +44,14 @@ public:
input *new_in,
display *new_out,
RNG *new_rng);
game_status run();
game_result run();
size_t get_curr_level() const;
size_t get_curr_turn() const;
const character *get_player() const;
void print();
private:
void new_level();
void move_enemies();
character *move_enemies();
};
#endif

View File

@ -39,7 +39,7 @@ game_command console_input::get_command() {
auto tmp = get_direction(cmd);
if (tmp != game_command_panic)
return tmp;
return (game_command)(tmp + move_north);
}
return game_command_pass;

View File

@ -114,31 +114,31 @@ void level::gen_potions(RNG *rng, std::vector<position_list> &tiles) {
void level::print(display *out) const {
map.print(out);
for (auto ch : elist)
ch->print(out);
for (size_t i = 0; i < plist.size(); ++i)
plist[i]->print(out);
for (auto p : plist)
p->print(out);
for (size_t i = 0; i < glist.size(); ++i)
out->print_char(glist[i].pos, 'G', COLOR_PAIR(COLOR_YELLOW));
for (auto gold : glist)
out->print_char(gold.pos, 'G', COLOR_PAIR(COLOR_YELLOW));
for (size_t i = 0; i < elist.size(); ++i)
elist[i]->print(out);
}
bool level::is_available(const position &pos, bool is_player) const {
if (!map.is_available(pos))
return false;
for (auto ch : elist)
if (pos == ch->get_pos())
for (size_t i = 0; i < elist.size(); ++i)
if (pos == elist[i]->get_pos())
return false;
if (!(enabled_features & FEATURE_WALK_OVER) && !is_player) {
for (auto p : plist)
if (pos == p->get_pos())
for (size_t i = 0; i < plist.size(); ++i)
if (pos == plist[i]->get_pos())
return false;
for (auto g : glist)
if (pos == g.pos)
for (size_t i = 0; i < glist.size(); ++i)
if (pos == glist[i].pos)
return false;
}
@ -149,16 +149,16 @@ bool level::is_available_all(const position &pos) const {
if (!map.is_available(pos))
return false;
for (auto ch : elist)
if (pos == ch->get_pos())
for (size_t i = 0; i < elist.size(); ++i)
if (pos == elist[i]->get_pos())
return false;
for (auto p : plist)
if (pos == p->get_pos())
for (size_t i = 0; i < plist.size(); ++i)
if (pos == plist[i]->get_pos())
return false;
for (auto g : glist)
if (pos == g.pos)
for (size_t i = 0; i < glist.size(); ++i)
if (pos == glist[i].pos)
return false;
return true;

View File

@ -22,12 +22,11 @@ int main(int argc, char **argv) {
return RETURN_FINE;
}
// CC3K game_proc(enabled_features, *in, *out, *log, *rng);
CC3K game_proc(enabled_features, in.get(), out.get(), rng.get());
// while (game_proc.run() != game_status::terminated) {
// out->render();
// out->clear();
// }
while (1)
if (game_proc.run() == game_status::terminated)
break;
return RETURN_FINE;
}

View File

@ -38,7 +38,8 @@ game_map::game_map(character *player, RNG *rng, const feature enabled_features):
for (size_t i = 0; i < rooms_tile_list.size(); ++i)
rooms_tile_list[i].shrink_to_fit();
rooms_tile_list.shrink_to_fit();
while (rooms_tile_list[rooms_tile_list.size() - 1].size() == 0)
rooms_tile_list.pop_back();
int player_room = rng->rand_under(room_data.size());
player->set_pos(rng->get_rand_in_vector(rooms_tile_list[player_room]));
@ -92,6 +93,9 @@ game_map::game_map(character *player, const std::string &map_data,
rooms_tile_list[map_data[i] - '0'].push_back(remap_index(i));
}
while (rooms_tile_list[rooms_tile_list.size() - 1].size() == 0)
rooms_tile_list.pop_back();
for (int i = 0; i <= max_room_num; ++i)
room_data.push_back({0, 0, 0, 0});
@ -99,7 +103,6 @@ game_map::game_map(character *player, const std::string &map_data,
player->set_pos(rng->get_rand_in_vector(rooms_tile_list[player_room]));
gen_stairs(player_room, rng);
}
bool game_map::is_available(const position &pos) const {

161
src/menu.cc Normal file
View File

@ -0,0 +1,161 @@
#include "menu.h"
#include "constants.h"
const int NORMAL_CNT = 5;
const int EXTRA_CNT = 5;
const enum race RACES[EXTRA_CNT] = {
rshade, rdrow, rgoblin, rvampire, rtroll
};
const position RACE_POS[EXTRA_CNT] = {
{4, 9}, {4, 11}, {4, 13}, {4, 15}, {4, 17}
};
menu::menu(const feature enabled_features):
enabled_features{enabled_features},
cur{RACE_POS[0]} {}
const int UP_LIMIT = 9;
const int DOWN_LIMIT = 17;
const int LEFT_LIMIT = 4;
const int RIGHT_LIMIT = 4;
const int EXTRA_UP_LIMIT = 9;
const int EXTRA_DOWN_LIMIT = 17;
const int EXTRA_LEFT_LIMIT = 4;
const int EXTRA_RIGHT_LIMIT = 4;
const int X_INCRE = 37;
const int Y_INCRE = 2;
const char *NORMAL_SCREEN =
"+-----------------------------------------------------------------------------+\
| ____ ____ _____ _ __ |\
| / _\\/ _\\\\__ \\/ |/ / |\
| | / | / / || / |\
| | \\_ | \\_ _\\ || \\ |\
| \\____/\\____//____/\\_|\\_\\ |\
+-----------------------------------------------------------------------------+\
| Choose your race | |\
+-----------------------------------------------------------------------------+\
| Shade | |\
+-----------------------------------------------------------------------------+\
| Drow | |\
+-----------------------------------------------------------------------------+\
| Goblin | |\
+-----------------------------------------------------------------------------+\
| Vampire | |\
+-----------------------------------------------------------------------------+\
| Troll | |\
+-----------------------------------------------------------------------------+\
| |\
| |\
| |\
| |\
| |\
+-----------------------------------------------------------------------------+";
const char *EXTRA_SCREEN =
"+-----------------------------------------------------------------------------+\
| ____ ____ _____ _ __ |\
| / _\\/ _\\\\__ \\/ |/ / |\
| | / | / / || / |\
| | \\_ | \\_ _\\ || \\ |\
| \\____/\\____//____/\\_|\\_\\ |\
+-----------------------------------------------------------------------------+\
| Choose your race | |\
+-----------------------------------------------------------------------------+\
| Shade | |\
+-----------------------------------------------------------------------------+\
| Drow | |\
+-----------------------------------------------------------------------------+\
| Goblin | |\
+-----------------------------------------------------------------------------+\
| Vampire | |\
+-----------------------------------------------------------------------------+\
| Troll | |\
+-----------------------------------------------------------------------------+\
| |\
| |\
| |\
| |\
| |\
+-----------------------------------------------------------------------------+";
int menu::run(input *in) {
auto cmd = in->get_command();
int up_limit = UP_LIMIT;
int down_limit = DOWN_LIMIT;
int left_limit = LEFT_LIMIT;
int right_limit = RIGHT_LIMIT;
if (enabled_features & FEATURE_EXTRA_STUFF) {
up_limit = EXTRA_UP_LIMIT;
down_limit = EXTRA_DOWN_LIMIT;
left_limit = EXTRA_LEFT_LIMIT;
right_limit = EXTRA_RIGHT_LIMIT;
}
switch (cmd) {
case game_command::enter: {
if (enabled_features & FEATURE_EXTRA_STUFF) {
for (int i = 0; i < EXTRA_CNT; ++i)
if (cur == RACE_POS[i])
return RACES[i];
return -1;
} else {
for (int i = 0; i < NORMAL_CNT; ++i)
if (cur == RACE_POS[i])
return RACES[i];
return -1;
}
}
case move_north: {
if (cur.y != up_limit)
cur.y -= Y_INCRE;
break;
}
case move_south: {
if (cur.y != down_limit)
cur.y += Y_INCRE;
break;
}
case move_east: {
if (cur.x != left_limit)
cur.x -= X_INCRE;
break;
}
case move_west: {
if (cur.x != right_limit)
cur.x += X_INCRE;
break;
}
case game_command_terminate:
return -2;
default:
break;
}
return -1;
}
void menu::print(display *out) {
if (enabled_features & FEATURE_EXTRA_STUFF)
out->print_str({0, 0}, NORMAL_SCREEN);
else
out->print_str({0, 0}, EXTRA_SCREEN);
out->print_str(cur, "->", COLOR_PAIR(COLOR_BLUE));
}

21
src/menu.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __MENU_H__
#define __MENU_H__
#include "position.h"
#include "display.h"
#include "input.h"
typedef unsigned int feature;
enum race : int;
class menu final {
private:
const feature enabled_features;
position cur;
public:
menu(const feature enabled_features);
int run(input *in);
void print(display *out);
};
#endif

45
src/result.cc Normal file
View File

@ -0,0 +1,45 @@
#include "result.h"
const char *WIN_SCREEN =
"+-----------------------------------------------------------------------------+\
| |\
| |\
| |\
| |\
| ___________ |\
| '._==_==_=_.' |\
| .-\\: /-. |\
| | (|:. |) | |\
| '-|:. |-' |\
| \\::. / |\
| '::. .' |\
| ) ( |\
| _.' '._ |\
| `.......` |\
| |\
| |\
| |\
| |\
| |\
| |\
| |\
| |\
| |\
| > |\
| |\
| |\
| |\
| |\
+-----------------------------------------------------------------------------+";
const position &MSG_START = {11, 24};
void game_result::run(input *in) {
in->get_command();
}
void game_result::print(display *out) {
out->print_str({0, 0}, WIN_SCREEN);
out->print_str(MSG_START, msg, COLOR_PAIR(COLOR_YELLOW));
}

18
src/result.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __RESULT_H__
#define __RESULT_H__
#include <string>
#include "display.h"
#include "input.h"
enum game_status : int;
struct game_result final {
game_status status;
std::string msg;
void run(input *in);
void print(display *out);
};
#endif