OSDN Git Service

1cea78108bd85713ccfcab4e6f3bd49221276a82
[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-race-hook.h"
8 #include "monster-race/monster-race.h"
9 #include "monster-race/race-flags1.h"
10 #include "monster-race/race-flags3.h"
11 #include "monster-race/race-flags7.h"
12 #include "monster-race/race-indice-types.h"
13 #include "monster/monster-flag-types.h"
14 #include "monster/monster-info.h"
15 #include "monster/monster-list.h"
16 #include "monster/monster-status-setter.h"
17 #include "monster/monster-status.h"
18 #include "object-enchant/trc-types.h"
19 #include "pet/pet-fall-off.h"
20 #include "pet/pet-util.h"
21 #include "player/player-status-flags.h"
22 #include "spell/spells-diceroll.h"
23 #include "status/bad-status-setter.h"
24 #include "system/floor-type-definition.h"
25 #include "system/grid-type-definition.h"
26 #include "system/monster-race-definition.h"
27 #include "system/monster-type-definition.h"
28 #include "system/player-type-definition.h"
29 #include "timed-effect/player-stun.h"
30 #include "timed-effect/timed-effects.h"
31 #include "util/bit-flags-calculator.h"
32 #include "view/display-messages.h"
33
34 static void effect_monster_charm_resist(player_type *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(MFLAG2::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(MFLAG2::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->flags3 & RF3_ANIMAL)
52             chg_virtue(player_ptr, V_NATURE, 1);
53     }
54 }
55
56 process_result effect_monster_charm(player_type *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(player_type *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->flags3 & RF3_UNDEAD)) {
92         em_ptr->note = _("には効果がなかった。", " is unaffected.");
93         em_ptr->obvious = false;
94         if (one_in_(4))
95             em_ptr->m_ptr->mflag2.set(MFLAG2::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(MFLAG2::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(player_type *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->flags3 & RF3_DEMON)) {
125         em_ptr->note = _("には効果がなかった。", " is unaffected.");
126         em_ptr->obvious = false;
127         if (one_in_(4))
128             em_ptr->m_ptr->mflag2.set(MFLAG2::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(MFLAG2::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(player_type *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->flags3 & RF3_ANIMAL)) {
158         em_ptr->note = _("には効果がなかった。", " is unaffected.");
159         em_ptr->obvious = false;
160         if (one_in_(4))
161             em_ptr->m_ptr->mflag2.set(MFLAG2::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(MFLAG2::NOPET);
166     } else {
167         em_ptr->note = _("はなついた。", " is tamed!");
168         set_pet(player_ptr, em_ptr->m_ptr);
169         if (em_ptr->r_ptr->flags3 & RF3_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(player_type *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(MFLAG2::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(MFLAG2::NOPET);
204     } else {
205         em_ptr->note = _("を支配した。", " is tamed!");
206         set_pet(player_ptr, em_ptr->m_ptr);
207         if (em_ptr->r_ptr->flags3 & RF3_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(player_type *player_ptr, effect_monster_type *em_ptr)
216 {
217     BadStatusSetter bss(player_ptr);
218     switch (randint1(4)) {
219     case 1:
220         (void)bss.stun(player_ptr->effects()->stun()->current() + em_ptr->dam / 2);
221         return;
222     case 2:
223         (void)bss.confusion(player_ptr->confused + 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.afraidness(player_ptr->afraid + 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(player_type *player_ptr, effect_monster_type *em_ptr)
238 {
239     bool is_corrupted = ((em_ptr->r_ptr->flags3 & (RF3_UNDEAD | RF3_DEMON)) != 0) && (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(player_type *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->flags1 & (RF1_UNIQUE | RF1_QUESTOR)) || (em_ptr->r_ptr->flags3 & RF3_NO_CONF)
281         || (em_ptr->r_ptr->level > randint1((em_ptr->dam - 10) < 1 ? 1 : (em_ptr->dam - 10)) + 10)) {
282         if (((em_ptr->r_ptr->flags3 & RF3_NO_CONF) != 0) && is_original_ap_and_seen(player_ptr, em_ptr->m_ptr))
283             em_ptr->r_ptr->r_flags3 |= (RF3_NO_CONF);
284
285         em_ptr->do_conf = 0;
286         effect_monster_domination_corrupted(player_ptr, em_ptr);
287         em_ptr->dam = 0;
288         return PROCESS_CONTINUE;
289     }
290
291     if (!common_saving_throw_charm(player_ptr, em_ptr->dam, em_ptr->m_ptr)) {
292         em_ptr->note = _("があなたに隷属した。", " is in your thrall!");
293         set_pet(player_ptr, em_ptr->m_ptr);
294         em_ptr->dam = 0;
295         return PROCESS_CONTINUE;
296     }
297
298     effect_monster_domination_addition(em_ptr);
299     em_ptr->dam = 0;
300     return PROCESS_CONTINUE;
301 }
302
303 static bool effect_monster_crusade_domination(player_type *player_ptr, effect_monster_type *em_ptr)
304 {
305     if (((em_ptr->r_ptr->flags3 & RF3_GOOD) == 0) || player_ptr->current_floor_ptr->inside_arena)
306         return false;
307
308     if (em_ptr->r_ptr->flags3 & RF3_NO_CONF)
309         em_ptr->dam -= 50;
310     if (em_ptr->dam < 1)
311         em_ptr->dam = 1;
312
313     if (is_pet(em_ptr->m_ptr)) {
314         em_ptr->note = _("の動きが速くなった。", " starts moving faster.");
315         (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, monster_fast_remaining(em_ptr->m_ptr) + 100);
316         return true;
317     }
318
319     if ((em_ptr->r_ptr->flags1 & RF1_QUESTOR) || (em_ptr->r_ptr->flags1 & RF1_UNIQUE) || em_ptr->m_ptr->mflag2.has(MFLAG2::NOPET) || has_aggravate(player_ptr)
320         || ((em_ptr->r_ptr->level + 10) > randint1(em_ptr->dam))) {
321         if (one_in_(4))
322             em_ptr->m_ptr->mflag2.set(MFLAG2::NOPET);
323
324         return false;
325     }
326
327     em_ptr->note = _("を支配した。", " is tamed!");
328     set_pet(player_ptr, em_ptr->m_ptr);
329     (void)set_monster_fast(player_ptr, em_ptr->g_ptr->m_idx, monster_fast_remaining(em_ptr->m_ptr) + 100);
330     if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr))
331         em_ptr->r_ptr->r_flags3 |= RF3_GOOD;
332
333     return true;
334 }
335
336 process_result effect_monster_crusade(player_type *player_ptr, effect_monster_type *em_ptr)
337 {
338     if (em_ptr->seen)
339         em_ptr->obvious = true;
340     bool success = effect_monster_crusade_domination(player_ptr, em_ptr);
341     if (success) {
342         em_ptr->dam = 0;
343         return PROCESS_CONTINUE;
344     }
345
346     if ((em_ptr->r_ptr->flags3 & RF3_NO_FEAR) == 0)
347         em_ptr->do_fear = randint1(90) + 10;
348     else if (is_original_ap_and_seen(player_ptr, em_ptr->m_ptr))
349         em_ptr->r_ptr->r_flags3 |= RF3_NO_FEAR;
350
351     em_ptr->dam = 0;
352     return PROCESS_CONTINUE;
353 }
354
355 /*!
356  * @brief モンスターボールで捕まえられる最大HPを計算する
357  * @param player_ptr プレイヤー情報への参照ポインタ
358  * @param m_ptr モンスター情報への参照ポインタ
359  * @param hp 計算対象のHP
360  * @return 捕まえられる最大HP
361  */
362 static HIT_POINT calcutate_capturable_hp(player_type *player_ptr, monster_type *m_ptr, HIT_POINT hp)
363 {
364     if (is_pet(m_ptr))
365         return hp * 4L;
366
367     if ((player_ptr->pclass == CLASS_BEASTMASTER) && monster_living(m_ptr->r_idx))
368         return hp * 3 / 10;
369
370     return hp * 3 / 20;
371 }
372
373 /*!
374  * @brief モンスターボールで捕らえた処理
375  * @param player_ptr プレイヤー情報への参照ポインタ
376  * @param em_ptr 効果情報への参照ポインタ
377  */
378 static void effect_monster_captured(player_type *player_ptr, effect_monster_type *em_ptr)
379 {
380     if (em_ptr->m_ptr->mflag2.has(MFLAG2::CHAMELEON))
381         choose_new_monster(player_ptr, em_ptr->g_ptr->m_idx, false, MON_CHAMELEON);
382
383     msg_format(_("%sを捕えた!", "You capture %^s!"), em_ptr->m_name);
384     cap_mon = em_ptr->m_ptr->r_idx;
385     cap_mspeed = em_ptr->m_ptr->mspeed;
386     cap_hp = em_ptr->m_ptr->hp;
387     cap_maxhp = em_ptr->m_ptr->max_maxhp;
388     cap_nickname = em_ptr->m_ptr->nickname;
389     if ((em_ptr->g_ptr->m_idx == player_ptr->riding) && process_fall_off_horse(player_ptr, -1, false))
390         msg_format(_("地面に落とされた。", "You have fallen from %s."), em_ptr->m_name);
391
392     delete_monster_idx(player_ptr, em_ptr->g_ptr->m_idx);
393     calculate_upkeep(player_ptr);
394 }
395
396 /*!
397  * @brief モンスターボールで捕らえる効果(GF_CAPTURE)
398  * @param player_ptr プレイヤー情報への参照ポインタ
399  * @param em_ptr 効果情報への参照ポインタ
400  * @return 効果発動結果
401  */
402 process_result effect_monster_capture(player_type *player_ptr, effect_monster_type *em_ptr)
403 {
404     floor_type *floor_ptr = player_ptr->current_floor_ptr;
405     if ((floor_ptr->inside_quest && (quest[floor_ptr->inside_quest].type == QUEST_TYPE_KILL_ALL) && !is_pet(em_ptr->m_ptr))
406         || any_bits(em_ptr->r_ptr->flags1, RF1_UNIQUE | RF1_QUESTOR) || any_bits(em_ptr->r_ptr->flags7, RF7_NAZGUL | RF7_UNIQUE2)
407         || em_ptr->m_ptr->parent_m_idx) {
408         msg_format(_("%sには効果がなかった。", "%s is unaffected."), em_ptr->m_name);
409         em_ptr->skipped = true;
410         return PROCESS_CONTINUE;
411     }
412
413     auto r_max_hp = em_ptr->r_ptr->hdice * em_ptr->r_ptr->hside;
414     auto threshold_hp = calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, r_max_hp);
415     auto capturable_hp = MAX(2, calcutate_capturable_hp(player_ptr, em_ptr->m_ptr, em_ptr->m_ptr->max_maxhp));
416
417     if (threshold_hp < 2 || em_ptr->m_ptr->hp >= capturable_hp) {
418         msg_format(_("もっと弱らせないと。", "You need to weaken %s more."), em_ptr->m_name);
419         em_ptr->skipped = true;
420         return PROCESS_CONTINUE;
421     }
422
423     if (em_ptr->m_ptr->hp <= randint1(capturable_hp)) {
424         effect_monster_captured(player_ptr, em_ptr);
425         return PROCESS_TRUE;
426     }
427
428     msg_format(_("うまく捕まえられなかった。", "You failed to capture %s."), em_ptr->m_name);
429     em_ptr->skipped = true;
430     return PROCESS_CONTINUE;
431 }