OSDN Git Service

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