OSDN Git Service

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