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-flags1.h"
11 #include "monster-race/race-flags3.h"
12 #include "monster-race/race-flags7.h"
13 #include "monster-race/race-indice-types.h"
14 #include "monster/monster-flag-types.h"
15 #include "monster/monster-info.h"
16 #include "monster/monster-list.h"
17 #include "monster/monster-status-setter.h"
18 #include "monster/monster-status.h"
19 #include "object-enchant/trc-types.h"
20 #include "pet/pet-fall-off.h"
21 #include "pet/pet-util.h"
22 #include "player-base/player-class.h"
23 #include "player/player-status-flags.h"
24 #include "spell/spells-diceroll.h"
25 #include "status/bad-status-setter.h"
26 #include "system/floor-type-definition.h"
27 #include "system/grid-type-definition.h"
28 #include "system/monster-entity.h"
29 #include "system/monster-race-info.h"
30 #include "system/player-type-definition.h"
31 #include "util/bit-flags-calculator.h"
32 #include "view/display-messages.h"
34 static void effect_monster_charm_resist(PlayerType *player_ptr, effect_monster_type *em_ptr)
36 if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr)) {
37 em_ptr->note = _("には効果がなかった。", " is unaffected.");
38 em_ptr->obvious = false;
41 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
43 } else if (has_aggravate(player_ptr)) {
44 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
46 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
49 em_ptr->note = _("は突然友好的になったようだ!", " suddenly seems friendly!");
50 set_pet(player_ptr, em_ptr->m_ptr);
52 chg_virtue(player_ptr, Virtue::INDIVIDUALISM, -1);
53 if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
54 chg_virtue(player_ptr, Virtue::NATURE, 1);
59 ProcessResult effect_monster_charm(PlayerType *player_ptr, effect_monster_type *em_ptr)
61 int vir = virtue_number(player_ptr, Virtue::HARMONY);
63 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
66 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
68 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
72 em_ptr->obvious = true;
75 effect_monster_charm_resist(player_ptr, em_ptr);
77 return ProcessResult::PROCESS_CONTINUE;
80 ProcessResult effect_monster_control_undead(PlayerType *player_ptr, effect_monster_type *em_ptr)
83 em_ptr->obvious = true;
86 int vir = virtue_number(player_ptr, Virtue::UNLIFE);
88 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
91 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
93 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
96 if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD)) {
97 em_ptr->note = _("には効果がなかった。", " is unaffected.");
98 em_ptr->obvious = false;
100 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
102 } else if (has_aggravate(player_ptr)) {
103 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
105 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
108 em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
109 set_pet(player_ptr, em_ptr->m_ptr);
113 return ProcessResult::PROCESS_CONTINUE;
116 ProcessResult effect_monster_control_demon(PlayerType *player_ptr, effect_monster_type *em_ptr)
119 em_ptr->obvious = true;
122 int vir = virtue_number(player_ptr, Virtue::UNLIFE);
124 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
127 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
129 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
132 if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::DEMON)) {
133 em_ptr->note = _("には効果がなかった。", " is unaffected.");
134 em_ptr->obvious = false;
136 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
138 } else if (has_aggravate(player_ptr)) {
139 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
141 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
144 em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
145 set_pet(player_ptr, em_ptr->m_ptr);
149 return ProcessResult::PROCESS_CONTINUE;
152 ProcessResult effect_monster_control_animal(PlayerType *player_ptr, effect_monster_type *em_ptr)
155 em_ptr->obvious = true;
158 int vir = virtue_number(player_ptr, Virtue::NATURE);
160 em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
163 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
165 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
168 if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::ANIMAL)) {
169 em_ptr->note = _("には効果がなかった。", " is unaffected.");
170 em_ptr->obvious = false;
172 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
174 } else if (has_aggravate(player_ptr)) {
175 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
177 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
180 em_ptr->note = _("はなついた。", " is tamed!");
181 set_pet(player_ptr, em_ptr->m_ptr);
182 if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
183 chg_virtue(player_ptr, Virtue::NATURE, 1);
188 return ProcessResult::PROCESS_CONTINUE;
191 ProcessResult effect_monster_charm_living(PlayerType *player_ptr, effect_monster_type *em_ptr)
193 int vir = virtue_number(player_ptr, Virtue::UNLIFE);
195 em_ptr->obvious = true;
198 vir = virtue_number(player_ptr, Virtue::UNLIFE);
200 em_ptr->dam -= player_ptr->virtues[vir - 1] / 10;
203 vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
205 em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
208 msg_format(_("%sを見つめた。", "You stare at %s."), em_ptr->m_name);
210 if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr) || !em_ptr->m_ptr->has_living_flag()) {
211 em_ptr->note = _("には効果がなかった。", " is unaffected.");
212 em_ptr->obvious = false;
214 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
216 } else if (has_aggravate(player_ptr)) {
217 em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
219 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
222 em_ptr->note = _("を支配した。", " is tamed!");
223 set_pet(player_ptr, em_ptr->m_ptr);
224 if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL)) {
225 chg_virtue(player_ptr, Virtue::NATURE, 1);
230 return ProcessResult::PROCESS_CONTINUE;
233 static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr, effect_monster_type *em_ptr)
235 BadStatusSetter bss(player_ptr);
236 switch (randint1(4)) {
238 (void)bss.mod_stun(em_ptr->dam / 2);
241 (void)bss.mod_confusion(em_ptr->dam / 2);
244 if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
245 em_ptr->note = _("には効果がなかった。", " is unaffected.");
247 (void)bss.mod_fear(static_cast<TIME_EFFECT>(em_ptr->dam));
254 // Powerful demons & undead can turn a mindcrafter's attacks back on them.
255 static void effect_monster_domination_corrupted(PlayerType *player_ptr, effect_monster_type *em_ptr)
257 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));
259 em_ptr->note = _("には効果がなかった。", " is unaffected.");
260 em_ptr->obvious = false;
264 em_ptr->note = nullptr;
265 msg_format(_("%s^の堕落した精神は攻撃を跳ね返した!",
266 (em_ptr->seen ? "%s^'s corrupted mind backlashes your attack!" : "%s^s corrupted mind backlashes your attack!")),
268 if (randint0(100 + em_ptr->r_ptr->level / 2) < player_ptr->skill_sav) {
269 msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
273 effect_monster_domination_corrupted_addition(player_ptr, em_ptr);
276 static void effect_monster_domination_addition(effect_monster_type *em_ptr)
278 switch (randint1(4)) {
280 em_ptr->do_stun = em_ptr->dam / 2;
283 em_ptr->do_conf = em_ptr->dam / 2;
286 em_ptr->do_fear = em_ptr->dam;
290 ProcessResult effect_monster_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
292 if (!em_ptr->m_ptr->is_hostile()) {
293 return ProcessResult::PROCESS_CONTINUE;
297 em_ptr->obvious = true;
300 const auto is_unique = em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
301 const auto is_questor = any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
302 const auto is_no_confusion = any_bits(em_ptr->r_ptr->flags3, RF3_NO_CONF);
303 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)) {
304 if (((em_ptr->r_ptr->flags3 & RF3_NO_CONF) != 0) && is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
305 em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
309 effect_monster_domination_corrupted(player_ptr, em_ptr);
311 return ProcessResult::PROCESS_CONTINUE;
314 if (!common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr)) {
315 em_ptr->note = _("があなたに隷属した。", " is in your thrall!");
316 set_pet(player_ptr, em_ptr->m_ptr);
318 return ProcessResult::PROCESS_CONTINUE;
321 effect_monster_domination_addition(em_ptr);
323 return ProcessResult::PROCESS_CONTINUE;
326 static bool effect_monster_crusade_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
328 if ((em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) || player_ptr->current_floor_ptr->inside_arena) {
332 if (em_ptr->r_ptr->flags3 & RF3_NO_CONF) {
335 if (em_ptr->dam < 1) {
339 if (em_ptr->m_ptr->is_pet()) {
340 em_ptr->note = _("の動きが速くなった。", " starts moving faster.");
341 (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->m_ptr->get_remaining_acceleration() + 100);
345 bool failed = any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
346 failed |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
347 failed |= em_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::NOPET);
348 failed |= has_aggravate(player_ptr);
349 failed |= (em_ptr->r_ptr->level + 10) > randint1(em_ptr->dam);
353 em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
359 em_ptr->note = _("を支配した。", " is tamed!");
360 set_pet(player_ptr, em_ptr->m_ptr);
361 (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, em_ptr->m_ptr->get_remaining_acceleration() + 100);
362 if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
363 em_ptr->r_ptr->r_kind_flags.set(MonsterKindType::GOOD);
369 ProcessResult effect_monster_crusade(PlayerType *player_ptr, effect_monster_type *em_ptr)
372 em_ptr->obvious = true;
374 bool success = effect_monster_crusade_domination(player_ptr, em_ptr);
377 return ProcessResult::PROCESS_CONTINUE;
380 if ((em_ptr->r_ptr->flags3 & RF3_NO_FEAR) == 0) {
381 em_ptr->do_fear = randint1(90) + 10;
382 } else if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr)) {
383 em_ptr->r_ptr->r_flags3 |= RF3_NO_FEAR;
387 return ProcessResult::PROCESS_CONTINUE;
391 * @brief モンスターボールで捕まえられる最大HPを計算する
392 * @param player_ptr プレイヤー情報への参照ポインタ
393 * @param m_ptr モンスター情報への参照ポインタ
397 static int calcutate_capturable_hp(PlayerType *player_ptr, MonsterEntity *m_ptr, int hp)
399 if (m_ptr->is_pet()) {
403 if (PlayerClass(player_ptr).equals(PlayerClassType::BEASTMASTER) && m_ptr->has_living_flag()) {
411 * @brief モンスターボールで捕らえた処理
412 * @param player_ptr プレイヤー情報への参照ポインタ
413 * @param em_ptr 効果情報への参照ポインタ
415 static void effect_monster_captured(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> tmp_cap_mon_ptr)
417 if (em_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON)) {
418 choose_new_monster(player_ptr, em_ptr->g_ptr->m_idx, false, MonsterRaceId::CHAMELEON);
421 msg_format(_("%sを捕えた!", "You capture %s^!"), em_ptr->m_name);
422 auto cap_mon_ptr = tmp_cap_mon_ptr.value();
423 cap_mon_ptr->r_idx = em_ptr->m_ptr->r_idx;
424 cap_mon_ptr->speed = em_ptr->m_ptr->mspeed;
425 cap_mon_ptr->current_hp = static_cast<short>(em_ptr->m_ptr->hp);
426 cap_mon_ptr->max_hp = static_cast<short>(em_ptr->m_ptr->max_maxhp);
427 cap_mon_ptr->nickname = em_ptr->m_ptr->nickname;
428 if ((em_ptr->g_ptr->m_idx == player_ptr->riding) && process_fall_off_horse(player_ptr, -1, false)) {
429 msg_print(_("地面に落とされた。", format("You have fallen from %s.", em_ptr->m_name)));
432 delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
433 calculate_upkeep(player_ptr);
437 * @brief モンスターボールで捕らえる効果(CAPTURE)
438 * @param player_ptr プレイヤー情報への参照ポインタ
439 * @param em_ptr 効果情報への参照ポインタ
442 ProcessResult effect_monster_capture(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
444 const auto &quest_list = QuestList::get_instance();
445 auto *floor_ptr = player_ptr->current_floor_ptr;
447 auto quest_monster = inside_quest(floor_ptr->quest_number);
448 quest_monster &= (quest_list[floor_ptr->quest_number].type == QuestKindType::KILL_ALL);
449 quest_monster &= !em_ptr->m_ptr->is_pet();
451 auto cannot_capture = quest_monster;
452 cannot_capture |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
453 cannot_capture |= any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
454 cannot_capture |= em_ptr->r_ptr->population_flags.has(MonsterPopulationType::NAZGUL);
455 cannot_capture |= any_bits(em_ptr->r_ptr->flags7, RF7_UNIQUE2);
456 cannot_capture |= (em_ptr->m_ptr->parent_m_idx != 0);
457 if (cannot_capture) {
458 msg_format(_("%sには効果がなかった。", "%s is unaffected."), em_ptr->m_name);
459 em_ptr->skipped = true;
460 return ProcessResult::PROCESS_CONTINUE;
463 auto r_max_hp = em_ptr->r_ptr->hdice * em_ptr->r_ptr->hside;
464 auto threshold_hp = calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, r_max_hp);
465 auto capturable_hp = std::max(2, calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, em_ptr->m_ptr->max_maxhp));
467 if (threshold_hp < 2 || em_ptr->m_ptr->hp >= capturable_hp) {
468 msg_print(_("もっと弱らせないと。", format("You need to weaken %s more.", em_ptr->m_name)));
469 em_ptr->skipped = true;
470 return ProcessResult::PROCESS_CONTINUE;
473 if (em_ptr->m_ptr->hp <= randint1(capturable_hp)) {
474 effect_monster_captured(player_ptr, em_ptr, cap_mon_ptr);
475 return ProcessResult::PROCESS_TRUE;
478 msg_print(_("うまく捕まえられなかった。", format("You failed to capture %s.", em_ptr->m_name)));
479 em_ptr->skipped = true;
480 return ProcessResult::PROCESS_CONTINUE;