1 #include "effect/effect-monster-charm.h"
2 #include "avatar/avatar.h"
3 #include "dungeon/quest.h"
4 #include "effect/effect-monster-util.h"
5 #include "effect/spells-effect-util.h"
6 #include "monster-floor/monster-remover.h"
7 #include "monster-race/monster-kind-mask.h"
8 #include "monster-race/monster-race-hook.h"
9 #include "monster-race/monster-race.h"
10 #include "monster-race/race-indice-types.h"
11 #include "monster/monster-flag-types.h"
12 #include "monster/monster-info.h"
13 #include "monster/monster-list.h"
14 #include "monster/monster-status-setter.h"
15 #include "monster/monster-status.h"
16 #include "object-enchant/trc-types.h"
17 #include "pet/pet-fall-off.h"
18 #include "pet/pet-util.h"
19 #include "player-base/player-class.h"
20 #include "player/player-status-flags.h"
21 #include "spell/spells-diceroll.h"
22 #include "status/bad-status-setter.h"
23 #include "system/floor-type-definition.h"
24 #include "system/grid-type-definition.h"
25 #include "system/monster-entity.h"
26 #include "system/monster-race-info.h"
27 #include "system/player-type-definition.h"
28 #include "util/bit-flags-calculator.h"
29 #include "view/display-messages.h"
31 static void effect_monster_charm_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
33 if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr)) {
34 em_ptr->note = _("には効果がなかった。", " is unaffected.");
35 em_ptr->obvious = false;
38 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
40 } else if (has_aggravate(player_ptr)) {
41 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
43 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
46 em_ptr->note = _("は突然友好的になったようだ!", " suddenly seems friendly!");
47 set_pet(player_ptr, em_ptr->m_ptr);
49 chg_virtue(player_ptr, Virtue::INDIVIDUALISM, -1);
50 if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
51 chg_virtue(player_ptr, Virtue::NATURE, 1);
56 ProcessResult effect_monster_charm(PlayerType *player_ptr, EffectMonster *em_ptr)
58 int vir = virtue_number(player_ptr, Virtue::HARMONY);
60 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
63 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
65 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
69 em_ptr->obvious = true;
72 effect_monster_charm_resist(player_ptr, em_ptr);
74 return ProcessResult::PROCESS_CONTINUE;
77 ProcessResult effect_monster_control_undead(PlayerType *player_ptr, EffectMonster *em_ptr)
80 em_ptr->obvious = true;
83 int vir = virtue_number(player_ptr, Virtue::UNLIFE);
85 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
88 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
90 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
93 if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD)) {
94 em_ptr->note = _("には効果がなかった。", " is unaffected.");
95 em_ptr->obvious = false;
97 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
99 } else if (has_aggravate(player_ptr)) {
100 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
102 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
105 em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
106 set_pet(player_ptr, em_ptr->m_ptr);
110 return ProcessResult::PROCESS_CONTINUE;
113 ProcessResult effect_monster_control_demon(PlayerType *player_ptr, EffectMonster *em_ptr)
116 em_ptr->obvious = true;
119 int vir = virtue_number(player_ptr, Virtue::UNLIFE);
121 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
124 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
126 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
129 if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::DEMON)) {
130 em_ptr->note = _("には効果がなかった。", " is unaffected.");
131 em_ptr->obvious = false;
133 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
135 } else if (has_aggravate(player_ptr)) {
136 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
138 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
141 em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
142 set_pet(player_ptr, em_ptr->m_ptr);
146 return ProcessResult::PROCESS_CONTINUE;
149 ProcessResult effect_monster_control_animal(PlayerType *player_ptr, EffectMonster *em_ptr)
152 em_ptr->obvious = true;
155 int vir = virtue_number(player_ptr, Virtue::NATURE);
157 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
160 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
162 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
165 if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::ANIMAL)) {
166 em_ptr->note = _("には効果がなかった。", " is unaffected.");
167 em_ptr->obvious = false;
169 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
171 } else if (has_aggravate(player_ptr)) {
172 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
174 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
177 em_ptr->note = _("はなついた。", " is tamed!");
178 set_pet(player_ptr, em_ptr->m_ptr);
179 if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
180 chg_virtue(player_ptr, Virtue::NATURE, 1);
185 return ProcessResult::PROCESS_CONTINUE;
188 ProcessResult effect_monster_charm_living(PlayerType *player_ptr, EffectMonster *em_ptr)
190 int vir = virtue_number(player_ptr, Virtue::UNLIFE);
192 em_ptr->obvious = true;
195 vir = virtue_number(player_ptr, Virtue::UNLIFE);
197 em_ptr->dam -= player_ptr->virtues[vir - 1] / 10;
200 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
202 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
205 msg_format(_("%sを見つめた。", "You stare at %s."), em_ptr->m_name);
207 if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr) || !em_ptr->m_ptr->has_living_flag()) {
208 em_ptr->note = _("には効果がなかった。", " is unaffected.");
209 em_ptr->obvious = false;
211 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
213 } else if (has_aggravate(player_ptr)) {
214 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
216 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
219 em_ptr->note = _("を支配した。", " is tamed!");
220 set_pet(player_ptr, em_ptr->m_ptr);
221 if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
222 chg_virtue(player_ptr, Virtue::NATURE, 1);
227 return ProcessResult::PROCESS_CONTINUE;
230 static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr, EffectMonster *em_ptr)
232 BadStatusSetter bss(player_ptr);
233 switch (randint1(4)) {
235 (void)bss.mod_stun(em_ptr->dam / 2);
238 (void)bss.mod_confusion(em_ptr->dam / 2);
241 if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
242 em_ptr->note = _("には効果がなかった。", " is unaffected.");
244 (void)bss.mod_fear(static_cast<TIME_EFFECT>(em_ptr->dam));
251 // Powerful demons & undead can turn a mindcrafter's attacks back on them.
252 static void effect_monster_domination_corrupted(PlayerType *player_ptr, EffectMonster *em_ptr)
254 bool is_corrupted = em_ptr->r_ptr->kind_flags.has_any_of(has_corrupted_mind) && (em_ptr->r_ptr->level > player_ptr->lev / 2) && (one_in_(2));
256 em_ptr->note = _("には効果がなかった。", " is unaffected.");
257 em_ptr->obvious = false;
262 msg_format(_("%s^の堕落した精神は攻撃を跳ね返した!",
263 (em_ptr->seen ? "%s^'s corrupted mind backlashes your attack!" : "%s^s corrupted mind backlashes your attack!")),
265 if (randint0(100 + em_ptr->r_ptr->level / 2) < player_ptr->skill_sav) {
266 msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
270 effect_monster_domination_corrupted_addition(player_ptr, em_ptr);
273 static void effect_monster_domination_addition(EffectMonster *em_ptr)
275 switch (randint1(4)) {
277 em_ptr->do_stun = em_ptr->dam / 2;
280 em_ptr->do_conf = em_ptr->dam / 2;
283 em_ptr->do_fear = em_ptr->dam;
287 ProcessResult effect_monster_domination(PlayerType *player_ptr, EffectMonster *em_ptr)
289 if (!em_ptr->m_ptr->is_hostile()) {
290 return ProcessResult::PROCESS_CONTINUE;
294 em_ptr->obvious = true;
297 const auto is_unique = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
298 const auto is_questor = em_ptr->r_ptr->misc_flags.has(MonsterMiscType::QUESTOR);
299 const auto is_no_confusion = em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF);
300 if (is_unique || is_questor || is_no_confusion || (em_ptr->r_ptr->level > randint1((em_ptr->dam - 10) < 1 ? 1 : (em_ptr->dam - 10)) + 10)) {
301 if ((em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) && is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
302 em_ptr->r_ptr->resistance_flags.set(MonsterResistanceType::NO_CONF);
306 effect_monster_domination_corrupted(player_ptr, em_ptr);
308 return ProcessResult::PROCESS_CONTINUE;
311 if (!common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr)) {
312 em_ptr->note = _("があなたに隷属した。", " is in your thrall!");
313 set_pet(player_ptr, em_ptr->m_ptr);
315 return ProcessResult::PROCESS_CONTINUE;
318 effect_monster_domination_addition(em_ptr);
320 return ProcessResult::PROCESS_CONTINUE;
323 static bool effect_monster_crusade_domination(PlayerType *player_ptr, EffectMonster *em_ptr)
325 if ((em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) || player_ptr->current_floor_ptr->inside_arena) {
329 if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
332 if (em_ptr->dam < 1) {
336 if (em_ptr->m_ptr->is_pet()) {
337 em_ptr->note = _("の動きが速くなった。", " starts moving faster.");
338 (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->m_ptr->get_remaining_acceleration() + 100);
342 bool failed = em_ptr->r_ptr->misc_flags.has(MonsterMiscType::QUESTOR);
343 failed |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
344 failed |= em_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::NOPET);
345 failed |= has_aggravate(player_ptr);
346 failed |= (em_ptr->r_ptr->level + 10) > randint1(em_ptr->dam);
350 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
356 em_ptr->note = _("を支配した。", " is tamed!");
357 set_pet(player_ptr, em_ptr->m_ptr);
358 (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->m_ptr->get_remaining_acceleration() + 100);
359 if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
360 em_ptr->r_ptr->r_kind_flags.set(MonsterKindType::GOOD);
366 ProcessResult effect_monster_crusade(PlayerType *player_ptr, EffectMonster *em_ptr)
369 em_ptr->obvious = true;
371 bool success = effect_monster_crusade_domination(player_ptr, em_ptr);
374 return ProcessResult::PROCESS_CONTINUE;
377 if (em_ptr->r_ptr->resistance_flags.has_not(MonsterResistanceType::NO_FEAR)) {
378 em_ptr->do_fear = randint1(90) + 10;
379 } else if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
380 em_ptr->r_ptr->r_resistance_flags.set(MonsterResistanceType::NO_FEAR);
384 return ProcessResult::PROCESS_CONTINUE;
388 * @brief モンスターボールで捕まえられる最大HPを計算する
389 * @param player_ptr プレイヤー情報への参照ポインタ
390 * @param m_ptr モンスター情報への参照ポインタ
394 static int calcutate_capturable_hp(PlayerType *player_ptr, MonsterEntity *m_ptr, int hp)
396 if (m_ptr->is_pet()) {
400 if (PlayerClass(player_ptr).equals(PlayerClassType::BEASTMASTER) && m_ptr->has_living_flag()) {
408 * @brief モンスターボールで捕らえた処理
409 * @param player_ptr プレイヤー情報への参照ポインタ
410 * @param em_ptr 効果情報への参照ポインタ
412 static void effect_monster_captured(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> tmp_cap_mon_ptr)
414 if (em_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
415 choose_new_monster(player_ptr, em_ptr->g_ptr->m_idx, false, MonsterRaceId::CHAMELEON);
418 msg_format(_("%sを捕えた!", "You capture %s^!"), em_ptr->m_name);
419 auto cap_mon_ptr = *tmp_cap_mon_ptr;
420 cap_mon_ptr->r_idx = em_ptr->m_ptr->r_idx;
421 cap_mon_ptr->speed = em_ptr->m_ptr->mspeed;
422 cap_mon_ptr->current_hp = static_cast<short>(em_ptr->m_ptr->hp);
423 cap_mon_ptr->max_hp = static_cast<short>(em_ptr->m_ptr->max_maxhp);
424 cap_mon_ptr->nickname = em_ptr->m_ptr->nickname;
425 if ((em_ptr->g_ptr->m_idx == player_ptr->riding) && process_fall_off_horse(player_ptr, -1, false)) {
426 msg_print(_("地面に落とされた。", format("You have fallen from %s.", em_ptr->m_name)));
429 delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
430 calculate_upkeep(player_ptr);
434 * @brief モンスターボールで捕らえる効果(CAPTURE)
435 * @param player_ptr プレイヤー情報への参照ポインタ
436 * @param em_ptr 効果情報への参照ポインタ
439 ProcessResult effect_monster_capture(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
441 const auto &quest_list = QuestList::get_instance();
442 auto *floor_ptr = player_ptr->current_floor_ptr;
444 auto quest_monster = floor_ptr->is_in_quest();
445 quest_monster &= (quest_list[floor_ptr->quest_number].type == QuestKindType::KILL_ALL);
446 quest_monster &= !em_ptr->m_ptr->is_pet();
448 auto cannot_capture = quest_monster;
449 cannot_capture |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
450 cannot_capture |= em_ptr->r_ptr->misc_flags.has(MonsterMiscType::QUESTOR);
451 cannot_capture |= em_ptr->r_ptr->population_flags.has(MonsterPopulationType::NAZGUL);
452 cannot_capture |= em_ptr->r_ptr->population_flags.has(MonsterPopulationType::ONLY_ONE);
453 cannot_capture |= (em_ptr->m_ptr->parent_m_idx != 0);
454 if (cannot_capture) {
455 msg_format(_("%sには効果がなかった。", "%s is unaffected."), em_ptr->m_name);
456 em_ptr->skipped = true;
457 return ProcessResult::PROCESS_CONTINUE;
460 auto r_max_hp = em_ptr->r_ptr->hdice * em_ptr->r_ptr->hside;
461 auto threshold_hp = calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, r_max_hp);
462 auto capturable_hp = std::max(2, calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, em_ptr->m_ptr->max_maxhp));
464 if (threshold_hp < 2 || em_ptr->m_ptr->hp >= capturable_hp) {
465 msg_print(_("もっと弱らせないと。", format("You need to weaken %s more.", em_ptr->m_name)));
466 em_ptr->skipped = true;
467 return ProcessResult::PROCESS_CONTINUE;
470 if (em_ptr->m_ptr->hp <= randint1(capturable_hp)) {
471 effect_monster_captured(player_ptr, em_ptr, cap_mon_ptr);
472 return ProcessResult::PROCESS_TRUE;
475 msg_print(_("うまく捕まえられなかった。", format("You failed to capture %s.", em_ptr->m_name)));
476 em_ptr->skipped = true;
477 return ProcessResult::PROCESS_CONTINUE;