finished the bulk of game
This commit is contained in:
33
Makefile
33
Makefile
@ -1,33 +0,0 @@
|
|||||||
# Universal makefile for single C++ program
|
|
||||||
#
|
|
||||||
# Use gcc flag -MMD (user) or -MD (user/system) to generate dependencies among source files.
|
|
||||||
# Use make default rules for commonly used file-name suffixes and make variables names.
|
|
||||||
#
|
|
||||||
# % make [ a.out ]
|
|
||||||
|
|
||||||
########## Variables ##########
|
|
||||||
|
|
||||||
CXX = g++ # compiler
|
|
||||||
CXXFLAGS = -std=c++20 -g -Wall -MMD -O0 # compiler flags
|
|
||||||
MAKEFILE_NAME = ${firstword ${MAKEFILE_LIST}} # makefile name
|
|
||||||
|
|
||||||
SOURCES = $(wildcard src/*.cc) # source files (*.cc)
|
|
||||||
OBJECTS = ${SOURCES:.cc=.o} # object files forming executable
|
|
||||||
DEPENDS = ${OBJECTS:.o=.d} # substitute ".o" with ".d"
|
|
||||||
EXEC = bin/cc3k # executable name
|
|
||||||
|
|
||||||
########## Targets ##########
|
|
||||||
|
|
||||||
.PHONY : clean # not file names
|
|
||||||
|
|
||||||
${EXEC} : ${OBJECTS} # link step
|
|
||||||
${CXX} ${CXXFLAGS} -O0 $^ -o $@ -lncurses # additional object files before $^
|
|
||||||
|
|
||||||
${OBJECTS} : ${MAKEFILE_NAME} # OPTIONAL : changes to this file => recompile
|
|
||||||
|
|
||||||
# make implicitly generates rules to compile C++ files that generate .o files
|
|
||||||
|
|
||||||
-include ${DEPENDS} # include *.d files containing program dependences
|
|
||||||
|
|
||||||
clean : # remove files that can be regenerated
|
|
||||||
rm -f ${DEPENDS} ${OBJECTS} ${EXEC}
|
|
33
bin/Makefile
33
bin/Makefile
@ -1,33 +0,0 @@
|
|||||||
# Universal makefile for single C++ program
|
|
||||||
#
|
|
||||||
# Use gcc flag -MMD (user) or -MD (user/system) to generate dependencies among source files.
|
|
||||||
# Use make default rules for commonly used file-name suffixes and make variables names.
|
|
||||||
#
|
|
||||||
# % make [ a.out ]
|
|
||||||
|
|
||||||
########## Variables ##########
|
|
||||||
|
|
||||||
CXX = g++ # compiler
|
|
||||||
CXXFLAGS = -std=c++20 -g -Wall -MMD -O0 # compiler flags
|
|
||||||
MAKEFILE_NAME = ${firstword ${MAKEFILE_LIST}} # makefile name
|
|
||||||
|
|
||||||
SOURCES = $(wildcard ../src/*.cc) # source files (*.cc)
|
|
||||||
OBJECTS = ${SOURCES:.cc=.o} # object files forming executable
|
|
||||||
DEPENDS = ${OBJECTS:.o=.d} # substitute ".o" with ".d"
|
|
||||||
EXEC = cc3k # executable name
|
|
||||||
|
|
||||||
########## Targets ##########
|
|
||||||
|
|
||||||
.PHONY : clean # not file names
|
|
||||||
|
|
||||||
${EXEC} : ${OBJECTS} # link step
|
|
||||||
${CXX} ${CXXFLAGS} -O0 $^ -o $@ -lncurses # additional object files before $^
|
|
||||||
|
|
||||||
${OBJECTS} : ${MAKEFILE_NAME} # OPTIONAL : changes to this file => recompile
|
|
||||||
|
|
||||||
# make implicitly generates rules to compile C++ files that generate .o files
|
|
||||||
|
|
||||||
-include ${DEPENDS} # include *.d files containing program dependences
|
|
||||||
|
|
||||||
clean : # remove files that can be regenerated
|
|
||||||
rm -f ${DEPENDS} ${OBJECTS} ${EXEC}
|
|
@ -11,17 +11,17 @@ CXX = g++ # compiler
|
|||||||
CXXFLAGS = -std=c++20 -g -Wall -MMD -O0 # compiler flags
|
CXXFLAGS = -std=c++20 -g -Wall -MMD -O0 # compiler flags
|
||||||
MAKEFILE_NAME = ${firstword ${MAKEFILE_LIST}} # makefile name
|
MAKEFILE_NAME = ${firstword ${MAKEFILE_LIST}} # makefile name
|
||||||
|
|
||||||
SOURCES = $(wildcard *.cc) # source files (*.cc)
|
SOURCES = $(wildcard *.cc) $(wildcard */*.cc) # source files (*.cc)
|
||||||
OBJECTS = ${SOURCES:.cc=.o} # object files forming executable
|
OBJECTS = ${SOURCES:.cc=.o} # object files forming executable
|
||||||
DEPENDS = ${OBJECTS:.o=.d} # substitute ".o" with ".d"
|
DEPENDS = ${OBJECTS:.o=.d} # substitute ".o" with ".d"
|
||||||
EXEC = ../bin/cc3k # executable name
|
EXEC = cc3k # executable name
|
||||||
|
|
||||||
########## Targets ##########
|
########## Targets ##########
|
||||||
|
|
||||||
.PHONY : clean # not file names
|
.PHONY : clean # not file names
|
||||||
|
|
||||||
${EXEC} : ${OBJECTS} # link step
|
${EXEC} : ${OBJECTS} # link step
|
||||||
${CXX} ${CXXFLAGS} $^ -o $@ -lncurses # additional object files before $^
|
${CXX} ${CXXFLAGS} $^ -o $@ -lncurses # additional object files before $^
|
||||||
|
|
||||||
${OBJECTS} : ${MAKEFILE_NAME} # OPTIONAL : changes to this file => recompile
|
${OBJECTS} : ${MAKEFILE_NAME} # OPTIONAL : changes to this file => recompile
|
||||||
|
|
||||||
|
@ -5,19 +5,20 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "file_input.h"
|
|
||||||
#include "file_output.h"
|
#include "constants.h"
|
||||||
#include "console_input.h"
|
#include "input/file_input.h"
|
||||||
#include "console_output.h"
|
#include "display/file_output.h"
|
||||||
#include "curses_input.h"
|
#include "input/console_input.h"
|
||||||
#include "curses_output.h"
|
#include "display/console_output.h"
|
||||||
|
#include "input/curses_input.h"
|
||||||
|
#include "display/curses_output.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
|
|
||||||
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<display> &out,
|
std::unique_ptr<display> &out,
|
||||||
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;
|
||||||
@ -53,6 +54,8 @@ feature proc_args(int argc, char **argv,
|
|||||||
result |= FEATURE_EXTRA_STUFF;
|
result |= FEATURE_EXTRA_STUFF;
|
||||||
} else if (str == "-E") {
|
} else if (str == "-E") {
|
||||||
result |= FEATURE_EXTRA_LEVELS;
|
result |= FEATURE_EXTRA_LEVELS;
|
||||||
|
} else if (str == "-o") {
|
||||||
|
result |= FEATURE_WALK_OVER;
|
||||||
} else if (str == "-s") {
|
} else if (str == "-s") {
|
||||||
++i;
|
++i;
|
||||||
str = argv[i];
|
str = argv[i];
|
||||||
@ -62,15 +65,6 @@ feature proc_args(int argc, char **argv,
|
|||||||
|
|
||||||
seed = str;
|
seed = str;
|
||||||
result |= FEATURE_SEED;
|
result |= FEATURE_SEED;
|
||||||
} else if (str == "-L") {
|
|
||||||
++i;
|
|
||||||
str = argv[i];
|
|
||||||
|
|
||||||
if (!fn_lout.empty() && fn_lout != str)
|
|
||||||
return FEATURE_CONFLICT | i;
|
|
||||||
|
|
||||||
fn_lout = str;
|
|
||||||
result |= FEATURE_LOG;
|
|
||||||
} else if (str == "-I") {
|
} else if (str == "-I") {
|
||||||
++i;
|
++i;
|
||||||
str = argv[i];
|
str = argv[i];
|
||||||
@ -116,15 +110,6 @@ feature proc_args(int argc, char **argv,
|
|||||||
} 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) {
|
|
||||||
std::ofstream lout(fn_lout);
|
|
||||||
|
|
||||||
if (!lout.good())
|
|
||||||
return FEATURE_PANIC_FILE | FEATURE_LOG;
|
|
||||||
|
|
||||||
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.get());
|
in = std::make_unique<curses_input>(curse.get());
|
||||||
@ -167,10 +152,6 @@ void panic_args(feature panic) {
|
|||||||
cerr << "Cannot open specified output file!" << endl;
|
cerr << "Cannot open specified output file!" << endl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FEATURE_LOG:
|
|
||||||
cerr << "Cannot open specified log file!" << endl;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cerr << "Something must have went really, really, wrong..."
|
cerr << "Something must have went really, really, wrong..."
|
||||||
<< endl;
|
<< endl;
|
||||||
@ -184,20 +165,18 @@ void panic_args(feature panic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void print_args_list() {
|
void print_args_list() {
|
||||||
|
|
||||||
|
|
||||||
static const char *ARGS_LIST = "-n : Use ncurses for I/O\n\
|
static const char *ARGS_LIST = "-n : Use ncurses for I/O\n\
|
||||||
-r : Randomly generate maps\n\
|
-r : Randomly generate maps\n\
|
||||||
-m : Enabled a main menu + options\n\
|
-m : Enabled a main menu + options\n\
|
||||||
-c : Enemies chase the player (through doors and up stairs)\n\
|
-c : Enemies chase the player (through doors and up stairs)\n\
|
||||||
-C : Give things better coloring\n\
|
-C : Give things better coloring\n\
|
||||||
-i : Enable inventory\n\
|
-i : Enable inventory (player can walk on potions)\n\
|
||||||
-t : Enable throw\n\
|
-t : Enable throw\n\
|
||||||
-R : Enable revisiting levels\n\
|
-R : Enable revisiting levels\n\
|
||||||
-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 monsters to go over gold and potions\n\
|
||||||
-s [seed] : Sets initial seed to seed\n\
|
-s [seed] : Sets initial seed to seed\n\
|
||||||
-L [file] : Enable logging to file\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\
|
||||||
-h/--help : Displays options list (doesn't start a game)";
|
-h/--help : Displays options list (doesn't start a game)";
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
#ifndef __ARGUMENTS_H__
|
#ifndef __ARGUMENTS_H__
|
||||||
#define __ARGUMENTS_H__
|
#define __ARGUMENTS_H__
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "log.h"
|
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
|
|
||||||
#include "constants.h"
|
typedef unsigned int feature;
|
||||||
|
|
||||||
// IMPORTANT: Errors include the index that caused them (or'ed into them)
|
// IMPORTANT: Errors include the index that caused them (or'ed into them)
|
||||||
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<display> &out,
|
std::unique_ptr<display> &out,
|
||||||
std::unique_ptr<logger> &log,
|
|
||||||
std::unique_ptr<RNG> &rng);
|
std::unique_ptr<RNG> &rng);
|
||||||
|
|
||||||
void panic_args(feature panic);
|
void panic_args(feature panic);
|
||||||
|
@ -1,161 +1,47 @@
|
|||||||
#include "characters.h"
|
#include "characters.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "level.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
character::character(RNG *rng, const enum race &nrace, const position &pos):
|
character::character(RNG *rng, const feature enabled_features,
|
||||||
rng{rng}, race{nrace}, HP{STARTING_HP[race]},
|
const enum race &nrace, const position &pos):
|
||||||
|
rng{rng}, enabled_features{enabled_features},
|
||||||
|
race{nrace}, HP{STARTING_HP[race]}, pos{pos},
|
||||||
ATK{STARTING_ATK[race]}, DEF{STARTING_DEF[race]},
|
ATK{STARTING_ATK[race]}, DEF{STARTING_DEF[race]},
|
||||||
base_hit_rate{1, 1}, pos{pos} {}
|
base_hit_rate{1, 1}, base_hit_rate_reset{1, 1} {}
|
||||||
|
|
||||||
void character::start_turn() {
|
void character::start_turn() {
|
||||||
ATK = STARTING_ATK[race];
|
ATK = STARTING_ATK[race];
|
||||||
DEF = STARTING_DEF[race];
|
DEF = STARTING_DEF[race];
|
||||||
base_hit_rate = {1, 1};
|
base_hit_rate = base_hit_rate_reset;
|
||||||
}
|
|
||||||
|
|
||||||
void character::print(display *out, bool player) {
|
|
||||||
out->print_char(pos, player ? '@' : CHARACTER_REP[race],
|
|
||||||
player ? COLOR_PAIR(COLOR_BLUE) : COLOR_PAIR(COLOR_RED));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum race character::get_race() const {
|
enum race character::get_race() const {
|
||||||
return race;
|
return race;
|
||||||
}
|
}
|
||||||
|
|
||||||
position character::get_position() const {
|
position character::get_pos() const {
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
int character::get_HP() const {
|
void character::set_pos(const position &npos) {
|
||||||
return HP;
|
|
||||||
}
|
|
||||||
|
|
||||||
int character::get_ATK() const {
|
|
||||||
return ATK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int character::get_DEF() const {
|
|
||||||
return DEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
int character::get_gold() const {
|
|
||||||
return gold;
|
|
||||||
}
|
|
||||||
|
|
||||||
float character::get_hitrate_real() const {
|
|
||||||
return base_hit_rate.real();
|
|
||||||
}
|
|
||||||
|
|
||||||
fraction character::get_hitrate() const {
|
|
||||||
return base_hit_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
int character::get_room_num() const {
|
|
||||||
return room_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
<<< <<< < HEAD
|
|
||||||
== == == =
|
|
||||||
bool character::is_hostile() const {
|
|
||||||
return hostile;
|
|
||||||
}
|
|
||||||
|
|
||||||
>>> >>> > AL - races
|
|
||||||
void character::set_room_num(const int room) {
|
|
||||||
room_num = room;
|
|
||||||
}
|
|
||||||
|
|
||||||
void character::set_position(const position &npos) {
|
|
||||||
pos = npos;
|
pos = npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void character::set_HP(const int nHP) {
|
void character::apply_effect(potion *effect) {
|
||||||
HP = nHP;
|
insert_effect(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void character::set_ATK(const int nATK) {
|
void character::insert_effect(potion *effect) {
|
||||||
ATK = nATK;
|
effects.push_back(effect);
|
||||||
}
|
|
||||||
|
|
||||||
void character::set_DEF(const int nDEF) {
|
|
||||||
DEF = nDEF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void character::set_gold(const int ngold) {
|
|
||||||
gold = ngold;
|
|
||||||
}
|
|
||||||
|
|
||||||
void character::set_hitrate(const fraction nhitrate) {
|
|
||||||
base_hit_rate = nhitrate;
|
|
||||||
}
|
|
||||||
|
|
||||||
<<< <<< < HEAD
|
|
||||||
== == == =
|
|
||||||
void character::set_hostile(const bool is_hostile) {
|
|
||||||
hostile = is_hostile;
|
|
||||||
}
|
|
||||||
|
|
||||||
void character::apply_buff(const stat_name statn, const int amount) {
|
|
||||||
// TODO: add checks for bounds
|
|
||||||
switch (statn) {
|
|
||||||
case stat_name::HP:
|
|
||||||
HP += amount;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case stat_name::ATK:
|
|
||||||
ATK += amount;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case stat_name::DEF:
|
|
||||||
DEF += amount;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case stat_name::hostile: {
|
|
||||||
if (amount > 0)
|
|
||||||
hostile = true;
|
|
||||||
else
|
|
||||||
hostile = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
>>> >>> > AL - races
|
|
||||||
direction_list character::moveable(const position_list &available_positions)
|
|
||||||
const {
|
|
||||||
direction_list result;
|
|
||||||
|
|
||||||
for (int i = 0; i < DIRECTION_CNT; ++i)
|
|
||||||
if (find(available_positions, pos + MOVE[i])
|
|
||||||
!= available_positions.size())
|
|
||||||
result.push_back((direction)i);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
character::apply_result character::apply(const direction &dir,
|
|
||||||
potion_list &plist) {
|
|
||||||
for (size_t i = 0; i < plist.size(); ++i)
|
|
||||||
if (pos + MOVE[dir] == plist[i]->get_pos()) {
|
|
||||||
apply_result res{applied, plist[i]};
|
|
||||||
insert_potion(plist[i]);
|
|
||||||
plist.erase(plist.begin() + i);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {applied_nothing, nullptr};
|
|
||||||
}
|
|
||||||
|
|
||||||
void character::insert_potion(potion *p) {
|
|
||||||
effects.push_back(p);
|
|
||||||
|
|
||||||
for (int i = effects.size() - 1; i > 0; --i)
|
for (int i = effects.size() - 1; i > 0; --i)
|
||||||
if (p->get_priority() < effects[i - 1]->get_priority())
|
if (effect->get_priority() < effects[i - 1]->get_priority())
|
||||||
std::swap(effects[i], effects[i - 1]);
|
std::swap(effects[i], effects[i - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
result character::apply_effects() {
|
result character::calc_effects() {
|
||||||
potion_list tmp;
|
potion_list tmp;
|
||||||
tmp.reserve(effects.size());
|
tmp.reserve(effects.size());
|
||||||
|
|
||||||
@ -190,17 +76,28 @@ void character::discard_level_effects() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
long_result character::move(level *lvl,
|
||||||
const position_list &available_positions) {
|
const position &p) {
|
||||||
if (find(available_positions, pos + MOVE[dir])
|
if (lvl->is_available(p)) {
|
||||||
!= available_positions.size()) {
|
pos = p;
|
||||||
pos += MOVE[dir];
|
return {result::moved, ""};
|
||||||
return result::moved;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result::fine;
|
return {result::fine, ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
int character::calc_dmg(const int ATK, const int DEF) {
|
int calc_dmg(const int ATK, const int DEF) {
|
||||||
return ceil((100.0f / (100.0f + DEF)) * ATK);
|
return ceil((100.0f / (100.0f + DEF)) * ATK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
character *get_ch_at(const position &pos, const character_list &chlist) {
|
||||||
|
for (auto ch : chlist)
|
||||||
|
if (ch->get_pos() == pos)
|
||||||
|
return ch;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool character::is_dead() const {
|
||||||
|
return HP <= 0;
|
||||||
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "constants.h"
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "fraction.h"
|
#include "fraction.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
@ -13,62 +12,38 @@
|
|||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
|
|
||||||
class character; // forward declaration
|
class level;
|
||||||
|
typedef unsigned int feature;
|
||||||
// Note: player should not be in the character list
|
struct long_result;
|
||||||
|
enum result : int;
|
||||||
|
|
||||||
class character {
|
class character {
|
||||||
public:
|
public:
|
||||||
character(RNG *rng, const race &nrace,
|
character(RNG *rng, const feature enabled_features,
|
||||||
const position &pos); // fills out the starting stats
|
const race &nrace, const position &pos); // fills out the starting stats
|
||||||
|
|
||||||
// usually I wouldn't do this but considering that the map has
|
virtual long_result move(level *lvl, const position &p);
|
||||||
// a super small size an O(n) solution is acceptable
|
|
||||||
// IMPORTANT: available_positions do NOT have characters in them
|
|
||||||
direction_list moveable(const position_list &available_positions) const;
|
|
||||||
virtual result move(const direction dir,
|
|
||||||
const position_list &available_positions);
|
|
||||||
|
|
||||||
struct attack_result {
|
virtual long_result attack(character *ch) = 0;
|
||||||
result res;
|
virtual long_result get_hit(character *ch, const int tATK,
|
||||||
std::string msg;
|
const fraction &hit_rate) = 0;
|
||||||
};
|
|
||||||
|
|
||||||
struct apply_result {
|
virtual void apply_effect(potion *effect);
|
||||||
result res;
|
|
||||||
std::string msg;
|
|
||||||
};
|
|
||||||
virtual result move(position_list spots, const direction &dir);
|
|
||||||
|
|
||||||
virtual attack_result attack(const direction dir, character *ch) = 0;
|
// override for different types
|
||||||
|
virtual void print(display *out) = 0;
|
||||||
|
|
||||||
virtual apply_result apply(const direction &dir,
|
result calc_effects();
|
||||||
potion_list &potions);
|
|
||||||
virtual attack_result get_hit(const enum race &race, const int atk,
|
|
||||||
const fraction hitrate) = 0;
|
|
||||||
|
|
||||||
// overload for different races
|
|
||||||
virtual void print(display *out);
|
|
||||||
|
|
||||||
virtual result calc_effects();
|
|
||||||
void discard_level_effects();
|
void discard_level_effects();
|
||||||
virtual void start_turn();
|
virtual void start_turn();
|
||||||
|
|
||||||
|
virtual const char *get_race_name() const = 0;
|
||||||
enum race get_race() const;
|
enum race get_race() const;
|
||||||
position get_pos() const;
|
position get_pos() const;
|
||||||
|
virtual std::string get_abbrev() const = 0;
|
||||||
void set_pos(const position &npos);
|
void set_pos(const position &npos);
|
||||||
|
|
||||||
int get_HP() const;
|
bool is_dead() const;
|
||||||
int get_ATK() const;
|
|
||||||
int get_DEF() const;
|
|
||||||
fraction get_hitrate() const;
|
|
||||||
int get_room_num() const;
|
|
||||||
void set_HP(const int nHP);
|
|
||||||
void set_ATK(const int nATK);
|
|
||||||
void set_DEF(const int nDEF);
|
|
||||||
void set_hitrate(const fraction nhitrate);
|
|
||||||
void set_room_num(const int room);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RNG *rng;
|
RNG *rng;
|
||||||
@ -79,18 +54,22 @@ protected:
|
|||||||
int HP;
|
int HP;
|
||||||
position pos;
|
position pos;
|
||||||
|
|
||||||
// IMPORTANT: keep track of ATK and DEF in game at turn time
|
// IMPORTANT: keep track at turn time
|
||||||
int ATK;
|
int ATK;
|
||||||
int DEF;
|
int DEF;
|
||||||
fraction base_hit_rate;
|
fraction base_hit_rate;
|
||||||
|
fraction base_hit_rate_reset;
|
||||||
|
|
||||||
potion_list effects;
|
potion_list effects;
|
||||||
|
|
||||||
int calc_dmg(const int ATK, const int DEF);
|
|
||||||
private:
|
private:
|
||||||
void insert_effect(potion *effect);
|
void insert_effect(potion *effect);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int calc_dmg(const int ATK, const int DEF);
|
||||||
|
|
||||||
typedef std::vector<character *> character_list;
|
typedef std::vector<character *> character_list;
|
||||||
|
|
||||||
|
character *get_ch_at(const position &pos, const character_list &chlist);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
#include "console_input.h"
|
|
||||||
#include <utility>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
console_input::console_input(std::istream &cin):
|
|
||||||
in{cin} {}
|
|
||||||
|
|
||||||
game_command console_input::get_command() {
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (in.eof())
|
|
||||||
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;
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#ifndef __CONSOLE_INPUT_H__
|
|
||||||
#define __CONSOLE_INPUT_H__
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
class console_input final : public input {
|
|
||||||
private:
|
|
||||||
std::istream ∈
|
|
||||||
public:
|
|
||||||
// This is for cin
|
|
||||||
console_input(std::istream &cin);
|
|
||||||
game_command get_command() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,98 +0,0 @@
|
|||||||
#include "console_output.h"
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
#include <ncurses.h>
|
|
||||||
|
|
||||||
console_output::console_output(std::ostream &cout): out{cout} {}
|
|
||||||
|
|
||||||
/* Attributes
|
|
||||||
black 30 40
|
|
||||||
red 31 41
|
|
||||||
green 32 42
|
|
||||||
yellow 33 43
|
|
||||||
blue 34 44
|
|
||||||
magenta 35 45
|
|
||||||
cyan 36 46
|
|
||||||
white 37 47
|
|
||||||
reset 0 (everything back to normal)
|
|
||||||
bold/bright 1 (often a brighter shade of the same colour)
|
|
||||||
underline 4
|
|
||||||
inverse 7 (swap foreground and background colours)
|
|
||||||
bold/bright off 21
|
|
||||||
underline off 24
|
|
||||||
inverse off 27
|
|
||||||
|
|
||||||
Format:
|
|
||||||
\033[X;Ym
|
|
||||||
X Y are numbers from above
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::string console_output::get_code(const int attrs) {
|
|
||||||
if (attrs < 255)
|
|
||||||
return "\033[0m";
|
|
||||||
|
|
||||||
std::string result = "\033[0m\033[";
|
|
||||||
|
|
||||||
if (attrs & A_BOLD)
|
|
||||||
result += "1;";
|
|
||||||
|
|
||||||
if (attrs & A_UNDERLINE)
|
|
||||||
result += "4;";
|
|
||||||
|
|
||||||
if (attrs & A_STANDOUT)
|
|
||||||
result += "7;";
|
|
||||||
|
|
||||||
if ((attrs & COLOR_PAIR(COLOR_WHITE)) == COLOR_PAIR(COLOR_WHITE))
|
|
||||||
result += "37;";
|
|
||||||
else if ((attrs & COLOR_PAIR(COLOR_CYAN)) == COLOR_PAIR(COLOR_CYAN))
|
|
||||||
result += "36;";
|
|
||||||
else if ((attrs & COLOR_PAIR(COLOR_MAGENTA)) == COLOR_PAIR(COLOR_MAGENTA))
|
|
||||||
result += "35;";
|
|
||||||
else if ((attrs & COLOR_PAIR(COLOR_BLUE)) == COLOR_PAIR(COLOR_BLUE))
|
|
||||||
result += "34;";
|
|
||||||
else if ((attrs & COLOR_PAIR(COLOR_YELLOW)) == COLOR_PAIR(COLOR_YELLOW))
|
|
||||||
result += "33;";
|
|
||||||
else if ((attrs & COLOR_PAIR(COLOR_RED)) == COLOR_PAIR(COLOR_RED))
|
|
||||||
result += "31;";
|
|
||||||
else if ((attrs & COLOR_PAIR(COLOR_GREEN)) == COLOR_PAIR(COLOR_GREEN))
|
|
||||||
result += "32;";
|
|
||||||
else if ((attrs & COLOR_PAIR(COLOR_BLACK_ON_WHITE)) == COLOR_BLACK_ON_WHITE)
|
|
||||||
result += "30;47;";
|
|
||||||
|
|
||||||
result[result.length() - 1] = 'm';
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void console_output::render() {
|
|
||||||
out << "\x1B[2J\x1B[H";
|
|
||||||
|
|
||||||
for (std::size_t idx = 0; idx < contents.size(); ++idx) {
|
|
||||||
if (idx % DISPLAY_WIDTH == 0 && idx)
|
|
||||||
out << std::endl;
|
|
||||||
|
|
||||||
out << get_code(contents[idx])
|
|
||||||
<< (char)(contents[idx] ? contents[idx] : ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
out << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void console_output::print_char(const position &pos, const char ch,
|
|
||||||
const int attrs) {
|
|
||||||
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
contents[pos.y * DISPLAY_WIDTH + pos.x] = attrs | ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void console_output::print_str(const position &pos, const std::string &str,
|
|
||||||
const int attrs) {
|
|
||||||
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int head = pos.y * DISPLAY_WIDTH + pos.x;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < str.length(); ++i)
|
|
||||||
contents[i + head] = attrs | str[i];
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
#ifndef __CONSOLE_OUTPUT_H__
|
|
||||||
#define __CONSOLE_OUTPUT_H__
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
class console_output final : public display {
|
|
||||||
private:
|
|
||||||
std::ostream &out;
|
|
||||||
std::string get_code(const int attrs);
|
|
||||||
public:
|
|
||||||
console_output(std::ostream &cout);
|
|
||||||
|
|
||||||
void render() override;
|
|
||||||
void print_char(const position &pos,
|
|
||||||
const char ch, const int attrs) override;
|
|
||||||
void print_str(const position &pos,
|
|
||||||
const std::string &str, const int attrs) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
184
src/constants.h
184
src/constants.h
@ -2,101 +2,102 @@
|
|||||||
#define __CONSTANTS_H__
|
#define __CONSTANTS_H__
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <ncurses.h>
|
#include <ncurses.h>
|
||||||
|
#include <string>
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
|
|
||||||
const int INF = 0x3F3F3F3F;
|
static const int INF = 0x3F3F3F3F;
|
||||||
|
|
||||||
enum error {none};
|
|
||||||
|
|
||||||
// TODO: update result to include subject
|
// TODO: update result to include subject
|
||||||
// fine will waste a turn
|
// fine will waste a turn
|
||||||
enum result {fine, died, go_down, go_up, hit, moved,
|
enum result : int {fine, died, go_down, go_up, hit, moved,
|
||||||
miss, terminate, applied, applied_nothing,
|
miss, terminate, applied, applied_nothing,
|
||||||
toggle_the_world, restart_game, unknown
|
toggle_the_world, restart_game, unknown
|
||||||
};
|
|
||||||
|
|
||||||
enum game_status {terminated, main_menu, in_game, options,
|
|
||||||
dead, won, escaped, restart
|
|
||||||
};
|
|
||||||
|
|
||||||
enum game_command {game_command_terminate = 0,
|
|
||||||
move_north, move_south, move_east, move_west,
|
|
||||||
move_northeast, move_northwest,
|
|
||||||
move_southeast, move_southwest,
|
|
||||||
apply_north, apply_south, apply_east, apply_west,
|
|
||||||
apply_northeast, apply_northwest,
|
|
||||||
apply_southeast, apply_southwest,
|
|
||||||
apply_panic, // for curses_input specifically
|
|
||||||
attack_north, attack_south, attack_east, attack_west,
|
|
||||||
attack_northeast, attack_northwest,
|
|
||||||
attack_southeast, attack_southwest,
|
|
||||||
up_stairs, down_stairs,
|
|
||||||
the_world, game_restart,
|
|
||||||
game_command_pass, game_command_panic
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Character generation related
|
struct long_result {
|
||||||
const int RACE_CNT = 12;
|
result res;
|
||||||
enum race {rshade = 0, rdrow, rvampire, rtroll,
|
std::string msg;
|
||||||
rgoblin, rhuman, rdwarf, relf,
|
|
||||||
rorc, rmerchant, rdragon, rhalfling
|
|
||||||
};
|
|
||||||
const char *RACE_NAME[RACE_CNT] = {
|
|
||||||
"Shade", "Drow", "Vampire", "Troll",
|
|
||||||
"Goblin", "Human", "Dwarf", "Elf",
|
|
||||||
"Orc", "Merchant", "Dragon", "Halfling"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const int MAX_HP[RACE_CNT] = {
|
enum game_status : int {terminated, main_menu, in_game, options,
|
||||||
|
dead, won, escaped, restart, skip_turn
|
||||||
|
};
|
||||||
|
|
||||||
|
enum game_command : int {game_command_terminate = 0,
|
||||||
|
move_north, move_south, move_east, move_west,
|
||||||
|
move_northeast, move_northwest,
|
||||||
|
move_southeast, move_southwest,
|
||||||
|
apply_north, apply_south, apply_east, apply_west,
|
||||||
|
apply_northeast, apply_northwest,
|
||||||
|
apply_southeast, apply_southwest,
|
||||||
|
apply_panic, // for curses_input specifically
|
||||||
|
attack_north, attack_south, attack_east, attack_west,
|
||||||
|
attack_northeast, attack_northwest,
|
||||||
|
attack_southeast, attack_southwest,
|
||||||
|
up_stairs, down_stairs,
|
||||||
|
the_world, game_restart,
|
||||||
|
game_command_pass, game_command_panic,
|
||||||
|
enter
|
||||||
|
};
|
||||||
|
|
||||||
|
// Character generation related
|
||||||
|
static const int RACE_CNT = 12;
|
||||||
|
enum race : int {rshade = 0, rdrow, rvampire, rtroll,
|
||||||
|
rgoblin, rhuman, rdwarf, relf,
|
||||||
|
rorc, rmerchant, rdragon, rhalfling
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char CHAR_REP[RACE_CNT] = {
|
||||||
|
's', 'd', 'v', 't', 'g', 'H', 'W', 'E', 'O', 'M', 'D', 'L'
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int MAX_HP[RACE_CNT] = {
|
||||||
125, 150, INF, 120, 110, 140, 100, 140, 180, 30, 150, 100
|
125, 150, INF, 120, 110, 140, 100, 140, 180, 30, 150, 100
|
||||||
};
|
};
|
||||||
const int STARTING_HP[RACE_CNT] = {
|
static const int STARTING_HP[RACE_CNT] = {
|
||||||
125, 150, 50, 120, 110, 140, 100, 140, 180, 30, 150, 100
|
125, 150, 50, 120, 110, 140, 100, 140, 180, 30, 150, 100
|
||||||
};
|
};
|
||||||
const int STARTING_ATK[RACE_CNT] = {
|
static const int STARTING_ATK[RACE_CNT] = {
|
||||||
25, 25, 25, 25, 15, 20, 20, 30, 30, 70, 20, 15
|
25, 25, 25, 25, 15, 20, 20, 30, 30, 70, 20, 15
|
||||||
};
|
};
|
||||||
const int STARTING_DEF[RACE_CNT] = {
|
static const int STARTING_DEF[RACE_CNT] = {
|
||||||
25, 15, 25, 15, 20, 20, 30, 10, 25, 5, 20, 20
|
25, 15, 25, 15, 20, 20, 30, 10, 25, 5, 20, 20
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Potion-related
|
// Potion-related
|
||||||
const int POTION_TYPE_CNT = 6;
|
static const int POTION_TYPE_CNT = 6;
|
||||||
const int DEFAULT_POTION_TYPE_CNT = 6;
|
static const int DEFAULT_POTION_TYPE_CNT = 6;
|
||||||
enum potion_type {restore_health = 0, boost_atk, boost_def,
|
enum potion_type : int {restore_health = 0, boost_atk, boost_def,
|
||||||
poison_health, wound_atk, wound_def
|
poison_health, wound_atk, wound_def
|
||||||
};
|
};
|
||||||
const char *POTION_REAL_NAME[POTION_TYPE_CNT] = {
|
|
||||||
"RH", "BA", "BD", "PH", "WA", "WD"
|
|
||||||
};
|
|
||||||
|
|
||||||
// Calculation priorities
|
// Calculation priorities
|
||||||
const int CALC_ADD_BASE = 0;
|
static const int CALC_ADD_BASE = 0;
|
||||||
const int CALC_MUL_BASE = 1;
|
static const int CALC_MUL_BASE = 1;
|
||||||
const int CALC_ADD_LATER = 2;
|
static const int CALC_ADD_LATER = 2;
|
||||||
const int CALC_MUL_LATER = 3;
|
static const int CALC_MUL_LATER = 3;
|
||||||
const int CALC_ADD_FIXED = 4;
|
static const int CALC_ADD_FIXED = 4;
|
||||||
|
|
||||||
|
|
||||||
const int DIRECTION_CNT = 8;
|
static 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
|
||||||
enum direction { north = 0, south, east, west, northeast,
|
enum direction : int { north = 0, south, east, west, northeast,
|
||||||
northwest, southeast, southwest
|
northwest, southeast, southwest
|
||||||
};
|
};
|
||||||
|
|
||||||
const position MOVE[DIRECTION_CNT] = {
|
static 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;
|
static const int MAP_HEIGHT = 25;
|
||||||
const int MAP_WIDTH = 79;
|
static const int MAP_WIDTH = 79;
|
||||||
const int DISPLAY_HEIGHT = 30;
|
static const int DISPLAY_HEIGHT = 30;
|
||||||
const int DISPLAY_WIDTH = 79;
|
static const int DISPLAY_WIDTH = 79;
|
||||||
const int DISPLAY_BUFFER_SIZE = DISPLAY_HEIGHT * DISPLAY_WIDTH +
|
static const int DISPLAY_BUFFER_SIZE = DISPLAY_HEIGHT * DISPLAY_WIDTH +
|
||||||
DISPLAY_WIDTH * 3;
|
DISPLAY_WIDTH * 3;
|
||||||
|
|
||||||
// TODO: list all extra features
|
// TODO: list all extra features
|
||||||
// using constants to keep track of features
|
// using constants to keep track of features
|
||||||
@ -105,38 +106,35 @@ const int DISPLAY_BUFFER_SIZE = DISPLAY_HEIGHT * DISPLAY_WIDTH +
|
|||||||
// check if feature is enabled:
|
// check if feature is enabled:
|
||||||
// features & FEATURE_XXX
|
// features & FEATURE_XXX
|
||||||
typedef unsigned int feature; // can extend to unsigned long (long) if needed
|
typedef unsigned int feature; // can extend to unsigned long (long) if needed
|
||||||
const feature FEATURE_NCURSES = 1 << 0;
|
static const feature FEATURE_NCURSES = 1 << 0;
|
||||||
const feature FEATURE_RAND_MAP = 1 << 1;
|
static const feature FEATURE_RAND_MAP = 1 << 1;
|
||||||
const feature FEATURE_ENEMIES_CHASE = 1 << 2;
|
static const feature FEATURE_ENEMIES_CHASE = 1 << 2;
|
||||||
const feature FEATURE_INVENTORY = 1 << 3;
|
static const feature FEATURE_INVENTORY = 1 << 3;
|
||||||
const feature FEATURE_THROW = 1 << 4;
|
static const feature FEATURE_THROW = 1 << 4;
|
||||||
const feature FEATURE_REVISIT = 1 << 5;
|
static const feature FEATURE_REVISIT = 1 << 5;
|
||||||
const feature FEATURE_LOG = 1 << 6;
|
static const feature FEATURE_WALK_OVER = 1 << 6;
|
||||||
const feature FEATURE_SEED = 1 << 7;
|
static const feature FEATURE_SEED = 1 << 7;
|
||||||
const feature FEATURE_MENU = 1 << 8;
|
static const feature FEATURE_MENU = 1 << 8;
|
||||||
const feature FEATURE_IN_FILE = 1 << 9;
|
static const feature FEATURE_IN_FILE = 1 << 9;
|
||||||
const feature FEATURE_OUT_FILE = 1 << 10;
|
static const feature FEATURE_OUT_FILE = 1 << 10;
|
||||||
const feature FEATURE_EXTRA_STUFF = 1 << 11;
|
static const feature FEATURE_EXTRA_STUFF = 1 << 11;
|
||||||
const feature FEATURE_EXTRA_LEVELS = 1 << 12;
|
static const feature FEATURE_EXTRA_LEVELS = 1 << 12;
|
||||||
const feature FEATURE_COLORFUL = 1 << 13;
|
static const feature FEATURE_COLORFUL = 1 << 13;
|
||||||
|
|
||||||
const feature FEATURE_PANIC_SEED = 1 << 27;
|
static const feature FEATURE_PANIC_SEED = 1 << 27;
|
||||||
const feature FEATURE_PANIC_FILE = 1 << 28;
|
static const feature FEATURE_PANIC_FILE = 1 << 28;
|
||||||
const feature FEATURE_PANIC = 1 << 29;
|
static const feature FEATURE_PANIC = 1 << 29;
|
||||||
const feature FEATURE_CONFLICT = 1 << 30;
|
static const feature FEATURE_CONFLICT = 1 << 30;
|
||||||
const feature FEATURE_LIST_ARGS = 1 << 31;
|
static const feature FEATURE_LIST_ARGS = 1 << 31;
|
||||||
|
|
||||||
const int RETURN_FINE = 0;
|
static const int RETURN_FINE = 0;
|
||||||
const int RETURN_PANICKED = 1;
|
static const int RETURN_PANICKED = 1;
|
||||||
|
|
||||||
const int COLOR_BLACK_ON_WHITE = 8;
|
static const int COLOR_BLACK_ON_WHITE = 8;
|
||||||
|
|
||||||
typedef std::vector<position> position_list;
|
static const int GOLD_SMALL = 1;
|
||||||
typedef std::vector<direction> direction_list;
|
static const int GOLD_NORMAL = 2;
|
||||||
|
static const int GOLD_MERCHANT = 4;
|
||||||
const int GOLD_SMALL = 1;
|
static const int GOLD_DRAGON = 6;
|
||||||
const int GOLD_NORMAL = 2;
|
|
||||||
const int GOLD_MERCHANT = 4;
|
|
||||||
const int GOLD_DRAGON = 6;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
#include "curses_input.h"
|
|
||||||
|
|
||||||
curses_input::curses_input(cursor *new_curse):
|
|
||||||
curse{new_curse} {}
|
|
||||||
|
|
||||||
game_command curses_input::get_command() {
|
|
||||||
switch (curse->getcmd()) {
|
|
||||||
case 'h':
|
|
||||||
return game_command::move_west;
|
|
||||||
|
|
||||||
case 'j':
|
|
||||||
return game_command::move_south;
|
|
||||||
|
|
||||||
case 'k':
|
|
||||||
return game_command::move_north;
|
|
||||||
|
|
||||||
case 'l':
|
|
||||||
return game_command::move_east;
|
|
||||||
|
|
||||||
case 'y':
|
|
||||||
return game_command::move_northwest;
|
|
||||||
|
|
||||||
case 'u':
|
|
||||||
return game_command::move_northeast;
|
|
||||||
|
|
||||||
case 'b':
|
|
||||||
return game_command::move_southwest;
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
return game_command::move_southeast;
|
|
||||||
|
|
||||||
case 'a':
|
|
||||||
break; // wait for another command
|
|
||||||
|
|
||||||
case '<':
|
|
||||||
return game_command::up_stairs;
|
|
||||||
|
|
||||||
case '>':
|
|
||||||
return game_command::down_stairs;
|
|
||||||
|
|
||||||
case 'q':
|
|
||||||
return game_command_terminate;
|
|
||||||
|
|
||||||
case 'f':
|
|
||||||
return game_command::the_world;
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
return game_restart;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return game_command_pass;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (curse->getcmd()) {
|
|
||||||
case 'h':
|
|
||||||
return game_command::apply_west;
|
|
||||||
|
|
||||||
case 'j':
|
|
||||||
return game_command::apply_south;
|
|
||||||
|
|
||||||
case 'k':
|
|
||||||
return game_command::apply_north;
|
|
||||||
|
|
||||||
case 'l':
|
|
||||||
return game_command::apply_east;
|
|
||||||
|
|
||||||
case 'y':
|
|
||||||
return game_command::apply_northwest;
|
|
||||||
|
|
||||||
case 'u':
|
|
||||||
return game_command::apply_northeast;
|
|
||||||
|
|
||||||
case 'b':
|
|
||||||
return game_command::apply_southwest;
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
return game_command::apply_southeast;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return game_command::apply_panic;
|
|
||||||
}
|
|
||||||
|
|
||||||
return game_command::game_command_panic;
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
#ifndef __CURSES_OUTPUT_H__
|
|
||||||
#define __CURSES_OUTPUT_H__
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
#include "cursor.h"
|
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
class curses_output final : public display {
|
|
||||||
private:
|
|
||||||
cursor *curse;
|
|
||||||
public:
|
|
||||||
curses_output(cursor *new_curse);
|
|
||||||
|
|
||||||
void render() override;
|
|
||||||
void clear() override;
|
|
||||||
void print_char(const position &pos,
|
|
||||||
const char ch, const int attrs) override;
|
|
||||||
void print_str(const position &pos,
|
|
||||||
const std::string &str, const int attrs) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,15 +1,17 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
#include "constants.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);
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
#ifndef __DISPLAY_H__
|
#ifndef __DISPLAY_H__
|
||||||
#define __DISPLAY_H__
|
#define __DISPLAY_H__
|
||||||
|
|
||||||
|
#include <ncurses.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "constants.h"
|
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
|
|
||||||
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
|
||||||
|
100
src/display/console_output.cc
Normal file
100
src/display/console_output.cc
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include "console_output.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
console_output::console_output(std::ostream &cout): out{cout} {}
|
||||||
|
|
||||||
|
/* Attributes
|
||||||
|
black 30 40
|
||||||
|
red 31 41
|
||||||
|
green 32 42
|
||||||
|
yellow 33 43
|
||||||
|
blue 34 44
|
||||||
|
magenta 35 45
|
||||||
|
cyan 36 46
|
||||||
|
white 37 47
|
||||||
|
reset 0 (everything back to normal)
|
||||||
|
bold/bright 1 (often a brighter shade of the same colour)
|
||||||
|
underline 4
|
||||||
|
inverse 7 (swap foreground and background colours)
|
||||||
|
bold/bright off 21
|
||||||
|
underline off 24
|
||||||
|
inverse off 27
|
||||||
|
|
||||||
|
Format:
|
||||||
|
\033[X;Ym
|
||||||
|
X Y are numbers from above
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::string console_output::get_code(const int attrs) {
|
||||||
|
if (attrs < 255)
|
||||||
|
return "\033[0m";
|
||||||
|
|
||||||
|
std::string result = "\033[0m\033[";
|
||||||
|
|
||||||
|
if (attrs & A_BOLD)
|
||||||
|
result += "1;";
|
||||||
|
|
||||||
|
if (attrs & A_UNDERLINE)
|
||||||
|
result += "4;";
|
||||||
|
|
||||||
|
if (attrs & A_STANDOUT)
|
||||||
|
result += "7;";
|
||||||
|
|
||||||
|
if ((attrs & COLOR_PAIR(COLOR_WHITE)) == COLOR_PAIR(COLOR_WHITE))
|
||||||
|
result += "37;";
|
||||||
|
else if ((attrs & COLOR_PAIR(COLOR_CYAN)) == COLOR_PAIR(COLOR_CYAN))
|
||||||
|
result += "36;";
|
||||||
|
else if ((attrs & COLOR_PAIR(COLOR_MAGENTA)) == COLOR_PAIR(COLOR_MAGENTA))
|
||||||
|
result += "35;";
|
||||||
|
else if ((attrs & COLOR_PAIR(COLOR_BLUE)) == COLOR_PAIR(COLOR_BLUE))
|
||||||
|
result += "34;";
|
||||||
|
else if ((attrs & COLOR_PAIR(COLOR_YELLOW)) == COLOR_PAIR(COLOR_YELLOW))
|
||||||
|
result += "33;";
|
||||||
|
else if ((attrs & COLOR_PAIR(COLOR_RED)) == COLOR_PAIR(COLOR_RED))
|
||||||
|
result += "31;";
|
||||||
|
else if ((attrs & COLOR_PAIR(COLOR_GREEN)) == COLOR_PAIR(COLOR_GREEN))
|
||||||
|
result += "32;";
|
||||||
|
else if ((attrs & COLOR_PAIR(COLOR_BLACK_ON_WHITE)) == COLOR_BLACK_ON_WHITE)
|
||||||
|
result += "30;47;";
|
||||||
|
|
||||||
|
result[result.length() - 1] = 'm';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_output::render() {
|
||||||
|
out << "\x1B[2J\x1B[H";
|
||||||
|
|
||||||
|
for (std::size_t idx = 0; idx < contents.size(); ++idx) {
|
||||||
|
if (idx % DISPLAY_WIDTH == 0 && idx)
|
||||||
|
out << std::endl;
|
||||||
|
|
||||||
|
out << get_code(contents[idx])
|
||||||
|
<< (char)(contents[idx] ? contents[idx] : ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_output::print_char(const position &pos, const char ch,
|
||||||
|
const int attrs) {
|
||||||
|
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
contents[pos.y * DISPLAY_WIDTH + pos.x] = attrs | ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void console_output::print_str(const position &pos, const std::string &str,
|
||||||
|
const int attrs) {
|
||||||
|
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int head = pos.y * DISPLAY_WIDTH + pos.x;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < str.length(); ++i)
|
||||||
|
contents[i + head] = attrs | str[i];
|
||||||
|
}
|
21
src/display/console_output.h
Normal file
21
src/display/console_output.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef __CONSOLE_OUTPUT_H__
|
||||||
|
#define __CONSOLE_OUTPUT_H__
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "../display.h"
|
||||||
|
|
||||||
|
class console_output final : public display {
|
||||||
|
private:
|
||||||
|
std::ostream &out;
|
||||||
|
std::string get_code(const int attrs);
|
||||||
|
public:
|
||||||
|
console_output(std::ostream &cout);
|
||||||
|
|
||||||
|
void render() override;
|
||||||
|
void print_char(const position &pos,
|
||||||
|
const char ch, const int attrs) override;
|
||||||
|
void print_str(const position &pos,
|
||||||
|
const std::string &str, const int attrs) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,5 +1,7 @@
|
|||||||
#include "curses_output.h"
|
#include "curses_output.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
curses_output::curses_output(cursor *new_curse):
|
curses_output::curses_output(cursor *new_curse):
|
||||||
curse{new_curse} {}
|
curse{new_curse} {}
|
||||||
|
|
||||||
@ -13,24 +15,24 @@ void curses_output::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};
|
||||||
}
|
}
|
||||||
}
|
}
|
23
src/display/curses_output.h
Normal file
23
src/display/curses_output.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef __CURSES_OUTPUT_H__
|
||||||
|
#define __CURSES_OUTPUT_H__
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <memory>
|
||||||
|
#include "../cursor.h"
|
||||||
|
#include "../display.h"
|
||||||
|
|
||||||
|
class curses_output final : public display {
|
||||||
|
private:
|
||||||
|
cursor *curse;
|
||||||
|
public:
|
||||||
|
curses_output(cursor *new_curse);
|
||||||
|
|
||||||
|
void render() override;
|
||||||
|
void clear() override;
|
||||||
|
void print_char(const position &pos,
|
||||||
|
const char ch, const int attrs) override;
|
||||||
|
void print_str(const position &pos,
|
||||||
|
const std::string &str, const int attrs) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
38
src/display/file_output.cc
Normal file
38
src/display/file_output.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "file_output.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
file_output::file_output(std::ofstream &&ofs):
|
||||||
|
out{std::move(ofs)} {}
|
||||||
|
|
||||||
|
void file_output::render() {
|
||||||
|
for (std::size_t idx = 0; idx < contents.size(); ++idx) {
|
||||||
|
if (idx % DISPLAY_WIDTH == 0 && idx)
|
||||||
|
out << std::endl;
|
||||||
|
|
||||||
|
out << (char)(contents[idx] ? contents[idx] : ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
out << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_output::print_char(const position &pos, const char ch,
|
||||||
|
const int attrs) {
|
||||||
|
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
contents[pos.y * DISPLAY_WIDTH + pos.x] = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_output::print_str(const position &pos, const std::string &str,
|
||||||
|
const int attrs) {
|
||||||
|
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int head = pos.y * DISPLAY_WIDTH + pos.x;
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < str.length(); ++i)
|
||||||
|
contents[i + head] = str[i];
|
||||||
|
}
|
20
src/display/file_output.h
Normal file
20
src/display/file_output.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef __FILE_OUTPUT_H__
|
||||||
|
#define __FILE_OUTPUT_H__
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include "../display.h"
|
||||||
|
|
||||||
|
class file_output final : public display {
|
||||||
|
private:
|
||||||
|
std::ofstream out;
|
||||||
|
public:
|
||||||
|
file_output(std::ofstream &&ofs);
|
||||||
|
|
||||||
|
void render() override;
|
||||||
|
void print_char(const position &pos,
|
||||||
|
const char ch, const int attrs) override;
|
||||||
|
void print_str(const position &pos,
|
||||||
|
const std::string &str, const int attrs) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -1,34 +0,0 @@
|
|||||||
#include "dragon.h"
|
|
||||||
|
|
||||||
dragon::dragon(RNG *rng, const position &pos):
|
|
||||||
character{rng, race::rdragon, pos} {
|
|
||||||
gold = 0;
|
|
||||||
hostile = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
result dragon::attack(const direction dir, character_list &chlist) {
|
|
||||||
position tmp{pos + MOVE[dir]};
|
|
||||||
|
|
||||||
for (auto &ch : chlist)
|
|
||||||
if (tmp == ch->get_position()) {
|
|
||||||
return ch->get_hit(race, ATK, base_hit_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result::fine;
|
|
||||||
}
|
|
||||||
|
|
||||||
result dragon::get_hit(const enum race &race, const int atk,
|
|
||||||
const fraction hitrate) {
|
|
||||||
if (rng->trial(hitrate)) // This is a hit!
|
|
||||||
HP = std::max(HP - calc_dmg(atk, DEF), 0);
|
|
||||||
|
|
||||||
if (HP == 0)
|
|
||||||
return result::died;
|
|
||||||
|
|
||||||
return result::hit;
|
|
||||||
}
|
|
||||||
|
|
||||||
result dragon::move(const direction dir,
|
|
||||||
const position_list &available_positions) {
|
|
||||||
return result::fine;
|
|
||||||
}
|
|
17
src/dragon.h
17
src/dragon.h
@ -1,17 +0,0 @@
|
|||||||
#ifndef __DRAGON_H__
|
|
||||||
#define __DRAGON_H__
|
|
||||||
|
|
||||||
#include "characters.h"
|
|
||||||
|
|
||||||
class dragon final: public character {
|
|
||||||
public:
|
|
||||||
dragon(RNG *rng, const position &pos);
|
|
||||||
virtual result attack(const direction dir,
|
|
||||||
character_list &chlist) override;
|
|
||||||
virtual result get_hit(const enum race &race, const int atk,
|
|
||||||
const fraction hit_rate) override;
|
|
||||||
virtual result move(const direction dir,
|
|
||||||
const position_list &avilable_positions) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
31
src/drow.cc
31
src/drow.cc
@ -1,31 +0,0 @@
|
|||||||
#include "drow.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
drow::drow(RNG *rng, const position &pos):
|
|
||||||
character{rng, race::rdrow, pos} {
|
|
||||||
gold = 0;
|
|
||||||
hostile = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
result drow::attack(const direction dir, character_list &chlist) {
|
|
||||||
position tmp{pos + MOVE[dir]};
|
|
||||||
|
|
||||||
for (auto &ch : chlist)
|
|
||||||
if (tmp == ch->get_position()) {
|
|
||||||
return ch->get_hit(race, ATK, base_hit_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result::fine;
|
|
||||||
}
|
|
||||||
|
|
||||||
result drow::get_hit(const enum race &race, const int atk,
|
|
||||||
const fraction hitrate) {
|
|
||||||
if (rng->trial(hitrate))
|
|
||||||
HP = std::max(HP - calc_dmg(atk, DEF), 0);
|
|
||||||
|
|
||||||
if (HP == 0)
|
|
||||||
return result::died;
|
|
||||||
|
|
||||||
return result::hit;
|
|
||||||
}
|
|
15
src/drow.h
15
src/drow.h
@ -1,15 +0,0 @@
|
|||||||
#ifndef __DROW_H__
|
|
||||||
#define __DROW_H__
|
|
||||||
#include "characters.h"
|
|
||||||
|
|
||||||
class drow final: public character {
|
|
||||||
public:
|
|
||||||
drow(RNG *rng,
|
|
||||||
const position &pos);
|
|
||||||
virtual result attack(const direction dir,
|
|
||||||
character_list &chlist) override;
|
|
||||||
virtual result get_hit(const enum race &race, const int atk,
|
|
||||||
const fraction hit_rate) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,20 +1,85 @@
|
|||||||
#include "enemies.h"
|
#include "enemies.h"
|
||||||
|
|
||||||
// TODO: implement after characters
|
#include "constants.h"
|
||||||
void new_enemy(RNG *rng, std::unique_ptr<character> &pch, const position &pos,
|
#include "enemies/dragon.h"
|
||||||
bool extras) {
|
#include "enemies/dwarf.h"
|
||||||
if (extras) {
|
#include "enemies/elf.h"
|
||||||
|
#include "enemies/halfling.h"
|
||||||
|
#include "enemies/human.h"
|
||||||
|
#include "enemies/merchant.h"
|
||||||
|
#include "enemies/orc.h"
|
||||||
|
|
||||||
} else {
|
void new_dragon(RNG *rng, std::unique_ptr<enemy_base> &p,
|
||||||
}
|
const position &pos, const position &fallback,
|
||||||
}
|
const feature enabled_features, int which_room) {
|
||||||
|
|
||||||
void new_dragon(RNG *rng, std::unique_ptr<character> &pch, const position &pos,
|
|
||||||
const position &fallback) {
|
|
||||||
const position nil{0, 0};
|
const position nil{0, 0};
|
||||||
|
|
||||||
if (pos != nil)
|
if (pos != nil)
|
||||||
pch = std::make_unique<dragon>(rng, pos);
|
p = std::make_unique<dragon>(rng, enabled_features,
|
||||||
|
pos, which_room);
|
||||||
else
|
else
|
||||||
pch = std::make_unique<dragon>(rng, fallback);
|
p = std::make_unique<dragon>(rng, enabled_features,
|
||||||
|
fallback, which_room);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int EXCNT = 6;
|
||||||
|
const race EXCHOICES[EXCNT] = {
|
||||||
|
rhuman, rdwarf, rhalfling, relf, rorc, rmerchant
|
||||||
|
};
|
||||||
|
const int CNT = 18;
|
||||||
|
const race CHOICES[CNT] = {
|
||||||
|
rhuman, rhuman, rhuman, rhuman,
|
||||||
|
rdwarf, rdwarf, rdwarf,
|
||||||
|
rhalfling, rhalfling, rhalfling, rhalfling, rhalfling,
|
||||||
|
relf, relf,
|
||||||
|
rorc, rorc,
|
||||||
|
rmerchant, rmerchant
|
||||||
|
};
|
||||||
|
|
||||||
|
enum race get_extra_race(RNG *rng) {
|
||||||
|
return EXCHOICES[rng->rand_under(EXCNT)];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum race get_normal_race(RNG *rng) {
|
||||||
|
return CHOICES[rng->rand_under(CNT)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_enemy(RNG *rng, std::unique_ptr<enemy_base> &p,
|
||||||
|
const position &pos, const feature enabled_features,
|
||||||
|
int which_room) {
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
enum race r;
|
||||||
|
|
||||||
|
if (enabled_features & FEATURE_EXTRA_STUFF)
|
||||||
|
r = get_extra_race(rng);
|
||||||
|
else
|
||||||
|
r = get_normal_race(rng);
|
||||||
|
|
||||||
|
p = nullptr;
|
||||||
|
|
||||||
|
switch (r) {
|
||||||
|
case rdwarf:
|
||||||
|
p = make_unique<dwarf>(rng, enabled_features, pos, which_room);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rhuman:
|
||||||
|
p = make_unique<human>(rng, enabled_features, pos, which_room);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case relf:
|
||||||
|
p = make_unique<elf>(rng, enabled_features, pos, which_room);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rorc:
|
||||||
|
p = make_unique<orc>(rng, enabled_features, pos, which_room);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rmerchant:
|
||||||
|
p = make_unique<merchant>(rng, enabled_features, pos, which_room);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
#define __ENEMIES_H__
|
#define __ENEMIES_H__
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "characters.h"
|
#include "enemy.h"
|
||||||
#include "races.h"
|
|
||||||
|
|
||||||
void new_enemy(RNG *rng, std::unique_ptr<character> &pch, const position &pos,
|
void new_dragon(RNG *rng, std::unique_ptr<enemy_base> &p,
|
||||||
bool extras);
|
const position &pos, const position &fallback,
|
||||||
|
const feature enabled_features, int which_room);
|
||||||
|
|
||||||
void new_dragon(RNG *rng, std::unique_ptr<character> &pch, const position &pos,
|
void new_enemy(RNG *rng, std::unique_ptr<enemy_base> &p,
|
||||||
const position &fallback);
|
const position &pos, const feature enabled_features,
|
||||||
|
int which_room);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
22
src/enemies/dragon.cc
Normal file
22
src/enemies/dragon.cc
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "dragon.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
dragon::dragon(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num):
|
||||||
|
enemy_base{rng, enabled_features, rdragon, pos, gen_room_num, "D"} {}
|
||||||
|
|
||||||
|
void dragon::print(display *out) {
|
||||||
|
out->print_char(pos, 'D', COLOR_PAIR(COLOR_RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dragon::get_race_name() const {
|
||||||
|
return "Dragon";
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result dragon::act(level *lvl, character *pc, bool hostile) {
|
||||||
|
if (is_adjacent(pos, pc->get_pos()) && hostile)
|
||||||
|
return attack(pc);
|
||||||
|
|
||||||
|
return {fine, ""};
|
||||||
|
}
|
15
src/enemies/dragon.h
Normal file
15
src/enemies/dragon.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __DRAGON_H__
|
||||||
|
#define __DRAGON_H__
|
||||||
|
|
||||||
|
#include "../enemy.h"
|
||||||
|
|
||||||
|
class dragon final: public enemy_base {
|
||||||
|
public:
|
||||||
|
dragon(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num);
|
||||||
|
void print(display *out) override;
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
long_result act(level *lvl, character *pc, bool hostile) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
src/enemies/dwarf.cc
Normal file
15
src/enemies/dwarf.cc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "dwarf.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
dwarf::dwarf(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num):
|
||||||
|
enemy_base{rng, enabled_features, rdwarf, pos, gen_room_num, "W"} {}
|
||||||
|
|
||||||
|
void dwarf::print(display *out) {
|
||||||
|
out->print_char(pos, 'W', COLOR_PAIR(COLOR_RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *dwarf::get_race_name() const {
|
||||||
|
return "Dwarf";
|
||||||
|
}
|
14
src/enemies/dwarf.h
Normal file
14
src/enemies/dwarf.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __DWARF_H__
|
||||||
|
#define __DWARF_H__
|
||||||
|
|
||||||
|
#include "../enemy.h"
|
||||||
|
|
||||||
|
class dwarf final: public enemy_base {
|
||||||
|
public:
|
||||||
|
dwarf(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num);
|
||||||
|
void print(display *out) override;
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
31
src/enemies/elf.cc
Normal file
31
src/enemies/elf.cc
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
elf::elf(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num):
|
||||||
|
enemy_base{rng, enabled_features, relf, pos, gen_room_num, "H"} {}
|
||||||
|
|
||||||
|
void elf::print(display *out) {
|
||||||
|
out->print_char(pos, 'H', COLOR_PAIR(COLOR_RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *elf::get_race_name() const {
|
||||||
|
return "Elf";
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result elf::attack(character *ch) {
|
||||||
|
auto res1 = ch->get_hit(this, ATK, base_hit_rate);
|
||||||
|
|
||||||
|
if (res1.res == result::died)
|
||||||
|
return res1;
|
||||||
|
|
||||||
|
auto res2 = ch->get_hit(this, ATK, base_hit_rate);
|
||||||
|
|
||||||
|
if (res1.res == miss && res2.res == miss)
|
||||||
|
return {miss, res1.msg + res2.msg};
|
||||||
|
else if (res2.res == died)
|
||||||
|
return {died, res1.msg + res2.msg};
|
||||||
|
else
|
||||||
|
return {hit, res1.msg + res2.msg};
|
||||||
|
}
|
15
src/enemies/elf.h
Normal file
15
src/enemies/elf.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __ELF_H__
|
||||||
|
#define __ELF_H__
|
||||||
|
|
||||||
|
#include "../enemy.h"
|
||||||
|
|
||||||
|
class elf final: public enemy_base {
|
||||||
|
public:
|
||||||
|
elf(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num);
|
||||||
|
void print(display *out) override;
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
long_result attack(character *ch) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
41
src/enemies/halfling.cc
Normal file
41
src/enemies/halfling.cc
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "halfling.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
fraction halfling::HIT_RATE_MUL = {1, 2};
|
||||||
|
|
||||||
|
halfling::halfling(RNG *rng, const feature enabled_features,
|
||||||
|
const position &pos,
|
||||||
|
const int gen_room_num):
|
||||||
|
enemy_base{rng, enabled_features, rhalfling, pos, gen_room_num, "L"} {}
|
||||||
|
|
||||||
|
void halfling::print(display *out) {
|
||||||
|
out->print_char(pos, 'L', COLOR_PAIR(COLOR_RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *halfling::get_race_name() const {
|
||||||
|
return "Halfling";
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result halfling::get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate) {
|
||||||
|
auto nhit_rate = HIT_RATE_MUL * hit_rate;
|
||||||
|
|
||||||
|
if (rng->trial(nhit_rate)) {
|
||||||
|
int tmp = calc_dmg(tATK, DEF);
|
||||||
|
tmp = tmp > HP ? HP : tmp;
|
||||||
|
HP -= tmp;
|
||||||
|
|
||||||
|
if (HP == 0)
|
||||||
|
return {result::hit,
|
||||||
|
"PC deals " + std::to_string(tmp) +
|
||||||
|
" damage to " + abbrev + ". " + abbrev +
|
||||||
|
" is slain by PC. "};
|
||||||
|
|
||||||
|
return {result::hit, "PC deals " +
|
||||||
|
std::to_string(tmp) + " damage to " + abbrev};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {miss, "PC tried to hit " + abbrev +
|
||||||
|
" but missed. The halfling laughed. "};
|
||||||
|
}
|
17
src/enemies/halfling.h
Normal file
17
src/enemies/halfling.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef __HALFLING_H__
|
||||||
|
#define __HALFLING_H__
|
||||||
|
|
||||||
|
#include "../enemy.h"
|
||||||
|
|
||||||
|
class halfling final: public enemy_base {
|
||||||
|
static fraction HIT_RATE_MUL;
|
||||||
|
public:
|
||||||
|
halfling(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num);
|
||||||
|
void print(display *out) override;
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
long_result get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
src/enemies/human.cc
Normal file
15
src/enemies/human.cc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "human.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
human::human(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num):
|
||||||
|
enemy_base{rng, enabled_features, rhuman, pos, gen_room_num, "H"} {}
|
||||||
|
|
||||||
|
void human::print(display *out) {
|
||||||
|
out->print_char(pos, 'H', COLOR_PAIR(COLOR_RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *human::get_race_name() const {
|
||||||
|
return "Human";
|
||||||
|
}
|
14
src/enemies/human.h
Normal file
14
src/enemies/human.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __HUMAN_H__
|
||||||
|
#define __HUMAN_H__
|
||||||
|
|
||||||
|
#include "../enemy.h"
|
||||||
|
|
||||||
|
class human final: public enemy_base {
|
||||||
|
public:
|
||||||
|
human(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num);
|
||||||
|
void print(display *out) override;
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
src/enemies/merchant.cc
Normal file
15
src/enemies/merchant.cc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "merchant.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
merchant::merchant(RNG *rng, const feature enabled_features,
|
||||||
|
const position &pos, const int gen_room_num):
|
||||||
|
enemy_base{rng, enabled_features, rmerchant, pos, gen_room_num, "M"} {}
|
||||||
|
|
||||||
|
void merchant::print(display *out) {
|
||||||
|
out->print_char(pos, 'M', COLOR_PAIR(COLOR_RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *merchant::get_race_name() const {
|
||||||
|
return "Merchant";
|
||||||
|
}
|
14
src/enemies/merchant.h
Normal file
14
src/enemies/merchant.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __MERCHANT_H__
|
||||||
|
#define __MERCHANT_H__
|
||||||
|
|
||||||
|
#include "../enemy.h"
|
||||||
|
|
||||||
|
class merchant final: public enemy_base {
|
||||||
|
public:
|
||||||
|
merchant(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num);
|
||||||
|
void print(display *out) override;
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
src/enemies/orc.cc
Normal file
15
src/enemies/orc.cc
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "orc.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
orc::orc(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num):
|
||||||
|
enemy_base{rng, enabled_features, rorc, pos, gen_room_num, "O"} {}
|
||||||
|
|
||||||
|
void orc::print(display *out) {
|
||||||
|
out->print_char(pos, 'O', COLOR_PAIR(COLOR_RED));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *orc::get_race_name() const {
|
||||||
|
return "Orc";
|
||||||
|
}
|
14
src/enemies/orc.h
Normal file
14
src/enemies/orc.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __ORC_H__
|
||||||
|
#define __ORC_H__
|
||||||
|
|
||||||
|
#include "../enemy.h"
|
||||||
|
|
||||||
|
class orc final: public enemy_base {
|
||||||
|
public:
|
||||||
|
orc(RNG *rng, const feature enabled_features, const position &pos,
|
||||||
|
const int gen_room_num);
|
||||||
|
void print(display *out) override;
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
115
src/enemy.cc
Normal file
115
src/enemy.cc
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include "enemy.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "level.h"
|
||||||
|
|
||||||
|
enemy_base::enemy_base(RNG *rng, const feature enabled_features,
|
||||||
|
const enum race &nrace, const position &pos,
|
||||||
|
const int gen_room_num, std::string abbrev):
|
||||||
|
character{rng, enabled_features, nrace, pos},
|
||||||
|
room_num{gen_room_num}, abbrev{abbrev} {
|
||||||
|
base_hit_rate_reset = {1, 2};
|
||||||
|
}
|
||||||
|
|
||||||
|
int enemy_base::get_room_num() const {
|
||||||
|
return room_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result enemy_base::act(level *lvl, character *pc, bool hostile) {
|
||||||
|
if (is_adjacent(pos, pc->get_pos()) && hostile)
|
||||||
|
return attack(pc);
|
||||||
|
|
||||||
|
if (enabled_features & FEATURE_ENEMIES_CHASE &&
|
||||||
|
distance_sqr(pos, pc->get_pos()) <= DIST_THRESHOLD_SQR) {
|
||||||
|
position tmp;
|
||||||
|
position target = {BIG_NUMBER, BIG_NUMBER};
|
||||||
|
|
||||||
|
for (int i = 0; i < DIRECTION_CNT; ++i) {
|
||||||
|
tmp = pos + MOVE[i];
|
||||||
|
|
||||||
|
if (lvl->get_room(tmp) == room_num &&
|
||||||
|
lvl->is_available(tmp) &&
|
||||||
|
distance_sqr(tmp, pc->get_pos()) <
|
||||||
|
distance_sqr(target, pc->get_pos()))
|
||||||
|
target = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = target;
|
||||||
|
return {fine, ""};
|
||||||
|
}
|
||||||
|
|
||||||
|
int choices_cnt = 0;
|
||||||
|
position choices[DIRECTION_CNT];
|
||||||
|
|
||||||
|
for (int i = 0; i < DIRECTION_CNT; ++i)
|
||||||
|
if (lvl->get_room(pos + MOVE[i]) == room_num &&
|
||||||
|
lvl->is_available(pos + MOVE[i])) {
|
||||||
|
choices[choices_cnt] = pos + MOVE[i];
|
||||||
|
++choices_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (choices_cnt)
|
||||||
|
pos = choices[rng->rand_under(choices_cnt)];
|
||||||
|
|
||||||
|
return {fine, ""};
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result enemy_base::attack(character *ch) {
|
||||||
|
return ch->get_hit(this, ATK, base_hit_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string enemy_base::get_abbrev() const {
|
||||||
|
return abbrev;
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result enemy_base::get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate) {
|
||||||
|
if (rng->trial(hit_rate)) {
|
||||||
|
int tmp = calc_dmg(tATK, DEF);
|
||||||
|
tmp = tmp > HP ? HP : tmp;
|
||||||
|
HP -= tmp;
|
||||||
|
|
||||||
|
if (HP == 0)
|
||||||
|
return {result::hit,
|
||||||
|
"PC deals " + std::to_string(tmp) +
|
||||||
|
" damage to " + abbrev + ". " + abbrev +
|
||||||
|
" is slain by PC. "};
|
||||||
|
|
||||||
|
return {result::hit, "PC deals " +
|
||||||
|
std::to_string(tmp) + " damage to " + abbrev};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {miss, "PC tried to hit " + abbrev + " but missed. "};
|
||||||
|
}
|
||||||
|
|
||||||
|
void enemy_base::dies(level *lvl, character *pc) {
|
||||||
|
auto elist = lvl->get_elist();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < elist.size(); ++i)
|
||||||
|
if (elist[i] == this) {
|
||||||
|
elist.erase(elist.begin() + i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (race == race::rdragon) {
|
||||||
|
return;
|
||||||
|
} else if (race == race::rmerchant) {
|
||||||
|
lvl->add_gold({GOLD_MERCHANT, pos});
|
||||||
|
} else if (race == race::rhuman) {
|
||||||
|
lvl->add_gold({GOLD_NORMAL, pos});
|
||||||
|
auto plist = lvl->get_available_around_all(pos);
|
||||||
|
lvl->add_gold({GOLD_NORMAL,
|
||||||
|
rng->get_rand_in_vector(plist)});
|
||||||
|
}
|
||||||
|
|
||||||
|
((player_base *)pc)->add_gold(rand_gold_drop(rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
enemy_base *get_enemy_at(const position &pos, const enemy_list &elist) {
|
||||||
|
for (auto e : elist)
|
||||||
|
if (e->get_pos() == pos)
|
||||||
|
return e;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
36
src/enemy.h
Normal file
36
src/enemy.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef __ENEMY_H__
|
||||||
|
#define __ENEMY_H__
|
||||||
|
|
||||||
|
#include "characters.h"
|
||||||
|
|
||||||
|
class enemy_base : public character {
|
||||||
|
private:
|
||||||
|
const static int BIG_NUMBER = 500;
|
||||||
|
const static int DIST_THRESHOLD_SQR = 8 * 8;
|
||||||
|
protected:
|
||||||
|
const int room_num;
|
||||||
|
|
||||||
|
std::string abbrev;
|
||||||
|
public:
|
||||||
|
enemy_base(RNG *rng, const feature enabled_features,
|
||||||
|
const enum race &nrace, const position &pos,
|
||||||
|
const int gen_room_num, std::string abbrev);
|
||||||
|
|
||||||
|
int get_room_num() const;
|
||||||
|
|
||||||
|
virtual long_result act(level *lvl, character *pc, bool hostile = true);
|
||||||
|
|
||||||
|
virtual long_result attack(character *ch) override;
|
||||||
|
virtual long_result get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate) override;
|
||||||
|
|
||||||
|
virtual std::string get_abbrev() const override;
|
||||||
|
|
||||||
|
virtual void dies(level *lvl, character *pc);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<enemy_base *> enemy_list;
|
||||||
|
|
||||||
|
enemy_base *get_enemy_at(const position &pos, const enemy_list &elist);
|
||||||
|
|
||||||
|
#endif
|
@ -1,42 +0,0 @@
|
|||||||
#include "file_input.h"
|
|
||||||
#include <utility>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
file_input::file_input(std::ifstream &&ifs):
|
|
||||||
in{std::move(ifs)} {}
|
|
||||||
|
|
||||||
game_command file_input::get_command() {
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (in.eof())
|
|
||||||
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;
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#ifndef __FILE_INPUT_H__
|
|
||||||
#define __FILE_INPUT_H__
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include "input.h"
|
|
||||||
|
|
||||||
class file_input final : public input {
|
|
||||||
private:
|
|
||||||
std::ifstream in;
|
|
||||||
public:
|
|
||||||
// This is for cin
|
|
||||||
file_input(std::ifstream &&ifs);
|
|
||||||
game_command get_command() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,36 +0,0 @@
|
|||||||
#include "file_output.h"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
file_output::file_output(std::ofstream &&ofs):
|
|
||||||
out{std::move(ofs)} {}
|
|
||||||
|
|
||||||
void file_output::render() {
|
|
||||||
for (std::size_t idx = 0; idx < contents.size(); ++idx) {
|
|
||||||
if (idx % DISPLAY_WIDTH == 0 && idx)
|
|
||||||
out << std::endl;
|
|
||||||
|
|
||||||
out << (char)(contents[idx] ? contents[idx] : ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
out << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_output::print_char(const position &pos, const char ch,
|
|
||||||
const int attrs) {
|
|
||||||
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
contents[pos.y * DISPLAY_WIDTH + pos.x] = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
void file_output::print_str(const position &pos, const std::string &str,
|
|
||||||
const int attrs) {
|
|
||||||
if (pos.x >= DISPLAY_WIDTH || pos.y >= DISPLAY_HEIGHT)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int head = pos.y * DISPLAY_WIDTH + pos.x;
|
|
||||||
|
|
||||||
for (std::size_t i = 0; i < str.length(); ++i)
|
|
||||||
contents[i + head] = str[i];
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
#ifndef __FILE_OUTPUT_H__
|
|
||||||
#define __FILE_OUTPUT_H__
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
class file_output final : public display {
|
|
||||||
private:
|
|
||||||
std::ofstream out;
|
|
||||||
public:
|
|
||||||
file_output(std::ofstream &&ofs);
|
|
||||||
|
|
||||||
void render() override;
|
|
||||||
void print_char(const position &pos,
|
|
||||||
const char ch, const int attrs) override;
|
|
||||||
void print_str(const position &pos,
|
|
||||||
const std::string &str, const int attrs) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,35 +1,35 @@
|
|||||||
#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() const {
|
float fraction::real() const {
|
||||||
@ -37,8 +37,21 @@ float fraction::real() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
fraction &fraction::operator=(const fraction &frac) {
|
||||||
|
numerator = frac.numerator;
|
||||||
|
denominator = frac.denominator;
|
||||||
|
this->simplify();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
fraction &fraction::operator*=(const fraction &frac) {
|
||||||
|
numerator *= frac.numerator;
|
||||||
|
denominator *= frac.denominator;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -2,17 +2,19 @@
|
|||||||
#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);
|
||||||
|
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() const;
|
float real() const;
|
||||||
private:
|
private:
|
||||||
int gcd(int a, int b);
|
int gcd(int a, int b);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
203
src/game.cc
203
src/game.cc
@ -1,25 +1,21 @@
|
|||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
#include "races.h"
|
#include "constants.h"
|
||||||
|
#include "pc.h"
|
||||||
|
|
||||||
game::game(const enum race starting_race,
|
game::game(const enum race starting_race,
|
||||||
const feature enabled_features,
|
const feature enabled_features,
|
||||||
input *new_in,
|
input *new_in,
|
||||||
display *new_out,
|
display *new_out,
|
||||||
logger *new_log,
|
|
||||||
RNG *new_rng):
|
RNG *new_rng):
|
||||||
enabled_features{enabled_features},
|
enabled_features{enabled_features},
|
||||||
in{new_in}, out{new_out}, log{new_log}, 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};
|
||||||
the_world = false;
|
the_world = false;
|
||||||
|
|
||||||
// TODO: add the other races
|
// TODO: add the other races
|
||||||
switch (starting_race) {
|
init_player(rng, player, enabled_features, starting_race);
|
||||||
case race::rshade:
|
|
||||||
player = std::make_unique<shade>(rng, nil);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enabled_features & FEATURE_EXTRA_LEVELS)
|
if (enabled_features & FEATURE_EXTRA_LEVELS)
|
||||||
max_level = rng->rand_between(MIN_LEVEL_CNT, MAX_LEVEL_CNT + 1);
|
max_level = rng->rand_between(MIN_LEVEL_CNT, MAX_LEVEL_CNT + 1);
|
||||||
@ -45,118 +41,43 @@ void game::new_level() {
|
|||||||
rng, enabled_features));
|
rng, enabled_features));
|
||||||
}
|
}
|
||||||
|
|
||||||
result game::player_moves(game_command cmd) {
|
|
||||||
if (cmd == game_command_terminate) {
|
|
||||||
return result::terminate;
|
|
||||||
} else if (cmd >= move_north && cmd <= move_southwest) { // Tried to move
|
|
||||||
if (enabled_features & FEATURE_NCURSES)
|
|
||||||
return player_move_or_attack((direction)(cmd - move_north));
|
|
||||||
|
|
||||||
return player->move((direction)(cmd - move_north),
|
|
||||||
levels[curr_level]->get_available_around(
|
|
||||||
player->get_position()));
|
|
||||||
} else if (cmd >= apply_north && cmd <= apply_southwest) {
|
|
||||||
auto res = player->apply((direction)(cmd - apply_north),
|
|
||||||
levels[curr_level]->get_plist());
|
|
||||||
|
|
||||||
if (res.res == applied) {
|
|
||||||
msg += "PC used potion ";
|
|
||||||
msg += POTION_REAL_NAME[res.which->get_type()];
|
|
||||||
msg += ". ";
|
|
||||||
} else {
|
|
||||||
msg += "PC tried to drink thin air. ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.res;
|
|
||||||
} else if (cmd == apply_panic) {
|
|
||||||
msg += "PC tried to use in some non-existent direction. ";
|
|
||||||
return fine;
|
|
||||||
} else if (cmd >= attack_north && cmd <= attack_southwest) {
|
|
||||||
auto res = player->attack((direction)(cmd - attack_north),
|
|
||||||
levels[curr_level]->get_chlist());
|
|
||||||
|
|
||||||
if (res.res == hit) {
|
|
||||||
msg += "PC deals " + std::to_string(res.dmg_dealt) +
|
|
||||||
" damage to " +
|
|
||||||
CHARACTER_REP[res.which->get_race()] +
|
|
||||||
" (" + std::to_string(res.remaining_HP) +
|
|
||||||
" HP). ";
|
|
||||||
} else if (res.res == miss) {
|
|
||||||
msg += "PC missed ";
|
|
||||||
msg += CHARACTER_REP[res.which->get_race()];
|
|
||||||
msg += ". ";
|
|
||||||
} else {
|
|
||||||
msg += "PC tried to attack thin air. ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.which->get_race() == rmerchant)
|
|
||||||
hostile_merchants = true;
|
|
||||||
|
|
||||||
return res.res;
|
|
||||||
} else if (cmd == up_stairs) {
|
|
||||||
if (player->get_position() ==
|
|
||||||
levels[curr_level]->get_up_stairs())
|
|
||||||
return go_up;
|
|
||||||
|
|
||||||
msg += "PC tried to fly through the ceiling. ";
|
|
||||||
return fine;
|
|
||||||
} else if (cmd == down_stairs) {
|
|
||||||
if (player->get_position() ==
|
|
||||||
levels[curr_level]->get_down_stairs())
|
|
||||||
return go_down;
|
|
||||||
|
|
||||||
msg += "PC tried to dig through the floor. ";
|
|
||||||
return fine;
|
|
||||||
} else if (cmd == the_world) {
|
|
||||||
msg += "PC toggled Stand: The World! ";
|
|
||||||
return toggle_the_world;
|
|
||||||
} else if (cmd == game_restart) {
|
|
||||||
return restart_game;
|
|
||||||
} else if (cmd == game_command_pass) {
|
|
||||||
return fine;
|
|
||||||
} else if (cmd == game_command_panic) {
|
|
||||||
msg += "PC tried to produce some undefined behaviour. ";
|
|
||||||
return unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
msg += "PC tried to produce some undefined behaviour. ";
|
|
||||||
return unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
bool compare_characters(character *&a, character *&b) {
|
bool compare_characters(const character *a, const character *b) {
|
||||||
return a->get_position() < b->get_position();
|
return a->get_pos() < b->get_pos();
|
||||||
}
|
}
|
||||||
|
|
||||||
void game::move_enemies() {
|
void game::move_enemies() {
|
||||||
if (the_world)
|
if (the_world)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
character_list enemies = levels[curr_level]->get_chlist();
|
auto enemies = levels[curr_level]->get_elist();
|
||||||
std::sort(enemies.begin(), enemies.end(), &game::compare_characters);
|
std::sort(enemies.begin(), enemies.end(), ::compare_characters);
|
||||||
|
|
||||||
for (auto ch : enemies) {
|
for (auto ch : enemies) {
|
||||||
|
bool hostile = ch->get_race() == rmerchant ?
|
||||||
|
hostile_merchants : true;
|
||||||
|
ch->start_turn();
|
||||||
|
ch->calc_effects();
|
||||||
|
auto res =
|
||||||
|
ch->act(levels[curr_level].get(), player.get(), hostile);
|
||||||
|
|
||||||
|
if (player->is_dead())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ch->is_dead())
|
||||||
|
ch->dies(levels[curr_level].get(), player.get());
|
||||||
|
|
||||||
|
msg += res.msg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game_status game::run() {
|
game_status game::run() {
|
||||||
msg = "";
|
player->start_turn();
|
||||||
auto res = player_moves(in->get_command());
|
auto res = player->interpret_command(levels[curr_level].get(),
|
||||||
|
in->get_command());
|
||||||
|
msg = res.msg;
|
||||||
|
|
||||||
if (!(enabled_features & FEATURE_NCURSES) &&
|
switch (res.res) {
|
||||||
res == result::moved &&
|
|
||||||
(player->get_position() ==
|
|
||||||
levels[curr_level]->get_down_stairs()))
|
|
||||||
res = go_down;
|
|
||||||
|
|
||||||
if (!(enabled_features & FEATURE_NCURSES) &&
|
|
||||||
res == result::moved &&
|
|
||||||
(player->get_position() ==
|
|
||||||
levels[curr_level]->get_up_stairs()))
|
|
||||||
res = go_up;
|
|
||||||
|
|
||||||
switch (res) {
|
|
||||||
case result::terminate:
|
case result::terminate:
|
||||||
return terminated;
|
return terminated;
|
||||||
|
|
||||||
@ -170,7 +91,6 @@ game_status game::run() {
|
|||||||
player->discard_level_effects();
|
player->discard_level_effects();
|
||||||
++curr_level;
|
++curr_level;
|
||||||
new_level();
|
new_level();
|
||||||
msg += "PC went down a floor. ";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,8 +100,7 @@ game_status game::run() {
|
|||||||
|
|
||||||
player->discard_level_effects();
|
player->discard_level_effects();
|
||||||
--curr_level;
|
--curr_level;
|
||||||
player->set_position(levels[curr_level]->get_down_stairs());
|
player->set_pos(levels[curr_level]->get_down_stairs());
|
||||||
msg += "PC went up a floor. ";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,14 +122,14 @@ game_status game::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
player->start_turn();
|
player->start_turn();
|
||||||
player->apply_effects();
|
player->calc_effects();
|
||||||
|
|
||||||
if (player->get_HP() <= 0)
|
if (player->is_dead())
|
||||||
return game_status::dead;
|
return game_status::dead;
|
||||||
|
|
||||||
move_enemies();
|
move_enemies();
|
||||||
|
|
||||||
if (player->get_HP() <= 0)
|
if (player->is_dead())
|
||||||
return game_status::dead;
|
return game_status::dead;
|
||||||
|
|
||||||
++curr_turn;
|
++curr_turn;
|
||||||
@ -223,8 +142,6 @@ const position STATUS_HP{0, 26};
|
|||||||
const position STATUS_ATK{0, 27};
|
const position STATUS_ATK{0, 27};
|
||||||
const position STATUS_DEF{0, 28};
|
const position STATUS_DEF{0, 28};
|
||||||
const position STATUS_ACTION{0, 29};
|
const position STATUS_ACTION{0, 29};
|
||||||
const char *ASK_ATK_MERCHANT =
|
|
||||||
"Action: Do you really want to attack the peaceful merchant? [Y/N]";
|
|
||||||
|
|
||||||
size_t game::get_curr_turn() const {
|
size_t game::get_curr_turn() const {
|
||||||
return curr_turn;
|
return curr_turn;
|
||||||
@ -237,61 +154,15 @@ void game::print() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
levels[curr_level]->print(out);
|
levels[curr_level]->print(out);
|
||||||
player->print(out, true);
|
player->print(out);
|
||||||
|
|
||||||
std::string tmp = "Race: ";
|
std::string tmp = "Race: ";
|
||||||
tmp += RACE_NAME[player->get_race()];
|
tmp += player->get_race_name();
|
||||||
tmp += " Gold: " + std::to_string(player->get_gold());
|
tmp += " Gold: " + std::to_string(player->get_gold());
|
||||||
out->print_str(STATUS_RACE, tmp);
|
out->print_str(STATUS_RACE, tmp);
|
||||||
|
out->print_str(STATUS_FLOOR, "Floor " + std::to_string(curr_level + 1));
|
||||||
tmp = "Floor " + std::to_string(curr_level + 1);
|
out->print_str(STATUS_HP, "HP: " + std::to_string(player->get_HP()));
|
||||||
out->print_str(STATUS_FLOOR, tmp);
|
out->print_str(STATUS_ATK, "Atk: " + std::to_string(player->get_ATK()));
|
||||||
|
out->print_str(STATUS_DEF, "Def: " + std::to_string(player->get_DEF()));
|
||||||
tmp = "Atk: " + std::to_string(player->get_ATK());
|
out->print_str(STATUS_ACTION, "Action: " + msg);
|
||||||
out->print_str(STATUS_ATK, tmp);
|
|
||||||
|
|
||||||
tmp = "Def: " + std::to_string(player->get_DEF());
|
|
||||||
out->print_str(STATUS_DEF, tmp);
|
|
||||||
|
|
||||||
tmp = "Action: " + msg;
|
|
||||||
out->print_str(STATUS_ACTION, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
result game::player_move_or_attack(const direction &dir) {
|
|
||||||
auto avlbl = levels[curr_level]->get_available_around(
|
|
||||||
player->get_position());
|
|
||||||
|
|
||||||
if (find(avlbl, player->get_position() + MOVE[dir])
|
|
||||||
!= avlbl.size()) {
|
|
||||||
player->set_position(player->get_position() + MOVE[dir]);
|
|
||||||
return result::moved;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto tmp = player->get_position() + MOVE[dir];
|
|
||||||
character *target;
|
|
||||||
|
|
||||||
for (auto ch : levels[curr_level]->get_chlist())
|
|
||||||
if (tmp == ch->get_position()) {
|
|
||||||
target = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto res = player->attack(dir, target);
|
|
||||||
|
|
||||||
if (target->get_race() == rmerchant)
|
|
||||||
hostile_merchants = true;
|
|
||||||
|
|
||||||
if (res.res == hit) {
|
|
||||||
msg += "PC deals " +
|
|
||||||
std::to_string(res.dmg_dealt) + " damage to " +
|
|
||||||
CHARACTER_REP[res.which->get_race()] + " (" +
|
|
||||||
std::to_string(res.remaining_HP) + " HP). ";
|
|
||||||
} else if (res.res == miss) {
|
|
||||||
msg += "PC missed ";
|
|
||||||
msg += CHARACTER_REP[res.which->get_race()];
|
|
||||||
msg += ". ";
|
|
||||||
} else {
|
|
||||||
msg += "PC tried to attack thin air. ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.res;
|
|
||||||
}
|
}
|
||||||
|
12
src/game.h
12
src/game.h
@ -2,13 +2,14 @@
|
|||||||
#define __GAME_H__
|
#define __GAME_H__
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "constants.h"
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "characters.h"
|
#include "characters.h"
|
||||||
#include "level.h"
|
#include "level.h"
|
||||||
#include "log.h"
|
#include "player.h"
|
||||||
|
|
||||||
|
enum game_status : int;
|
||||||
|
|
||||||
class game final {
|
class game final {
|
||||||
private:
|
private:
|
||||||
@ -21,12 +22,11 @@ private:
|
|||||||
|
|
||||||
input *in;
|
input *in;
|
||||||
display *out;
|
display *out;
|
||||||
logger *log;
|
|
||||||
RNG *rng;
|
RNG *rng;
|
||||||
|
|
||||||
unsigned int curr_turn;
|
unsigned int curr_turn;
|
||||||
|
|
||||||
std::unique_ptr<character> player;
|
std::unique_ptr<player_base> player;
|
||||||
std::vector<std::unique_ptr<level>> levels;
|
std::vector<std::unique_ptr<level>> levels;
|
||||||
|
|
||||||
size_t max_level;
|
size_t max_level;
|
||||||
@ -42,7 +42,6 @@ public:
|
|||||||
const feature enabled_features,
|
const feature enabled_features,
|
||||||
input *new_in,
|
input *new_in,
|
||||||
display *new_out,
|
display *new_out,
|
||||||
logger *new_log,
|
|
||||||
RNG *new_rng);
|
RNG *new_rng);
|
||||||
game_status run();
|
game_status run();
|
||||||
size_t get_curr_level() const;
|
size_t get_curr_level() const;
|
||||||
@ -50,11 +49,8 @@ public:
|
|||||||
const character *get_player() const;
|
const character *get_player() const;
|
||||||
void print();
|
void print();
|
||||||
private:
|
private:
|
||||||
result player_moves(game_command cmd);
|
|
||||||
void new_level();
|
void new_level();
|
||||||
void move_enemies();
|
void move_enemies();
|
||||||
result player_move_or_attack(const direction &dir);
|
|
||||||
bool compare_characters(const character *&a, const character *&b);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
#include "goblin.h"
|
|
||||||
|
|
||||||
goblin::goblin(RNG *rng, const position &pos):
|
|
||||||
character{rng, race::rgoblin, pos} {
|
|
||||||
gold = 0;
|
|
||||||
hostile = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
result goblin::attack(const direction dir, character_list &chlist) {
|
|
||||||
position tmp{pos + MOVE[dir]};
|
|
||||||
|
|
||||||
for (auto &ch : chlist)
|
|
||||||
if (tmp == ch->get_position()) {
|
|
||||||
auto res = ch->get_hit(race, ATK, base_hit_rate);
|
|
||||||
|
|
||||||
if (res == result::died) {
|
|
||||||
gold += GAIN_GOLD;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result::fine;
|
|
||||||
}
|
|
||||||
|
|
||||||
result goblin::get_hit(const enum race &race, const int atk,
|
|
||||||
const fraction hitrate) {
|
|
||||||
if (rng->trial(hitrate))
|
|
||||||
HP = std::max(HP - calc_dmg(atk, DEF), 0);
|
|
||||||
|
|
||||||
if (HP == 0)
|
|
||||||
return result::died;
|
|
||||||
|
|
||||||
return result::hit;
|
|
||||||
}
|
|
16
src/goblin.h
16
src/goblin.h
@ -1,16 +0,0 @@
|
|||||||
#ifndef __GOBLIN_H__
|
|
||||||
#define __GOBLIN_H__
|
|
||||||
|
|
||||||
#include "characters.h"
|
|
||||||
|
|
||||||
class goblin final: public character {
|
|
||||||
static const int GAIN_GOLD = 5;
|
|
||||||
public:
|
|
||||||
goblin(RNG *rng, const position &pos);
|
|
||||||
virtual result attack(const direction dir,
|
|
||||||
character_list &chlist) override;
|
|
||||||
virtual result get_hit(const enum race &race, const int atk,
|
|
||||||
const fraction hit_rate) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
22
src/gold.cc
22
src/gold.cc
@ -1,5 +1,7 @@
|
|||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
int rand_gold_pile(RNG *rng) {
|
int rand_gold_pile(RNG *rng) {
|
||||||
const int denominator = 8;
|
const int denominator = 8;
|
||||||
const int normal = 5;
|
const int normal = 5;
|
||||||
@ -16,3 +18,23 @@ int rand_gold_pile(RNG *rng) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gold get_gold_at(const position &pos, gold_list &glist) {
|
||||||
|
gold ret = {0, {0, 0}};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < glist.size(); ++i)
|
||||||
|
if (glist[i].pos == pos) {
|
||||||
|
ret = glist[i];
|
||||||
|
glist.erase(i + glist.begin());
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rand_gold_drop(RNG *rng) {
|
||||||
|
if (rng->coin_flip())
|
||||||
|
return GOLD_NORMAL;
|
||||||
|
|
||||||
|
return GOLD_SMALL;
|
||||||
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define __GOLD_H__
|
#define __GOLD_H__
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "constants.h"
|
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
|
|
||||||
@ -13,6 +12,8 @@ struct gold {
|
|||||||
|
|
||||||
typedef std::vector<gold> gold_list;
|
typedef std::vector<gold> gold_list;
|
||||||
|
|
||||||
|
gold get_gold_at(const position &pos, gold_list &glist);
|
||||||
int rand_gold_pile(RNG *rng);
|
int rand_gold_pile(RNG *rng);
|
||||||
|
int rand_gold_drop(RNG *rng);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
12
src/input.cc
12
src/input.cc
@ -1,14 +1,16 @@
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
|
||||||
|
#include "constants.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;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
#ifndef __INPUT_H__
|
#ifndef __INPUT_H__
|
||||||
#define __INPUT_H__
|
#define __INPUT_H__
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "constants.h"
|
|
||||||
|
enum game_command : int;
|
||||||
|
|
||||||
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);
|
||||||
|
46
src/input/console_input.cc
Normal file
46
src/input/console_input.cc
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "console_input.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <string>
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
console_input::console_input(std::istream &cin):
|
||||||
|
in{cin} {}
|
||||||
|
|
||||||
|
game_command console_input::get_command() {
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (in.eof())
|
||||||
|
return game_command_panic;
|
||||||
|
|
||||||
|
return (game_command)((tmp = get_direction(cmd)) ==
|
||||||
|
game_command_panic
|
||||||
|
? tmp : tmp - move_north +
|
||||||
|
(use ? apply_north : attack_north));
|
||||||
|
} else if (cmd == "yes") {
|
||||||
|
return game_command::enter;
|
||||||
|
} else {
|
||||||
|
auto tmp = get_direction(cmd);
|
||||||
|
|
||||||
|
if (tmp != game_command_panic)
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return game_command_pass;
|
||||||
|
}
|
16
src/input/console_input.h
Normal file
16
src/input/console_input.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef __CONSOLE_INPUT_H__
|
||||||
|
#define __CONSOLE_INPUT_H__
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "../input.h"
|
||||||
|
|
||||||
|
class console_input final : public input {
|
||||||
|
private:
|
||||||
|
std::istream ∈
|
||||||
|
public:
|
||||||
|
// This is for cin
|
||||||
|
console_input(std::istream &cin);
|
||||||
|
game_command get_command() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
89
src/input/curses_input.cc
Normal file
89
src/input/curses_input.cc
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "curses_input.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
curses_input::curses_input(cursor *new_curse):
|
||||||
|
curse{new_curse} {}
|
||||||
|
|
||||||
|
game_command curses_input::get_command() {
|
||||||
|
switch (curse->getcmd()) {
|
||||||
|
case 'h':
|
||||||
|
return game_command::move_west;
|
||||||
|
|
||||||
|
case 'j':
|
||||||
|
return game_command::move_south;
|
||||||
|
|
||||||
|
case 'k':
|
||||||
|
return game_command::move_north;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
return game_command::move_east;
|
||||||
|
|
||||||
|
case 'y':
|
||||||
|
return game_command::move_northwest;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
return game_command::move_northeast;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
return game_command::move_southwest;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
return game_command::move_southeast;
|
||||||
|
|
||||||
|
case 'a':
|
||||||
|
break; // wait for another command
|
||||||
|
|
||||||
|
case '<':
|
||||||
|
return game_command::up_stairs;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
return game_command::down_stairs;
|
||||||
|
|
||||||
|
case 'q':
|
||||||
|
return game_command_terminate;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
return game_command::the_world;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
return game_restart;
|
||||||
|
|
||||||
|
case KEY_ENTER:
|
||||||
|
return game_command::enter;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return game_command_pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (curse->getcmd()) {
|
||||||
|
case 'h':
|
||||||
|
return game_command::apply_west;
|
||||||
|
|
||||||
|
case 'j':
|
||||||
|
return game_command::apply_south;
|
||||||
|
|
||||||
|
case 'k':
|
||||||
|
return game_command::apply_north;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
return game_command::apply_east;
|
||||||
|
|
||||||
|
case 'y':
|
||||||
|
return game_command::apply_northwest;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
return game_command::apply_northeast;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
return game_command::apply_southwest;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
return game_command::apply_southeast;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return game_command::apply_panic;
|
||||||
|
}
|
||||||
|
|
||||||
|
return game_command::game_command_panic;
|
||||||
|
}
|
@ -2,9 +2,8 @@
|
|||||||
#define __CURSES_INPUT_H__
|
#define __CURSES_INPUT_H__
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "input.h"
|
#include "../input.h"
|
||||||
#include "constants.h"
|
#include "../cursor.h"
|
||||||
#include "cursor.h"
|
|
||||||
|
|
||||||
class curses_input final: public input {
|
class curses_input final: public input {
|
||||||
private:
|
private:
|
46
src/input/file_input.cc
Normal file
46
src/input/file_input.cc
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#include "file_input.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <string>
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
file_input::file_input(std::ifstream &&ifs):
|
||||||
|
in{std::move(ifs)} {}
|
||||||
|
|
||||||
|
game_command file_input::get_command() {
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (in.eof())
|
||||||
|
return game_command_panic;
|
||||||
|
|
||||||
|
return (game_command)((tmp = get_direction(cmd)) ==
|
||||||
|
game_command_panic
|
||||||
|
? tmp : tmp - move_north +
|
||||||
|
(use ? apply_north : attack_north));
|
||||||
|
} else if (cmd == "yes") {
|
||||||
|
return game_command::enter;
|
||||||
|
} else {
|
||||||
|
auto tmp = get_direction(cmd);
|
||||||
|
|
||||||
|
if (tmp != game_command_panic)
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return game_command_pass;
|
||||||
|
}
|
16
src/input/file_input.h
Normal file
16
src/input/file_input.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef __FILE_INPUT_H__
|
||||||
|
#define __FILE_INPUT_H__
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include "../input.h"
|
||||||
|
|
||||||
|
class file_input final : public input {
|
||||||
|
private:
|
||||||
|
std::ifstream in;
|
||||||
|
public:
|
||||||
|
// This is for cin
|
||||||
|
file_input(std::ifstream &&ifs);
|
||||||
|
game_command get_command() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
86
src/level.cc
86
src/level.cc
@ -1,5 +1,7 @@
|
|||||||
#include "level.h"
|
#include "level.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
level::level(character *player, RNG *rng, const feature enabled_features):
|
level::level(character *player, RNG *rng, const feature enabled_features):
|
||||||
enabled_features{enabled_features}, map{player, rng, enabled_features},
|
enabled_features{enabled_features}, map{player, rng, enabled_features},
|
||||||
player{player} {
|
player{player} {
|
||||||
@ -34,24 +36,29 @@ void level::gen_enemies(RNG *rng, std::vector<position_list> &tiles) {
|
|||||||
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();
|
||||||
|
|
||||||
chlist.reserve(cnt);
|
elist.reserve(cnt);
|
||||||
pchlist.reserve(cnt);
|
pelist.reserve(cnt);
|
||||||
|
|
||||||
for (size_t i = 0; i < dhoard.size(); ++i) {
|
for (size_t i = 0; i < dhoard.size(); ++i) {
|
||||||
auto spots = get_available_around(dhoard[i].pos);
|
position_list spots;
|
||||||
pchlist.push_back(nullptr);
|
|
||||||
new_dragon(rng, pchlist[i], rng->get_rand_in_vector(spots),
|
for (int i = 0; i < DIRECTION_CNT; ++i)
|
||||||
dhoard[i].pos);
|
if (map.which_room(dhoard[i].pos + MOVE[i]) != -1)
|
||||||
chlist.push_back(pchlist[i].get());
|
spots.push_back(dhoard[i].pos + MOVE[i]);
|
||||||
|
|
||||||
|
pelist.push_back(nullptr);
|
||||||
|
new_dragon(rng, pelist[i], rng->get_rand_in_vector(spots),
|
||||||
|
dhoard[i].pos, enabled_features,
|
||||||
|
map.which_room(dhoard[i].pos));
|
||||||
|
elist.push_back(pelist[i].get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int i = dhoard.size(); i < cnt; ++i) {
|
for (int i = dhoard.size(); i < cnt; ++i) {
|
||||||
pchlist.push_back(nullptr);
|
pelist.push_back(nullptr);
|
||||||
new_enemy(rng, pchlist[i], get_rand_pos(rng, tiles),
|
auto p = get_rand_pos(rng, tiles);
|
||||||
enabled_features & FEATURE_EXTRA_STUFF);
|
new_enemy(rng, pelist[i], p, enabled_features, map.which_room(p));
|
||||||
pchlist[i]->set_room_num(map.which_room(pchlist[i]->get_position()));
|
elist.push_back(pelist[i].get());
|
||||||
chlist.push_back(pchlist[i].get());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +76,10 @@ position level::get_rand_pos(RNG *rng, std::vector<position_list> &tiles) {
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void level::add_gold(gold g) {
|
||||||
|
glist.push_back(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);
|
||||||
|
|
||||||
@ -103,7 +114,7 @@ void level::gen_potions(RNG *rng, std::vector<position_list> &tiles) {
|
|||||||
void level::print(display *out) const {
|
void level::print(display *out) const {
|
||||||
map.print(out);
|
map.print(out);
|
||||||
|
|
||||||
for (auto ch : chlist)
|
for (auto ch : elist)
|
||||||
ch->print(out);
|
ch->print(out);
|
||||||
|
|
||||||
for (auto p : plist)
|
for (auto p : plist)
|
||||||
@ -113,21 +124,50 @@ void level::print(display *out) const {
|
|||||||
out->print_char(gold.pos, 'G', COLOR_PAIR(COLOR_YELLOW));
|
out->print_char(gold.pos, 'G', COLOR_PAIR(COLOR_YELLOW));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool level::is_available(const position &pos) const {
|
bool level::is_available(const position &pos, bool is_player) const {
|
||||||
if (!map.is_available(pos))
|
if (!map.is_available(pos))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (auto ch : chlist)
|
for (auto ch : elist)
|
||||||
if (pos == ch->get_position())
|
if (pos == ch->get_pos())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(enabled_features & FEATURE_WALK_OVER) && !is_player) {
|
||||||
|
for (auto p : plist)
|
||||||
|
if (pos == p->get_pos())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto g : glist)
|
||||||
|
if (pos == g.pos)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool level::is_available_all(const position &pos) const {
|
||||||
|
if (!map.is_available(pos))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto ch : elist)
|
||||||
|
if (pos == ch->get_pos())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (auto p : plist)
|
for (auto p : plist)
|
||||||
if (pos == p->get_pos())
|
if (pos == p->get_pos())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
for (auto g : glist)
|
||||||
|
if (pos == g.pos)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int level::get_room(const position &pos) const {
|
||||||
|
return map.which_room(pos);
|
||||||
|
}
|
||||||
|
|
||||||
position_list level::get_available_around(const position &pos) const {
|
position_list level::get_available_around(const position &pos) const {
|
||||||
position_list result;
|
position_list result;
|
||||||
|
|
||||||
@ -138,6 +178,16 @@ position_list level::get_available_around(const position &pos) const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position_list level::get_available_around_all(const position &pos) const {
|
||||||
|
position_list result;
|
||||||
|
|
||||||
|
for (int i = 0; i < DIRECTION_CNT; ++i)
|
||||||
|
if (is_available_all(pos + MOVE[i]))
|
||||||
|
result.push_back(pos + MOVE[i]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
position level::get_up_stairs() const {
|
position level::get_up_stairs() const {
|
||||||
return map.get_up_stairs();
|
return map.get_up_stairs();
|
||||||
}
|
}
|
||||||
@ -146,8 +196,8 @@ position level::get_down_stairs() const {
|
|||||||
return map.get_down_stairs();
|
return map.get_down_stairs();
|
||||||
}
|
}
|
||||||
|
|
||||||
character_list &level::get_chlist() {
|
enemy_list &level::get_elist() {
|
||||||
return chlist;
|
return elist;
|
||||||
}
|
}
|
||||||
|
|
||||||
potion_list &level::get_plist() {
|
potion_list &level::get_plist() {
|
||||||
|
16
src/level.h
16
src/level.h
@ -7,8 +7,8 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "gold.h"
|
#include "gold.h"
|
||||||
#include "enemies.h"
|
#include "enemies.h"
|
||||||
|
#include "enemy.h"
|
||||||
#include "potions.h"
|
#include "potions.h"
|
||||||
#include "constants.h"
|
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
|
||||||
class level {
|
class level {
|
||||||
@ -22,9 +22,9 @@ private:
|
|||||||
const feature enabled_features;
|
const feature enabled_features;
|
||||||
game_map map;
|
game_map map;
|
||||||
character *player;
|
character *player;
|
||||||
std::vector<std::unique_ptr<character>>pchlist;
|
std::vector<std::unique_ptr<enemy_base>>pelist;
|
||||||
std::vector<std::unique_ptr<potion>>pplist;
|
std::vector<std::unique_ptr<potion>>pplist;
|
||||||
character_list chlist;
|
enemy_list elist;
|
||||||
potion_list plist;
|
potion_list plist;
|
||||||
gold_list glist;
|
gold_list glist;
|
||||||
public:
|
public:
|
||||||
@ -35,15 +35,21 @@ public:
|
|||||||
const feature enabled_features);
|
const feature enabled_features);
|
||||||
void print(display *out) const;
|
void print(display *out) const;
|
||||||
|
|
||||||
bool is_available(const position &pos) const;
|
bool is_available(const position &pos, bool is_player = false) const;
|
||||||
|
bool is_available_all(const position &pos) const;
|
||||||
|
|
||||||
|
int get_room(const position &pos) const;
|
||||||
position_list get_available_around(const position &pos) const;
|
position_list get_available_around(const position &pos) const;
|
||||||
|
position_list get_available_around_all(const position &pos) const;
|
||||||
position get_up_stairs() const;
|
position get_up_stairs() const;
|
||||||
position get_down_stairs() const;
|
position get_down_stairs() const;
|
||||||
|
|
||||||
// you can delete the pointers to the stuff
|
// you can delete the pointers to the stuff
|
||||||
character_list &get_chlist();
|
enemy_list &get_elist();
|
||||||
potion_list &get_plist();
|
potion_list &get_plist();
|
||||||
gold_list &get_glist();
|
gold_list &get_glist();
|
||||||
|
|
||||||
|
void add_gold(gold g);
|
||||||
private:
|
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);
|
||||||
|
10
src/log.cc
10
src/log.cc
@ -1,10 +0,0 @@
|
|||||||
#include "log.h"
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
logger::logger(std::ofstream &&new_out):
|
|
||||||
out{std::move(new_out)} {}
|
|
||||||
|
|
||||||
void logger::render() {
|
|
||||||
|
|
||||||
}
|
|
28
src/log.h
28
src/log.h
@ -1,28 +0,0 @@
|
|||||||
#ifndef __LOG_H__
|
|
||||||
#define __LOG_H__
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include "constants.h"
|
|
||||||
#include "characters.h"
|
|
||||||
|
|
||||||
class logger final {
|
|
||||||
private:
|
|
||||||
std::ofstream out;
|
|
||||||
std::vector<char> contents;
|
|
||||||
public:
|
|
||||||
logger(std::ofstream &&new_out);
|
|
||||||
|
|
||||||
// called once every turn
|
|
||||||
void render();
|
|
||||||
void print_char(const position &pos, const char ch);
|
|
||||||
void print_str(const position &pos, const std::string &str);
|
|
||||||
void print_turn(const unsigned turn);
|
|
||||||
void print_player(const character &player);
|
|
||||||
void print_chlist(const character_list &chlist);
|
|
||||||
void print_gold(const gold_list &gold_piles);
|
|
||||||
void print_potions(const potion_list &potions);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
17
src/main.cc
17
src/main.cc
@ -2,18 +2,17 @@
|
|||||||
|
|
||||||
#include "cc3k.h"
|
#include "cc3k.h"
|
||||||
#include "arguments.h"
|
#include "arguments.h"
|
||||||
|
#include "constants.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<RNG> rng;
|
||||||
std::unique_ptr<RNG> rng;
|
|
||||||
|
|
||||||
feature enabled_features = proc_args(argc, argv,
|
feature enabled_features = proc_args(argc, argv, curse, in, out, rng);
|
||||||
curse, in, out, log, rng);
|
|
||||||
|
|
||||||
if (enabled_features &
|
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);
|
||||||
@ -30,5 +29,5 @@ int main(int argc, char **argv) {
|
|||||||
// out->clear();
|
// out->clear();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return RETURN_FINE;
|
return RETURN_FINE;
|
||||||
}
|
}
|
||||||
|
18
src/map.cc
18
src/map.cc
@ -1,9 +1,10 @@
|
|||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "constants.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} {
|
||||||
map.reserve(MAP_HEIGHT * MAP_WIDTH);
|
map.reserve(MAP_HEIGHT * MAP_WIDTH);
|
||||||
@ -25,7 +26,6 @@ game_map::game_map(character *player, RNG *rng, const feature enabled_features):
|
|||||||
|
|
||||||
gen_path(layer_data, rng);
|
gen_path(layer_data, rng);
|
||||||
|
|
||||||
|
|
||||||
rooms_tile_list.reserve(room_data.size());
|
rooms_tile_list.reserve(room_data.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < room_data.size(); ++i)
|
for (size_t i = 0; i < room_data.size(); ++i)
|
||||||
@ -41,7 +41,7 @@ game_map::game_map(character *player, RNG *rng, const feature enabled_features):
|
|||||||
rooms_tile_list.shrink_to_fit();
|
rooms_tile_list.shrink_to_fit();
|
||||||
|
|
||||||
int player_room = rng->rand_under(room_data.size());
|
int player_room = rng->rand_under(room_data.size());
|
||||||
player->set_position(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);
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ game_map::game_map(character *player, const std::string &map_data,
|
|||||||
room_data.push_back({0, 0, 0, 0});
|
room_data.push_back({0, 0, 0, 0});
|
||||||
|
|
||||||
int player_room = rng->rand_under(room_data.size());
|
int player_room = rng->rand_under(room_data.size());
|
||||||
player->set_position(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);
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ std::vector<game_map::room> game_map::distr_rooms(RNG *rng,
|
|||||||
if (l == r) {
|
if (l == r) {
|
||||||
result.push_back({
|
result.push_back({
|
||||||
0, rng->rand_under(ACTUAL_MAP_WIDTH -
|
0, rng->rand_under(ACTUAL_MAP_WIDTH -
|
||||||
room_dims[l].first.x + 1),
|
room_dims[l].first.x + 1),
|
||||||
room_dims[l].first.x,
|
room_dims[l].first.x,
|
||||||
room_dims[l].first.y, {0, 0}, {0, 0}});
|
room_dims[l].first.y, {0, 0}, {0, 0}});
|
||||||
continue;
|
continue;
|
||||||
@ -557,3 +557,11 @@ bool game_map::hit_room(const position &a, const room &r) {
|
|||||||
return a.y >= r.top - 1 && a.y <= r.top + r.height &&
|
return a.y >= r.top - 1 && a.y <= r.top + r.height &&
|
||||||
a.x >= r.left - 1 && a.x <= r.left + r.width;
|
a.x >= r.left - 1 && a.x <= r.left + r.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position game_map::remap_index(const int idx) const {
|
||||||
|
return {idx % MAP_WIDTH, idx / MAP_WIDTH};
|
||||||
|
}
|
||||||
|
|
||||||
|
int game_map::remap_position(const position &pos) const {
|
||||||
|
return pos.y * MAP_WIDTH + pos.x;
|
||||||
|
}
|
||||||
|
18
src/map.h
18
src/map.h
@ -3,11 +3,12 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "constants.h"
|
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
#include "fraction.h"
|
#include "fraction.h"
|
||||||
|
#include "player.h"
|
||||||
#include "characters.h"
|
#include "characters.h"
|
||||||
|
|
||||||
class game_map final {
|
class game_map final {
|
||||||
@ -18,8 +19,8 @@ private:
|
|||||||
static const int MAX_ROOM_WIDTH = 20;
|
static const int MAX_ROOM_WIDTH = 20;
|
||||||
static const int MAX_ROOM_HEIGHT = 5;
|
static const int MAX_ROOM_HEIGHT = 5;
|
||||||
// setup safezones
|
// setup safezones
|
||||||
static const int ACTUAL_MAP_WIDTH = MAP_WIDTH - 6;
|
static const int ACTUAL_MAP_WIDTH = 73;
|
||||||
static const int ACTUAL_MAP_HEIGHT = MAP_HEIGHT - 5;
|
static const int ACTUAL_MAP_HEIGHT = 20;
|
||||||
static const int MAP_PADDING = 3;
|
static const int MAP_PADDING = 3;
|
||||||
static const int MIN_ROOM_SPACING = 3;
|
static const int MIN_ROOM_SPACING = 3;
|
||||||
static const int WIDTH_RESERVED = 6;
|
static const int WIDTH_RESERVED = 6;
|
||||||
@ -72,16 +73,10 @@ public:
|
|||||||
int get_down_stairs_room() const;
|
int get_down_stairs_room() const;
|
||||||
|
|
||||||
int get_room_cnt() const;
|
int get_room_cnt() const;
|
||||||
room get_room(std::size_t idx) const;
|
|
||||||
private:
|
private:
|
||||||
std::vector<room> room_data;
|
std::vector<room> room_data;
|
||||||
position remap_index(const int idx) const {
|
position remap_index(const int idx) const;
|
||||||
return {idx % MAP_WIDTH, idx / MAP_WIDTH};
|
int remap_position(const position &pos) const;
|
||||||
}
|
|
||||||
|
|
||||||
int remap_position(const position &pos) const {
|
|
||||||
return pos.y * MAP_WIDTH + pos.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
position random_size(int min_width, int min_height,
|
position random_size(int min_width, int min_height,
|
||||||
int max_width, int max_height,
|
int max_width, int max_height,
|
||||||
@ -113,6 +108,7 @@ private:
|
|||||||
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(int player_room, RNG *rng);
|
||||||
|
room get_room(std::size_t idx) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string default_map =
|
const std::string default_map =
|
||||||
|
40
src/pc.cc
Normal file
40
src/pc.cc
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include "pc.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "player/goblin.h"
|
||||||
|
#include "player/drow.h"
|
||||||
|
#include "player/shade.h"
|
||||||
|
#include "player/troll.h"
|
||||||
|
#include "player/vampire.h"
|
||||||
|
|
||||||
|
void init_player(RNG *rng, std::unique_ptr<player_base> &pc,
|
||||||
|
const feature enabled_features, const enum race &r) {
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
pc = nullptr;
|
||||||
|
|
||||||
|
switch (r) {
|
||||||
|
case rgoblin:
|
||||||
|
pc = make_unique<goblin>(rng, enabled_features);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rdrow:
|
||||||
|
pc = make_unique<drow>(rng, enabled_features);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rshade:
|
||||||
|
pc = make_unique<shade>(rng, enabled_features);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rtroll:
|
||||||
|
pc = make_unique<troll>(rng, enabled_features);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case rvampire:
|
||||||
|
pc = make_unique<vampire>(rng, enabled_features);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
10
src/pc.h
Normal file
10
src/pc.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef __PC_H__
|
||||||
|
#define __PC_H__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
void init_player(RNG *rng, std::unique_ptr<player_base> &pc,
|
||||||
|
const feature enabled_features, const enum race &r);
|
||||||
|
|
||||||
|
#endif
|
151
src/player.cc
Normal file
151
src/player.cc
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "enemy.h"
|
||||||
|
#include "level.h"
|
||||||
|
|
||||||
|
player_base::player_base(RNG *rng, const feature enabled_features,
|
||||||
|
const enum race &nrace):
|
||||||
|
character{rng, enabled_features, nrace, {0, 0}}, gold_cnt(0) {}
|
||||||
|
|
||||||
|
void player_base::print(display *out) {
|
||||||
|
out->print_char(pos, '@', COLOR_PAIR(COLOR_BLUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string player_base::get_abbrev() const {
|
||||||
|
return "PC";
|
||||||
|
}
|
||||||
|
|
||||||
|
int player_base::get_gold() const {
|
||||||
|
return this->gold_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int player_base::get_ATK() const {
|
||||||
|
return this->ATK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int player_base::get_DEF() const {
|
||||||
|
return this->DEF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int player_base::get_HP() const {
|
||||||
|
return this->HP;
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result player_base::apply(potion *p) {
|
||||||
|
if (p == nullptr)
|
||||||
|
return {result::applied_nothing,
|
||||||
|
"PC tried to breathe the magic in the air. "};
|
||||||
|
|
||||||
|
apply_effect(p);
|
||||||
|
|
||||||
|
return {result::applied,
|
||||||
|
(std::string)"PC applied potion of " + p->get_name()};
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result player_base::attack(character *ch) {
|
||||||
|
if (ch == nullptr)
|
||||||
|
return {result::fine,
|
||||||
|
"PC tried to attack thin air. "};
|
||||||
|
|
||||||
|
return ch->get_hit(this, ATK, base_hit_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result player_base::move(level *lvl,
|
||||||
|
const position &p) {
|
||||||
|
if (enabled_features & FEATURE_NCURSES) {
|
||||||
|
enemy_base *tmp = nullptr;
|
||||||
|
|
||||||
|
if (lvl->is_available(p, true)) {
|
||||||
|
pos = p;
|
||||||
|
return {result::moved, ""};
|
||||||
|
} else if ((tmp = get_enemy_at(p, lvl->get_elist())) != nullptr) {
|
||||||
|
auto res = attack((character *)tmp);
|
||||||
|
|
||||||
|
if (tmp->is_dead())
|
||||||
|
tmp->dies(lvl, this);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else if (lvl->get_up_stairs() == p &&
|
||||||
|
enabled_features & FEATURE_REVISIT) {
|
||||||
|
return {result::go_up, "PC went up the stairs. "};
|
||||||
|
} else if (lvl->get_down_stairs() == p) {
|
||||||
|
return {result::go_down, "PC went down the stairs. "};
|
||||||
|
} else if (lvl->is_available(p, true)) {
|
||||||
|
pos = p;
|
||||||
|
return {result::moved, ""};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result::fine, "PC tried to move into non-existent space. "};
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result player_base::get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate) {
|
||||||
|
if (rng->trial(hit_rate)) {
|
||||||
|
int tmp = calc_dmg(tATK, DEF);
|
||||||
|
tmp = tmp > HP ? HP : tmp;
|
||||||
|
HP -= tmp;
|
||||||
|
|
||||||
|
if (HP == 0)
|
||||||
|
return {result::died,
|
||||||
|
ch->get_abbrev() + " deals " +
|
||||||
|
std::to_string(tmp) +
|
||||||
|
" damage to PC. PC is slain by " +
|
||||||
|
ch->get_abbrev() + ". "};
|
||||||
|
|
||||||
|
return {result::hit, ch->get_abbrev() + " deals " +
|
||||||
|
std::to_string(tmp) +
|
||||||
|
" damage to PC. "};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result::miss, ch->get_abbrev() + " tried to hit PC but missed. "};
|
||||||
|
}
|
||||||
|
|
||||||
|
void player_base::add_gold(int amount) {
|
||||||
|
gold_cnt += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result player_base::interpret_command(level *lvl, game_command cmd) {
|
||||||
|
if (cmd == game_command_terminate) {
|
||||||
|
return {result::terminate, ""};
|
||||||
|
} else if (cmd >= move_north && cmd <= move_southwest) {
|
||||||
|
return move(lvl, pos + MOVE[cmd - move_north]);
|
||||||
|
} else if (cmd >= apply_north && cmd <= apply_southwest) {
|
||||||
|
return apply(get_potion_at(pos + MOVE[cmd - apply_north],
|
||||||
|
lvl->get_plist()));
|
||||||
|
} else if (cmd == apply_panic) {
|
||||||
|
return {result::fine,
|
||||||
|
"PC tried to use in some non-existent direction. "};
|
||||||
|
} else if (cmd >= attack_north && cmd <= attack_southwest) {
|
||||||
|
enemy_base *tmp = get_enemy_at(pos + MOVE[cmd - attack_north],
|
||||||
|
lvl->get_elist());
|
||||||
|
auto res = attack((character *)tmp);
|
||||||
|
|
||||||
|
if (tmp->is_dead())
|
||||||
|
tmp->dies(lvl, this);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} else if (cmd == up_stairs) {
|
||||||
|
if (lvl->get_up_stairs() == pos &&
|
||||||
|
enabled_features & FEATURE_REVISIT)
|
||||||
|
return {go_up, "PC went up the stairs. "};
|
||||||
|
|
||||||
|
return {result::fine,
|
||||||
|
"PC tried to fly through the ceiling. "};
|
||||||
|
} else if (cmd == down_stairs) {
|
||||||
|
if (lvl->get_down_stairs() == pos)
|
||||||
|
return {go_down, "PC went down the stairs. "};
|
||||||
|
|
||||||
|
return {result::fine,
|
||||||
|
"PC tried to dig through the floor. "};
|
||||||
|
} else if (cmd == the_world) {
|
||||||
|
return{toggle_the_world, "PC toggled Stand: The World! "};
|
||||||
|
} else if (cmd == game_restart) {
|
||||||
|
return {restart_game, ""};
|
||||||
|
} else if (cmd == game_command_pass) {
|
||||||
|
return {result::fine, ""};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {unknown, "PC tried to produce some undefined behaviour. "};
|
||||||
|
}
|
38
src/player.h
Normal file
38
src/player.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __PLAYER_H__
|
||||||
|
#define __PLAYER_H__
|
||||||
|
|
||||||
|
#include "characters.h"
|
||||||
|
|
||||||
|
enum game_command : int;
|
||||||
|
|
||||||
|
class player_base: public character {
|
||||||
|
protected:
|
||||||
|
int gold_cnt;
|
||||||
|
potion_list potions;
|
||||||
|
public:
|
||||||
|
player_base(RNG *rng, const feature enabled_features,
|
||||||
|
const enum race &nrace);
|
||||||
|
virtual long_result move(level *lvl,
|
||||||
|
const position &p) override;
|
||||||
|
|
||||||
|
virtual long_result apply(potion *p);
|
||||||
|
|
||||||
|
virtual long_result attack(character *ch) override;
|
||||||
|
virtual long_result get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate) override;
|
||||||
|
|
||||||
|
virtual void add_gold(int amount);
|
||||||
|
|
||||||
|
void print(display *out) override;
|
||||||
|
|
||||||
|
std::string get_abbrev() const override;
|
||||||
|
|
||||||
|
long_result interpret_command(level *lvl, game_command cmd);
|
||||||
|
|
||||||
|
int get_gold() const;
|
||||||
|
int get_ATK() const;
|
||||||
|
int get_DEF() const;
|
||||||
|
int get_HP() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
10
src/player/drow.cc
Normal file
10
src/player/drow.cc
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "drow.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
drow::drow(RNG *rng, const feature enabled_features):
|
||||||
|
player_base{rng, enabled_features, race::rdrow} {}
|
||||||
|
|
||||||
|
const char *drow::get_race_name() const {
|
||||||
|
return "Drow";
|
||||||
|
}
|
12
src/player/drow.h
Normal file
12
src/player/drow.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __DROW_H__
|
||||||
|
#define __DROW_H__
|
||||||
|
|
||||||
|
#include "../player.h"
|
||||||
|
|
||||||
|
class drow final: public player_base {
|
||||||
|
public:
|
||||||
|
drow(RNG *rng, const feature enabled_features);
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
53
src/player/goblin.cc
Normal file
53
src/player/goblin.cc
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "goblin.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
goblin::goblin(RNG *rng, const feature enabled_features):
|
||||||
|
player_base{rng, enabled_features, race::rgoblin} {};
|
||||||
|
|
||||||
|
const char *goblin::get_race_name() const {
|
||||||
|
return "Goblin";
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result goblin::attack(character *ch) {
|
||||||
|
if (ch == nullptr)
|
||||||
|
return {result::fine,
|
||||||
|
"PC tried to attack thin air. "};
|
||||||
|
|
||||||
|
auto res = ch->get_hit(this, ATK, base_hit_rate);
|
||||||
|
|
||||||
|
if (ch->is_dead()) {
|
||||||
|
gold_cnt += GAIN_GOLD;
|
||||||
|
res.msg += "PC feels greedy. ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result goblin::get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate) {
|
||||||
|
if (rng->trial(hit_rate)) {
|
||||||
|
int tmp = calc_dmg(tATK, DEF);
|
||||||
|
std::string msg = "";
|
||||||
|
|
||||||
|
if (ch->get_race() == rorc) {
|
||||||
|
msg += "PC feels scared. ";
|
||||||
|
tmp *= ORC_DMG_MUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = tmp > HP ? HP : tmp;
|
||||||
|
HP -= tmp;
|
||||||
|
msg += ch->get_abbrev() + " deals " +
|
||||||
|
std::to_string(tmp) +
|
||||||
|
" damage to PC. ";
|
||||||
|
|
||||||
|
if (HP == 0)
|
||||||
|
return {result::died,
|
||||||
|
msg + "PC is slain by " +
|
||||||
|
ch->get_abbrev() + ". "};
|
||||||
|
|
||||||
|
return {result::hit, msg};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {result::miss, ch->get_abbrev() + " tried to hit PC but missed. "};
|
||||||
|
}
|
17
src/player/goblin.h
Normal file
17
src/player/goblin.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef __GOBLIN_H__
|
||||||
|
#define __GOBLIN_H__
|
||||||
|
|
||||||
|
#include "../player.h"
|
||||||
|
|
||||||
|
class goblin final: public player_base {
|
||||||
|
static const int GAIN_GOLD = 5;
|
||||||
|
constexpr static const float ORC_DMG_MUL = 1.5f;
|
||||||
|
public:
|
||||||
|
goblin(RNG *rng, const feature enabled_features);
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
long_result attack(character *ch) override;
|
||||||
|
long_result get_hit(character *ch, const int tATK,
|
||||||
|
const fraction &hit_rate) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
10
src/player/shade.cc
Normal file
10
src/player/shade.cc
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "shade.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
shade::shade(RNG *rng, const feature enabled_features):
|
||||||
|
player_base{rng, enabled_features, race::rshade} {}
|
||||||
|
|
||||||
|
const char *shade::get_race_name() const {
|
||||||
|
return "Shade";
|
||||||
|
}
|
12
src/player/shade.h
Normal file
12
src/player/shade.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __SHADE_H__
|
||||||
|
#define __SHADE_H__
|
||||||
|
|
||||||
|
#include "../player.h"
|
||||||
|
|
||||||
|
class shade final: public player_base {
|
||||||
|
public:
|
||||||
|
shade(RNG *rng, const feature enabled_features);
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
17
src/player/troll.cc
Normal file
17
src/player/troll.cc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "troll.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
troll::troll(RNG *rng, const feature enabled_features):
|
||||||
|
player_base{rng, enabled_features, rtroll} {}
|
||||||
|
|
||||||
|
const char *troll::get_race_name() const {
|
||||||
|
return "Troll";
|
||||||
|
}
|
||||||
|
|
||||||
|
void troll::start_turn() {
|
||||||
|
ATK = STARTING_ATK[rtroll];
|
||||||
|
DEF = STARTING_DEF[rtroll];
|
||||||
|
base_hit_rate = {1, 1};
|
||||||
|
HP = HP + GAIN_HP < MAX_HP[rtroll] ? HP + GAIN_HP : MAX_HP[rtroll];
|
||||||
|
}
|
14
src/player/troll.h
Normal file
14
src/player/troll.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __TROLL_H__
|
||||||
|
#define __TROLL_H__
|
||||||
|
|
||||||
|
#include "../player.h"
|
||||||
|
|
||||||
|
class troll final: public player_base {
|
||||||
|
static const int GAIN_HP = 5;
|
||||||
|
public:
|
||||||
|
troll(RNG *rng, const feature enabled_features);
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
void start_turn() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
33
src/player/vampire.cc
Normal file
33
src/player/vampire.cc
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "vampire.h"
|
||||||
|
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
vampire::vampire(RNG *rng, const feature enabled_features):
|
||||||
|
player_base{rng, enabled_features, race::rvampire} {};
|
||||||
|
|
||||||
|
const char *vampire::get_race_name() const {
|
||||||
|
return "Vampire";
|
||||||
|
}
|
||||||
|
|
||||||
|
long_result vampire::attack(character *ch) {
|
||||||
|
if (ch == nullptr)
|
||||||
|
return {result::fine,
|
||||||
|
"PC tried to drain thin air. "};
|
||||||
|
|
||||||
|
auto res = ch->get_hit(this, ATK, base_hit_rate);
|
||||||
|
|
||||||
|
if (res.res == miss)
|
||||||
|
return {miss, res.msg + "PC is unhappy. "};
|
||||||
|
|
||||||
|
if (ch->get_race() == rdwarf) {
|
||||||
|
HP -= GAIN_HP;
|
||||||
|
|
||||||
|
if (is_dead())
|
||||||
|
return {died, ""};
|
||||||
|
|
||||||
|
return {hit, res.msg + "PC accidentally drained themselves. "};
|
||||||
|
}
|
||||||
|
|
||||||
|
HP += GAIN_HP;
|
||||||
|
return {hit, res.msg + "PC is happy. "};
|
||||||
|
}
|
14
src/player/vampire.h
Normal file
14
src/player/vampire.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __VAMPIRE_H__
|
||||||
|
#define __VAMPIRE_H__
|
||||||
|
|
||||||
|
#include "../player.h"
|
||||||
|
|
||||||
|
class vampire final: public player_base {
|
||||||
|
static const int GAIN_HP = 5;
|
||||||
|
public:
|
||||||
|
vampire(RNG *rng, const feature enabled_features);
|
||||||
|
const char *get_race_name() const override;
|
||||||
|
long_result attack(character *ch) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -3,28 +3,29 @@
|
|||||||
#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,
|
typedef std::vector<position> position_list;
|
||||||
|
|
||||||
|
std::size_t find(const position_list &sorted_list,
|
||||||
const position &target);
|
const position &target);
|
||||||
|
|
||||||
// requires: all elements of excluded are in sorted_positions
|
// requires: all elements of excluded are in sorted_positions
|
||||||
std::vector<position> remove_from_list(const std::vector<position>
|
std::vector<position> remove_from_list(const position_list &sorted_positions,
|
||||||
&sorted_positions,
|
position_list excluded);
|
||||||
std::vector<position> excluded);
|
void remove_from_list(position_list &sorted_positions,
|
||||||
void remove_from_list(std::vector<position> &sorted_positions,
|
|
||||||
position &excluded);
|
position &excluded);
|
||||||
|
|
||||||
float distance(const position &a, const position &b);
|
float distance(const position &a, const position &b);
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
#include "potion.h"
|
#include "potion.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
|
||||||
potion::potion(const potion_type type, const int duration, const position &pos):
|
potion::potion(const potion_type type, const int duration, const position &pos):
|
||||||
type{type}, remaining_duration{duration}, pos{pos} {}
|
type{type}, remaining_duration{duration}, pos{pos} {}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
position potion::get_pos() const {
|
position potion::get_pos() const {
|
||||||
@ -44,3 +46,16 @@ potion &potion::operator=(potion &&p) {
|
|||||||
void potion::print(display *out) {
|
void potion::print(display *out) {
|
||||||
out->print_char(pos, 'P', COLOR_PAIR(COLOR_GREEN));
|
out->print_char(pos, 'P', COLOR_PAIR(COLOR_GREEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
potion *get_potion_at(const position &pos, potion_list &plist) {
|
||||||
|
potion *ret = nullptr;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < plist.size(); ++i)
|
||||||
|
if (plist[i]->get_pos() == pos) {
|
||||||
|
ret = plist[i];
|
||||||
|
plist.erase(plist.begin() + i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
#define __POTION_H__
|
#define __POTION_H__
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "constants.h"
|
|
||||||
#include "fraction.h"
|
#include "fraction.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
|
|
||||||
|
enum potion_type : int;
|
||||||
|
enum race : int;
|
||||||
|
|
||||||
// IMPORTANT: pop all potions of duration == 0, and when entering a
|
// IMPORTANT: pop all potions of duration == 0, and when entering a
|
||||||
// new level, pop all potions of duration == -1
|
// new level, pop all potions of duration == -1
|
||||||
|
|
||||||
@ -32,10 +34,13 @@ public:
|
|||||||
int get_duration() const;
|
int get_duration() const;
|
||||||
position get_pos() const;
|
position get_pos() const;
|
||||||
void set_pos(const position &npos);
|
void set_pos(const position &npos);
|
||||||
|
virtual const char *get_name() const = 0;
|
||||||
|
|
||||||
virtual void print(display *out);
|
virtual void print(display *out);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<potion *> potion_list;
|
typedef std::vector<potion *> potion_list;
|
||||||
|
|
||||||
|
potion *get_potion_at(const position &pos, potion_list &plist);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,12 +1,40 @@
|
|||||||
#include "potions.h"
|
#include "potions.h"
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "potions/restore_health.h"
|
||||||
|
#include "potions/boost_atk.h"
|
||||||
|
#include "potions/boost_def.h"
|
||||||
|
#include "potions/poison_health.h"
|
||||||
|
#include "potions/wound_atk.h"
|
||||||
|
#include "potions/wound_def.h"
|
||||||
|
|
||||||
void new_potion(std::unique_ptr<potion> &pp, potion_type type,
|
void new_potion(std::unique_ptr<potion> &pp, potion_type type,
|
||||||
const position &pos) {
|
const position &pos) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case potion_type::restore_health:
|
case restore_health:
|
||||||
pp = std::make_unique<class restore_health>(pos);
|
pp = std::make_unique<class restore_health>(pos);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case boost_atk:
|
||||||
|
pp = std::make_unique<class boost_atk>(pos);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case boost_def:
|
||||||
|
pp = std::make_unique<class boost_def>(pos);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case poison_health:
|
||||||
|
pp = std::make_unique<class poison_health>(pos);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case wound_atk:
|
||||||
|
pp = std::make_unique<class wound_atk>(pos);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case wound_def:
|
||||||
|
pp = std::make_unique<class wound_def>(pos);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define __POTIONS_H__
|
#define __POTIONS_H__
|
||||||
|
|
||||||
#include "potion.h"
|
#include "potion.h"
|
||||||
#include "restore_health.h"
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "boost_atk.h"
|
#include "boost_atk.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
const int BOOST_ATK = 5;
|
const int BOOST_ATK = 5;
|
||||||
const int BOOST_ATK_DROW = 7;
|
const int BOOST_ATK_DROW = 7;
|
||||||
@ -23,3 +24,7 @@ void boost_atk::apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
|||||||
int boost_atk::get_priority() const {
|
int boost_atk::get_priority() const {
|
||||||
return CALC_ADD_BASE;
|
return CALC_ADD_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *boost_atk::get_name() const {
|
||||||
|
return "BA";
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef __BOOST_ATK_H__
|
#ifndef __BOOST_ATK_H__
|
||||||
#define __BOOST_ATK_H__
|
#define __BOOST_ATK_H__
|
||||||
|
|
||||||
#include "potion.h"
|
#include "../potion.h"
|
||||||
|
|
||||||
class boost_atk final: public potion {
|
class boost_atk final: public potion {
|
||||||
public:
|
public:
|
||||||
@ -9,6 +9,7 @@ public:
|
|||||||
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
||||||
fraction &base_hit_rate) override;
|
fraction &base_hit_rate) override;
|
||||||
int get_priority() const override;
|
int get_priority() const override;
|
||||||
|
const char *get_name() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,6 +1,7 @@
|
|||||||
#include "boost_def.h"
|
#include "boost_def.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
// TODO: move into class def as static constants
|
// TODO: move into class def as static constants
|
||||||
const int BOOST_DEF = 5;
|
const int BOOST_DEF = 5;
|
||||||
@ -24,3 +25,7 @@ void boost_def::apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
|||||||
int boost_def::get_priority() const {
|
int boost_def::get_priority() const {
|
||||||
return CALC_ADD_BASE;
|
return CALC_ADD_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *boost_def::get_name() const {
|
||||||
|
return "BD";
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef __BOOST_DEF_H__
|
#ifndef __BOOST_DEF_H__
|
||||||
#define __BOOST_DEF_H__
|
#define __BOOST_DEF_H__
|
||||||
|
|
||||||
#include "potion.h"
|
#include "../potion.h"
|
||||||
|
|
||||||
class boost_def final: public potion {
|
class boost_def final: public potion {
|
||||||
public:
|
public:
|
||||||
@ -9,6 +9,7 @@ public:
|
|||||||
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
||||||
fraction &base_hit_rate) override;
|
fraction &base_hit_rate) override;
|
||||||
int get_priority() const override;
|
int get_priority() const override;
|
||||||
|
const char *get_name() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,6 +1,7 @@
|
|||||||
#include "poison_health.h"
|
#include "poison_health.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
poison_health::poison_health(const position &pos):
|
poison_health::poison_health(const position &pos):
|
||||||
potion{potion_type::poison_health, 1, pos} {}
|
potion{potion_type::poison_health, 1, pos} {}
|
||||||
@ -20,3 +21,7 @@ void poison_health::apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
|||||||
int poison_health::get_priority() const {
|
int poison_health::get_priority() const {
|
||||||
return CALC_ADD_BASE;
|
return CALC_ADD_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *poison_health::get_name() const {
|
||||||
|
return "PH";
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef __POISON_HEALTH_H__
|
#ifndef __POISON_HEALTH_H__
|
||||||
#define __POISON_HEALTH_H__
|
#define __POISON_HEALTH_H__
|
||||||
|
|
||||||
#include "potion.h"
|
#include "../potion.h"
|
||||||
|
|
||||||
class poison_health final: public potion {
|
class poison_health final: public potion {
|
||||||
public:
|
public:
|
||||||
@ -9,6 +9,7 @@ public:
|
|||||||
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
||||||
fraction &base_hit_rate) override;
|
fraction &base_hit_rate) override;
|
||||||
int get_priority() const override;
|
int get_priority() const override;
|
||||||
|
const char *get_name() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,6 +1,7 @@
|
|||||||
#include "restore_health.h"
|
#include "restore_health.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
restore_health::restore_health(const position &pos):
|
restore_health::restore_health(const position &pos):
|
||||||
potion{potion_type::restore_health, -1, pos} {}
|
potion{potion_type::restore_health, -1, pos} {}
|
||||||
@ -13,10 +14,14 @@ void restore_health::apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *restore_health::get_name() const {
|
||||||
|
return "RH";
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef __RESTORE_HEALTH_H__
|
#ifndef __RESTORE_HEALTH_H__
|
||||||
#define __RESTORE_HEALTH_H__
|
#define __RESTORE_HEALTH_H__
|
||||||
|
|
||||||
#include "potion.h"
|
#include "../potion.h"
|
||||||
|
|
||||||
class restore_health final: public potion {
|
class restore_health final: public potion {
|
||||||
public:
|
public:
|
||||||
@ -9,6 +9,7 @@ public:
|
|||||||
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
void apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
||||||
fraction &base_hit_rate) override;
|
fraction &base_hit_rate) override;
|
||||||
int get_priority() const override;
|
int get_priority() const override;
|
||||||
|
const char *get_name() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,6 +1,7 @@
|
|||||||
#include "wound_atk.h"
|
#include "wound_atk.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
const int WOUND_ATK = 5;
|
const int WOUND_ATK = 5;
|
||||||
const int WOUND_ATK_DROW = 7;
|
const int WOUND_ATK_DROW = 7;
|
||||||
@ -23,3 +24,7 @@ void wound_atk::apply(const enum race &race, int &HP, int &ATK, int &DEF,
|
|||||||
int wound_atk::get_priority() const {
|
int wound_atk::get_priority() const {
|
||||||
return CALC_ADD_BASE;
|
return CALC_ADD_BASE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *wound_atk::get_name() const {
|
||||||
|
return "WA";
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user