* @author Hourier
*/
-#include "monster/monster-damage.h"
+#include <algorithm>
+
+#include "avatar/avatar-changer.h"
#include "core/player-redraw-types.h"
#include "core/speed-table.h"
#include "core/stuff-handler.h"
-#include "dungeon/dungeon.h"
#include "game-option/birth-options.h"
#include "game-option/play-record-options.h"
#include "io/files-util.h"
#include "monster-floor/place-monster-types.h"
#include "monster-race/monster-race-hook.h"
#include "monster-race/monster-race.h"
-#include "monster-race/race-ability-mask.h"
#include "monster-race/race-flags1.h"
#include "monster-race/race-flags2.h"
#include "monster-race/race-flags3.h"
#include "monster-race/race-flags7.h"
#include "monster-race/race-flags8.h"
+#include "monster/monster-damage.h"
#include "monster/monster-describer.h"
#include "monster/monster-description-types.h"
#include "monster/monster-info.h"
#include "monster/monster-status-setter.h"
#include "monster/monster-status.h"
#include "object-enchant/object-curse.h"
-#include "player-info/avatar.h"
#include "player/player-status.h"
#include "player/special-defense-types.h"
#include "spell-kind/spells-random.h"
#include "util/bit-flags-calculator.h"
#include "view/display-messages.h"
#include "world/world.h"
-#include <algorithm>
/*
* @brief コンストラクタ
- * @param target_ptr プレーヤーへの参照ポインタ
+ * @param player_ptr プレイヤーへの参照ポインタ
* @param m_idx ダメージを与えたモンスターのID
* @param dam 与えたダメージ量
* @param fear ダメージによってモンスターが恐慌状態に陥ったならばtrue
+ * @param attribute 与えたダメージの種類 (単一属性)
* @param note モンスターが倒された際の特別なメッセージ述語
*/
-MonsterDamageProcessor::MonsterDamageProcessor(player_type *target_ptr, MONSTER_IDX m_idx, HIT_POINT dam, bool *fear)
- : target_ptr(target_ptr)
+MonsterDamageProcessor::MonsterDamageProcessor(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *fear, AttributeType attribute)
+ : player_ptr(player_ptr)
, m_idx(m_idx)
, dam(dam)
, fear(fear)
{
+ this->attribute_flags.clear();
+ this->attribute_flags.set((AttributeType)attribute);
+}
+
+/*
+ * @brief コンストラクタ
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param m_idx ダメージを与えたモンスターのID
+ * @param dam 与えたダメージ量
+ * @param fear ダメージによってモンスターが恐慌状態に陥ったならばtrue
+ * @param attribute_flags 与えたダメージの種類 (複数属性)
+ * @param note モンスターが倒された際の特別なメッセージ述語
+ */
+MonsterDamageProcessor::MonsterDamageProcessor(PlayerType *player_ptr, MONSTER_IDX m_idx, int dam, bool *fear, AttributeFlags attribute_flags)
+ : player_ptr(player_ptr)
+ , m_idx(m_idx)
+ , dam(dam)
+ , fear(fear)
+ , attribute_flags(attribute_flags)
+{
}
/*!
*/
bool MonsterDamageProcessor::mon_take_hit(concptr note)
{
- auto *m_ptr = &this->target_ptr->current_floor_ptr->m_list[this->m_idx];
- auto innocent = true;
- auto thief = false;
-
- monster_type exp_mon;
- (void)COPY(&exp_mon, m_ptr, monster_type);
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
+ auto exp_mon = *m_ptr;
auto exp_dam = (m_ptr->hp > this->dam) ? this->dam : m_ptr->hp;
m_ptr->dealt_damage = m_ptr->max_maxhp * 100;
}
- if (current_world_ptr->wizard) {
+ if (w_ptr->wizard) {
msg_format(_("合計%d/%dのダメージを与えた。", "You do %d (out of %d) damage."), m_ptr->dealt_damage, m_ptr->maxhp);
}
- auto *r_ptr = &r_info[m_ptr->r_idx];
- if (m_ptr->hp < 0) {
- this->death_special_flag_monster();
- if (r_ptr->r_akills < MAX_SHORT) {
- r_ptr->r_akills++;
- }
-
- this->increase_kill_numbers();
- GAME_TEXT m_name[MAX_NLEN];
- monster_desc(this->target_ptr, m_name, m_ptr, MD_TRUE_NAME);
- this->death_amberites(m_name);
- this->dying_scream(m_name);
- this->change_virtue_non_beginner();
- if (r_ptr->flags1 & RF1_UNIQUE) {
- if (r_ptr->flags3 & (RF3_EVIL | RF3_GOOD))
- chg_virtue(this->target_ptr, V_HARMONY, 2);
-
- if (r_ptr->flags3 & RF3_GOOD) {
- chg_virtue(this->target_ptr, V_UNLIFE, 2);
- chg_virtue(this->target_ptr, V_VITALITY, -2);
- }
-
- if (one_in_(3))
- chg_virtue(this->target_ptr, V_INDIVIDUALISM, -1);
- }
-
- if (m_ptr->r_idx == MON_BEGGAR || m_ptr->r_idx == MON_LEPER) {
- chg_virtue(this->target_ptr, V_COMPASSION, -1);
- }
-
- auto *floor_ptr = this->target_ptr->current_floor_ptr;
- if ((r_ptr->flags3 & RF3_GOOD) && ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100)))
- chg_virtue(this->target_ptr, V_UNLIFE, 1);
-
- if (any_bits(r_ptr->flags3, RF3_ANGEL)) {
- if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
- chg_virtue(this->target_ptr, V_FAITH, -2);
- } else if ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100)) {
- auto change_value = any_bits(r_ptr->flags3, RF3_GOOD) ? -1 : 1;
- chg_virtue(this->target_ptr, V_FAITH, change_value);
- }
- } else if (any_bits(r_ptr->flags3, RF3_DEMON)) {
- if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
- chg_virtue(this->target_ptr, V_FAITH, 2);
- } else if ((r_ptr->level) / 10 + (3 * floor_ptr->dun_level) >= randint1(100)) {
- chg_virtue(this->target_ptr, V_FAITH, 1);
- }
- }
-
- if (any_bits(r_ptr->flags3, RF3_UNDEAD) && any_bits(r_ptr->flags1, RF1_UNIQUE)) {
- chg_virtue(this->target_ptr, V_VITALITY, 2);
- }
-
- if (r_ptr->r_deaths > 0) {
- if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
- chg_virtue(this->target_ptr, V_HONOUR, 10);
- } else if ((r_ptr->level) / 10 + (2 * this->target_ptr->current_floor_ptr->dun_level) >= randint1(100)) {
- chg_virtue(this->target_ptr, V_HONOUR, 1);
- }
- }
-
- if (any_bits(r_ptr->flags2, RF2_MULTIPLY) && (r_ptr->r_akills > 1000) && one_in_(10)) {
- chg_virtue(this->target_ptr, V_VALOUR, -1);
- }
-
- for (auto i = 0; i < MAX_NUM_BLOWS; i++) {
- if (r_ptr->blow[i].d_dice != 0) {
- innocent = false;
- }
-
- if ((r_ptr->blow[i].effect == RBE_EAT_ITEM) || (r_ptr->blow[i].effect == RBE_EAT_GOLD)) {
- thief = true;
- }
- }
-
- if (r_ptr->level > 0) {
- innocent = false;
- }
-
- if (thief) {
- if (any_bits(r_ptr->flags1, RF1_UNIQUE)) {
- chg_virtue(this->target_ptr, V_JUSTICE, 3);
- } else if (1 + ((r_ptr->level) / 10 + (2 * this->target_ptr->current_floor_ptr->dun_level)) >= randint1(100)) {
- chg_virtue(this->target_ptr, V_JUSTICE, 1);
- }
- } else if (innocent) {
- chg_virtue(this->target_ptr, V_JUSTICE, -1);
- }
-
- auto magic_ability_flags = r_ptr->ability_flags;
- magic_ability_flags.reset(RF_ABILITY_NOMAGIC_MASK);
- if (any_bits(r_ptr->flags3, RF3_ANIMAL) && none_bits(r_ptr->flags3, RF3_EVIL) && magic_ability_flags.none()) {
- if (one_in_(4)) {
- chg_virtue(this->target_ptr, V_NATURE, -1);
- }
- }
-
- if (any_bits(r_ptr->flags1, RF1_UNIQUE) && record_destroy_uniq) {
- char note_buf[160];
- sprintf(note_buf, "%s%s", r_ptr->name.c_str(), m_ptr->mflag2.has(MFLAG2::CLONED) ? _("(クローン)", "(Clone)") : "");
- exe_write_diary(this->target_ptr, DIARY_UNIQUE, 0, note_buf);
- }
-
- sound(SOUND_KILL);
- if (note != nullptr) {
- msg_format("%^s%s", m_name, note);
- } else if (!m_ptr->ml) {
-#ifdef JP
- if (is_echizen(this->target_ptr))
- msg_format("せっかくだから%sを殺した。", m_name);
- else
- msg_format("%sを殺した。", m_name);
-#else
- msg_format("You have killed %s.", m_name);
-#endif
- } else if (!monster_living(m_ptr->r_idx)) {
- bool explode = false;
- for (auto i = 0; i < 4; i++) {
- if (r_ptr->blow[i].method == RBM_EXPLODE) {
- explode = true;
- }
- }
-
- if (explode) {
- msg_format(_("%sは爆発して粉々になった。", "%^s explodes into tiny shreds."), m_name);
- } else {
-#ifdef JP
- if (is_echizen(this->target_ptr))
- msg_format("せっかくだから%sを倒した。", m_name);
- else
- msg_format("%sを倒した。", m_name);
-#else
- msg_format("You have destroyed %s.", m_name);
-#endif
- }
- } else {
-#ifdef JP
- if (is_echizen(this->target_ptr))
- msg_format("せっかくだから%sを葬り去った。", m_name);
- else
- msg_format("%sを葬り去った。", m_name);
-#else
- msg_format("You have slain %s.", m_name);
-#endif
- }
-
- if (any_bits(r_ptr->flags1, RF1_UNIQUE) && m_ptr->mflag2.has_not(MFLAG2::CLONED) && !vanilla_town) {
- for (auto i = 0; i < MAX_BOUNTY; i++) {
- if ((current_world_ptr->bounty_r_idx[i] == m_ptr->r_idx) && m_ptr->mflag2.has_not(MFLAG2::CHAMELEON)) {
- msg_format(_("%sの首には賞金がかかっている。", "There is a price on %s's head."), m_name);
- break;
- }
- }
- }
-
- monster_death(this->target_ptr, this->m_idx, true);
- this->summon_special_unique();
- this->get_exp_from_mon(&exp_mon, exp_mon.max_maxhp * 2);
- *this->fear = false;
+ if (this->process_dead_exp_virtue(note, &exp_mon)) {
return true;
}
- if (monster_fear_remaining(m_ptr) && (this->dam > 0)) {
- auto fear_remining = monster_fear_remaining(m_ptr) - randint1(this->dam);
- if (set_monster_monfear(this->target_ptr, this->m_idx, fear_remining)) {
- *this->fear = false;
- }
- }
-
- // 恐怖の更なる加算.
- if (!monster_fear_remaining(m_ptr) && none_bits(r_ptr->flags3, RF3_NO_FEAR)) {
- int percentage = (100L * m_ptr->hp) / m_ptr->maxhp;
- if ((randint1(10) >= percentage) || ((this->dam >= m_ptr->hp) && (randint0(100) < 80))) {
- *this->fear = true;
- (void)set_monster_monfear(
- this->target_ptr, this->m_idx, (randint1(10) + (((this->dam >= m_ptr->hp) && (percentage > 7)) ? 20 : ((11 - percentage) * 5))));
- }
- }
-
+ this->add_monster_fear();
return false;
}
bool MonsterDamageProcessor::genocide_chaos_patron()
{
- auto *m_ptr = &this->target_ptr->current_floor_ptr->m_list[this->m_idx];
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
if (!monster_is_valid(m_ptr)) {
this->m_idx = 0;
}
this->set_redraw();
- (void)set_monster_csleep(this->target_ptr, this->m_idx, 0);
- if (this->target_ptr->special_defense & NINJA_S_STEALTH) {
- set_superstealth(this->target_ptr, false);
- }
+ (void)set_monster_csleep(this->player_ptr, this->m_idx, 0);
+ set_superstealth(this->player_ptr, false);
return this->m_idx == 0;
}
+bool MonsterDamageProcessor::process_dead_exp_virtue(concptr note, monster_type *exp_mon)
+{
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
+ auto *r_ptr = real_r_ptr(m_ptr);
+ if (m_ptr->hp >= 0) {
+ return false;
+ }
+
+ this->death_special_flag_monster();
+ if (r_ptr->r_akills < MAX_SHORT) {
+ r_ptr->r_akills++;
+ }
+
+ this->increase_kill_numbers();
+ GAME_TEXT m_name[MAX_NLEN];
+ monster_desc(this->player_ptr, m_name, m_ptr, MD_TRUE_NAME);
+ this->death_amberites(m_name);
+ this->dying_scream(m_name);
+ AvatarChanger ac(player_ptr, m_ptr);
+ ac.change_virtue();
+ if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE) && record_destroy_uniq) {
+ char note_buf[160];
+ sprintf(note_buf, "%s%s", r_ptr->name.c_str(), m_ptr->mflag2.has(MonsterConstantFlagType::CLONED) ? _("(クローン)", "(Clone)") : "");
+ exe_write_diary(this->player_ptr, DIARY_UNIQUE, 0, note_buf);
+ }
+
+ sound(SOUND_KILL);
+ this->show_kill_message(note, m_name);
+ this->show_bounty_message(m_name);
+ monster_death(this->player_ptr, this->m_idx, true, this->attribute_flags);
+ this->summon_special_unique();
+ this->get_exp_from_mon(exp_mon, exp_mon->max_maxhp * 2);
+ *this->fear = false;
+ return true;
+}
+
/*
* @brief たぬき、カメレオン、ナズグル、ユニークの死亡時処理
* @param m_ptr ダメージを与えたモンスターの構造体参照ポインタ
*/
void MonsterDamageProcessor::death_special_flag_monster()
{
- auto *m_ptr = &this->target_ptr->current_floor_ptr->m_list[this->m_idx];
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
auto r_idx = m_ptr->r_idx;
auto *r_ptr = &r_info[r_idx];
if (any_bits(r_info[r_idx].flags7, RF7_TANUKI)) {
}
}
- if (m_ptr->mflag2.has(MFLAG2::CHAMELEON)) {
+ if (m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
r_ptr = real_r_ptr(m_ptr);
+ r_idx = real_r_idx(m_ptr);
if (r_ptr->r_sights < MAX_SHORT) {
r_ptr->r_sights++;
}
}
- if (m_ptr->mflag2.has(MFLAG2::CLONED)) {
+ if (m_ptr->mflag2.has(MonsterConstantFlagType::CLONED)) {
return;
}
return;
}
- if (none_bits(r_ptr->flags1, RF1_UNIQUE)) {
+ if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
return;
}
void MonsterDamageProcessor::death_unique_monster(monster_race_type r_idx)
{
r_info[r_idx].max_num = 0;
- std::vector<monster_race_type> combined_uniques;
- if (!check_combined_unique(r_idx, &combined_uniques)) {
+ std::vector<monster_race_type> combined_unique_vec;
+ if (!check_combined_unique(r_idx, &combined_unique_vec)) {
return;
}
- std::vector<std::tuple<monster_race_type, monster_race_type, monster_race_type>> uniques;
+ combined_uniques uniques;
const int one_unit = 3;
- for (auto i = 0U; i < combined_uniques.size(); i += one_unit) {
- auto unique = std::make_tuple(combined_uniques[i], combined_uniques[i + 1], combined_uniques[i + 2]);
+ for (auto i = 0U; i < combined_unique_vec.size(); i += one_unit) {
+ auto unique = std::make_tuple(combined_unique_vec[i], combined_unique_vec[i + 1], combined_unique_vec[i + 2]);
uniques.push_back(unique);
}
* @param united_uniques 分裂/合体を行う特殊ユニーク
* @details 合体後、合体前1、合体前2 の順にpush_backすること
*/
-bool MonsterDamageProcessor::check_combined_unique(const monster_race_type r_idx, std::vector<monster_race_type> *combined_uniques)
+bool MonsterDamageProcessor::check_combined_unique(const monster_race_type r_idx, std::vector<monster_race_type> *combined_unique_vec)
{
- combined_uniques->push_back(MON_BANORLUPART);
- combined_uniques->push_back(MON_BANOR);
- combined_uniques->push_back(MON_LUPART);
+ combined_unique_vec->push_back(MON_BANORLUPART);
+ combined_unique_vec->push_back(MON_BANOR);
+ combined_unique_vec->push_back(MON_LUPART);
- for (const auto &unique : *combined_uniques) {
+ for (const auto &unique : *combined_unique_vec) {
if (r_idx == unique) {
return true;
}
* @param m_ptr ダメージを与えたモンスターの構造体参照ポインタ
* @uniques 分裂/合体を行う特殊ユニークのリスト
*/
-void MonsterDamageProcessor::death_combined_uniques(
- const monster_race_type r_idx, std::vector<std::tuple<monster_race_type, monster_race_type, monster_race_type>> *combined_uniques)
+void MonsterDamageProcessor::death_combined_uniques(const monster_race_type r_idx, combined_uniques *combined_uniques)
{
for (const auto &unique : *combined_uniques) {
auto united = (monster_race_type)0;
void MonsterDamageProcessor::increase_kill_numbers()
{
- auto *m_ptr = &this->target_ptr->current_floor_ptr->m_list[this->m_idx];
- auto *r_ptr = &r_info[m_ptr->r_idx];
- if (((m_ptr->ml == 0) || this->target_ptr->image) && none_bits(r_ptr->flags1, RF1_UNIQUE)) {
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
+ auto *r_ptr = real_r_ptr(m_ptr);
+ if (((m_ptr->ml == 0) || this->player_ptr->hallucinated) && r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
return;
}
- if (m_ptr->mflag2.has(MFLAG2::KAGE) && (r_info[MON_KAGE].r_pkills < MAX_SHORT)) {
+ if (m_ptr->mflag2.has(MonsterConstantFlagType::KAGE) && (r_info[MON_KAGE].r_pkills < MAX_SHORT)) {
r_info[MON_KAGE].r_pkills++;
} else if (r_ptr->r_pkills < MAX_SHORT) {
r_ptr->r_pkills++;
}
- if (m_ptr->mflag2.has(MFLAG2::KAGE) && (r_info[MON_KAGE].r_tkills < MAX_SHORT)) {
+ if (m_ptr->mflag2.has(MonsterConstantFlagType::KAGE) && (r_info[MON_KAGE].r_tkills < MAX_SHORT)) {
r_info[MON_KAGE].r_tkills++;
} else if (r_ptr->r_tkills < MAX_SHORT) {
r_ptr->r_tkills++;
}
- monster_race_track(this->target_ptr, m_ptr->ap_r_idx);
+ monster_race_track(this->player_ptr, m_ptr->ap_r_idx);
}
void MonsterDamageProcessor::death_amberites(GAME_TEXT *m_name)
{
- auto *m_ptr = &this->target_ptr->current_floor_ptr->m_list[this->m_idx];
- auto *r_ptr = &r_info[m_ptr->r_idx];
- if (none_bits(r_ptr->flags3, RF3_AMBERITE) || one_in_(2)) {
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
+ auto *r_ptr = real_r_ptr(m_ptr);
+ if (r_ptr->kind_flags.has_not(MonsterKindType::AMBERITE) || one_in_(2)) {
return;
}
auto stop_ty = false;
auto count = 0;
msg_format(_("%^sは恐ろしい血の呪いをあなたにかけた!", "%^s puts a terrible blood curse on you!"), m_name);
- curse_equipment(this->target_ptr, 100, 50);
+ curse_equipment(this->player_ptr, 100, 50);
do {
- stop_ty = activate_ty_curse(this->target_ptr, stop_ty, &count);
+ stop_ty = activate_ty_curse(this->player_ptr, stop_ty, &count);
} while (--curses);
}
void MonsterDamageProcessor::dying_scream(GAME_TEXT *m_name)
{
- auto *m_ptr = &this->target_ptr->current_floor_ptr->m_list[this->m_idx];
- auto *r_ptr = &r_info[m_ptr->r_idx];
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
+ auto *r_ptr = real_r_ptr(m_ptr);
if (none_bits(r_ptr->flags2, RF2_CAN_SPEAK)) {
return;
}
#ifdef WORLD_SCORE
if (m_ptr->r_idx == MON_SERPENT) {
- screen_dump = make_screen_dump(this->target_ptr);
+ screen_dump = make_screen_dump(this->player_ptr);
}
#endif
}
-void MonsterDamageProcessor::change_virtue_non_beginner()
+void MonsterDamageProcessor::show_kill_message(concptr note, GAME_TEXT *m_name)
{
- auto *floor_ptr = this->target_ptr->current_floor_ptr;
+ auto *floor_ptr = this->player_ptr->current_floor_ptr;
auto *m_ptr = &floor_ptr->m_list[this->m_idx];
- auto *r_ptr = &r_info[m_ptr->r_idx];
- if (d_info[this->target_ptr->dungeon_idx].flags.has(DF::BEGINNER)) {
+ auto *r_ptr = real_r_ptr(m_ptr);
+ if (note != nullptr) {
+ msg_format("%^s%s", m_name, note);
return;
}
- if ((floor_ptr->dun_level == 0) && !this->target_ptr->ambush_flag && !floor_ptr->inside_arena) {
- chg_virtue(this->target_ptr, V_VALOUR, -1);
- } else if (r_ptr->level > floor_ptr->dun_level) {
- if (randint1(10) <= (r_ptr->level - floor_ptr->dun_level)) {
- chg_virtue(this->target_ptr, V_VALOUR, 1);
+ if (!m_ptr->ml) {
+ auto mes = is_echizen(this->player_ptr) ? _("せっかくだから%sを殺した。", "Because it's time, you have killed %s.")
+ : _("%sを殺した。", "You have killed %s.");
+ msg_format(mes, m_name);
+ return;
+ }
+
+ if (monster_living(m_ptr->r_idx)) {
+ auto mes = is_echizen(this->player_ptr) ? _("せっかくだから%sを殺した。", "Because it's time, you have slain %s.")
+ : _("%sを殺した。", "You have slain %s.");
+ msg_format(mes, m_name);
+ return;
+ }
+
+ auto explode = false;
+ for (auto i = 0; i < 4; i++) {
+ if (r_ptr->blow[i].method == RaceBlowMethodType::EXPLODE) {
+ explode = true;
}
}
- if (r_ptr->level > 60) {
- chg_virtue(this->target_ptr, V_VALOUR, 1);
+ if (explode) {
+ msg_format(_("%sは爆発して粉々になった。", "%^s explodes into tiny shreds."), m_name);
+ return;
+ }
+
+ auto mes = is_echizen(this->player_ptr) ? _("せっかくだから%sを殺した。", "Because it's time, you have destroyed %s.")
+ : _("%sを殺した。", "You have destroyed %s.");
+ msg_format(mes, m_name);
+}
+
+void MonsterDamageProcessor::show_bounty_message(GAME_TEXT *m_name)
+{
+ auto *floor_ptr = this->player_ptr->current_floor_ptr;
+ auto *m_ptr = &floor_ptr->m_list[this->m_idx];
+ auto *r_ptr = real_r_ptr(m_ptr);
+ if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) || m_ptr->mflag2.has(MonsterConstantFlagType::CLONED) || vanilla_town) {
+ return;
}
- if (r_ptr->level >= 2 * (this->target_ptr->lev + 1)) {
- chg_virtue(this->target_ptr, V_VALOUR, 2);
+ for (auto i = 0; i < MAX_BOUNTY; i++) {
+ if ((w_ptr->bounty_r_idx[i] == m_ptr->r_idx) && m_ptr->mflag2.has_not(MonsterConstantFlagType::CHAMELEON)) {
+ msg_format(_("%sの首には賞金がかかっている。", "There is a price on %s's head."), m_name);
+ break;
+ }
}
}
* experience point of a monster later.
* </pre>
*/
-void MonsterDamageProcessor::get_exp_from_mon(monster_type *m_ptr, HIT_POINT exp_dam)
+void MonsterDamageProcessor::get_exp_from_mon(monster_type *m_ptr, int exp_dam)
{
auto *r_ptr = &r_info[m_ptr->r_idx];
- if (!monster_is_valid(m_ptr) || is_pet(m_ptr) || this->target_ptr->phase_out) {
+ if (!monster_is_valid(m_ptr) || is_pet(m_ptr) || this->player_ptr->phase_out) {
return;
}
* - Varying speed effects
* - Get a fraction in proportion of damage point
*/
- auto new_exp = r_ptr->level * SPEED_TO_ENERGY(m_ptr->mspeed) * exp_dam;
+ auto new_exp = r_ptr->level * speed_to_energy(m_ptr->mspeed) * exp_dam;
auto new_exp_frac = 0U;
auto div_h = 0;
- auto div_l = (uint)((this->target_ptr->max_plv + 2) * SPEED_TO_ENERGY(r_ptr->speed));
+ auto div_l = (uint)((this->player_ptr->max_plv + 2) * speed_to_energy(r_ptr->speed));
/* Use (average maxhp * 2) as a denominator */
auto compensation = any_bits(r_ptr->flags1, RF1_FORCE_MAXHP) ? r_ptr->hside * 2 : r_ptr->hside + 1;
s64b_mul(&div_h, &div_l, 0, r_ptr->hdice * (ironman_nightmare ? 2 : 1) * compensation);
/* Special penalty in the wilderness */
- if (!this->target_ptr->current_floor_ptr->dun_level && (none_bits(r_ptr->flags8, RF8_WILD_ONLY) || none_bits(r_ptr->flags1, RF1_UNIQUE))) {
+ if (!this->player_ptr->current_floor_ptr->dun_level && (none_bits(r_ptr->flags8, RF8_WILD_ONLY) || r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE))) {
s64b_mul(&div_h, &div_l, 0, 5);
}
}
s64b_mul(&new_exp, &new_exp_frac, 0, r_ptr->mexp);
- gain_exp_64(this->target_ptr, new_exp, new_exp_frac);
+ gain_exp_64(this->player_ptr, new_exp, new_exp_frac);
}
void MonsterDamageProcessor::set_redraw()
{
- if (this->target_ptr->health_who == this->m_idx) {
- this->target_ptr->redraw |= PR_HEALTH;
+ if (this->player_ptr->health_who == this->m_idx) {
+ this->player_ptr->redraw |= PR_HEALTH;
}
- if (this->target_ptr->riding == this->m_idx) {
- this->target_ptr->redraw |= PR_UHEALTH;
+ if (this->player_ptr->riding == this->m_idx) {
+ this->player_ptr->redraw |= PR_UHEALTH;
}
}
*/
void MonsterDamageProcessor::summon_special_unique()
{
- auto *m_ptr = &this->target_ptr->current_floor_ptr->m_list[this->m_idx];
- auto *r_ptr = &r_info[m_ptr->r_idx];
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
bool is_special_summon = m_ptr->r_idx == MON_IKETA;
is_special_summon |= m_ptr->r_idx == MON_DOPPIO;
- if (!is_special_summon || this->target_ptr->current_floor_ptr->inside_arena || this->target_ptr->phase_out) {
- delete_monster_idx(this->target_ptr, this->m_idx);
+ if (!is_special_summon || this->player_ptr->current_floor_ptr->inside_arena || this->player_ptr->phase_out) {
+ delete_monster_idx(this->player_ptr, this->m_idx);
return;
}
break;
}
- delete_monster_idx(this->target_ptr, this->m_idx);
- if (summon_named_creature(this->target_ptr, 0, dummy_y, dummy_x, new_unique_idx, mode)) {
+ delete_monster_idx(this->player_ptr, this->m_idx);
+ if (summon_named_creature(this->player_ptr, 0, dummy_y, dummy_x, new_unique_idx, mode)) {
msg_print(mes);
}
}
+
+void MonsterDamageProcessor::add_monster_fear()
+{
+ auto *m_ptr = &this->player_ptr->current_floor_ptr->m_list[this->m_idx];
+ if (monster_fear_remaining(m_ptr) && (this->dam > 0)) {
+ auto fear_remining = monster_fear_remaining(m_ptr) - randint1(this->dam);
+ if (set_monster_monfear(this->player_ptr, this->m_idx, fear_remining)) {
+ *this->fear = false;
+ }
+ }
+
+ auto *r_ptr = &r_info[m_ptr->r_idx];
+ if (monster_fear_remaining(m_ptr) || any_bits(r_ptr->flags3, RF3_NO_FEAR)) {
+ return;
+ }
+
+ int percentage = (100L * m_ptr->hp) / m_ptr->maxhp;
+ if ((randint1(10) < percentage) && ((this->dam < m_ptr->hp) || (randint0(100) >= 80))) {
+ return;
+ }
+
+ *this->fear = true;
+ auto fear_condition = (this->dam >= m_ptr->hp) && (percentage > 7);
+ auto fear_value = randint1(10) + (fear_condition ? 20 : (11 - percentage) * 5);
+ (void)set_monster_monfear(this->player_ptr, this->m_idx, fear_value);
+}