OSDN Git Service

160b1b9f49900372adf3b50ce9addd76b462d55d
[hengbandforosx/hengbandosx.git] / src / effect / effect-monster-charm.cpp
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"
33
34 static void effect_monster_charm_resist(PlayerType *player_ptr, effect_monster_type *em_ptr)
35 {
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;
39
40         if (one_in_(4)) {
41             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
42         }
43     } else if (has_aggravate(player_ptr)) {
44         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
45         if (one_in_(4)) {
46             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
47         }
48     } else {
49         em_ptr->note = _("は突然友好的になったようだ!", " suddenly seems friendly!");
50         set_pet(player_ptr, em_ptr->m_ptr);
51
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);
55         }
56     }
57 }
58
59 ProcessResult effect_monster_charm(PlayerType *player_ptr, effect_monster_type *em_ptr)
60 {
61     int vir = virtue_number(player_ptr, Virtue::HARMONY);
62     if (vir) {
63         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
64     }
65
66     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
67     if (vir) {
68         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
69     }
70
71     if (em_ptr->seen) {
72         em_ptr->obvious = true;
73     }
74
75     effect_monster_charm_resist(player_ptr, em_ptr);
76     em_ptr->dam = 0;
77     return ProcessResult::PROCESS_CONTINUE;
78 }
79
80 ProcessResult effect_monster_control_undead(PlayerType *player_ptr, effect_monster_type *em_ptr)
81 {
82     if (em_ptr->seen) {
83         em_ptr->obvious = true;
84     }
85
86     int vir = virtue_number(player_ptr, Virtue::UNLIFE);
87     if (vir) {
88         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
89     }
90
91     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
92     if (vir) {
93         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
94     }
95
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;
99         if (one_in_(4)) {
100             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
101         }
102     } else if (has_aggravate(player_ptr)) {
103         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
104         if (one_in_(4)) {
105             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
106         }
107     } else {
108         em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
109         set_pet(player_ptr, em_ptr->m_ptr);
110     }
111
112     em_ptr->dam = 0;
113     return ProcessResult::PROCESS_CONTINUE;
114 }
115
116 ProcessResult effect_monster_control_demon(PlayerType *player_ptr, effect_monster_type *em_ptr)
117 {
118     if (em_ptr->seen) {
119         em_ptr->obvious = true;
120     }
121
122     int vir = virtue_number(player_ptr, Virtue::UNLIFE);
123     if (vir) {
124         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
125     }
126
127     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
128     if (vir) {
129         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
130     }
131
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;
135         if (one_in_(4)) {
136             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
137         }
138     } else if (has_aggravate(player_ptr)) {
139         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
140         if (one_in_(4)) {
141             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
142         }
143     } else {
144         em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
145         set_pet(player_ptr, em_ptr->m_ptr);
146     }
147
148     em_ptr->dam = 0;
149     return ProcessResult::PROCESS_CONTINUE;
150 }
151
152 ProcessResult effect_monster_control_animal(PlayerType *player_ptr, effect_monster_type *em_ptr)
153 {
154     if (em_ptr->seen) {
155         em_ptr->obvious = true;
156     }
157
158     int vir = virtue_number(player_ptr, Virtue::NATURE);
159     if (vir) {
160         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
161     }
162
163     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
164     if (vir) {
165         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
166     }
167
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;
171         if (one_in_(4)) {
172             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
173         }
174     } else if (has_aggravate(player_ptr)) {
175         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
176         if (one_in_(4)) {
177             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
178         }
179     } else {
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);
184         }
185     }
186
187     em_ptr->dam = 0;
188     return ProcessResult::PROCESS_CONTINUE;
189 }
190
191 ProcessResult effect_monster_charm_living(PlayerType *player_ptr, effect_monster_type *em_ptr)
192 {
193     int vir = virtue_number(player_ptr, Virtue::UNLIFE);
194     if (em_ptr->seen) {
195         em_ptr->obvious = true;
196     }
197
198     vir = virtue_number(player_ptr, Virtue::UNLIFE);
199     if (vir) {
200         em_ptr->dam -= player_ptr->virtues[vir - 1] / 10;
201     }
202
203     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
204     if (vir) {
205         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
206     }
207
208     msg_format(_("%sを見つめた。", "You stare at %s."), em_ptr->m_name);
209
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;
213         if (one_in_(4)) {
214             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
215         }
216     } else if (has_aggravate(player_ptr)) {
217         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
218         if (one_in_(4)) {
219             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
220         }
221     } else {
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);
226         }
227     }
228
229     em_ptr->dam = 0;
230     return ProcessResult::PROCESS_CONTINUE;
231 }
232
233 static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr, effect_monster_type *em_ptr)
234 {
235     BadStatusSetter bss(player_ptr);
236     switch (randint1(4)) {
237     case 1:
238         (void)bss.mod_stun(em_ptr->dam / 2);
239         return;
240     case 2:
241         (void)bss.mod_confusion(em_ptr->dam / 2);
242         return;
243     default:
244         if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
245             em_ptr->note = _("には効果がなかった。", " is unaffected.");
246         } else {
247             (void)bss.mod_fear(static_cast<TIME_EFFECT>(em_ptr->dam));
248         }
249
250         return;
251     }
252 }
253
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)
256 {
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));
258     if (!is_corrupted) {
259         em_ptr->note = _("には効果がなかった。", " is unaffected.");
260         em_ptr->obvious = false;
261         return;
262     }
263
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!")),
267         em_ptr->m_name);
268     if (randint0(100 + em_ptr->r_ptr->level / 2) < player_ptr->skill_sav) {
269         msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
270         return;
271     }
272
273     effect_monster_domination_corrupted_addition(player_ptr, em_ptr);
274 }
275
276 static void effect_monster_domination_addition(effect_monster_type *em_ptr)
277 {
278     switch (randint1(4)) {
279     case 1:
280         em_ptr->do_stun = em_ptr->dam / 2;
281         break;
282     case 2:
283         em_ptr->do_conf = em_ptr->dam / 2;
284         break;
285     default:
286         em_ptr->do_fear = em_ptr->dam;
287     }
288 }
289
290 ProcessResult effect_monster_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
291 {
292     if (!em_ptr->m_ptr->is_hostile()) {
293         return ProcessResult::PROCESS_CONTINUE;
294     }
295
296     if (em_ptr->seen) {
297         em_ptr->obvious = true;
298     }
299
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);
306         }
307
308         em_ptr->do_conf = 0;
309         effect_monster_domination_corrupted(player_ptr, em_ptr);
310         em_ptr->dam = 0;
311         return ProcessResult::PROCESS_CONTINUE;
312     }
313
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);
317         em_ptr->dam = 0;
318         return ProcessResult::PROCESS_CONTINUE;
319     }
320
321     effect_monster_domination_addition(em_ptr);
322     em_ptr->dam = 0;
323     return ProcessResult::PROCESS_CONTINUE;
324 }
325
326 static bool effect_monster_crusade_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
327 {
328     if ((em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) || player_ptr->current_floor_ptr->inside_arena) {
329         return false;
330     }
331
332     if (em_ptr->r_ptr->flags3 & RF3_NO_CONF) {
333         em_ptr->dam -= 50;
334     }
335     if (em_ptr->dam < 1) {
336         em_ptr->dam = 1;
337     }
338
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);
342         return true;
343     }
344
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);
350
351     if (failed) {
352         if (one_in_(4)) {
353             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
354         }
355
356         return false;
357     }
358
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);
364     }
365
366     return true;
367 }
368
369 ProcessResult effect_monster_crusade(PlayerType *player_ptr, effect_monster_type *em_ptr)
370 {
371     if (em_ptr->seen) {
372         em_ptr->obvious = true;
373     }
374     bool success = effect_monster_crusade_domination(player_ptr, em_ptr);
375     if (success) {
376         em_ptr->dam = 0;
377         return ProcessResult::PROCESS_CONTINUE;
378     }
379
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;
384     }
385
386     em_ptr->dam = 0;
387     return ProcessResult::PROCESS_CONTINUE;
388 }
389
390 /*!
391  * @brief モンスターボールで捕まえられる最大HPを計算する
392  * @param player_ptr プレイヤー情報への参照ポインタ
393  * @param m_ptr モンスター情報への参照ポインタ
394  * @param hp 計算対象のHP
395  * @return 捕まえられる最大HP
396  */
397 static int calcutate_capturable_hp(PlayerType *player_ptr, MonsterEntity *m_ptr, int hp)
398 {
399     if (m_ptr->is_pet()) {
400         return hp * 4L;
401     }
402
403     if (PlayerClass(player_ptr).equals(PlayerClassType::BEASTMASTER) && m_ptr->has_living_flag()) {
404         return hp * 3 / 10;
405     }
406
407     return hp * 3 / 20;
408 }
409
410 /*!
411  * @brief モンスターボールで捕らえた処理
412  * @param player_ptr プレイヤー情報への参照ポインタ
413  * @param em_ptr 効果情報への参照ポインタ
414  */
415 static void effect_monster_captured(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> tmp_cap_mon_ptr)
416 {
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);
419     }
420
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)));
430     }
431
432     delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
433     calculate_upkeep(player_ptr);
434 }
435
436 /*!
437  * @brief モンスターボールで捕らえる効果(CAPTURE)
438  * @param player_ptr プレイヤー情報への参照ポインタ
439  * @param em_ptr 効果情報への参照ポインタ
440  * @return 効果発動結果
441  */
442 ProcessResult effect_monster_capture(PlayerType *player_ptr, effect_monster_type *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
443 {
444     const auto &quest_list = QuestList::get_instance();
445     auto *floor_ptr = player_ptr->current_floor_ptr;
446
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();
450
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;
461     }
462
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));
466
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;
471     }
472
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;
476     }
477
478     msg_print(_("うまく捕まえられなかった。", format("You failed to capture %s.", em_ptr->m_name)));
479     em_ptr->skipped = true;
480     return ProcessResult::PROCESS_CONTINUE;
481 }