#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 + " (" + std::to_string(HP) + " HP). " + abbrev + " is slain by PC. "}; return {result::hit, "PC deals " + std::to_string(tmp) + " damage to " + abbrev + " (" + std::to_string(HP) + " HP). "}; } 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; }