OSDN Git Service

Merge pull request #2652 from Hourier/Enter-MonsterType-Functions
[hengbandforosx/hengbandosx.git] / src / player / eldritch-horror.cpp
1 /*!
2  * @brief エルドリッチホラー処理
3  * @date 2020/06/07
4  * @author Hourier
5  */
6
7 #include "player/eldritch-horror.h"
8 #include "core/player-update-types.h"
9 #include "core/stuff-handler.h"
10 #include "locale/english.h"
11 #include "monster-race/monster-race-hook.h"
12 #include "monster-race/monster-race.h"
13 #include "monster-race/race-flags1.h"
14 #include "monster-race/race-flags2.h"
15 #include "monster-race/race-flags3.h"
16 #include "monster/horror-descriptions.h"
17 #include "monster/monster-describer.h"
18 #include "monster/monster-info.h"
19 #include "monster/monster-list.h"
20 #include "monster/monster-util.h"
21 #include "monster/smart-learn-types.h"
22 #include "mutation/mutation-flag-types.h"
23 #include "player-base/player-race.h"
24 #include "player-info/mimic-info-table.h"
25 #include "player/player-status-flags.h"
26 #include "player/player-status.h"
27 #include "status/bad-status-setter.h"
28 #include "status/base-status.h"
29 #include "system/floor-type-definition.h"
30 #include "system/monster-race-definition.h"
31 #include "system/monster-type-definition.h"
32 #include "system/player-type-definition.h"
33 #include "timed-effect/player-hallucination.h"
34 #include "timed-effect/timed-effects.h"
35 #include "view/display-messages.h"
36 #include "world/world.h"
37
38 /*!
39  * @brief エルドリッチホラーの形容詞種別を決める
40  * @param r_ptr モンスター情報への参照ポインタ
41  * @return
42  */
43 static concptr decide_horror_message(monster_race *r_ptr)
44 {
45     int horror_num = randint0(MAX_SAN_HORROR_SUM);
46     if (horror_num < MAX_SAN_HORROR_COMMON) {
47         return horror_desc_common[horror_num];
48     }
49
50     if (r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
51         return horror_desc_evil[horror_num - MAX_SAN_HORROR_COMMON];
52     }
53
54     return horror_desc_neutral[horror_num - MAX_SAN_HORROR_COMMON];
55 }
56
57 /*!
58  * @brief エルドリッチホラー持ちのモンスターを見た時の反応 (モンスター名版)
59  * @param m_name モンスター名
60  * @param r_ptr モンスター情報への参照ポインタ
61  * @todo m_nameとdescで何が違うのかは良く分からない
62  */
63 static void see_eldritch_horror(GAME_TEXT *m_name, monster_race *r_ptr)
64 {
65     concptr horror_message = decide_horror_message(r_ptr);
66     msg_format(_("%s%sの顔を見てしまった!", "You behold the %s visage of %s!"), horror_message, m_name);
67     r_ptr->r_flags2 |= RF2_ELDRITCH_HORROR;
68 }
69
70 /*!
71  * @brief エルドリッチホラー持ちのモンスターを見た時の反応 (モンスター名版)
72  * @param desc モンスター名 (エルドリッチホラー持ちの全モンスターからランダム…のはず)
73  * @param r_ptr モンスターへの参照ポインタ
74  */
75 static void feel_eldritch_horror(concptr desc, monster_race *r_ptr)
76 {
77     concptr horror_message = decide_horror_message(r_ptr);
78     msg_format(_("%s%sの顔を見てしまった!", "You behold the %s visage of %s!"), horror_message, desc);
79     r_ptr->r_flags2 |= RF2_ELDRITCH_HORROR;
80 }
81
82 /*!
83  * @brief ELDRITCH_HORRORによるプレイヤーの精神破壊処理
84  * @param m_ptr ELDRITCH_HORRORを引き起こしたモンスターの参照ポインタ。薬・罠・魔法の影響ならnullptr
85  * @param necro 暗黒領域魔法の詠唱失敗によるものならばTRUEを返す
86  */
87 void sanity_blast(PlayerType *player_ptr, monster_type *m_ptr, bool necro)
88 {
89     if (player_ptr->phase_out || !w_ptr->character_dungeon) {
90         return;
91     }
92
93     int power = 100;
94     if (!necro && m_ptr) {
95         GAME_TEXT m_name[MAX_NLEN];
96         auto *r_ptr = &r_info[m_ptr->ap_r_idx];
97         power = r_ptr->level / 2;
98         monster_desc(player_ptr, m_name, m_ptr, 0);
99         if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
100             if (r_ptr->flags1 & RF1_FRIENDS) {
101                 power /= 2;
102             }
103         } else {
104             power *= 2;
105         }
106
107         if (!w_ptr->is_loading_now) {
108             return;
109         }
110
111         if (!m_ptr->ml) {
112             return;
113         }
114
115         if (!(r_ptr->flags2 & RF2_ELDRITCH_HORROR)) {
116             return;
117         }
118
119         if (m_ptr->is_pet()) {
120             return;
121         }
122
123         if (randint1(100) > power) {
124             return;
125         }
126
127         if (saving_throw(player_ptr->skill_sav - power)) {
128             return;
129         }
130
131         if (player_ptr->effects()->hallucination()->is_hallucinated()) {
132             msg_format(_("%s%sの顔を見てしまった!", "You behold the %s visage of %s!"), funny_desc[randint0(MAX_SAN_FUNNY)], m_name);
133             if (one_in_(3)) {
134                 msg_print(funny_comments[randint0(MAX_SAN_COMMENT)]);
135                 BadStatusSetter(player_ptr).mod_hallucination(randint1(r_ptr->level));
136             }
137
138             return;
139         }
140
141         see_eldritch_horror(m_name, r_ptr);
142         switch (PlayerRace(player_ptr).life()) {
143         case PlayerRaceLifeType::DEMON:
144             return;
145         case PlayerRaceLifeType::UNDEAD:
146             if (saving_throw(25 + player_ptr->lev)) {
147                 return;
148             }
149             break;
150         default:
151             break;
152         }
153     } else if (!necro) {
154         monster_race *r_ptr;
155         GAME_TEXT m_name[MAX_NLEN];
156         concptr desc;
157         get_mon_num_prep(player_ptr, get_nightmare, nullptr);
158         r_ptr = &r_info[get_mon_num(player_ptr, 0, MAX_DEPTH, 0)];
159         power = r_ptr->level + 10;
160         desc = r_ptr->name.c_str();
161         get_mon_num_prep(player_ptr, nullptr, nullptr);
162 #ifdef JP
163 #else
164
165         if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
166             sprintf(m_name, "%s %s", (is_a_vowel(desc[0]) ? "an" : "a"), desc);
167         } else
168 #endif
169         sprintf(m_name, "%s", desc);
170
171         if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
172             if (r_ptr->flags1 & RF1_FRIENDS) {
173                 power /= 2;
174             }
175         } else {
176             power *= 2;
177         }
178
179         if (saving_throw(player_ptr->skill_sav * 100 / power)) {
180             msg_format(_("夢の中で%sに追いかけられた。", "%^s chases you through your dreams."), m_name);
181             return;
182         }
183
184         if (player_ptr->effects()->hallucination()->is_hallucinated()) {
185             msg_format(_("%s%sの顔を見てしまった!", "You behold the %s visage of %s!"), funny_desc[randint0(MAX_SAN_FUNNY)], m_name);
186             if (one_in_(3)) {
187                 msg_print(funny_comments[randint0(MAX_SAN_COMMENT)]);
188                 BadStatusSetter(player_ptr).mod_hallucination(randint1(r_ptr->level));
189             }
190
191             return;
192         }
193
194         feel_eldritch_horror(desc, r_ptr);
195         switch (PlayerRace(player_ptr).life()) {
196         case PlayerRaceLifeType::DEMON:
197             if (saving_throw(20 + player_ptr->lev)) {
198                 return;
199             }
200             break;
201         case PlayerRaceLifeType::UNDEAD:
202             if (saving_throw(10 + player_ptr->lev)) {
203                 return;
204             }
205             break;
206         default:
207             break;
208         }
209     } else {
210         msg_print(_("ネクロノミコンを読んで正気を失った!", "Your sanity is shaken by reading the Necronomicon!"));
211     }
212
213     /* 過去の効果無効率再現のため5回saving_throw 実行 */
214     if (saving_throw(player_ptr->skill_sav - power) && saving_throw(player_ptr->skill_sav - power) && saving_throw(player_ptr->skill_sav - power) && saving_throw(player_ptr->skill_sav - power) && saving_throw(player_ptr->skill_sav - power)) {
215         return;
216     }
217
218     switch (randint1(22)) {
219     case 1: {
220         if (player_ptr->muta.has_not(PlayerMutationType::MORONIC)) {
221             if ((player_ptr->stat_use[A_INT] < 4) && (player_ptr->stat_use[A_WIS] < 4)) {
222                 msg_print(_("あなたは完璧な馬鹿になったような気がした。しかしそれは元々だった。", "You turn into an utter moron!"));
223             } else {
224                 msg_print(_("あなたは完璧な馬鹿になった!", "You turn into an utter moron!"));
225             }
226
227             if (player_ptr->muta.has(PlayerMutationType::HYPER_INT)) {
228                 msg_print(_("あなたの脳は生体コンピュータではなくなった。", "Your brain is no longer a living computer."));
229                 player_ptr->muta.reset(PlayerMutationType::HYPER_INT);
230             }
231
232             player_ptr->muta.set(PlayerMutationType::MORONIC);
233         }
234
235         break;
236     }
237     case 2: {
238         if (player_ptr->muta.has_not(PlayerMutationType::COWARDICE) && !has_resist_fear(player_ptr)) {
239             msg_print(_("あなたはパラノイアになった!", "You become paranoid!"));
240             if (player_ptr->muta.has(PlayerMutationType::FEARLESS)) {
241                 msg_print(_("あなたはもう恐れ知らずではなくなった。", "You are no longer fearless."));
242                 player_ptr->muta.reset(PlayerMutationType::FEARLESS);
243             }
244
245             player_ptr->muta.set(PlayerMutationType::COWARDICE);
246         }
247
248         break;
249     }
250     case 3: {
251         if (player_ptr->muta.has_not(PlayerMutationType::HALLU) && !has_resist_chaos(player_ptr)) {
252             msg_print(_("幻覚をひき起こす精神錯乱に陥った!", "You are afflicted by a hallucinatory insanity!"));
253             player_ptr->muta.set(PlayerMutationType::HALLU);
254         }
255
256         break;
257     }
258     case 4: {
259         if (player_ptr->muta.has_not(PlayerMutationType::BERS_RAGE) && !has_resist_conf(player_ptr)) {
260             msg_print(_("激烈な感情の発作におそわれるようになった!", "You become subject to fits of berserk rage!"));
261             player_ptr->muta.set(PlayerMutationType::BERS_RAGE);
262         }
263
264         break;
265     }
266     case 5:
267     case 6:
268     case 7:
269     case 8:
270     case 9:
271     case 10:
272     case 11:
273     case 12: {
274         BadStatusSetter bss(player_ptr);
275         if (!has_resist_conf(player_ptr)) {
276             (void)bss.mod_confusion(randint0(4) + 4);
277         }
278
279         if (!has_resist_chaos(player_ptr) && one_in_(3)) {
280             (void)bss.mod_hallucination(randint0(250) + 150);
281         }
282
283         /*!< @todo いつからかは不明だがreturnとbreakが同時に存在している。どちらがデッドコードか不明瞭なので保留 */
284         return;
285         break;
286     }
287     case 13:
288     case 14:
289     case 15: {
290         BadStatusSetter bss(player_ptr);
291         if (!has_resist_conf(player_ptr)) {
292             (void)bss.mod_confusion(randint0(4) + 4);
293         }
294         if (!player_ptr->free_act) {
295             (void)bss.mod_paralysis(randint0(4) + 4);
296         }
297         if (!has_resist_chaos(player_ptr)) {
298             (void)bss.mod_hallucination(randint0(250) + 150);
299         }
300
301         do {
302             (void)do_dec_stat(player_ptr, A_INT);
303         } while (randint0(100) > player_ptr->skill_sav && one_in_(2));
304
305         do {
306             (void)do_dec_stat(player_ptr, A_WIS);
307         } while (randint0(100) > player_ptr->skill_sav && one_in_(2));
308
309         break;
310     }
311     case 16:
312     case 17: {
313         if (lose_all_info(player_ptr)) {
314             msg_print(_("あまりの恐怖に全てのことを忘れてしまった!", "You forget everything in your utmost terror!"));
315         }
316         break;
317     }
318     case 18:
319     case 19:
320     case 20:
321     case 21:
322     case 22: {
323         do_dec_stat(player_ptr, A_INT);
324         do_dec_stat(player_ptr, A_WIS);
325         break;
326     }
327     default:
328         break;
329     }
330
331     player_ptr->update |= PU_BONUS;
332     handle_stuff(player_ptr);
333 }