added option to read level data from file
This commit is contained in:
@ -19,7 +19,8 @@ feature proc_args(int argc, char **argv,
|
||||
std::unique_ptr<cursor> &curse,
|
||||
std::unique_ptr<input> &in,
|
||||
std::unique_ptr<output> &out,
|
||||
std::unique_ptr<RNG> &rng) {
|
||||
std::unique_ptr<RNG> &rng,
|
||||
std::ifstream &data) {
|
||||
feature result = 0;
|
||||
std::string str;
|
||||
std::string fn_fin;
|
||||
@ -37,6 +38,9 @@ feature proc_args(int argc, char **argv,
|
||||
|
||||
result |= FEATURE_NCURSES;
|
||||
} else if (str == "-r") {
|
||||
if (result & FEATURE_READ_MAP)
|
||||
return FEATURE_CONFLICT | i;
|
||||
|
||||
result |= FEATURE_RAND_MAP;
|
||||
} else if (str == "-c") {
|
||||
result |= FEATURE_ENEMIES_CHASE;
|
||||
@ -56,6 +60,14 @@ feature proc_args(int argc, char **argv,
|
||||
result |= FEATURE_EXTRA_LEVELS;
|
||||
} else if (str == "-o") {
|
||||
result |= FEATURE_WALK_OVER;
|
||||
} else if (str == "-m") {
|
||||
if (result & FEATURE_RAND_MAP)
|
||||
return FEATURE_CONFLICT | i;
|
||||
|
||||
result |= FEATURE_READ_MAP;
|
||||
++i;
|
||||
str = argv[i];
|
||||
data.open(str);
|
||||
} else if (str == "-s") {
|
||||
++i;
|
||||
str = argv[i];
|
||||
@ -172,7 +184,7 @@ void panic_args(feature panic) {
|
||||
}
|
||||
|
||||
const char *ARGS_LIST = "\
|
||||
-n : Use ncurses for I/O\n\
|
||||
-n : Use ncurses for I/O\n\
|
||||
-r : Randomly generate maps\n\
|
||||
-c : Enemies chase the player (CAUTION: THEY CAN REALLY CHASE!!!)\n\
|
||||
-d : Enemies can go through doors (CAUTION: DO NOT ENABLE WITH CHASING!)\n\
|
||||
@ -182,6 +194,7 @@ const char *ARGS_LIST = "\
|
||||
-e : Enable extra potions and races\n\
|
||||
-E : Enable extra levels\n\
|
||||
-o : Allows characters to go over gold and potions\n\
|
||||
-m [file] : Reads map data from file. CANNOT BE USED WITH -r. DOES NOT PANIC!\n\
|
||||
-s [seed] : Sets initial seed to seed\n\
|
||||
-I [file] : Reads commands from file. CANNOT BE USED WITH -n.\n\
|
||||
-O [file] : Outputs to file. CANNOT BE USED WITH -n.\n\
|
||||
|
@ -12,8 +12,9 @@ typedef unsigned int feature;
|
||||
feature proc_args(int argc, char **argv,
|
||||
std::unique_ptr<cursor> &curse,
|
||||
std::unique_ptr<input> &in,
|
||||
std::unique_ptr<output> &out,
|
||||
std::unique_ptr<RNG> &rng);
|
||||
std::unique_ptr<output> &out,
|
||||
std::unique_ptr<RNG> &rng,
|
||||
std::ifstream &data);
|
||||
|
||||
void panic_args(feature panic);
|
||||
|
||||
|
155
src/cc3k.cc
155
src/cc3k.cc
@ -1,9 +1,11 @@
|
||||
#include "cc3k.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "constants.h"
|
||||
|
||||
CC3K::CC3K(const feature enabled_features,
|
||||
input *in, output *out, RNG *rng):
|
||||
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);
|
||||
@ -11,6 +13,9 @@ CC3K::CC3K(const feature enabled_features,
|
||||
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() {
|
||||
@ -28,7 +33,8 @@ game_status CC3K::run() {
|
||||
curr_game =
|
||||
std::make_unique<game>(static_cast<race>(tmp),
|
||||
enabled_features,
|
||||
in, out, rng);
|
||||
in, out, rng,
|
||||
lvls);
|
||||
out->clear();
|
||||
curr_game->print();
|
||||
out->render();
|
||||
@ -91,3 +97,148 @@ game_status CC3K::run() {
|
||||
|
||||
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 += '.';
|
||||
}
|
||||
|
12
src/cc3k.h
12
src/cc3k.h
@ -1,6 +1,7 @@
|
||||
#ifndef __CC3K_H__
|
||||
#define __CC3K_H__
|
||||
|
||||
#include <string>
|
||||
#include "input.h"
|
||||
#include "output.h"
|
||||
#include "game.h"
|
||||
@ -9,6 +10,7 @@
|
||||
|
||||
class CC3K final {
|
||||
private:
|
||||
static const int DEFAULT_LVL_CNT = 5;
|
||||
const feature enabled_features;
|
||||
input *in;
|
||||
output *out;
|
||||
@ -17,9 +19,17 @@ private:
|
||||
game_result gresult;
|
||||
std::unique_ptr<game> curr_game;
|
||||
std::unique_ptr<menu> curr_menu;
|
||||
|
||||
std::vector<level_data> lvls;
|
||||
void proc_lvls(std::ifstream &data);
|
||||
void push_tile(const char ch, const position &pos, level_data &lvl);
|
||||
void number_rooms(level_data &lvl);
|
||||
size_t remap_pos(const position &pos);
|
||||
void number_block(std::string &map_data, const position &pos, int num);
|
||||
bool in_bounds(const position &pos);
|
||||
public:
|
||||
CC3K(const feature enabled_features,
|
||||
input *in, output *out, RNG *rng);
|
||||
input *in, output *out, RNG *rng, std::ifstream &data);
|
||||
game_status run();
|
||||
};
|
||||
|
||||
|
@ -145,6 +145,7 @@ static const feature FEATURE_OUT_FILE = 1 << 9;
|
||||
static const feature FEATURE_EXTRA_STUFF = 1 << 10;
|
||||
static const feature FEATURE_EXTRA_LEVELS = 1 << 11;
|
||||
static const feature FEATURE_DOORS = 1 << 12;
|
||||
static const feature FEATURE_READ_MAP = 1 << 13;
|
||||
|
||||
static const feature FEATURE_LIST_COMMANDS = 1 << 23;
|
||||
static const feature FEATURE_LIST_RACES = 1 << 24;
|
||||
@ -170,4 +171,6 @@ static const size_t WHAT_ENEMY = 1 << 29;
|
||||
static const size_t WHAT_WALL = 1 << 30;
|
||||
static const size_t WHAT_SPACE = 1 << 31;
|
||||
|
||||
static const position POS_NIL = {0, 0};
|
||||
|
||||
#endif
|
||||
|
@ -55,8 +55,6 @@ enum race get_normal_race(RNG *rng) {
|
||||
std::unique_ptr<enemy_base> new_enemy(RNG *rng, const position &pos,
|
||||
const feature enabled_features,
|
||||
int which_room) {
|
||||
using std::make_unique;
|
||||
|
||||
enum race r;
|
||||
|
||||
if (enabled_features & FEATURE_EXTRA_STUFF)
|
||||
@ -64,7 +62,15 @@ std::unique_ptr<enemy_base> new_enemy(RNG *rng, const position &pos,
|
||||
else
|
||||
r = get_normal_race(rng);
|
||||
|
||||
switch (r) {
|
||||
return new_enemy(r, pos, enabled_features, which_room, rng);
|
||||
}
|
||||
|
||||
std::unique_ptr<enemy_base> new_enemy(const race &race, const position &pos,
|
||||
const feature enabled_features,
|
||||
int which_room, RNG *rng) {
|
||||
using std::make_unique;
|
||||
|
||||
switch (race) {
|
||||
case DWARF:
|
||||
return make_unique<dwarf>(rng, enabled_features,
|
||||
pos, which_room);
|
||||
@ -113,6 +119,10 @@ std::unique_ptr<enemy_base> new_enemy(RNG *rng, const position &pos,
|
||||
return make_unique<baby_dragon>(rng, enabled_features,
|
||||
pos, which_room);
|
||||
|
||||
case DRAGON:
|
||||
return make_unique<dragon>(rng, enabled_features,
|
||||
pos, which_room);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <memory>
|
||||
#include "enemy.h"
|
||||
|
||||
enum race : int;
|
||||
|
||||
std::unique_ptr<enemy_base> new_dragon(RNG *rng, const position &pos,
|
||||
const position &fallback,
|
||||
const feature enabled_features,
|
||||
@ -13,4 +15,8 @@ std::unique_ptr<enemy_base> new_enemy(RNG *rng, const position &pos,
|
||||
const feature enabled_features,
|
||||
int which_room);
|
||||
|
||||
std::unique_ptr<enemy_base> new_enemy(const race &race, const position &pos,
|
||||
const feature enabled_features,
|
||||
int which_room, RNG *rng);
|
||||
|
||||
#endif
|
||||
|
44
src/game.cc
44
src/game.cc
@ -7,8 +7,9 @@ game::game(const enum race starting_race,
|
||||
const feature enabled_features,
|
||||
input *new_in,
|
||||
output *new_out,
|
||||
RNG *new_rng):
|
||||
enabled_features{enabled_features},
|
||||
RNG *new_rng,
|
||||
const std::vector<level_data> &lvls):
|
||||
enabled_features{enabled_features}, lvls{lvls},
|
||||
in{new_in}, out{new_out}, rng{new_rng},
|
||||
curr_turn{0} {
|
||||
const position nil{0, 0};
|
||||
@ -33,12 +34,19 @@ game::game(const enum race starting_race,
|
||||
}
|
||||
|
||||
void game::new_level() {
|
||||
|
||||
if (enabled_features & FEATURE_RAND_MAP)
|
||||
levels.push_back(std::make_unique<level>(player.get(),
|
||||
rng, enabled_features));
|
||||
else if (enabled_features & FEATURE_READ_MAP)
|
||||
levels.push_back(std::make_unique<level>(lvls[curr_level],
|
||||
player.get(), rng, enabled_features));
|
||||
else
|
||||
levels.push_back(std::make_unique<level>(DEFAULT_MAP, player.get(),
|
||||
rng, enabled_features));
|
||||
levels.push_back(std::make_unique<level>(
|
||||
level_data{POS_NIL, {}, {}, {},
|
||||
DEFAULT_MAP, POS_NIL},
|
||||
player.get(), rng,
|
||||
enabled_features));
|
||||
}
|
||||
|
||||
enemy_list game::sort_enemies(const enemy_list &elist) {
|
||||
@ -115,11 +123,8 @@ game_result game::run() {
|
||||
|
||||
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!"};
|
||||
return {WON, "You won! Your final score is: " +
|
||||
str_score() + ". "};
|
||||
|
||||
player->start_turn();
|
||||
|
||||
@ -138,11 +143,9 @@ game_result game::run() {
|
||||
|
||||
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!"};
|
||||
return {ESCAPED,
|
||||
"You escaped the dungeon with a score of" +
|
||||
str_score() + ". Coward!"};
|
||||
|
||||
player->start_turn();
|
||||
|
||||
@ -185,10 +188,11 @@ game_result game::run() {
|
||||
|
||||
if (player->is_dead()) {
|
||||
if (killer == nullptr)
|
||||
return {DEAD, "You died: killed by your own stupidity!"};
|
||||
return {DEAD,
|
||||
"You died: killed by your own stupidity!"};
|
||||
|
||||
return {DEAD, std::string{"You died: killed by a(n) "} +
|
||||
killer->get_race_name()};
|
||||
killer->get_race_name() + ". "};
|
||||
}
|
||||
|
||||
return {IN_GAME, ""};
|
||||
@ -227,3 +231,11 @@ void game::print() {
|
||||
out->print_str(STATUS_DEF, "Def: " + std::to_string(player->get_DEF()));
|
||||
out->print_str(STATUS_ACTION, "Action: " + msg);
|
||||
}
|
||||
|
||||
std::string game::str_score() const {
|
||||
if (player->get_race() == SHADE)
|
||||
return std::to_string(static_cast<int>(player->get_gold() *
|
||||
SHADE_SCORE_MUL));
|
||||
|
||||
return std::to_string(player->get_gold());
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ private:
|
||||
static const size_t MIN_LEVEL_CNT = 30;
|
||||
static const size_t DEFAULT_MAX_LEVEL = 5;
|
||||
static const size_t MAX_MSG_LENGTH = 300;
|
||||
inline static const float SHADE_SCORE_MUL = 1.5f;
|
||||
|
||||
const feature enabled_features;
|
||||
const std::vector<level_data> &lvls;
|
||||
|
||||
input *in;
|
||||
output *out;
|
||||
@ -43,7 +45,8 @@ public:
|
||||
const feature enabled_features,
|
||||
input *new_in,
|
||||
output *new_out,
|
||||
RNG *new_rng);
|
||||
RNG *new_rng,
|
||||
const std::vector<level_data> &lvls);
|
||||
game_result run();
|
||||
size_t get_curr_level() const;
|
||||
size_t get_curr_turn() const;
|
||||
@ -53,6 +56,7 @@ private:
|
||||
void new_level();
|
||||
character *move_enemies();
|
||||
enemy_list sort_enemies(const enemy_list &elist);
|
||||
std::string str_score() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
62
src/level.cc
62
src/level.cc
@ -19,13 +19,13 @@ level::level(character *player, RNG *rng, const feature enabled_features):
|
||||
|
||||
gen_potions(rng, tiles);
|
||||
gen_gold(rng, tiles);
|
||||
gen_enemies(rng, tiles);
|
||||
gen_enemies({}, rng, tiles);
|
||||
}
|
||||
|
||||
level::level(const std::string &map_data, character *player, RNG *rng,
|
||||
level::level(const level_data &lvl, character *player, RNG *rng,
|
||||
const feature enabled_features):
|
||||
enabled_features{enabled_features},
|
||||
map{player, map_data, rng, enabled_features}, player{player} {
|
||||
map{lvl, player, rng, enabled_features}, player{player} {
|
||||
auto tiles = map.get_room_list();
|
||||
|
||||
for (size_t i = 0; i < tiles.size(); ++i)
|
||||
@ -38,23 +38,63 @@ level::level(const std::string &map_data, character *player, RNG *rng,
|
||||
for (size_t i = 0; i < tiles.size(); ++i)
|
||||
remove_from_list(tiles[i], map.get_up_stairs());
|
||||
|
||||
if (enabled_features & FEATURE_READ_MAP)
|
||||
fill(lvl, tiles, rng);
|
||||
|
||||
gen_potions(rng, tiles);
|
||||
gen_gold(rng, tiles);
|
||||
gen_enemies(rng, tiles);
|
||||
gen_enemies(lvl, rng, tiles);
|
||||
}
|
||||
|
||||
gold_list level::dragon_hoard() {
|
||||
void level::fill(const level_data &lvl, std::vector<position_list> &tiles,
|
||||
RNG *rng) {
|
||||
for (auto [type, pos] : lvl.enemies) {
|
||||
for (size_t i = 0; i < tiles.size(); ++i)
|
||||
remove_from_list(tiles[i], pos);
|
||||
|
||||
pelist.push_back(new_enemy(type, pos, enabled_features,
|
||||
map.which_room(pos), rng));
|
||||
elist.push_back(pelist[pelist.size() - 1].get());
|
||||
}
|
||||
|
||||
for (auto [type, pos] : lvl.potions) {
|
||||
for (size_t i = 0; i < tiles.size(); ++i)
|
||||
remove_from_list(tiles[i], pos);
|
||||
|
||||
pplist.push_back(new_potion(type, pos));
|
||||
plist.push_back(pplist[pplist.size() - 1].get());
|
||||
}
|
||||
|
||||
for (auto g : lvl.gold_piles) {
|
||||
for (size_t i = 0; i < tiles.size(); ++i)
|
||||
remove_from_list(tiles[i], g.get_pos());
|
||||
|
||||
glist.push_back(g);
|
||||
}
|
||||
}
|
||||
|
||||
gold_list level::dragon_hoard(const level_data &lvl) {
|
||||
gold_list result;
|
||||
|
||||
for (auto g : glist)
|
||||
if (g.get_amount() == GOLD_DRAGON)
|
||||
if (g.get_amount() == GOLD_DRAGON &&
|
||||
!is_in_glist(g, lvl.gold_piles))
|
||||
result.push_back(g);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void level::gen_enemies(RNG *rng, std::vector<position_list> &tiles) {
|
||||
auto dhoard = dragon_hoard();
|
||||
bool level::is_in_glist(gold &g, const gold_list &gl) {
|
||||
for (auto tmp : gl)
|
||||
if (tmp.get_pos() == g.get_pos())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void level::gen_enemies(const level_data &lvl, RNG *rng,
|
||||
std::vector<position_list> &tiles) {
|
||||
auto dhoard = dragon_hoard(lvl);
|
||||
int cnt = enabled_features & FEATURE_EXTRA_STUFF ?
|
||||
rng->rand_between(MIN_ENEMIE_CNT, MAX_ENEMIE_CNT + 1) :
|
||||
MIN_ENEMIE_CNT + dhoard.size();
|
||||
@ -87,7 +127,7 @@ void level::gen_enemies(RNG *rng, std::vector<position_list> &tiles) {
|
||||
}
|
||||
|
||||
|
||||
for (int i = dhoard.size(); i < cnt; ++i) {
|
||||
for (int i = elist.size(); i < cnt; ++i) {
|
||||
auto p = get_rand_pos(rng, tiles);
|
||||
pelist.push_back(new_enemy(rng, p, enabled_features,
|
||||
map.which_room(p)));
|
||||
@ -116,7 +156,7 @@ void level::add_gold(gold g) {
|
||||
void level::gen_gold(RNG *rng, std::vector<position_list> &tiles) {
|
||||
glist.reserve(GOLD_CNT);
|
||||
|
||||
for (int i = 0; i < GOLD_CNT; ++i)
|
||||
for (int i = glist.size(); i < GOLD_CNT; ++i)
|
||||
glist.push_back(gold{get_rand_pos(rng, tiles), rand_gold_pile(rng)});
|
||||
}
|
||||
|
||||
@ -135,7 +175,7 @@ void level::gen_potions(RNG *rng, std::vector<position_list> &tiles) {
|
||||
plist.reserve(cnt);
|
||||
pplist.reserve(cnt);
|
||||
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
for (int i = pplist.size(); i < cnt; ++i) {
|
||||
pplist.push_back(new_potion(static_cast<potion_type>
|
||||
(rng->rand_under(max_type)),
|
||||
get_rand_pos(rng, tiles)));
|
||||
|
23
src/level.h
23
src/level.h
@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include "output.h"
|
||||
#include "gold.h"
|
||||
#include "enemies.h"
|
||||
@ -11,6 +12,17 @@
|
||||
#include "potions.h"
|
||||
#include "map.h"
|
||||
|
||||
enum race : int;
|
||||
|
||||
struct level_data {
|
||||
position pc_pos;
|
||||
std::vector<std::pair<race, position>> enemies;
|
||||
std::vector<std::pair<potion_type, position>> potions;
|
||||
gold_list gold_piles;
|
||||
std::string map_data;
|
||||
position stairs;
|
||||
};
|
||||
|
||||
class level {
|
||||
private:
|
||||
static const int MAX_POTION_CNT = 15;
|
||||
@ -30,8 +42,8 @@ private:
|
||||
public:
|
||||
// randomly generate a map
|
||||
level(character *player, RNG *rng, const feature enabled_features);
|
||||
// read map from a string
|
||||
level(const std::string &map_data, character *player, RNG *rng,
|
||||
// read map from data
|
||||
level(const level_data &lvl_data, character *player, RNG *rng,
|
||||
const feature enabled_features);
|
||||
void print(output *out) const;
|
||||
|
||||
@ -59,10 +71,13 @@ private:
|
||||
// every gen will delete the positions in tiles
|
||||
void gen_potions(RNG *rng, std::vector<position_list> &tiles);
|
||||
void gen_gold(RNG *rng, std::vector<position_list> &tiles);
|
||||
void gen_enemies(RNG *rng, std::vector<position_list> &tiles);
|
||||
void gen_enemies(const level_data &lvl, RNG *rng,
|
||||
std::vector<position_list> &tiles);
|
||||
|
||||
position get_rand_pos(RNG *rng, std::vector<position_list> &tiles);
|
||||
gold_list dragon_hoard();
|
||||
gold_list dragon_hoard(const level_data &lvl);
|
||||
bool is_in_glist(gold &g, const gold_list &gl);
|
||||
void fill(const level_data &lvl, std::vector<position_list> &tiles, RNG *rng);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "cc3k.h"
|
||||
#include "arguments.h"
|
||||
@ -9,8 +10,9 @@ int main(int argc, char **argv) {
|
||||
std::unique_ptr<input> in;
|
||||
std::unique_ptr<output> out;
|
||||
std::unique_ptr<RNG> rng;
|
||||
std::ifstream data;
|
||||
|
||||
feature enabled_features = proc_args(argc, argv, curse, in, out, rng);
|
||||
feature enabled_features = proc_args(argc, argv, curse, in, out, rng, data);
|
||||
|
||||
if (enabled_features &
|
||||
(FEATURE_PANIC | FEATURE_PANIC_FILE |
|
||||
@ -25,7 +27,7 @@ int main(int argc, char **argv) {
|
||||
return RETURN_FINE;
|
||||
}
|
||||
|
||||
CC3K game_proc(enabled_features, in.get(), out.get(), rng.get());
|
||||
CC3K game_proc(enabled_features, in.get(), out.get(), rng.get(), data);
|
||||
|
||||
while (1)
|
||||
if (game_proc.run() == game_status::TERMINATED)
|
||||
|
62
src/map.cc
62
src/map.cc
@ -4,6 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "constants.h"
|
||||
#include "level.h"
|
||||
|
||||
game_map::game_map(character *player, RNG *rng, const feature enabled_features):
|
||||
enabled_features{enabled_features} {
|
||||
@ -44,10 +45,18 @@ game_map::game_map(character *player, RNG *rng, const feature enabled_features):
|
||||
int player_room = rng->rand_under(room_data.size());
|
||||
player->set_pos(rng->get_rand_in_vector(rooms_tile_list[player_room]));
|
||||
|
||||
gen_stairs(player_room, rng);
|
||||
gen_stairs({}, player_room, rng);
|
||||
}
|
||||
|
||||
void game_map::gen_stairs(int player_room, RNG *rng) {
|
||||
void game_map::gen_stairs(const level_data &lvl, int player_room,
|
||||
RNG *rng) {
|
||||
if (enabled_features & FEATURE_READ_MAP) {
|
||||
int stairs_room = rng->exclude_middle(0, room_data.size(),
|
||||
player_room);
|
||||
down_stairs = get_available_spot(lvl, stairs_room, rng);
|
||||
return;
|
||||
}
|
||||
|
||||
down_stairs = rng->get_rand_in_vector(rooms_tile_list[
|
||||
rng->exclude_middle(0, room_data.size(), player_room)]);
|
||||
|
||||
@ -69,7 +78,7 @@ position game_map::random_size(int min_width, int min_height,
|
||||
rng->rand_between(min_height, max_height + 1)};
|
||||
}
|
||||
|
||||
game_map::game_map(character *player, const std::string &map_data,
|
||||
game_map::game_map(const level_data &lvl, character *player,
|
||||
RNG *rng, const feature enabled_features):
|
||||
enabled_features{enabled_features} {
|
||||
int map_size = MAP_HEIGHT * MAP_WIDTH;
|
||||
@ -82,15 +91,17 @@ game_map::game_map(character *player, const std::string &map_data,
|
||||
int max_room_num = 0;
|
||||
|
||||
for (int i = 0; i < map_size; ++i) {
|
||||
if (map_data[i] >= '0' && map_data[i] <= '9') {
|
||||
map.push_back(map_data[i] - '0');
|
||||
max_room_num = std::max(max_room_num, map_data[i] - '0');
|
||||
if (lvl.map_data[i] >= '0' && lvl.map_data[i] <= '9') {
|
||||
map.push_back(lvl.map_data[i] - '0');
|
||||
max_room_num = std::max(max_room_num,
|
||||
lvl.map_data[i] - '0');
|
||||
} else {
|
||||
map.push_back(map_data[i]);
|
||||
map.push_back(lvl.map_data[i]);
|
||||
}
|
||||
|
||||
if (map_data[i] >= '0' && map_data[i] <= '9')
|
||||
rooms_tile_list[map_data[i] - '0'].push_back(remap_index(i));
|
||||
if (lvl.map_data[i] >= '0' && lvl.map_data[i] <= '9')
|
||||
rooms_tile_list[lvl.map_data[i] - '0'].push_back(
|
||||
remap_index(i));
|
||||
}
|
||||
|
||||
while (rooms_tile_list[rooms_tile_list.size() - 1].size() == 0)
|
||||
@ -98,11 +109,38 @@ game_map::game_map(character *player, const std::string &map_data,
|
||||
|
||||
for (int i = 0; i <= max_room_num; ++i)
|
||||
room_data.push_back({0, 0, 0, 0});
|
||||
int player_room;
|
||||
|
||||
int player_room = rng->rand_under(room_data.size());
|
||||
player->set_pos(rng->get_rand_in_vector(rooms_tile_list[player_room]));
|
||||
if (lvl.pc_pos != POS_NIL) {
|
||||
player->set_pos(lvl.pc_pos);
|
||||
player_room = which_room(lvl.pc_pos);
|
||||
} else {
|
||||
player_room = rng->rand_under(room_data.size());
|
||||
player->set_pos(get_available_spot(lvl, player_room, rng));
|
||||
}
|
||||
|
||||
gen_stairs(player_room, rng);
|
||||
if (lvl.stairs == POS_NIL) {
|
||||
gen_stairs(lvl, player_room, rng);
|
||||
} else {
|
||||
down_stairs = lvl.stairs;
|
||||
map[remap_position(down_stairs)] = '\\';
|
||||
}
|
||||
}
|
||||
|
||||
position game_map::get_available_spot(const level_data &lvl, int room,
|
||||
RNG *rng) {
|
||||
position_list spots = rooms_tile_list[room];
|
||||
|
||||
for (auto [type, pos] : lvl.enemies)
|
||||
remove_from_list(spots, pos);
|
||||
|
||||
for (auto [type, pos] : lvl.potions)
|
||||
remove_from_list(spots, pos);
|
||||
|
||||
for (auto g : lvl.gold_piles)
|
||||
remove_from_list(spots, g.get_pos());
|
||||
|
||||
return rng->get_rand_in_vector(spots);
|
||||
}
|
||||
|
||||
bool game_map::is_available(const position &pos) const {
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "player.h"
|
||||
#include "characters.h"
|
||||
|
||||
struct level_data;
|
||||
|
||||
class game_map final {
|
||||
private:
|
||||
static const int MAX_ROOM_CNT = 20;
|
||||
@ -54,7 +56,7 @@ public:
|
||||
// randomly generate a map
|
||||
game_map(character *player, RNG *rng, const feature enabled_features);
|
||||
// read map from a string
|
||||
game_map(character *player, const std::string &map_data, RNG *rng,
|
||||
game_map(const level_data &lvl, character *player, RNG *rng,
|
||||
const feature enabled_features);
|
||||
|
||||
bool is_available(const position &pos) const;
|
||||
@ -74,6 +76,7 @@ public:
|
||||
|
||||
int get_room_cnt() const;
|
||||
private:
|
||||
position get_available_spot(const level_data &lvl, int room, RNG *rng);
|
||||
std::vector<room> room_data;
|
||||
position remap_index(const int idx) const;
|
||||
int remap_position(const position &pos) const;
|
||||
@ -107,7 +110,7 @@ private:
|
||||
room hit_room(const position &a);
|
||||
bool hit_room(const position &a, const room &r);
|
||||
|
||||
void gen_stairs(int player_room, RNG *rng);
|
||||
void gen_stairs(const level_data &lvl, int player_room, RNG *rng);
|
||||
room get_room(std::size_t idx) const;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user