OSDN Git Service

949f0b1646e992643406a505d26dfbc0fa872cbf
[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-race-definition.h"
29 #include "system/monster-type-definition.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     } else if (has_aggravate(player_ptr)) {
43         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
44         if (one_in_(4))
45             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
46     } else {
47         em_ptr->note = _("は突然友好的になったようだ!", " suddenly seems friendly!");
48         set_pet(player_ptr, em_ptr->m_ptr);
49
50         chg_virtue(player_ptr, V_INDIVIDUALISM, -1);
51         if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL))
52             chg_virtue(player_ptr, V_NATURE, 1);
53     }
54 }
55
56 process_result effect_monster_charm(PlayerType *player_ptr, effect_monster_type *em_ptr)
57 {
58     int vir = virtue_number(player_ptr, V_HARMONY);
59     if (vir) {
60         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
61     }
62
63     vir = virtue_number(player_ptr, V_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     effect_monster_charm_resist(player_ptr, em_ptr);
72     em_ptr->dam = 0;
73     return PROCESS_CONTINUE;
74 }
75
76 process_result effect_monster_control_undead(PlayerType *player_ptr, effect_monster_type *em_ptr)
77 {
78     if (em_ptr->seen)
79         em_ptr->obvious = true;
80
81     int vir = virtue_number(player_ptr, V_UNLIFE);
82     if (vir) {
83         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
84     }
85
86     vir = virtue_number(player_ptr, V_INDIVIDUALISM);
87     if (vir) {
88         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
89     }
90
91     if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNDEAD)) {
92         em_ptr->note = _("には効果がなかった。", " is unaffected.");
93         em_ptr->obvious = false;
94         if (one_in_(4))
95             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
96     } else if (has_aggravate(player_ptr)) {
97         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
98         if (one_in_(4))
99             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
100     } else {
101         em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
102         set_pet(player_ptr, em_ptr->m_ptr);
103     }
104
105     em_ptr->dam = 0;
106     return PROCESS_CONTINUE;
107 }
108
109 process_result effect_monster_control_demon(PlayerType *player_ptr, effect_monster_type *em_ptr)
110 {
111     if (em_ptr->seen)
112         em_ptr->obvious = true;
113
114     int vir = virtue_number(player_ptr, V_UNLIFE);
115     if (vir) {
116         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
117     }
118
119     vir = virtue_number(player_ptr, V_INDIVIDUALISM);
120     if (vir) {
121         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
122     }
123
124     if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::DEMON)) {
125         em_ptr->note = _("には効果がなかった。", " is unaffected.");
126         em_ptr->obvious = false;
127         if (one_in_(4))
128             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
129     } else if (has_aggravate(player_ptr)) {
130         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
131         if (one_in_(4))
132             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
133     } else {
134         em_ptr->note = _("は既にあなたの奴隷だ!", " is in your thrall!");
135         set_pet(player_ptr, em_ptr->m_ptr);
136     }
137
138     em_ptr->dam = 0;
139     return PROCESS_CONTINUE;
140 }
141
142 process_result effect_monster_control_animal(PlayerType *player_ptr, effect_monster_type *em_ptr)
143 {
144     if (em_ptr->seen)
145         em_ptr->obvious = true;
146
147     int vir = virtue_number(player_ptr, V_NATURE);
148     if (vir) {
149         em_ptr->dam += player_ptr->virtues[vir - 1] / 10;
150     }
151
152     vir = virtue_number(player_ptr, V_INDIVIDUALISM);
153     if (vir) {
154         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
155     }
156
157     if (common_saving_throw_control(player_ptr, em_ptr->dam, em_ptr->m_ptr) || em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::ANIMAL)) {
158         em_ptr->note = _("には効果がなかった。", " is unaffected.");
159         em_ptr->obvious = false;
160         if (one_in_(4))
161             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
162     } else if (has_aggravate(player_ptr)) {
163         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
164         if (one_in_(4))
165             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
166     } else {
167         em_ptr->note = _("はなついた。", " is tamed!");
168         set_pet(player_ptr, em_ptr->m_ptr);
169         if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL))
170             chg_virtue(player_ptr, V_NATURE, 1);
171     }
172
173     em_ptr->dam = 0;
174     return PROCESS_CONTINUE;
175 }
176
177 process_result effect_monster_charm_living(PlayerType *player_ptr, effect_monster_type *em_ptr)
178 {
179     int vir = virtue_number(player_ptr, V_UNLIFE);
180     if (em_ptr->seen)
181         em_ptr->obvious = true;
182
183     vir = virtue_number(player_ptr, V_UNLIFE);
184     if (vir) {
185         em_ptr->dam -= player_ptr->virtues[vir - 1] / 10;
186     }
187
188     vir = virtue_number(player_ptr, V_INDIVIDUALISM);
189     if (vir) {
190         em_ptr->dam -= player_ptr->virtues[vir - 1] / 20;
191     }
192
193     msg_format(_("%sを見つめた。", "You stare at %s."), em_ptr->m_name);
194
195     if (common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr) || !monster_living(em_ptr->m_ptr->r_idx)) {
196         em_ptr->note = _("には効果がなかった。", " is unaffected.");
197         em_ptr->obvious = false;
198         if (one_in_(4))
199             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
200     } else if (has_aggravate(player_ptr)) {
201         em_ptr->note = _("はあなたに敵意を抱いている!", " hates you too much!");
202         if (one_in_(4))
203             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
204     } else {
205         em_ptr->note = _("を支配した。", " is tamed!");
206         set_pet(player_ptr, em_ptr->m_ptr);
207         if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::ANIMAL))
208             chg_virtue(player_ptr, V_NATURE, 1);
209     }
210
211     em_ptr->dam = 0;
212     return PROCESS_CONTINUE;
213 }
214
215 static void effect_monster_domination_corrupted_addition(PlayerType *player_ptr, effect_monster_type *em_ptr)
216 {
217     BadStatusSetter bss(player_ptr);
218     switch (randint1(4)) {
219     case 1:
220         (void)bss.mod_stun(em_ptr->dam / 2);
221         return;
222     case 2:
223         (void)bss.mod_confusion(em_ptr->dam / 2);
224         return;
225     default:
226         if (any_bits(em_ptr->r_ptr->flags3, RF3_NO_FEAR)) {
227             em_ptr->note = _("には効果がなかった。", " is unaffected.");
228         } else {
229             (void)bss.mod_afraidness(static_cast<TIME_EFFECT>(em_ptr->dam));
230         }
231
232         return;
233     }
234 }
235
236 // Powerful demons & undead can turn a mindcrafter's attacks back on them.
237 static void effect_monster_domination_corrupted(PlayerType *player_ptr, effect_monster_type *em_ptr)
238 {
239     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));
240     if (!is_corrupted) {
241         em_ptr->note = _("には効果がなかった。", " is unaffected.");
242         em_ptr->obvious = false;
243         return;
244     }
245
246     em_ptr->note = nullptr;
247     msg_format(_("%^sの堕落した精神は攻撃を跳ね返した!",
248                    (em_ptr->seen ? "%^s's corrupted mind backlashes your attack!" : "%^ss corrupted mind backlashes your attack!")),
249         em_ptr->m_name);
250     if (randint0(100 + em_ptr->r_ptr->level / 2) < player_ptr->skill_sav) {
251         msg_print(_("しかし効力を跳ね返した!", "You resist the effects!"));
252         return;
253     }
254
255     effect_monster_domination_corrupted_addition(player_ptr, em_ptr);
256 }
257
258 static void effect_monster_domination_addition(effect_monster_type *em_ptr)
259 {
260     switch (randint1(4)) {
261     case 1:
262         em_ptr->do_stun = em_ptr->dam / 2;
263         break;
264     case 2:
265         em_ptr->do_conf = em_ptr->dam / 2;
266         break;
267     default:
268         em_ptr->do_fear = em_ptr->dam;
269     }
270 }
271
272 process_result effect_monster_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
273 {
274     if (!is_hostile(em_ptr->m_ptr))
275         return PROCESS_CONTINUE;
276
277     if (em_ptr->seen)
278         em_ptr->obvious = true;
279
280     if (em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR) || (em_ptr->r_ptr->flags3 & RF3_NO_CONF) || (em_ptr->r_ptr->level > randint1((em_ptr->dam - 10) < 1 ? 1 : (em_ptr->dam - 10)) + 10)) {
281         if (((em_ptr->r_ptr->flags3 & RF3_NO_CONF) != 0) && is_original_ap_and_seen(player_ptr, em_ptr->m_ptr))
282             em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
283
284         em_ptr->do_conf = 0;
285         effect_monster_domination_corrupted(player_ptr, em_ptr);
286         em_ptr->dam = 0;
287         return PROCESS_CONTINUE;
288     }
289
290     if (!common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr)) {
291         em_ptr->note = _("があなたに隷属した。", " is in your thrall!");
292         set_pet(player_ptr, em_ptr->m_ptr);
293         em_ptr->dam = 0;
294         return PROCESS_CONTINUE;
295     }
296
297     effect_monster_domination_addition(em_ptr);
298     em_ptr->dam = 0;
299     return PROCESS_CONTINUE;
300 }
301
302 static bool effect_monster_crusade_domination(PlayerType *player_ptr, effect_monster_type *em_ptr)
303 {
304     if ((em_ptr->r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) || player_ptr->current_floor_ptr->inside_arena)
305         return false;
306
307     if (em_ptr->r_ptr->flags3 & RF3_NO_CONF)
308         em_ptr->dam -= 50;
309     if (em_ptr->dam < 1)
310         em_ptr->dam = 1;
311
312     if (is_pet(em_ptr->m_ptr)) {
313         em_ptr->note = _("の動きが速くなった。", " starts moving faster.");
314         (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, monster_fast_remaining(em_ptr->m_ptr) + 100);
315         return true;
316     }
317
318     bool failed = any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
319     failed |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
320     failed |= em_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::NOPET);
321     failed |= has_aggravate(player_ptr);
322     failed |= (em_ptr->r_ptr->level + 10) > randint1(em_ptr->dam);
323
324     if (failed) {
325         if (one_in_(4))
326             em_ptr->m_ptr->mflag2.set(MonsterConstantFlagType::NOPET);
327
328         return false;
329     }
330
331     em_ptr->note = _("を支配した。", " is tamed!");
332     set_pet(player_ptr, em_ptr->m_ptr);
333     (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, monster_fast_remaining(em_ptr->m_ptr) + 100);
334     if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr))
335         em_ptr->r_ptr->r_kind_flags.set(MonsterKindType::GOOD);
336
337     return true;
338 }
339
340 process_result effect_monster_crusade(PlayerType *player_ptr, effect_monster_type *em_ptr)
341 {
342     if (em_ptr->seen)
343         em_ptr->obvious = true;
344     bool success = effect_monster_crusade_domination(player_ptr, em_ptr);
345     if (success) {
346         em_ptr->dam = 0;
347         return PROCESS_CONTINUE;
348     }
349
350     if ((em_ptr->r_ptr->flags3 & RF3_NO_FEAR) == 0)
351         em_ptr->do_fear = randint1(90) + 10;
352     else if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr))
353         em_ptr->r_ptr->r_flags3 |= RF3_NO_FEAR;
354
355     em_ptr->dam = 0;
356     return PROCESS_CONTINUE;
357 }
358
359 /*!
360  * @brief モンスターボールで捕まえられる最大HPを計算する
361  * @param player_ptr プレイヤー情報への参照ポインタ
362  * @param m_ptr モンスター情報への参照ポインタ
363  * @param hp 計算対象のHP
364  * @return 捕まえられる最大HP
365  */
366 static HIT_POINT calcutate_capturable_hp(PlayerType *player_ptr, monster_type *m_ptr, HIT_POINT hp)
367 {
368     if (is_pet(m_ptr))
369         return hp * 4L;
370
371     if (PlayerClass(player_ptr).equals(PlayerClassType::BEASTMASTER) && monster_living(m_ptr->r_idx))
372         return hp * 3 / 10;
373
374     return hp * 3 / 20;
375 }
376
377 /*!
378  * @brief モンスターボールで捕らえた処理
379  * @param player_ptr プレイヤー情報への参照ポインタ
380  * @param em_ptr 効果情報への参照ポインタ
381  */
382 static void effect_monster_captured(PlayerType *player_ptr, effect_monster_type *em_ptr)
383 {
384     if (em_ptr->m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON))
385         choose_new_monster(player_ptr, em_ptr->g_ptr->m_idx, false, MON_CHAMELEON);
386
387     msg_format(_("%sを捕えた!", "You capture %^s!"), em_ptr->m_name);
388     cap_mon = em_ptr->m_ptr->r_idx;
389     cap_mspeed = static_cast<byte>(em_ptr->m_ptr->mspeed);
390     cap_hp = static_cast<short>(em_ptr->m_ptr->hp);
391     cap_maxhp = static_cast<short>(em_ptr->m_ptr->max_maxhp);
392     cap_nickname = em_ptr->m_ptr->nickname;
393     if ((em_ptr->g_ptr->m_idx == player_ptr->riding) && process_fall_off_horse(player_ptr, -1, false))
394         msg_format(_("地面に落とされた。", "You have fallen from %s."), em_ptr->m_name);
395
396     delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
397     calculate_upkeep(player_ptr);
398 }
399
400 /*!
401  * @brief モンスターボールで捕らえる効果(CAPTURE)
402  * @param player_ptr プレイヤー情報への参照ポインタ
403  * @param em_ptr 効果情報への参照ポインタ
404  * @return 効果発動結果
405  */
406 process_result effect_monster_capture(PlayerType *player_ptr, effect_monster_type *em_ptr)
407 {
408     auto *floor_ptr = player_ptr->current_floor_ptr;
409
410     bool cannot_capture = (inside_quest(floor_ptr->quest_number) && (quest[enum2i(floor_ptr->quest_number)].type == QuestKindType::KILL_ALL) && !is_pet(em_ptr->m_ptr));
411     cannot_capture |= em_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE);
412     cannot_capture |= any_bits(em_ptr->r_ptr->flags1, RF1_QUESTOR);
413     cannot_capture |= any_bits(em_ptr->r_ptr->flags7, RF7_NAZGUL | RF7_UNIQUE2);
414     cannot_capture |= (em_ptr->m_ptr->parent_m_idx != 0);
415     if (cannot_capture) {
416         msg_format(_("%sには効果がなかった。", "%s is unaffected."), em_ptr->m_name);
417         em_ptr->skipped = true;
418         return PROCESS_CONTINUE;
419     }
420
421     auto r_max_hp = em_ptr->r_ptr->hdice * em_ptr->r_ptr->hside;
422     auto threshold_hp = calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, r_max_hp);
423     auto capturable_hp = std::max(2, calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, em_ptr->m_ptr->max_maxhp));
424
425     if (threshold_hp < 2 || em_ptr->m_ptr->hp >= capturable_hp) {
426         msg_format(_("もっと弱らせないと。", "You need to weaken %s more."), em_ptr->m_name);
427         em_ptr->skipped = true;
428         return PROCESS_CONTINUE;
429     }
430
431     if (em_ptr->m_ptr->hp <= randint1(capturable_hp)) {
432         effect_monster_captured(player_ptr, em_ptr);
433         return PROCESS_TRUE;
434     }
435
436     msg_format(_("うまく捕まえられなかった。", "You failed to capture %s."), em_ptr->m_name);
437     em_ptr->skipped = true;
438     return PROCESS_CONTINUE;
439 }