This commit is contained in:
a25liang
2024-07-12 16:41:42 -04:00
parent e7865b0c57
commit 50f058e7ea
57 changed files with 853 additions and 871 deletions

View File

@ -19,157 +19,157 @@ feature proc_args(int argc, char **argv,
std::unique_ptr<display> &out, std::unique_ptr<display> &out,
std::unique_ptr<logger> &log, std::unique_ptr<logger> &log,
std::unique_ptr<RNG> &rng) { std::unique_ptr<RNG> &rng) {
feature result = 0; feature result = 0;
std::string str; std::string str;
std::string fn_fin; std::string fn_fin;
std::string fn_fout; std::string fn_fout;
std::string fn_lout; std::string fn_lout;
std::string fn_save; std::string fn_save;
std::string seed; std::string seed;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
str = argv[i]; str = argv[i];
if (str == "-n") { if (str == "-n") {
if (result & (FEATURE_IN_FILE | FEATURE_OUT_FILE)) if (result & (FEATURE_IN_FILE | FEATURE_OUT_FILE))
return FEATURE_CONFLICT | i; return FEATURE_CONFLICT | i;
result |= FEATURE_NCURSES; result |= FEATURE_NCURSES;
} else if (str == "-r") { } else if (str == "-r") {
result |= FEATURE_RAND_MAP; result |= FEATURE_RAND_MAP;
} else if (str == "-m") { } else if (str == "-m") {
result |= FEATURE_MENU; result |= FEATURE_MENU;
} else if (str == "-c") { } else if (str == "-c") {
result |= FEATURE_ENEMIES_CHASE; result |= FEATURE_ENEMIES_CHASE;
} else if (str == "-i") { } else if (str == "-i") {
result |= FEATURE_INVENTORY; result |= FEATURE_INVENTORY;
} else if (str == "-t") { } else if (str == "-t") {
result |= FEATURE_THROW; result |= FEATURE_THROW;
} else if (str == "-R") { } else if (str == "-R") {
result |= FEATURE_REVISIT; result |= FEATURE_REVISIT;
} else if (str == "-s") { } else if (str == "-s") {
++i; ++i;
str = argv[i]; str = argv[i];
if (!seed.empty() && seed != str) if (!seed.empty() && seed != str)
return FEATURE_CONFLICT | i; return FEATURE_CONFLICT | i;
seed = str; seed = str;
result |= FEATURE_SEED; result |= FEATURE_SEED;
} else if (str == "-L") { } else if (str == "-L") {
++i; ++i;
str = argv[i]; str = argv[i];
if (!fn_lout.empty() && fn_lout != str) if (!fn_lout.empty() && fn_lout != str)
return FEATURE_CONFLICT | i; return FEATURE_CONFLICT | i;
fn_lout = str; fn_lout = str;
result |= FEATURE_LOG; result |= FEATURE_LOG;
} else if (str == "-I") { } else if (str == "-I") {
++i; ++i;
str = argv[i]; str = argv[i];
if (!fn_fin.empty() && fn_fin != str) if (!fn_fin.empty() && fn_fin != str)
return FEATURE_CONFLICT | i; return FEATURE_CONFLICT | i;
fn_fin = str; fn_fin = str;
result |= FEATURE_IN_FILE; result |= FEATURE_IN_FILE;
} else if (str == "-O") { } else if (str == "-O") {
++i; ++i;
str = argv[i]; str = argv[i];
if (!fn_fout.empty() && fn_fout != str) if (!fn_fout.empty() && fn_fout != str)
return FEATURE_CONFLICT | i; return FEATURE_CONFLICT | i;
fn_fout = str; fn_fout = str;
result |= FEATURE_OUT_FILE; result |= FEATURE_OUT_FILE;
} else if (str == "-h" || str == "--help") { } else if (str == "-h" || str == "--help") {
return FEATURE_LIST_ARGS; return FEATURE_LIST_ARGS;
} else { } else {
return FEATURE_PANIC | i; return FEATURE_PANIC | i;
}
} }
}
if (result & FEATURE_IN_FILE) { if (result & FEATURE_IN_FILE) {
std::ifstream fin(fn_fin); std::ifstream fin(fn_fin);
if (!fin.good()) if (!fin.good())
return FEATURE_PANIC_FILE | FEATURE_IN_FILE; return FEATURE_PANIC_FILE | FEATURE_IN_FILE;
in = std::make_unique<file_input>(std::move(fin)); in = std::make_unique<file_input>(std::move(fin));
} else if (!(result & FEATURE_NCURSES)) } else if (!(result & FEATURE_NCURSES))
in = std::make_unique<console_input>(std::cin); in = std::make_unique<console_input>(std::cin);
if (result & FEATURE_OUT_FILE) { if (result & FEATURE_OUT_FILE) {
std::ofstream fout(fn_fout); std::ofstream fout(fn_fout);
if (!fout.good()) if (!fout.good())
return FEATURE_PANIC_FILE | FEATURE_OUT_FILE; return FEATURE_PANIC_FILE | FEATURE_OUT_FILE;
out = std::make_unique<file_output>(std::move(fout)); out = std::make_unique<file_output>(std::move(fout));
} else if (!(result & FEATURE_NCURSES)) } else if (!(result & FEATURE_NCURSES))
out = std::make_unique<console_output>(std::cout); out = std::make_unique<console_output>(std::cout);
if (result & FEATURE_LOG) { if (result & FEATURE_LOG) {
std::ofstream lout(fn_lout); std::ofstream lout(fn_lout);
if (!lout.good()) if (!lout.good())
return FEATURE_PANIC_FILE | FEATURE_LOG; return FEATURE_PANIC_FILE | FEATURE_LOG;
log = std::make_unique<logger>(std::move(lout)); log = std::make_unique<logger>(std::move(lout));
} }
if (result & FEATURE_NCURSES) { if (result & FEATURE_NCURSES) {
curse = std::make_unique<cursor>(); curse = std::make_unique<cursor>();
in = std::make_unique<curses_input>(*curse); in = std::make_unique<curses_input>(*curse);
out = std::make_unique<curses_output>(*curse); out = std::make_unique<curses_output>(*curse);
} }
if (result & FEATURE_SEED) { if (result & FEATURE_SEED) {
std::istringstream iss {seed}; std::istringstream iss {seed};
unsigned int tmp; unsigned int tmp;
iss >> tmp; iss >> tmp;
if (!iss.good()) if (!iss.good())
return FEATURE_PANIC_SEED; return FEATURE_PANIC_SEED;
rng = std::make_unique<RNG>(tmp); rng = std::make_unique<RNG>(tmp);
} }
return result; return result;
} }
// IMPORTANT: This is meant for already panicking // IMPORTANT: This is meant for already panicking
void panic_args(feature panic) { void panic_args(feature panic) {
using namespace std; using namespace std;
if (panic & FEATURE_PANIC) if (panic & FEATURE_PANIC)
cerr << "Invalid argument No. " << (panic ^ FEATURE_PANIC) cerr << "Invalid argument No. " << (panic ^ FEATURE_PANIC)
<< " !" << endl; << " !" << endl;
else if (panic & FEATURE_CONFLICT) else if (panic & FEATURE_CONFLICT)
cerr << "Argument No. " << (panic ^ FEATURE_CONFLICT) cerr << "Argument No. " << (panic ^ FEATURE_CONFLICT)
<< " conflicts with a previous argument!" << endl; << " conflicts with a previous argument!" << endl;
else if (panic & FEATURE_PANIC_FILE) { else if (panic & FEATURE_PANIC_FILE) {
switch (panic ^ FEATURE_PANIC_FILE) { switch (panic ^ FEATURE_PANIC_FILE) {
case FEATURE_IN_FILE: case FEATURE_IN_FILE:
cerr << "Cannot open specified input file!" << endl; cerr << "Cannot open specified input file!" << endl;
break; break;
case FEATURE_OUT_FILE: case FEATURE_OUT_FILE:
cerr << "Cannot open specified output file!" << endl; cerr << "Cannot open specified output file!" << endl;
break; break;
case FEATURE_LOG: case FEATURE_LOG:
cerr << "Cannot open specified log file!" << endl; cerr << "Cannot open specified log file!" << endl;
break; break;
default: default:
cerr << "Something must have went really, really, wrong..." cerr << "Something must have went really, really, wrong..."
<< endl; << endl;
} }
} else if (panic & FEATURE_PANIC_SEED) { } else if (panic & FEATURE_PANIC_SEED) {
cerr << "Invalid seed" << endl; cerr << "Invalid seed" << endl;
} else } else
cerr << "Something must have went really, really, wrong..." cerr << "Something must have went really, really, wrong..."
<< endl; << endl;
} }

View File

@ -7,7 +7,6 @@
#include "input.h" #include "input.h"
#include "rng.h" #include "rng.h"
#include "constants.h" #include "constants.h"
/* Arguments /* Arguments

View File

@ -6,23 +6,20 @@ const int BOOST_ATK = 5;
const int BOOST_ATK_DROW = 7; const int BOOST_ATK_DROW = 7;
boost_atk::boost_atk(): boost_atk::boost_atk():
potion{potion_type::boost_atk, -1} {} potion{potion_type::boost_atk, -1} {}
void boost_atk::apply(enum race &race, int &HP, int &ATK, int &DEF, void boost_atk::apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) { float &base_hit_rate) {
if (remaining_duration > 0) { if (remaining_duration > 0) {
if (race == rdrow) if (race == rdrow)
ATK += BOOST_ATK_DROW; ATK += BOOST_ATK_DROW;
else else
ATK += BOOST_ATK; ATK += BOOST_ATK;
--remaining_duration; --remaining_duration;
} }
} }
int boost_atk::get_priority() const { int boost_atk::get_priority() const {
return CALC_ADD_BASE; return CALC_ADD_BASE;
} }

View File

@ -5,11 +5,10 @@
class boost_atk final: public potion { class boost_atk final: public potion {
public: public:
boost_atk(); boost_atk();
void apply(enum race &race, int &HP, int &ATK, int &DEF, void apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) override; float &base_hit_rate) override;
int get_priority() const override; int get_priority() const override;
}; };
#endif #endif

View File

@ -5,22 +5,21 @@
const int BOOST_DEF = 5; const int BOOST_DEF = 5;
const int BOOST_DEF_DROW = 7; const int BOOST_DEF_DROW = 7;
boost_def::boost_def(): boost_def::boost_def():
potion{potion_type::boost_def, -1} {} potion{potion_type::boost_def, -1} {}
void boost_def::apply(enum race &race, int &HP, int &ATK, int &DEF, void boost_def::apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) { float &base_hit_rate) {
if (remaining_duration > 0) { if (remaining_duration > 0) {
if (race == rdrow) if (race == rdrow)
DEF += BOOST_DEF_DROW; DEF += BOOST_DEF_DROW;
else else
DEF += BOOST_DEF; DEF += BOOST_DEF;
--remaining_duration; --remaining_duration;
} }
} }
int boost_def::get_priority() const { int boost_def::get_priority() const {
return CALC_ADD_BASE; return CALC_ADD_BASE;
} }

View File

@ -5,10 +5,10 @@
class boost_def final: public potion { class boost_def final: public potion {
public: public:
boost_def(); boost_def();
void apply(enum race &race, int &HP, int &ATK, int &DEF, void apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) override; float &base_hit_rate) override;
int get_priority() const override; int get_priority() const override;
}; };
#endif #endif

View File

@ -3,156 +3,154 @@
#include <algorithm> #include <algorithm>
character::character(RNG &rng, const enum race &nrace): character::character(RNG &rng, const enum race &nrace):
rng{rng}, rng{rng},
race{nrace}, HP{STARTING_HP[race]}, race{nrace}, HP{STARTING_HP[race]},
ATK{STARTING_ATK[race]}, DEF{STARTING_DEF[race]} {} ATK{STARTING_ATK[race]}, DEF{STARTING_DEF[race]} {}
enum race character::get_race() const { enum race character::get_race() const {
return race; return race;
} }
position character::get_position() const { position character::get_position() const {
return pos; return pos;
} }
int character::get_HP() const { int character::get_HP() const {
return HP; return HP;
} }
int character::get_ATK() const { int character::get_ATK() const {
return ATK; return ATK;
} }
int character::get_DEF() const { int character::get_DEF() const {
return DEF; return DEF;
} }
int character::get_gold() const { int character::get_gold() const {
return gold; return gold;
} }
float character::get_hitrate() const { float character::get_hitrate() const {
return base_hit_rate; return base_hit_rate;
} }
bool character::is_hostile() const { bool character::is_hostile() const {
return hostile; return hostile;
} }
void character::set_position(const position &npos) { void character::set_position(const position &npos) {
pos = npos; pos = npos;
} }
void character::set_HP(const int nHP) { void character::set_HP(const int nHP) {
HP = nHP; HP = nHP;
} }
void character::set_ATK(const int nATK) { void character::set_ATK(const int nATK) {
ATK = nATK; ATK = nATK;
} }
void character::set_DEF(const int nDEF) { void character::set_DEF(const int nDEF) {
DEF = nDEF; DEF = nDEF;
} }
void character::set_gold(const int ngold) { void character::set_gold(const int ngold) {
gold = ngold; gold = ngold;
} }
void character::set_hitrate(const float nhitrate) { void character::set_hitrate(const float nhitrate) {
base_hit_rate = nhitrate; base_hit_rate = nhitrate;
} }
void character::set_hostile(const bool is_hostile) { void character::set_hostile(const bool is_hostile) {
hostile = is_hostile; hostile = is_hostile;
} }
void character::apply_buff(const stat_name statn, const int amount) { void character::apply_buff(const stat_name statn, const int amount) {
// TODO: add checks for bounds // TODO: add checks for bounds
switch (statn) { switch (statn) {
case stat_name::HP: case stat_name::HP:
HP += amount; HP += amount;
break; break;
case stat_name::ATK: case stat_name::ATK:
ATK += amount; ATK += amount;
break; break;
case stat_name::DEF: case stat_name::DEF:
DEF += amount; DEF += amount;
break; break;
case stat_name::hostile: { case stat_name::hostile: {
if (amount > 0) if (amount > 0)
hostile = true; hostile = true;
else else
hostile = false; hostile = false;
break; break;
} }
} }
} }
direction_list character::moveable(const position_list &available_positions) direction_list character::moveable(const position_list &available_positions)
const { const {
direction_list result; direction_list result;
for (int i = 0; i < DIRECTION_CNT; ++i) for (int i = 0; i < DIRECTION_CNT; ++i)
if (find(available_positions, pos + MOVE[i]) if (find(available_positions, pos + MOVE[i])
!= available_positions.size()) != available_positions.size())
result.push_back((direction)i); result.push_back((direction)i);
return result; return result;
} }
result character::apply(direction &dir, const potion_list &potions) { result character::apply(direction &dir, const potion_list &potions) {
// TODO: implement this after implementing potions // TODO: implement this after implementing potions
return result::fine; return result::fine;
} }
position_list remove_from_list(const position_list &sorted_positions, position_list remove_from_list(const position_list &sorted_positions,
position_list excluded) { position_list excluded) {
std::sort(excluded.begin(), excluded.end()); std::sort(excluded.begin(), excluded.end());
position_list result{sorted_positions.size() - excluded.size()}; position_list result{sorted_positions.size() - excluded.size()};
auto exc = excluded.begin(); auto exc = excluded.begin();
for (auto src : sorted_positions) { for (auto src : sorted_positions) {
if (exc != excluded.end() && src == *exc) if (exc != excluded.end() && src == *exc)
++exc; ++exc;
else else
result.push_back(src); result.push_back(src);
} }
return result; return result;
} }
// IMPORTANT: remember to check if player is on the stairs // IMPORTANT: remember to check if player is on the stairs
result character::move(const direction dir, result character::move(const direction dir,
const position_list &available_positions) { const position_list &available_positions) {
if (find(available_positions, pos + MOVE[dir]) if (find(available_positions, pos + MOVE[dir])
!= available_positions.size()) { != available_positions.size()) {
pos += MOVE[dir]; pos += MOVE[dir];
return result::moved; return result::moved;
} }
return result::fine; return result::fine;
} }
result character::move_or_attack(const direction dir, result character::move_or_attack(const direction dir,
const position_list &available_positions, const position_list &available_positions,
character_list &chlist) { character_list &chlist) {
auto res = this->move(dir, available_positions); auto res = this->move(dir, available_positions);
if (res != result::fine) if (res != result::fine)
return res; return res;
return this->attack(dir, chlist); return this->attack(dir, chlist);
} }
int calc_dmg(const int ATK, const int DEF) { int calc_dmg(const int ATK, const int DEF) {
return ceil((100 / (100 + DEF)) * ATK); return ceil((100 / (100 + DEF)) * ATK);
} }

View File

@ -25,71 +25,70 @@ typedef std::vector<character> character_list;
class character { class character {
public: public:
character(RNG &rng, const race &nrace); // fills out the starting stats character(RNG &rng, const race &nrace); // fills out the starting stats
// usually I wouldn't do this but considering that the map has // usually I wouldn't do this but considering that the map has
// a super small size an O(n) solution is acceptable // a super small size an O(n) solution is acceptable
// IMPORTANT: available_positions do NOT have characters in them // IMPORTANT: available_positions do NOT have characters in them
direction_list moveable(const position_list &available_positions) const; direction_list moveable(const position_list &available_positions) const;
virtual result move(const direction dir, virtual result move(const direction dir,
const position_list &available_positions); const position_list &available_positions);
virtual result attack(const direction dir, virtual result attack(const direction dir,
character_list &chlist) = 0; character_list &chlist) = 0;
virtual result move_or_attack(const direction dir, virtual result move_or_attack(const direction dir,
const position_list &available_positions, const position_list &available_positions,
character_list &chlist); character_list &chlist);
virtual result apply(direction &dir, virtual result apply(direction &dir,
const potion_list &potions); const potion_list &potions);
virtual result get_hit(const enum race &race, const int atk, virtual result get_hit(const enum race &race, const int atk,
const float hitrate) = 0; const float hitrate) = 0;
enum race get_race() const; enum race get_race() const;
position get_position() const; position get_position() const;
int get_HP() const; int get_HP() const;
int get_ATK() const; int get_ATK() const;
int get_DEF() const; int get_DEF() const;
int get_gold() const; int get_gold() const;
float get_hitrate() const; float get_hitrate() const;
bool is_hostile() const; bool is_hostile() const;
void set_position(const position &npos); void set_position(const position &npos);
void set_HP(const int nHP); void set_HP(const int nHP);
void set_ATK(const int nATK); void set_ATK(const int nATK);
void set_DEF(const int nDEF); void set_DEF(const int nDEF);
void set_gold(const int ngold); void set_gold(const int ngold);
void set_hitrate(const float nhitrate); void set_hitrate(const float nhitrate);
void set_hostile(const bool is_hostile); void set_hostile(const bool is_hostile);
// if stat is hostile, positive to set it to hostile, // if stat is hostile, positive to set it to hostile,
// negative to set it to peaceful // negative to set it to peaceful
void apply_buff(const stat_name statn, const int amount); void apply_buff(const stat_name statn, const int amount);
// void apply_buff(const stat_name statn, const float mul); // void apply_buff(const stat_name statn, const float mul);
// reserved for later // reserved for later
protected: protected:
RNG &rng; RNG &rng;
const enum race race; const enum race race;
int HP; int HP;
// IMPORTANT: keep track of ATK and DEF in game at turn time // IMPORTANT: keep track of ATK and DEF in game at turn time
int ATK; int ATK;
int DEF; int DEF;
position pos; position pos;
int gold; // characters spawn with gold int gold; // characters spawn with gold
potion_list potions;// inventory inventory; // Reserved potion_list potions;// inventory inventory; // Reserved
float base_hit_rate; // requires: between [0,1] float base_hit_rate; // requires: between [0,1]
bool hostile; bool hostile;
}; };
// requires: all elements of excluded are in sorted_positions // requires: all elements of excluded are in sorted_positions
position_list remove_from_list(const position_list &sorted_positions, position_list remove_from_list(const position_list &sorted_positions,
position_list excluded); position_list excluded);
int calc_dmg(const int ATK, const int DEF); int calc_dmg(const int ATK, const int DEF);
#endif #endif

View File

@ -6,11 +6,11 @@
class console_input final : public input { class console_input final : public input {
private: private:
std::istream &in; std::istream &in;
public: public:
// This is for cin // This is for cin
console_input(std::istream &cin); console_input(std::istream &cin);
game_command get_command() override; game_command get_command() override;
}; };
#endif #endif

View File

@ -4,7 +4,6 @@
#include <utility> #include <utility>
#include <ncurses.h> #include <ncurses.h>
console_output::console_output(std::ostream &cout): out{cout} {} console_output::console_output(std::ostream &cout): out{cout} {}
/* Attributes /* Attributes
@ -30,70 +29,70 @@ console_output::console_output(std::ostream &cout): out{cout} {}
*/ */
std::string console_output::get_code(const int attrs) { std::string console_output::get_code(const int attrs) {
if (attrs < 255) if (attrs < 255)
return "\033[0m"; return "\033[0m";
std::string result = "\033[0m\033["; std::string result = "\033[0m\033[";
if (attrs & A_BOLD) if (attrs & A_BOLD)
result += "1;"; result += "1;";
if (attrs & A_UNDERLINE) if (attrs & A_UNDERLINE)
result += "4;"; result += "4;";
if (attrs & A_STANDOUT) if (attrs & A_STANDOUT)
result += "7;"; result += "7;";
if ((attrs & COLOR_PAIR(COLOR_WHITE)) == COLOR_PAIR(COLOR_WHITE)) if ((attrs & COLOR_PAIR(COLOR_WHITE)) == COLOR_PAIR(COLOR_WHITE))
result += "37;"; result += "37;";
else if ((attrs & COLOR_PAIR(COLOR_CYAN)) == COLOR_PAIR(COLOR_CYAN)) else if ((attrs & COLOR_PAIR(COLOR_CYAN)) == COLOR_PAIR(COLOR_CYAN))
result += "36;"; result += "36;";
else if ((attrs & COLOR_PAIR(COLOR_MAGENTA)) == COLOR_PAIR(COLOR_MAGENTA)) else if ((attrs & COLOR_PAIR(COLOR_MAGENTA)) == COLOR_PAIR(COLOR_MAGENTA))
result += "35;"; result += "35;";
else if ((attrs & COLOR_PAIR(COLOR_BLUE)) == COLOR_PAIR(COLOR_BLUE)) else if ((attrs & COLOR_PAIR(COLOR_BLUE)) == COLOR_PAIR(COLOR_BLUE))
result += "34;"; result += "34;";
else if ((attrs & COLOR_PAIR(COLOR_YELLOW)) == COLOR_PAIR(COLOR_YELLOW)) else if ((attrs & COLOR_PAIR(COLOR_YELLOW)) == COLOR_PAIR(COLOR_YELLOW))
result += "33;"; result += "33;";
else if ((attrs & COLOR_PAIR(COLOR_RED)) == COLOR_PAIR(COLOR_RED)) else if ((attrs & COLOR_PAIR(COLOR_RED)) == COLOR_PAIR(COLOR_RED))
result += "31;"; result += "31;";
else if ((attrs & COLOR_PAIR(COLOR_GREEN)) == COLOR_PAIR(COLOR_GREEN)) else if ((attrs & COLOR_PAIR(COLOR_GREEN)) == COLOR_PAIR(COLOR_GREEN))
result += "32;"; result += "32;";
else if ((attrs & COLOR_PAIR(COLOR_BLACK_ON_WHITE)) == COLOR_BLACK_ON_WHITE) else if ((attrs & COLOR_PAIR(COLOR_BLACK_ON_WHITE)) == COLOR_BLACK_ON_WHITE)
result += "30;47;"; result += "30;47;";
result[result.length() - 1] = 'm'; result[result.length() - 1] = 'm';
return result; return result;
} }
void console_output::render() { void console_output::render() {
out << "\x1B[2J\x1B[H"; out << "\x1B[2J\x1B[H";
for (std::size_t idx = 0; idx < contents.size(); ++idx) { for (std::size_t idx = 0; idx < contents.size(); ++idx) {
if (idx % DISPLAY_WIDTH == 0 && idx) if (idx % DISPLAY_WIDTH == 0 && idx)
out << std::endl; out << std::endl;
out << get_code(contents[idx]) out << get_code(contents[idx])
<< (char)(contents[idx] ? contents[idx] : ' '); << (char)(contents[idx] ? contents[idx] : ' ');
} }
out << std::endl; out << std::endl;
} }
void console_output::print_char(const position &pos, const char ch, void console_output::print_char(const position &pos, const char ch,
const int attrs) { const int attrs) {
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
return; return;
contents[pos.y * DISPLAY_WIDTH + pos.x] = attrs | ch; contents[pos.y * DISPLAY_WIDTH + pos.x] = attrs | ch;
} }
void console_output::print_str(const position &pos, const std::string &str, void console_output::print_str(const position &pos, const std::string &str,
const int attrs) { const int attrs) {
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
return; return;
int head = pos.y * DISPLAY_WIDTH + pos.x; int head = pos.y * DISPLAY_WIDTH + pos.x;
for (std::size_t i = 0; i < str.length(); ++i) for (std::size_t i = 0; i < str.length(); ++i)
contents[i + head] = attrs | str[i]; contents[i + head] = attrs | str[i];
} }

View File

@ -6,16 +6,16 @@
class console_output final : public display { class console_output final : public display {
private: private:
std::ostream &out; std::ostream &out;
std::string get_code(const int attrs); std::string get_code(const int attrs);
public: public:
console_output(std::ostream &cout); console_output(std::ostream &cout);
void render() override; void render() override;
void print_char(const position &pos, void print_char(const position &pos,
const char ch, const int attrs) override; const char ch, const int attrs) override;
void print_str(const position &pos, void print_str(const position &pos,
const std::string &str, const int attrs) override; const std::string &str, const int attrs) override;
}; };
#endif #endif

View File

@ -53,8 +53,6 @@ const int CALC_ADD_LATER = 2;
const int CALC_MUL_LATER = 3; const int CALC_MUL_LATER = 3;
const int CALC_ADD_FIXED = 4; const int CALC_ADD_FIXED = 4;
const int DIRECTION_CNT = 8; const int DIRECTION_CNT = 8;
// IMPORTANT: east is positive for x and SOUTH is positive for y // IMPORTANT: east is positive for x and SOUTH is positive for y
// initializes all directions to an int // initializes all directions to an int
@ -63,8 +61,8 @@ enum direction { north = 0, south, east, west, northeast,
}; };
const position MOVE[DIRECTION_CNT] = { const position MOVE[DIRECTION_CNT] = {
{0, -1}, {0, 1}, {1, 0}, {-1, 0}, {0, -1}, {0, 1}, {1, 0}, {-1, 0},
{1, -1}, {-1, -1}, {1, 1}, {-1, 1} {1, -1}, {-1, -1}, {1, 1}, {-1, 1}
}; };
const int MAP_HEIGHT = 25; const int MAP_HEIGHT = 25;

View File

@ -1,84 +1,84 @@
#include "curses_input.h" #include "curses_input.h"
curses_input::curses_input(cursor &new_curse): curses_input::curses_input(cursor &new_curse):
curse{new_curse} {} curse{new_curse} {}
game_command curses_input::get_command() { game_command curses_input::get_command() {
switch (curse.getcmd()) { switch (curse.getcmd()) {
case 'h': case 'h':
return game_command::move_west; return game_command::move_west;
case 'j': case 'j':
return game_command::move_south; return game_command::move_south;
case 'k': case 'k':
return game_command::move_north; return game_command::move_north;
case 'l': case 'l':
return game_command::move_east; return game_command::move_east;
case 'y': case 'y':
return game_command::move_northwest; return game_command::move_northwest;
case 'u': case 'u':
return game_command::move_northeast; return game_command::move_northeast;
case 'b': case 'b':
return game_command::move_southwest; return game_command::move_southwest;
case 'n': case 'n':
return game_command::move_southeast; return game_command::move_southeast;
case 'a': case 'a':
break; // wait for another command break; // wait for another command
case '<': case '<':
return game_command::up_stairs; return game_command::up_stairs;
case '>': case '>':
return game_command::down_stairs; return game_command::down_stairs;
case 'q': case 'q':
return game_command_terminate; return game_command_terminate;
case 'f': case 'f':
return game_command::the_world; return game_command::the_world;
case 'r': case 'r':
return game_restart; return game_restart;
default: default:
return game_command_pass; return game_command_pass;
} }
switch (curse.getcmd()) { switch (curse.getcmd()) {
case 'h': case 'h':
return game_command::apply_west; return game_command::apply_west;
case 'j': case 'j':
return game_command::apply_south; return game_command::apply_south;
case 'k': case 'k':
return game_command::apply_north; return game_command::apply_north;
case 'l': case 'l':
return game_command::apply_east; return game_command::apply_east;
case 'y': case 'y':
return game_command::apply_northwest; return game_command::apply_northwest;
case 'u': case 'u':
return game_command::apply_northeast; return game_command::apply_northeast;
case 'b': case 'b':
return game_command::apply_southwest; return game_command::apply_southwest;
case 'n': case 'n':
return game_command::apply_southeast; return game_command::apply_southeast;
default: default:
return game_command::apply_panic; return game_command::apply_panic;
} }
return game_command::game_command_panic; return game_command::game_command_panic;
} }

View File

@ -8,10 +8,10 @@
class curses_input final: public input { class curses_input final: public input {
private: private:
cursor &curse; cursor &curse;
public: public:
curses_input(cursor &new_curse); curses_input(cursor &new_curse);
game_command get_command() override; game_command get_command() override;
}; };
#endif #endif

View File

@ -1,36 +1,36 @@
#include "curses_output.h" #include "curses_output.h"
curses_output::curses_output(cursor &new_curse): curses_output::curses_output(cursor &new_curse):
curse{new_curse} {} curse{new_curse} {}
void curses_output::render() { void curses_output::render() {
curse.show(); curse.show();
} }
void curses_output::clear() { void curses_output::clear() {
curse.clear(); curse.clear();
} }
void curses_output::print_char(const position &pos, const char ch, void curses_output::print_char(const position &pos, const char ch,
const int attrs) { const int attrs) {
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
return; return;
curse.print_char(pos, ch, attrs); curse.print_char(pos, ch, attrs);
} }
void curses_output::print_str(const position &pos, const std::string &str, void curses_output::print_str(const position &pos, const std::string &str,
const int attrs) { const int attrs) {
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
return; return;
position tmp = pos; position tmp = pos;
for (std::size_t i = 0; i < str.length(); ++i) { for (std::size_t i = 0; i < str.length(); ++i) {
curse.print_char(tmp, str[i], attrs); curse.print_char(tmp, str[i], attrs);
tmp += {1, 0}; tmp += {1, 0};
if (tmp.x >= DISPLAY_WIDTH) if (tmp.x >= DISPLAY_WIDTH)
tmp = {0, tmp.y + 1}; tmp = {0, tmp.y + 1};
} }
} }

View File

@ -8,16 +8,16 @@
class curses_output final : public display { class curses_output final : public display {
private: private:
cursor &curse; cursor &curse;
public: public:
curses_output(cursor &new_curse); curses_output(cursor &new_curse);
void render() override; void render() override;
void clear() override; void clear() override;
void print_char(const position &pos, void print_char(const position &pos,
const char ch, const int attrs) override; const char ch, const int attrs) override;
void print_str(const position &pos, void print_str(const position &pos,
const std::string &str, const int attrs) override; const std::string &str, const int attrs) override;
}; };
#endif #endif

View File

@ -2,53 +2,53 @@
#include "constants.h" #include "constants.h"
cursor::cursor() { cursor::cursor() {
initscr(); initscr();
if (has_colors()) { if (has_colors()) {
start_color(); start_color();
init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK); init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK); init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK); init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK); init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK); init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK); init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK); init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
init_pair(COLOR_BLACK_ON_WHITE, COLOR_BLACK, COLOR_WHITE); init_pair(COLOR_BLACK_ON_WHITE, COLOR_BLACK, COLOR_WHITE);
} }
} }
cursor::~cursor() { cursor::~cursor() {
endwin(); endwin();
} }
int cursor::getcmd() const { int cursor::getcmd() const {
return getch(); return getch();
} }
void cursor::show() const { void cursor::show() const {
refresh(); refresh();
} }
void cursor::clear() const { void cursor::clear() const {
::clear(); ::clear();
} }
void cursor::print_char(const position &pos, const char ch, void cursor::print_char(const position &pos, const char ch,
const int attrs) const { const int attrs) const {
attrset(attrs); attrset(attrs);
mvaddch(pos.y, pos.x, ch); mvaddch(pos.y, pos.x, ch);
} }
void cursor::print_str(const position &pos, const std::string str, void cursor::print_str(const position &pos, const std::string str,
const int attrs) const { const int attrs) const {
attrset(attrs); attrset(attrs);
mvaddstr(pos.y, pos.x, str.c_str()); mvaddstr(pos.y, pos.x, str.c_str());
} }
bool check_terminal_size() { bool check_terminal_size() {
int max_x; int max_x;
int max_y; int max_y;
getmaxyx(stdscr, max_y, max_x); getmaxyx(stdscr, max_y, max_x);
return max_x >= DISPLAY_WIDTH && max_y >= DISPLAY_HEIGHT; return max_x >= DISPLAY_WIDTH && max_y >= DISPLAY_HEIGHT;
} }

View File

@ -37,20 +37,20 @@
class cursor final { class cursor final {
private: private:
public: public:
cursor(); cursor();
~cursor(); ~cursor();
int getcmd() const; int getcmd() const;
void show() const; void show() const;
void clear() const ; void clear() const ;
void print_char(const position &pos, const char ch, const int attrs) const; void print_char(const position &pos, const char ch, const int attrs) const;
void print_str(const position &head, const std::string str, void print_str(const position &head, const std::string str,
const int attrs) const; const int attrs) const;
}; };
// IMPORTANT: this will fail when terminal size changes // IMPORTANT: this will fail when terminal size changes

View File

@ -1,15 +1,15 @@
#include "display.h" #include "display.h"
display::display(): display::display():
contents{DISPLAY_BUFFER_SIZE, 0} { contents{DISPLAY_BUFFER_SIZE, 0} {
for (int i = 0; i < DISPLAY_BUFFER_SIZE; ++i) for (int i = 0; i < DISPLAY_BUFFER_SIZE; ++i)
contents.push_back(0); contents.push_back(0);
} }
void display::clear() { void display::clear() {
contents.clear(); contents.clear();
contents.reserve(DISPLAY_BUFFER_SIZE); contents.reserve(DISPLAY_BUFFER_SIZE);
for (int i = 0; i < DISPLAY_BUFFER_SIZE; ++i) for (int i = 0; i < DISPLAY_BUFFER_SIZE; ++i)
contents.push_back(0); contents.push_back(0);
} }

View File

@ -8,28 +8,28 @@
class display { class display {
protected: protected:
// use an array of ints to keep track of what's on the screen // use an array of ints to keep track of what's on the screen
// This will have a bit of buffer for the last line // This will have a bit of buffer for the last line
// just in case it overflows // just in case it overflows
std::vector<int> contents; std::vector<int> contents;
public: public:
display(); display();
virtual ~display() = default; virtual ~display() = default;
// Only call this to refresh the entire output // Only call this to refresh the entire output
virtual void render() = 0; virtual void render() = 0;
// Clears the contents buffer // Clears the contents buffer
virtual void clear(); virtual void clear();
virtual void print_char(const position &pos, const char ch, virtual void print_char(const position &pos, const char ch,
const int attrs = const int attrs =
A_NORMAL | COLOR_PAIR(COLOR_WHITE)) = 0; A_NORMAL | COLOR_PAIR(COLOR_WHITE)) = 0;
virtual void print_str(const position &pos, const std::string &str, virtual void print_str(const position &pos, const std::string &str,
const int attrs = const int attrs =
A_NORMAL | COLOR_PAIR(COLOR_WHITE)) = 0; A_NORMAL | COLOR_PAIR(COLOR_WHITE)) = 0;
// default arguments are to be set in the base class's declaration // default arguments are to be set in the base class's declaration
}; };
#endif #endif

View File

@ -3,30 +3,30 @@
#include <math.h> #include <math.h>
drow::drow(RNG &rng, const position_list &available_positions): drow::drow(RNG &rng, const position_list &available_positions):
character{rng, race::rdrow} { character{rng, race::rdrow} {
pos = available_positions[rng.rand_under(available_positions.size())]; pos = available_positions[rng.rand_under(available_positions.size())];
gold = 0; gold = 0;
hostile = true; hostile = true;
} }
result drow::attack(const direction dir, character_list &chlist) { result drow::attack(const direction dir, character_list &chlist) {
position tmp{pos + MOVE[dir]}; position tmp{pos + MOVE[dir]};
for (auto &ch : chlist) for (auto &ch : chlist)
if (tmp == ch.get_position()) { if (tmp == ch.get_position()) {
return ch.get_hit(race, ATK, base_hit_rate); return ch.get_hit(race, ATK, base_hit_rate);
} }
return result::fine; return result::fine;
} }
result drow::get_hit(const enum race &race, const int atk, result drow::get_hit(const enum race &race, const int atk,
const float hitrate) { const float hitrate) {
if (rng.rand_num() <= hitrate * (float)RAND_MAX) if (rng.rand_num() <= hitrate * (float)RAND_MAX)
HP = std::max(HP - calc_dmg(atk, DEF), 0); HP = std::max(HP - calc_dmg(atk, DEF), 0);
if (HP == 0) if (HP == 0)
return result::died; return result::died;
return result::hit; return result::hit;
} }

View File

@ -4,12 +4,12 @@
class drow final: public character { class drow final: public character {
public: public:
drow(RNG &rng, drow(RNG &rng,
const position_list &available_positions); const position_list &available_positions);
virtual result attack(const direction dir, virtual result attack(const direction dir,
character_list &chlist) override; character_list &chlist) override;
virtual result get_hit(const enum race &race, const int atk, virtual result get_hit(const enum race &race, const int atk,
const float hit_rate) override; const float hit_rate) override;
}; };
#endif #endif

View File

@ -3,40 +3,40 @@
#include <string> #include <string>
file_input::file_input(std::ifstream &&ifs): file_input::file_input(std::ifstream &&ifs):
in{std::move(ifs)} {} in{std::move(ifs)} {}
game_command file_input::get_command() { game_command file_input::get_command() {
std::string cmd; std::string cmd;
in >> cmd;
game_command tmp;
if (in.eof())
return game_command_terminate;
if (cmd == "q")
return game_command_terminate;
else if (cmd == "f")
return the_world;
else if (cmd == "r")
return game_restart;
else if (cmd == "u" || cmd == "a") {
bool use = cmd == "u";
in >> cmd; in >> cmd;
game_command tmp;
if (in.eof()) if (in.eof())
return game_command_terminate; return game_command_panic;
if (cmd == "q") return (game_command)((tmp = get_direction(cmd)) ==
return game_command_terminate; game_command_panic
else if (cmd == "f") ? tmp : tmp - move_north +
return the_world; (use ? apply_north : attack_north));
else if (cmd == "r") } else {
return game_restart; auto tmp = get_direction(cmd);
else if (cmd == "u" || cmd == "a") {
bool use = cmd == "u";
in >> cmd; if (tmp != game_command_panic)
return tmp;
}
if (in.eof()) return game_command_pass;
return game_command_panic;
return (game_command)((tmp = get_direction(cmd)) ==
game_command_panic
? tmp : tmp - move_north +
(use ? apply_north : attack_north));
} else {
auto tmp = get_direction(cmd);
if (tmp != game_command_panic)
return tmp;
}
return game_command_pass;
} }

View File

@ -6,11 +6,11 @@
class file_input final : public input { class file_input final : public input {
private: private:
std::ifstream in; std::ifstream in;
public: public:
// This is for cin // This is for cin
file_input(std::ifstream &&ifs); file_input(std::ifstream &&ifs);
game_command get_command() override; game_command get_command() override;
}; };
#endif #endif

View File

@ -3,34 +3,34 @@
#include <utility> #include <utility>
file_output::file_output(std::ofstream &&ofs): file_output::file_output(std::ofstream &&ofs):
out{std::move(ofs)} {} out{std::move(ofs)} {}
void file_output::render() { void file_output::render() {
for (std::size_t idx = 0; idx < contents.size(); ++idx) { for (std::size_t idx = 0; idx < contents.size(); ++idx) {
if (idx % DISPLAY_WIDTH == 0 && idx) if (idx % DISPLAY_WIDTH == 0 && idx)
out << std::endl; out << std::endl;
out << (char)(contents[idx] ? contents[idx] : ' '); out << (char)(contents[idx] ? contents[idx] : ' ');
} }
out << std::endl; out << std::endl;
} }
void file_output::print_char(const position &pos, const char ch, void file_output::print_char(const position &pos, const char ch,
const int attrs) { const int attrs) {
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
return; return;
contents[pos.y * DISPLAY_WIDTH + pos.x] = ch; contents[pos.y * DISPLAY_WIDTH + pos.x] = ch;
} }
void file_output::print_str(const position &pos, const std::string &str, void file_output::print_str(const position &pos, const std::string &str,
const int attrs) { const int attrs) {
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT) if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
return; return;
int head = pos.y * DISPLAY_WIDTH + pos.x; int head = pos.y * DISPLAY_WIDTH + pos.x;
for (std::size_t i = 0; i < str.length(); ++i) for (std::size_t i = 0; i < str.length(); ++i)
contents[i + head] = str[i]; contents[i + head] = str[i];
} }

View File

@ -6,15 +6,15 @@
class file_output final : public display { class file_output final : public display {
private: private:
std::ofstream out; std::ofstream out;
public: public:
file_output(std::ofstream &&ofs); file_output(std::ofstream &&ofs);
void render() override; void render() override;
void print_char(const position &pos, void print_char(const position &pos,
const char ch, const int attrs) override; const char ch, const int attrs) override;
void print_str(const position &pos, void print_str(const position &pos,
const std::string &str, const int attrs) override; const std::string &str, const int attrs) override;
}; };
#endif #endif

View File

@ -1,44 +1,44 @@
#include "fraction.h" #include "fraction.h"
fraction fraction::operator+(const fraction &frac) { fraction fraction::operator+(const fraction &frac) {
fraction tmp = *this; fraction tmp = *this;
tmp.numerator = tmp.numerator * frac.denominator + tmp.numerator = tmp.numerator * frac.denominator +
tmp.denominator * frac.numerator; tmp.denominator * frac.numerator;
tmp.denominator = tmp.denominator * frac.denominator; tmp.denominator = tmp.denominator * frac.denominator;
return tmp.simplify(); return tmp.simplify();
} }
fraction fraction::operator*(const fraction &frac) { fraction fraction::operator*(const fraction &frac) {
fraction tmp = *this; fraction tmp = *this;
tmp.numerator = tmp.numerator * frac.numerator; tmp.numerator = tmp.numerator * frac.numerator;
tmp.denominator = tmp.denominator * frac.denominator; tmp.denominator = tmp.denominator * frac.denominator;
return tmp.simplify(); return tmp.simplify();
} }
bool fraction::operator==(const fraction &frac) { bool fraction::operator==(const fraction &frac) {
this->simplify(); this->simplify();
return gcd(frac.numerator, this->numerator) == this->numerator && return gcd(frac.numerator, this->numerator) == this->numerator &&
gcd(frac.denominator, this->denominator) == this->denominator; gcd(frac.denominator, this->denominator) == this->denominator;
} }
bool fraction::operator!=(const fraction &frac) { bool fraction::operator!=(const fraction &frac) {
return !(*this == frac); return !(*this == frac);
} }
fraction &fraction::simplify() { fraction &fraction::simplify() {
int g = gcd(numerator, denominator); int g = gcd(numerator, denominator);
numerator /= g; numerator /= g;
denominator /= g; denominator /= g;
return *this; return *this;
} }
float fraction::real() { float fraction::real() {
return (float)numerator / denominator; return (float)numerator / denominator;
} }
int fraction::gcd(int a, int b) { int fraction::gcd(int a, int b) {
if (a % b == 0) if (a % b == 0)
return b; return b;
return gcd(b, a % b); return gcd(b, a % b);
} }

View File

@ -2,17 +2,17 @@
#define __FRACTION_H__ #define __FRACTION_H__
struct fraction final { struct fraction final {
int numerator; int numerator;
int denominator; int denominator;
fraction operator+(const fraction &frac); fraction operator+(const fraction &frac);
fraction operator*(const fraction &frac); fraction operator*(const fraction &frac);
bool operator==(const fraction &frac); bool operator==(const fraction &frac);
bool operator!=(const fraction &frac); bool operator!=(const fraction &frac);
fraction &simplify(); fraction &simplify();
float real(); float real();
private: private:
int gcd(int a, int b); int gcd(int a, int b);
}; };
#endif #endif

View File

@ -12,21 +12,21 @@
class game final { class game final {
private: private:
feature features; feature features;
input &in; input &in;
display &out; display &out;
logger &log; logger &log;
RNG &rng; RNG &rng;
std::unique_ptr<character> player; std::unique_ptr<character> player;
public: public:
game(const feature enabled_features, game(const feature enabled_features,
input &new_in, input &new_in,
display &new_out, display &new_out,
logger &new_log, logger &new_log,
RNG &new_rng); RNG &new_rng);
game_status run(); game_status run();
private: private:
int getcmd() const; int getcmd() const;
}; };
#endif #endif

View File

@ -3,36 +3,36 @@
#include <math.h> #include <math.h>
goblin::goblin(RNG &rng, const position_list &available_positions): goblin::goblin(RNG &rng, const position_list &available_positions):
character{rng, race::rshade} { character{rng, race::rshade} {
pos = available_positions[rng.rand_under(available_positions.size())]; pos = available_positions[rng.rand_under(available_positions.size())];
gold = 0; gold = 0;
hostile = true; hostile = true;
} }
result goblin::attack(const direction dir, character_list &chlist) { result goblin::attack(const direction dir, character_list &chlist) {
position tmp{pos + MOVE[dir]}; position tmp{pos + MOVE[dir]};
for (auto &ch : chlist) for (auto &ch : chlist)
if (tmp == ch.get_position()) { if (tmp == ch.get_position()) {
auto res = ch.get_hit(race, ATK, base_hit_rate); auto res = ch.get_hit(race, ATK, base_hit_rate);
if (res == result::died) { if (res == result::died) {
gold += GAIN_GOLD; gold += GAIN_GOLD;
} }
return res; return res;
} }
return result::fine; return result::fine;
} }
result goblin::get_hit(const enum race &race, const int atk, result goblin::get_hit(const enum race &race, const int atk,
const float hitrate) { const float hitrate) {
if (rng.rand_num() <= hitrate * (float)RAND_MAX) if (rng.rand_num() <= hitrate * (float)RAND_MAX)
HP = std::max(HP - calc_dmg(atk, DEF), 0); HP = std::max(HP - calc_dmg(atk, DEF), 0);
if (HP == 0) if (HP == 0)
return result::died; return result::died;
return result::hit; return result::hit;
} }

View File

@ -6,12 +6,12 @@ const int GAIN_GOLD = 5;
class goblin final: public character { class goblin final: public character {
public: public:
goblin(RNG &rng, goblin(RNG &rng,
const position_list &available_positions); const position_list &available_positions);
virtual result attack(const direction dir, virtual result attack(const direction dir,
character_list &chlist) override; character_list &chlist) override;
virtual result get_hit(const enum race &race, const int atk, virtual result get_hit(const enum race &race, const int atk,
const float hit_rate) override; const float hit_rate) override;
}; };
#endif #endif

View File

@ -1,15 +1,14 @@
#include "input.h" #include "input.h"
const char *COMMANDS[] = { const char *COMMANDS[] = {
"no", "so", "ea", "we", "ne", "nw", "se", "sw" "no", "so", "ea", "we", "ne", "nw", "se", "sw"
}; };
const int COMMANDS_CNT = 8; const int COMMANDS_CNT = 8;
game_command get_direction(std::string &str) { game_command get_direction(std::string &str) {
for (int i = 0; i < COMMANDS_CNT; ++i) for (int i = 0; i < COMMANDS_CNT; ++i)
if (str == COMMANDS[i]) if (str == COMMANDS[i])
return (game_command)i; return (game_command)i;
return game_command_panic; return game_command_panic;
} }

View File

@ -5,8 +5,8 @@
class input { class input {
public: public:
virtual ~input() = default; virtual ~input() = default;
virtual game_command get_command() = 0; virtual game_command get_command() = 0;
}; };
game_command get_direction(std::string &str); game_command get_direction(std::string &str);

View File

@ -3,7 +3,7 @@
#include <utility> #include <utility>
logger::logger(std::ofstream &&new_out): logger::logger(std::ofstream &&new_out):
out{std::move(new_out)} {} out{std::move(new_out)} {}
void logger::render() { void logger::render() {

View File

@ -9,20 +9,20 @@
class logger final { class logger final {
private: private:
std::ofstream out; std::ofstream out;
std::vector<char> contents; std::vector<char> contents;
public: public:
logger(std::ofstream &&new_out); logger(std::ofstream &&new_out);
// called once every turn // called once every turn
void render(); void render();
void print_char(const position &pos, const char ch); void print_char(const position &pos, const char ch);
void print_str(const position &pos, const std::string &str); void print_str(const position &pos, const std::string &str);
void print_turn(const unsigned turn); void print_turn(const unsigned turn);
void print_player(const character &player); void print_player(const character &player);
void print_chlist(const character_list &chlist); void print_chlist(const character_list &chlist);
void print_gold(const gold_list &gold_piles); void print_gold(const gold_list &gold_piles);
void print_potions(const potion_list &potions); void print_potions(const potion_list &potions);
}; };
#endif #endif

View File

@ -2,27 +2,26 @@
#include "arguments.h" #include "arguments.h"
int main(int argc, char **argv) { int main(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<display> out; std::unique_ptr<display> out;
std::unique_ptr<logger> log; std::unique_ptr<logger> log;
std::unique_ptr<RNG> rng; std::unique_ptr<RNG> rng;
feature enabled_features = proc_args(argc, argv,
curse, in, out, log, rng);
feature enabled_features = proc_args(argc, argv, if (enabled_features &
curse, in, out, log, rng);
if (enabled_features &
(FEATURE_PANIC | FEATURE_PANIC_FILE | (FEATURE_PANIC | FEATURE_PANIC_FILE |
FEATURE_CONFLICT | FEATURE_PANIC_SEED)) { FEATURE_CONFLICT | FEATURE_PANIC_SEED)) {
panic_args(enabled_features); panic_args(enabled_features);
return RETURN_PANICKED; return RETURN_PANICKED;
} }
game game_proc(enabled_features, *in, *out, *log, *rng); game game_proc(enabled_features, *in, *out, *log, *rng);
while (game_proc.run() != game_status::terminated) while (game_proc.run() != game_status::terminated)
out->render(); out->render();
return RETURN_FINE; return RETURN_FINE;
} }

View File

@ -6,63 +6,63 @@
#include <algorithm> #include <algorithm>
game_map::game_map(int lvl) { game_map::game_map(int lvl) {
level = lvl; level = lvl;
// TODO: randomly generate a map // TODO: randomly generate a map
} }
game_map::game_map(const std::string &map_data, int lvl) { game_map::game_map(const std::string &map_data, int lvl) {
level = lvl; level = lvl;
std::istringstream iss{map_data}; std::istringstream iss{map_data};
std::string line; std::string line;
for (int i = 0; i < MAP_HEIGHT; ++i) { for (int i = 0; i < MAP_HEIGHT; ++i) {
getline(iss, line); getline(iss, line);
map[i] = line; map[i] = line;
} }
} }
game_map::~game_map() {} game_map::~game_map() {}
int game_map::get_level() const { int game_map::get_level() const {
return this->level; return this->level;
} }
std::vector<position> game_map::get_available_positions() const { std::vector<position> game_map::get_available_positions() const {
std::vector<position> result; std::vector<position> result;
for (int line = 0; line < MAP_HEIGHT; ++line) for (int line = 0; line < MAP_HEIGHT; ++line)
for (int x = 0; x < MAP_WIDTH; ++x) for (int x = 0; x < MAP_WIDTH; ++x)
if (map[line][x] == '.' || if (map[line][x] == '.' ||
map[line][x] == '#' || map[line][x] == '#' ||
map[line][x] == '+') map[line][x] == '+')
result.push_back(position{x, line}); result.push_back(position{x, line});
return result; return result;
} }
void game_map::print() const { void game_map::print() const {
// TODO: write a print function using ncurses // TODO: write a print function using ncurses
} }
void game_map::print(display &display) const { void game_map::print(display &display) const {
for (int i = 0; i < MAP_HEIGHT; ++i) for (int i = 0; i < MAP_HEIGHT; ++i)
display.print_str(position{0, i}, map[i]); display.print_str(position{0, i}, map[i]);
} }
void game_map::apply_potion(character *who, const stat_name statn, void game_map::apply_potion(character *who, const stat_name statn,
const int amount) { const int amount) {
effects.push_back(effect{who, statn, amount}); effects.push_back(effect{who, statn, amount});
who->apply_buff(statn, amount); who->apply_buff(statn, amount);
} }
void game_map::enter_level(character *who) { void game_map::enter_level(character *who) {
for (auto eff : effects) for (auto eff : effects)
if (eff.who == who) if (eff.who == who)
who->apply_buff(eff.statn, eff.amount); who->apply_buff(eff.statn, eff.amount);
} }
void game_map::leave_level(character *who) { void game_map::leave_level(character *who) {
who->set_ATK(STARTING_ATK[who->get_race()]); who->set_ATK(STARTING_ATK[who->get_race()]);
who->set_DEF(STARTING_DEF[who->get_race()]); who->set_DEF(STARTING_DEF[who->get_race()]);
} }

View File

@ -15,46 +15,46 @@
class game_map final { class game_map final {
public: public:
game_map(int lvl = 0); // randomly generate one game_map(int lvl = 0); // randomly generate one
// initialize using stored data // initialize using stored data
game_map(const std::string &map_data, int lvl); game_map(const std::string &map_data, int lvl);
~game_map(); // placeholder ~game_map(); // placeholder
int get_level() const; int get_level() const;
position_list get_available_positions() const; position_list get_available_positions() const;
// IMPORTANT: always print a map before anything else // IMPORTANT: always print a map before anything else
// prints using ncurses // prints using ncurses
void print() const; void print() const;
// prints to a string // prints to a string
void print(display &display) const; void print(display &display) const;
// This is implemented this way to do two things: // This is implemented this way to do two things:
// 1. avoid directly accessing heap memory (bonus points) // 1. avoid directly accessing heap memory (bonus points)
// 2. make a level revisitable // 2. make a level revisitable
void apply_potion(character *who, const stat_name statn, const int amount); void apply_potion(character *who, const stat_name statn, const int amount);
// just in case you want to retain the potion effects // just in case you want to retain the potion effects
void enter_level(character *who); void enter_level(character *who);
void leave_level(character *who); void leave_level(character *who);
public: public:
struct effect { struct effect {
character *who; character *who;
stat_name statn; stat_name statn;
int amount; int amount;
}; };
std::string map[MAP_HEIGHT]; std::string map[MAP_HEIGHT];
int level; int level;
// use this to remember every applied potion // use this to remember every applied potion
std::vector<effect> effects; std::vector<effect> effects;
}; };
const std::string default_map = const std::string default_map =
"|-----------------------------------------------------------------------------|\n| |\n| |--------------------------| |-----------------------| |\n| |..........................| |.......................| |\n| |..........................+########+.......................|-------| |\n| |..........................| # |...............................|--| |\n| |..........................| # |..................................|--| |\n| |----------+---------------| # |----+----------------|...............| |\n| # ############# |...............| |\n| # # |-----+------| |...............| |\n| # # |............| |...............| |\n| ################### |............| ######+...............| |\n| # # |............| # |...............| |\n| # # |-----+------| # |--------+------| |\n| |---------+-----------| # # # # |\n| |.....................| # # # |----+------| |\n| |.....................| ######################## |...........| |\n| |.....................| # # |...........| |\n| |.....................| # |------+--------------------|...........| |\n| |.....................| # |.......................................| |\n| |.....................+##########+.......................................| |\n| |.....................| |.......................................| |\n| |---------------------| |---------------------------------------| |\n| |\n|-----------------------------------------------------------------------------|"; "|-----------------------------------------------------------------------------|\n| |\n| |--------------------------| |-----------------------| |\n| |..........................| |.......................| |\n| |..........................+########+.......................|-------| |\n| |..........................| # |...............................|--| |\n| |..........................| # |..................................|--| |\n| |----------+---------------| # |----+----------------|...............| |\n| # ############# |...............| |\n| # # |-----+------| |...............| |\n| # # |............| |...............| |\n| ################### |............| ######+...............| |\n| # # |............| # |...............| |\n| # # |-----+------| # |--------+------| |\n| |---------+-----------| # # # # |\n| |.....................| # # # |----+------| |\n| |.....................| ######################## |...........| |\n| |.....................| # # |...........| |\n| |.....................| # |------+--------------------|...........| |\n| |.....................| # |.......................................| |\n| |.....................+##########+.......................................| |\n| |.....................| |.......................................| |\n| |---------------------| |---------------------------------------| |\n| |\n|-----------------------------------------------------------------------------|";
#endif #endif

View File

@ -3,20 +3,20 @@
#include <algorithm> #include <algorithm>
poison_health::poison_health(): poison_health::poison_health():
potion{potion_type::poison_health, 1} {} potion{potion_type::poison_health, 1} {}
void poison_health::apply(enum race &race, int &HP, int &ATK, int &DEF, void poison_health::apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) { float &base_hit_rate) {
if (remaining_duration > 0) { if (remaining_duration > 0) {
if (race == rdrow) if (race == rdrow)
HP = std::max(HP - 7, 0); HP = std::max(HP - 7, 0);
else else
HP = std::max(HP - 5, 0); HP = std::max(HP - 5, 0);
--remaining_duration; --remaining_duration;
} }
} }
int poison_health::get_priority() const { int poison_health::get_priority() const {
return CALC_ADD_BASE; return CALC_ADD_BASE;
} }

View File

@ -5,10 +5,10 @@
class poison_health final: public potion { class poison_health final: public potion {
public: public:
poison_health(); poison_health();
void apply(enum race &race, int &HP, int &ATK, int &DEF, void apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) override; float &base_hit_rate) override;
int get_priority() const override; int get_priority() const override;
}; };
#endif #endif

View File

@ -5,41 +5,41 @@ position::position(): x{0}, y{0} {}
position::position(int nx, int ny): x{nx}, y{ny} {} position::position(int nx, int ny): x{nx}, y{ny} {}
position position::operator+(const position &other) const { position position::operator+(const position &other) const {
position result{x + other.x, y + other.y}; position result{x + other.x, y + other.y};
return result; return result;
} }
position &position::operator=(const position &other) { position &position::operator=(const position &other) {
x = other.x; x = other.x;
y = other.y; y = other.y;
return *this; return *this;
} }
position &position::operator+=(const position &other) { position &position::operator+=(const position &other) {
return *this = *this + other; return *this = *this + other;
} }
bool position::operator==(const position &other) const { bool position::operator==(const position &other) const {
return x == other.x && y == other.y; return x == other.x && y == other.y;
} }
bool position::operator!=(const position &other) const { bool position::operator!=(const position &other) const {
return x != other.x || y != other.y; return x != other.x || y != other.y;
} }
bool position::operator<(const position &other) const { bool position::operator<(const position &other) const {
return y < other.y || x < other.x; return y < other.y || x < other.x;
} }
#include <iostream> #include <iostream>
size_t find(const std::vector<position> &sorted_list, size_t find(const std::vector<position> &sorted_list,
const position &target) { const position &target) {
// TODO: implement binary searching // TODO: implement binary searching
for (size_t i = 0; i < sorted_list.size(); ++i) for (size_t i = 0; i < sorted_list.size(); ++i)
if (sorted_list[i] == target) if (sorted_list[i] == target)
return i; return i;
return sorted_list.size(); return sorted_list.size();
} }

View File

@ -9,18 +9,18 @@
#include <vector> #include <vector>
typedef struct position { typedef struct position {
int x; int x;
int y; int y;
position(); position();
position(int nx, int ny); position(int nx, int ny);
position operator+(const position &other) const; position operator+(const position &other) const;
position &operator=(const position &other); position &operator=(const position &other);
position &operator+=(const position &other); position &operator+=(const position &other);
bool operator==(const position &other) const; bool operator==(const position &other) const;
bool operator!=(const position &other) const; bool operator!=(const position &other) const;
bool operator<(const position &other) const; bool operator<(const position &other) const;
} position; } position;
std::size_t find(const std::vector<position> &sorted_list, std::size_t find(const std::vector<position> &sorted_list,

View File

@ -1,12 +1,12 @@
#include "potion.h" #include "potion.h"
potion::potion(const potion_type type, const int duration): potion::potion(const potion_type type, const int duration):
type{type}, remaining_duration{duration} {} type{type}, remaining_duration{duration} {}
potion_type potion::get_type() const { potion_type potion::get_type() const {
return type; return type;
} }
int potion::get_duration() const { int potion::get_duration() const {
return remaining_duration; return remaining_duration;
} }

View File

@ -9,20 +9,20 @@
class potion { class potion {
protected: protected:
// Use -1 to denote that the effect will last until leaving the level // Use -1 to denote that the effect will last until leaving the level
// Otherwise, use a positive number // Otherwise, use a positive number
// Single use potions have a starting duration of 1 // Single use potions have a starting duration of 1
const potion_type type; const potion_type type;
int remaining_duration; int remaining_duration;
public: public:
potion(const potion_type type, const int duration); potion(const potion_type type, const int duration);
// apply decrements remaining_duration if it's positive, and // apply decrements remaining_duration if it's positive, and
// won't do anything if it's non-negative // won't do anything if it's non-negative
virtual void apply(enum race &race, int &HP, int &ATK, int &DEF, virtual void apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) = 0; float &base_hit_rate) = 0;
virtual int get_priority() const = 0; virtual int get_priority() const = 0;
potion_type get_type() const; potion_type get_type() const;
int get_duration() const; int get_duration() const;
}; };
typedef std::vector<potion> potion_list; typedef std::vector<potion> potion_list;

View File

@ -3,20 +3,20 @@
#include <algorithm> #include <algorithm>
restore_health::restore_health(): restore_health::restore_health():
potion{potion_type::restore_health, 1} {} potion{potion_type::restore_health, 1} {}
void restore_health::apply(enum race &race, int &HP, int &ATK, int &DEF, void restore_health::apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) { float &base_hit_rate) {
if (remaining_duration > 0) { if (remaining_duration > 0) {
if (race == rdrow) if (race == rdrow)
HP = std::min(HP + 7, MAX_HP[race]); HP = std::min(HP + 7, MAX_HP[race]);
else else
HP = std::min(HP + 5, MAX_HP[race]); HP = std::min(HP + 5, MAX_HP[race]);
--remaining_duration; --remaining_duration;
} }
} }
int restore_health::get_priority() const { int restore_health::get_priority() const {
return CALC_ADD_BASE; return CALC_ADD_BASE;
} }

View File

@ -5,10 +5,10 @@
class restore_health final: public potion { class restore_health final: public potion {
public: public:
restore_health(); restore_health();
void apply(enum race &race, int &HP, int &ATK, int &DEF, void apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) override; float &base_hit_rate) override;
int get_priority() const override; int get_priority() const override;
}; };
#endif #endif

View File

@ -1,43 +1,43 @@
#include "rng.h" #include "rng.h"
RNG::RNG(): init_seed(time(0)), curr_rand_num(0) { RNG::RNG(): init_seed(time(0)), curr_rand_num(0) {
srand(init_seed); srand(init_seed);
} }
RNG::RNG(const unsigned int seed): init_seed(seed), curr_rand_num(0) { RNG::RNG(const unsigned int seed): init_seed(seed), curr_rand_num(0) {
srand(init_seed); srand(init_seed);
} }
int RNG::rand_num() { int RNG::rand_num() {
return curr_rand_num = rand(); return curr_rand_num = rand();
} }
int RNG::rand_between(const int lower_bound, const int upper_bound) { int RNG::rand_between(const int lower_bound, const int upper_bound) {
curr_rand_num = rand(); curr_rand_num = rand();
return lower_bound + (curr_rand_num % (upper_bound - lower_bound)); return lower_bound + (curr_rand_num % (upper_bound - lower_bound));
} }
int RNG::rand_under(const int upper_bound) { int RNG::rand_under(const int upper_bound) {
curr_rand_num = rand(); curr_rand_num = rand();
return curr_rand_num % upper_bound; return curr_rand_num % upper_bound;
} }
unsigned int RNG::get_init_seed() const { unsigned int RNG::get_init_seed() const {
return init_seed; return init_seed;
} }
int RNG::get_curr_rand_num() const { int RNG::get_curr_rand_num() const {
return curr_rand_num; return curr_rand_num;
} }
bool RNG::trial(fraction &psuccess) { bool RNG::trial(fraction &psuccess) {
return (rand() % psuccess.denominator) < psuccess.numerator; return (rand() % psuccess.denominator) < psuccess.numerator;
} }
template<class T> T &RNG::get_rand_in_vector(const std::vector<T> &vec) { template<class T> T &RNG::get_rand_in_vector(const std::vector<T> &vec) {
curr_rand_num = rand(); curr_rand_num = rand();
return vec[curr_rand_num % vec.size()]; return vec[curr_rand_num % vec.size()];
} }

View File

@ -11,24 +11,24 @@
// IMPORTANT: pass all RNG objects as references // IMPORTANT: pass all RNG objects as references
class RNG final { class RNG final {
private: private:
const unsigned int init_seed; const unsigned int init_seed;
int curr_rand_num; int curr_rand_num;
public: public:
RNG(); // use time(0) as the seed RNG(); // use time(0) as the seed
RNG(const unsigned int seed); // use a seed RNG(const unsigned int seed); // use a seed
int rand_num(); // returns a random number between 0 and RAND_MAX int rand_num(); // returns a random number between 0 and RAND_MAX
// IMPORTANT: all upper bounds are not included, all lower bounds are // IMPORTANT: all upper bounds are not included, all lower bounds are
int rand_between(const int lower_bound, const int upper_bound); int rand_between(const int lower_bound, const int upper_bound);
// returns a random number between 0 and upper_bound // returns a random number between 0 and upper_bound
int rand_under(const int upper_bound); int rand_under(const int upper_bound);
unsigned int get_init_seed() const; unsigned int get_init_seed() const;
int get_curr_rand_num() const; int get_curr_rand_num() const;
bool trial(fraction &psuccess); bool trial(fraction &psuccess);
template<class T> T &get_rand_in_vector(const std::vector<T> &vec); template<class T> T &get_rand_in_vector(const std::vector<T> &vec);
}; };
#endif #endif

View File

@ -1,6 +1,4 @@
#ifndef __ROOM_H__ #ifndef __ROOM_H__
#define __ROOM_H__ #define __ROOM_H__
#endif #endif

View File

@ -4,31 +4,30 @@
#include <math.h> #include <math.h>
shade::shade(RNG &rng, const position_list &available_positions): shade::shade(RNG &rng, const position_list &available_positions):
character{rng, race::rshade} { character{rng, race::rshade} {
pos = available_positions[rng.rand_under(available_positions.size())]; pos = available_positions[rng.rand_under(available_positions.size())];
gold = 0; gold = 0;
hostile = true; hostile = true;
} }
result shade::attack(const direction dir, character_list &chlist) { result shade::attack(const direction dir, character_list &chlist) {
position tmp{pos + MOVE[dir]}; position tmp{pos + MOVE[dir]};
for (auto &ch : chlist) for (auto &ch : chlist)
if (tmp == ch.get_position()) { if (tmp == ch.get_position()) {
return ch.get_hit(race, ATK, base_hit_rate); return ch.get_hit(race, ATK, base_hit_rate);
} }
return result::fine; return result::fine;
} }
result shade::get_hit(const enum race &race, const int atk, result shade::get_hit(const enum race &race, const int atk,
const float hitrate) { const float hitrate) {
if (rng.rand_num() <= hitrate * (float)RAND_MAX) // This is a hit! if (rng.rand_num() <= hitrate * (float)RAND_MAX) // This is a hit!
HP = std::max(HP - calc_dmg(atk, DEF), 0); HP = std::max(HP - calc_dmg(atk, DEF), 0);
if (HP == 0) if (HP == 0)
return result::died; return result::died;
return result::hit; return result::hit;
} }

View File

@ -5,12 +5,12 @@
class shade final: public character { class shade final: public character {
public: public:
shade(RNG &rng, const position_list shade(RNG &rng, const position_list
&available_positions); // spawn at a random place &available_positions); // spawn at a random place
virtual result attack(const direction dir, virtual result attack(const direction dir,
character_list &chlist) override; character_list &chlist) override;
virtual result get_hit(const enum race &race, const int atk, virtual result get_hit(const enum race &race, const int atk,
const float hit_rate) override; const float hit_rate) override;
}; };
#endif #endif

View File

@ -3,36 +3,36 @@
#include <math.h> #include <math.h>
vampire::vampire(RNG &rng, const position_list &available_positions): vampire::vampire(RNG &rng, const position_list &available_positions):
character{rng, race::rvampire} { character{rng, race::rvampire} {
pos = available_positions[rng.rand_under(available_positions.size())]; pos = available_positions[rng.rand_under(available_positions.size())];
gold = 0; gold = 0;
hostile = true; hostile = true;
} }
result vampire::attack(const direction dir, character_list &chlist) { result vampire::attack(const direction dir, character_list &chlist) {
position tmp{pos + MOVE[dir]}; position tmp{pos + MOVE[dir]};
for (auto &ch : chlist) for (auto &ch : chlist)
if (tmp == ch.get_position()) { if (tmp == ch.get_position()) {
auto res = ch.get_hit(race, ATK, base_hit_rate); auto res = ch.get_hit(race, ATK, base_hit_rate);
if (res != result::miss) { if (res != result::miss) {
HP += GAIN_HP; HP += GAIN_HP;
} }
return res; return res;
} }
return result::fine; return result::fine;
} }
result vampire::get_hit(const enum race &race, const int atk, result vampire::get_hit(const enum race &race, const int atk,
const float hitrate) { const float hitrate) {
if (rng.rand_num() <= hitrate * (float)RAND_MAX) if (rng.rand_num() <= hitrate * (float)RAND_MAX)
HP = std::max(HP - calc_dmg(atk, DEF), 0); HP = std::max(HP - calc_dmg(atk, DEF), 0);
if (HP == 0) if (HP == 0)
return result::died; return result::died;
return result::hit; return result::hit;
} }

View File

@ -6,12 +6,12 @@ const int GAIN_HP = 5;
class vampire final: public character { class vampire final: public character {
public: public:
vampire(RNG &rng, vampire(RNG &rng,
const position_list &available_positions); const position_list &available_positions);
virtual result attack(const direction dir, virtual result attack(const direction dir,
character_list &chlist) override; character_list &chlist) override;
virtual result get_hit(const enum race &race, const int atk, virtual result get_hit(const enum race &race, const int atk,
const float hit_rate) override; const float hit_rate) override;
}; };
#endif #endif

View File

@ -6,21 +6,20 @@ const int WOUND_ATK = 5;
const int WOUND_ATK_DROW = 7; const int WOUND_ATK_DROW = 7;
wound_atk::wound_atk(): wound_atk::wound_atk():
potion{potion_type::wound_atk, -1} {} potion{potion_type::wound_atk, -1} {}
void wound_atk::apply(enum race &race, int &HP, int &ATK, int &DEF, void wound_atk::apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) { float &base_hit_rate) {
if (remaining_duration > 0) { if (remaining_duration > 0) {
if (race == rdrow) if (race == rdrow)
ATK = std::max(ATK - WOUND_ATK_DROW, 0); ATK = std::max(ATK - WOUND_ATK_DROW, 0);
else else
ATK = std::max(ATK - WOUND_ATK, 0); ATK = std::max(ATK - WOUND_ATK, 0);
--remaining_duration; --remaining_duration;
} }
} }
int wound_atk::get_priority() const { int wound_atk::get_priority() const {
return CALC_ADD_BASE; return CALC_ADD_BASE;
} }

View File

@ -5,10 +5,10 @@
class wound_atk final: public potion { class wound_atk final: public potion {
public: public:
wound_atk(); wound_atk();
void apply(enum race &race, int &HP, int &ATK, int &DEF, void apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) override; float &base_hit_rate) override;
int get_priority() const override; int get_priority() const override;
}; };
#endif #endif

View File

@ -6,20 +6,20 @@ const int WOUND_DEF = 5;
const int WOUND_DEF_DROW = 7; const int WOUND_DEF_DROW = 7;
wound_def::wound_def(): wound_def::wound_def():
potion{potion_type::wound_def, -1} {} potion{potion_type::wound_def, -1} {}
void wound_def::apply(enum race &race, int &HP, int &ATK, int &DEF, void wound_def::apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) { float &base_hit_rate) {
if (remaining_duration > 0) { if (remaining_duration > 0) {
if (race == rdrow) if (race == rdrow)
DEF = std::max(DEF - WOUND_DEF_DROW, 0); DEF = std::max(DEF - WOUND_DEF_DROW, 0);
else else
DEF = std::max(DEF - WOUND_DEF, 0); DEF = std::max(DEF - WOUND_DEF, 0);
--remaining_duration; --remaining_duration;
} }
} }
int wound_def::get_priority() const { int wound_def::get_priority() const {
return CALC_ADD_BASE; return CALC_ADD_BASE;
} }

View File

@ -5,10 +5,10 @@
class wound_def final: public potion { class wound_def final: public potion {
public: public:
wound_def(); wound_def();
void apply(enum race &race, int &HP, int &ATK, int &DEF, void apply(enum race &race, int &HP, int &ATK, int &DEF,
float &base_hit_rate) override; float &base_hit_rate) override;
int get_priority() const override; int get_priority() const override;
}; };
#endif #endif