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