OSDN Git Service

Merge pull request #3814 from Slimebreath6078/feature/Add_Laffey_II
[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-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"
30
31 static void effect_monster_charm_resist(PlayerType *player_ptr, EffectMonster *em_ptr)
32 {
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;
36
37         if (one_in_(4)) {
38             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
39         }
40     } else if (has_aggravate(player_ptr)) {
41         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
42         if (one_in_(4)) {
43             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
44         }
45     } else {
46         em_ptr->note = _("は突然友好的になったようだ!", " suddenly seems friendly!");
47         set_pet(player_ptr, em_ptr->m_ptr);
48
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);
52         }
53     }
54 }
55
56 ProcessResult effect_monster_charm(PlayerType *player_ptr, EffectMonster *em_ptr)
57 {
58     int vir = virtue_number(player_ptr, Virtue::HARMONY);
59     if (vir) {
60         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
61     }
62
63     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
64     if (vir) {
65         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
66     }
67
68     if (em_ptr->seen) {
69         em_ptr->obvious = true;
70     }
71
72     effect_monster_charm_resist(player_ptr, em_ptr);
73     em_ptr->dam = 0;
74     return ProcessResult::PROCESS_CONTINUE;
75 }
76
77 ProcessResult effect_monster_control_undead(PlayerType *player_ptr, EffectMonster *em_ptr)
78 {
79     if (em_ptr->seen) {
80         em_ptr->obvious = true;
81     }
82
83     int vir = virtue_number(player_ptr, Virtue::UNLIFE);
84     if (vir) {
85         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
86     }
87
88     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
89     if (vir) {
90         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
91     }
92
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;
96         if (one_in_(4)) {
97             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
98         }
99     } else if (has_aggravate(player_ptr)) {
100         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
101         if (one_in_(4)) {
102             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
103         }
104     } else {
105         em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
106         set_pet(player_ptr, em_ptr->m_ptr);
107     }
108
109     em_ptr->dam = 0;
110     return ProcessResult::PROCESS_CONTINUE;
111 }
112
113 ProcessResult effect_monster_control_demon(PlayerType *player_ptr, EffectMonster *em_ptr)
114 {
115     if (em_ptr->seen) {
116         em_ptr->obvious = true;
117     }
118
119     int vir = virtue_number(player_ptr, Virtue::UNLIFE);
120     if (vir) {
121         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
122     }
123
124     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
125     if (vir) {
126         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
127     }
128
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;
132         if (one_in_(4)) {
133             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
134         }
135     } else if (has_aggravate(player_ptr)) {
136         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
137         if (one_in_(4)) {
138             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
139         }
140     } else {
141         em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
142         set_pet(player_ptr, em_ptr->m_ptr);
143     }
144
145     em_ptr->dam = 0;
146     return ProcessResult::PROCESS_CONTINUE;
147 }
148
149 ProcessResult effect_monster_control_animal(PlayerType *player_ptr, EffectMonster *em_ptr)
150 {
151     if (em_ptr->seen) {
152         em_ptr->obvious = true;
153     }
154
155     int vir = virtue_number(player_ptr, Virtue::NATURE);
156     if (vir) {
157         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
158     }
159
160     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
161     if (vir) {
162         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
163     }
164
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;
168         if (one_in_(4)) {
169             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
170         }
171     } else if (has_aggravate(player_ptr)) {
172         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
173         if (one_in_(4)) {
174             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
175         }
176     } else {
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);
181         }
182     }
183
184     em_ptr->dam = 0;
185     return ProcessResult::PROCESS_CONTINUE;
186 }
187
188 ProcessResult effect_monster_charm_living(PlayerType *player_ptr, EffectMonster *em_ptr)
189 {
190     int vir = virtue_number(player_ptr, Virtue::UNLIFE);
191     if (em_ptr->seen) {
192         em_ptr->obvious = true;
193     }
194
195     vir = virtue_number(player_ptr, Virtue::UNLIFE);
196     if (vir) {
197         em_ptr->dam -= player_ptr->virtues[vir - 1] / 10;
198     }
199
200     vir = virtue_number(player_ptr, Virtue::INDIVIDUALISM);
201     if (vir) {
202         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
203     }
204
205     msg_format(_("%sを見つめた。", "You stare at %s."), em_ptr->m_name);
206
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;
210         if (one_in_(4)) {
211             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
212         }
213     } else if (has_aggravate(player_ptr)) {
214         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
215         if (one_in_(4)) {
216             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
217         }
218     } else {
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);
223         }
224     }
225
226     em_ptr->dam = 0;
227     return ProcessResult::PROCESS_CONTINUE;
228 }
229
230 static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr, EffectMonster *em_ptr)
231 {
232     BadStatusSetter bss(player_ptr);
233     switch (randint1(4)) {
234     case 1:
235         (void)bss.mod_stun(em_ptr->dam / 2);
236         return;
237     case 2:
238         (void)bss.mod_confusion(em_ptr->dam / 2);
239         return;
240     default:
241         if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_FEAR)) {
242             em_ptr->note = _("には効果がなかった。", " is unaffected.");
243         } else {
244             (void)bss.mod_fear(static_cast<TIME_EFFECT>(em_ptr->dam));
245         }
246
247         return;
248     }
249 }
250
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)
253 {
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));
255     if (!is_corrupted) {
256         em_ptr->note = _("には効果がなかった。", " is unaffected.");
257         em_ptr->obvious = false;
258         return;
259     }
260
261     em_ptr->note = "";
262     msg_format(_("%s^の堕落した精神は攻撃を跳ね返した!",
263                    (em_ptr->seen ? "%s^'s corrupted mind backlashes your attack!" : "%s^s corrupted mind backlashes your attack!")),
264         em_ptr->m_name);
265     if (randint0(100 + em_ptr->r_ptr->level / 2) < player_ptr->skill_sav) {
266         msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
267         return;
268     }
269
270     effect_monster_domination_corrupted_addition(player_ptr, em_ptr);
271 }
272
273 static void effect_monster_domination_addition(EffectMonster *em_ptr)
274 {
275     switch (randint1(4)) {
276     case 1:
277         em_ptr->do_stun = em_ptr->dam / 2;
278         break;
279     case 2:
280         em_ptr->do_conf = em_ptr->dam / 2;
281         break;
282     default:
283         em_ptr->do_fear = em_ptr->dam;
284     }
285 }
286
287 ProcessResult effect_monster_domination(PlayerType *player_ptr, EffectMonster *em_ptr)
288 {
289     if (!em_ptr->m_ptr->is_hostile()) {
290         return ProcessResult::PROCESS_CONTINUE;
291     }
292
293     if (em_ptr->seen) {
294         em_ptr->obvious = true;
295     }
296
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);
303         }
304
305         em_ptr->do_conf = 0;
306         effect_monster_domination_corrupted(player_ptr, em_ptr);
307         em_ptr->dam = 0;
308         return ProcessResult::PROCESS_CONTINUE;
309     }
310
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);
314         em_ptr->dam = 0;
315         return ProcessResult::PROCESS_CONTINUE;
316     }
317
318     effect_monster_domination_addition(em_ptr);
319     em_ptr->dam = 0;
320     return ProcessResult::PROCESS_CONTINUE;
321 }
322
323 static bool effect_monster_crusade_domination(PlayerType *player_ptr, EffectMonster *em_ptr)
324 {
325     if ((em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) || player_ptr->current_floor_ptr->inside_arena) {
326         return false;
327     }
328
329     if (em_ptr->r_ptr->resistance_flags.has(MonsterResistanceType::NO_CONF)) {
330         em_ptr->dam -= 50;
331     }
332     if (em_ptr->dam < 1) {
333         em_ptr->dam = 1;
334     }
335
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);
339         return true;
340     }
341
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);
347
348     if (failed) {
349         if (one_in_(4)) {
350             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
351         }
352
353         return false;
354     }
355
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);
361     }
362
363     return true;
364 }
365
366 ProcessResult effect_monster_crusade(PlayerType *player_ptr, EffectMonster *em_ptr)
367 {
368     if (em_ptr->seen) {
369         em_ptr->obvious = true;
370     }
371     bool success = effect_monster_crusade_domination(player_ptr, em_ptr);
372     if (success) {
373         em_ptr->dam = 0;
374         return ProcessResult::PROCESS_CONTINUE;
375     }
376
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);
381     }
382
383     em_ptr->dam = 0;
384     return ProcessResult::PROCESS_CONTINUE;
385 }
386
387 /*!
388  * @brief モンスターボールで捕まえられる最大HPを計算する
389  * @param player_ptr プレイヤー情報への参照ポインタ
390  * @param m_ptr モンスター情報への参照ポインタ
391  * @param hp 計算対象のHP
392  * @return 捕まえられる最大HP
393  */
394 static int calcutate_capturable_hp(PlayerType *player_ptr, MonsterEntity *m_ptr, int hp)
395 {
396     if (m_ptr->is_pet()) {
397         return hp * 4L;
398     }
399
400     if (PlayerClass(player_ptr).equals(PlayerClassType::BEASTMASTER) && m_ptr->has_living_flag()) {
401         return hp * 3 / 10;
402     }
403
404     return hp * 3 / 20;
405 }
406
407 /*!
408  * @brief モンスターボールで捕らえた処理
409  * @param player_ptr プレイヤー情報への参照ポインタ
410  * @param em_ptr 効果情報への参照ポインタ
411  */
412 static void effect_monster_captured(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> tmp_cap_mon_ptr)
413 {
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);
416     }
417
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)));
427     }
428
429     delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
430     calculate_upkeep(player_ptr);
431 }
432
433 /*!
434  * @brief モンスターボールで捕らえる効果(CAPTURE)
435  * @param player_ptr プレイヤー情報への参照ポインタ
436  * @param em_ptr 効果情報への参照ポインタ
437  * @return 効果発動結果
438  */
439 ProcessResult effect_monster_capture(PlayerType *player_ptr, EffectMonster *em_ptr, std::optional<CapturedMonsterType *> cap_mon_ptr)
440 {
441     const auto &quest_list = QuestList::get_instance();
442     auto *floor_ptr = player_ptr->current_floor_ptr;
443
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();
447
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;
458     }
459
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));
463
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;
468     }
469
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;
473     }
474
475     msg_print(_("うまく捕まえられなかった。", format("You failed to capture %s.", em_ptr->m_name)));
476     em_ptr->skipped = true;
477     return ProcessResult::PROCESS_CONTINUE;
478 }