#include "characters.h" #include character::character(RNG *rng, const enum race &nrace, const position &pos): rng{rng}, race{nrace}, HP{STARTING_HP[race]}, ATK{STARTING_ATK[race]}, DEF{STARTING_DEF[race]}, base_hit_rate{1, 1}, pos{pos} {} void character::start_turn() { ATK = STARTING_ATK[race]; DEF = STARTING_DEF[race]; base_hit_rate = {1, 1}; } 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 { return race; } position character::get_position() const { return pos; } int character::get_HP() const { 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; } bool character::is_hostile() const { return hostile; } void character::set_room_num(const int room) { room_num = room; } void character::set_position(const position &npos) { pos = npos; } void character::set_HP(const int nHP) { HP = nHP; } void character::set_ATK(const int nATK) { ATK = nATK; } 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; } 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; } } } 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; } void character::apply(direction &dir, potion_list &plist) { for (size_t i = 0; i < plist.size(); ++i) if (pos + MOVE[dir] == plist[i]->get_pos()) { insert_potion(plist[i]); plist.erase(plist.begin() + i); return; } } void character::insert_potion(potion *p) { effects.push_back(p); for (int i = effects.size() - 1; i > 0; --i) if (p->get_priority() < effects[i - 1]->get_priority()) std::swap(effects[i], effects[i - 1]); } result character::apply_effects() { potion_list tmp; tmp.reserve(effects.size()); for (auto p : effects) { p->apply(this->race, HP, ATK, DEF, base_hit_rate); if (HP <= 0) return result::died; if (p->get_duration() != 0) tmp.push_back(p); } tmp.shrink_to_fit(); std::swap(tmp, effects); return result::fine; } void character::discard_level_effects() { potion_list tmp; tmp.reserve(effects.size()); for (auto p : effects) if (p->get_duration() != -1) tmp.push_back(p); tmp.shrink_to_fit(); std::swap(tmp, effects); } // IMPORTANT: remember to check if player is on the stairs result character::move(const direction dir, const position_list &available_positions) { if (find(available_positions, pos + MOVE[dir]) != available_positions.size()) { pos += MOVE[dir]; return result::moved; } return result::fine; } result character::move_or_attack(const direction dir, const position_list &available_positions, character_list &chlist) { auto res = this->move(dir, available_positions); if (res != result::fine) return res; return this->attack(dir, chlist); } int calc_dmg(const int ATK, const int DEF) { return ceil((100 / (100 + DEF)) * ATK); }