OSDN Git Service

[Refactor] #38844 Continued removing inclusion of monster-race.h in angband.h
[hengband/hengband.git] / src / spell-kind / spells-sight.c
1 #include "spell-kind/spells-sight.h"
2 #include "core/stuff-handler.h"
3 #include "effect/effect-characteristics.h"
4 #include "floor/floor.h"
5 #include "game-option/birth-options.h"
6 #include "io/input-key-acceptor.h"
7 #include "locale/english.h"
8 #include "lore/lore-store.h"
9 #include "monster-race/monster-race.h"
10 #include "monster-race/race-flags3.h"
11 #include "monster/monster-describer.h"
12 #include "monster/monster-description-types.h"
13 #include "monster/monster-flag-types.h"
14 #include "monster/monster-info.h"
15 #include "monster/monster-status.h"
16 #include "monster/smart-learn-types.h"
17 #include "player/avatar.h"
18 #include "spell/process-effect.h"
19 #include "spell/spell-types.h"
20 #include "term/screen-processor.h"
21 #include "view/display-main-window.h"
22 #include "view/display-messages.h"
23
24 /*!
25  * @brief 視界内モンスターに魔法効果を与える / Apply a "project()" directly to all viewable monsters
26  * @param typ 属性効果
27  * @param dam 効果量
28  * @return 効力があった場合TRUEを返す
29  * @details
30  * <pre>
31  * Note that affected monsters are NOT auto-tracked by this usage.
32  *
33  * To avoid misbehavior when monster deaths have side-effects,
34  * this is done in two passes. -- JDL
35  * </pre>
36  */
37 bool project_all_los(player_type *caster_ptr, EFFECT_ID typ, HIT_POINT dam)
38 {
39     for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
40         monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
41         if (!monster_is_valid(m_ptr))
42             continue;
43
44         POSITION y = m_ptr->fy;
45         POSITION x = m_ptr->fx;
46         if (!player_has_los_bold(caster_ptr, y, x) || !projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x))
47             continue;
48
49         m_ptr->mflag |= (MFLAG_LOS);
50     }
51
52     BIT_FLAGS flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE;
53     bool obvious = FALSE;
54     for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
55         monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
56         if (!(m_ptr->mflag & (MFLAG_LOS)))
57             continue;
58
59         m_ptr->mflag &= ~(MFLAG_LOS);
60         POSITION y = m_ptr->fy;
61         POSITION x = m_ptr->fx;
62
63         if (project(caster_ptr, 0, 0, y, x, dam, typ, flg, -1))
64             obvious = TRUE;
65     }
66
67     return obvious;
68 }
69
70 /*!
71  * @brief 視界内モンスターを加速する処理 / Speed monsters
72  * @param caster_ptr プレーヤーへの参照ポインタ
73  * @return 効力があった場合TRUEを返す
74  */
75 bool speed_monsters(player_type *caster_ptr) { return (project_all_los(caster_ptr, GF_OLD_SPEED, caster_ptr->lev)); }
76
77 /*!
78  * @brief 視界内モンスターを加速する処理 / Slow monsters
79  * @param caster_ptr プレーヤーへの参照ポインタ
80  * @return 効力があった場合TRUEを返す
81  */
82 bool slow_monsters(player_type *caster_ptr, int power) { return (project_all_los(caster_ptr, GF_OLD_SLOW, power)); }
83
84 /*!
85  * @brief 視界内モンスターを眠らせる処理 / Sleep monsters
86  * @param caster_ptr プレーヤーへの参照ポインタ
87  * @return 効力があった場合TRUEを返す
88  */
89 bool sleep_monsters(player_type *caster_ptr, int power) { return (project_all_los(caster_ptr, GF_OLD_SLEEP, power)); }
90
91 /*!
92  * @brief 視界内の邪悪なモンスターをテレポート・アウェイさせる処理 / Banish evil monsters
93  * @param caster_ptr プレーヤーへの参照ポインタ
94  * @return 効力があった場合TRUEを返す
95  */
96 bool banish_evil(player_type *caster_ptr, int dist) { return (project_all_los(caster_ptr, GF_AWAY_EVIL, dist)); }
97
98 /*!
99  * @brief 視界内のアンデッド・モンスターを恐怖させる処理 / Turn undead
100  * @return 効力があった場合TRUEを返す
101  */
102 bool turn_undead(player_type *caster_ptr)
103 {
104     bool tester = (project_all_los(caster_ptr, GF_TURN_UNDEAD, caster_ptr->lev));
105     if (tester)
106         chg_virtue(caster_ptr, V_UNLIFE, -1);
107     return tester;
108 }
109
110 /*!
111  * @brief 視界内のアンデッド・モンスターにダメージを与える処理 / Dispel undead monsters
112  * @param caster_ptr プレーヤーへの参照ポインタ
113  * @return 効力があった場合TRUEを返す
114  */
115 bool dispel_undead(player_type *caster_ptr, HIT_POINT dam)
116 {
117     bool tester = (project_all_los(caster_ptr, GF_DISP_UNDEAD, dam));
118     if (tester)
119         chg_virtue(caster_ptr, V_UNLIFE, -2);
120     return tester;
121 }
122
123 /*!
124  * @brief 視界内の邪悪なモンスターにダメージを与える処理 / Dispel evil monsters
125  * @param caster_ptr プレーヤーへの参照ポインタ
126  * @return 効力があった場合TRUEを返す
127  */
128 bool dispel_evil(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_DISP_EVIL, dam)); }
129
130 /*!
131  * @brief 視界内の善良なモンスターにダメージを与える処理 / Dispel good monsters
132  * @param caster_ptr プレーヤーへの参照ポインタ
133  * @return 効力があった場合TRUEを返す
134  */
135 bool dispel_good(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_DISP_GOOD, dam)); }
136
137 /*!
138  * @brief 視界内のあらゆるモンスターにダメージを与える処理 / Dispel all monsters
139  * @param caster_ptr プレーヤーへの参照ポインタ
140  * @return 効力があった場合TRUEを返す
141  */
142 bool dispel_monsters(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_DISP_ALL, dam)); }
143
144 /*!
145  * @brief 視界内の生命のあるモンスターにダメージを与える処理 / Dispel 'living' monsters
146  * @param caster_ptr プレーヤーへの参照ポインタ
147  * @return 効力があった場合TRUEを返す
148  */
149 bool dispel_living(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_DISP_LIVING, dam)); }
150
151 /*!
152  * @brief 視界内の悪魔系モンスターにダメージを与える処理 / Dispel 'living' monsters
153  * @param caster_ptr プレーヤーへの参照ポインタ
154  * @return 効力があった場合TRUEを返す
155  */
156 bool dispel_demons(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_DISP_DEMON, dam)); }
157
158 /*!
159  * @brief 視界内のモンスターに「聖戦」効果を与える処理
160  * @param caster_ptr プレーヤーへの参照ポインタ
161  * @return 効力があった場合TRUEを返す
162  */
163 bool crusade(player_type *caster_ptr) { return (project_all_los(caster_ptr, GF_CRUSADE, caster_ptr->lev * 4)); }
164
165 /*!
166  * @brief 視界内モンスターを怒らせる処理 / Wake up all monsters, and speed up "los" monsters.
167  * @param caster_ptr プレーヤーへの参照ポインタ
168  * @param who 怒らせる原因を起こしたモンスター(0ならばプレイヤー)
169  * @return なし
170  */
171 void aggravate_monsters(player_type *caster_ptr, MONSTER_IDX who)
172 {
173     bool sleep = FALSE;
174     bool speed = FALSE;
175     for (MONSTER_IDX i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
176         monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
177         if (!monster_is_valid(m_ptr))
178             continue;
179         if (i == who)
180             continue;
181
182         if (m_ptr->cdis < MAX_SIGHT * 2) {
183             if (monster_csleep_remaining(m_ptr)) {
184                 (void)set_monster_csleep(caster_ptr, i, 0);
185                 sleep = TRUE;
186             }
187
188             if (!is_pet(m_ptr))
189                 m_ptr->mflag2 |= MFLAG2_NOPET;
190         }
191
192         if (player_has_los_bold(caster_ptr, m_ptr->fy, m_ptr->fx)) {
193             if (!is_pet(m_ptr)) {
194                 (void)set_monster_fast(caster_ptr, i, monster_fast_remaining(m_ptr) + 100);
195                 speed = TRUE;
196             }
197         }
198     }
199
200     if (speed)
201         msg_print(_("付近で何かが突如興奮したような感じを受けた!", "You feel a sudden stirring nearby!"));
202     else if (sleep)
203         msg_print(_("何かが突如興奮したような騒々しい音が遠くに聞こえた!", "You hear a sudden stirring in the distance!"));
204     if (caster_ptr->riding)
205         caster_ptr->update |= PU_BONUS;
206 }
207
208 /*!
209  * @brief パニック・モンスター効果(プレイヤー視界範囲内) / Confuse monsters
210  * @param caster_ptr プレーヤーへの参照ポインタ
211  * @param dam 効力
212  * @return 作用が実際にあった場合TRUEを返す
213  */
214 bool confuse_monsters(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_OLD_CONF, dam)); }
215
216 /*!
217  * @brief チャーム・モンスター効果(プレイヤー視界範囲内) / Charm monsters
218  * @param caster_ptr プレーヤーへの参照ポインタ
219  * @param dam 効力
220  * @return 作用が実際にあった場合TRUEを返す
221  */
222 bool charm_monsters(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_CHARM, dam)); }
223
224 /*!
225  * @brief 動物魅了効果(プレイヤー視界範囲内) / Charm Animals
226  * @param caster_ptr プレーヤーへの参照ポインタ
227  * @param dam 効力
228  * @return 作用が実際にあった場合TRUEを返す
229  */
230 bool charm_animals(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_CONTROL_ANIMAL, dam)); }
231
232 /*!
233  * @brief モンスター朦朧効果(プレイヤー視界範囲内) / Stun monsters
234  * @param caster_ptr プレーヤーへの参照ポインタ
235  * @param dam 効力
236  * @return 作用が実際にあった場合TRUEを返す
237  */
238 bool stun_monsters(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_STUN, dam)); }
239
240 /*!
241  * @brief モンスター停止効果(プレイヤー視界範囲内) / Stasis monsters
242  * @param caster_ptr プレーヤーへの参照ポインタ
243  * @param dam 効力
244  * @return 作用が実際にあった場合TRUEを返す
245  */
246 bool stasis_monsters(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_STASIS, dam)); }
247
248 /*!
249  * @brief モンスター精神攻撃効果(プレイヤー視界範囲内) / Mindblast monsters
250  * @param caster_ptr プレーヤーへの参照ポインタ
251  * @param dam 効力
252  * @return 作用が実際にあった場合TRUEを返す
253  */
254 bool mindblast_monsters(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_PSI, dam)); }
255
256 /*!
257  * @brief モンスター追放効果(プレイヤー視界範囲内) / Banish all monsters
258  * @param caster_ptr プレーヤーへの参照ポインタ
259  * @param dist 効力(距離)
260  * @return 作用が実際にあった場合TRUEを返す
261  */
262 bool banish_monsters(player_type *caster_ptr, int dist) { return (project_all_los(caster_ptr, GF_AWAY_ALL, dist)); }
263
264 /*!
265  * @brief 邪悪退散効果(プレイヤー視界範囲内) / Turn evil
266  * @param caster_ptr プレーヤーへの参照ポインタ
267  * @param dam 効力
268  * @return 作用が実際にあった場合TRUEを返す
269  */
270 bool turn_evil(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_TURN_EVIL, dam)); }
271
272 /*!
273  * @brief 全モンスター退散効果(プレイヤー視界範囲内) / Turn everyone
274  * @param caster_ptr プレーヤーへの参照ポインタ
275  * @param dam 効力
276  * @return 作用が実際にあった場合TRUEを返す
277  */
278 bool turn_monsters(player_type *caster_ptr, HIT_POINT dam) { return (project_all_los(caster_ptr, GF_TURN_ALL, dam)); }
279
280 /*!
281  * @brief 死の光線(プレイヤー視界範囲内) / Death-ray all monsters (note: OBSCENELY powerful)
282  * @param caster_ptr プレーヤーへの参照ポインタ
283  * @return 作用が実際にあった場合TRUEを返す
284  */
285 bool deathray_monsters(player_type *caster_ptr) { return (project_all_los(caster_ptr, GF_DEATH_RAY, caster_ptr->lev * 200)); }
286
287 /*!
288  * @brief 周辺モンスターを調査する / Probe nearby monsters
289  * @return 効力があった場合TRUEを返す
290  */
291 bool probing(player_type *caster_ptr)
292 {
293     bool cu = Term->scr->cu;
294     bool cv = Term->scr->cv;
295     Term->scr->cu = 0;
296     Term->scr->cv = 1;
297
298     bool probe = FALSE;
299     int speed;
300     char buf[256];
301     concptr align;
302     for (int i = 1; i < caster_ptr->current_floor_ptr->m_max; i++) {
303         monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[i];
304         monster_race *r_ptr = &r_info[m_ptr->r_idx];
305         if (!monster_is_valid(m_ptr))
306             continue;
307         if (!player_has_los_bold(caster_ptr, m_ptr->fy, m_ptr->fx))
308             continue;
309         if (!m_ptr->ml)
310             continue;
311
312         GAME_TEXT m_name[MAX_NLEN];
313         if (!probe)
314             msg_print(_("調査中...", "Probing..."));
315         msg_print(NULL);
316
317         if (!is_original_ap(m_ptr)) {
318             if (m_ptr->mflag2 & MFLAG2_KAGE)
319                 m_ptr->mflag2 &= ~(MFLAG2_KAGE);
320
321             m_ptr->ap_r_idx = m_ptr->r_idx;
322             lite_spot(caster_ptr, m_ptr->fy, m_ptr->fx);
323         }
324
325         monster_desc(caster_ptr, m_name, m_ptr, MD_IGNORE_HALLU | MD_INDEF_HIDDEN);
326         speed = m_ptr->mspeed - 110;
327         if (monster_fast_remaining(m_ptr))
328             speed += 10;
329         if (monster_slow_remaining(m_ptr))
330             speed -= 10;
331         if (ironman_nightmare)
332             speed += 5;
333
334         if ((r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)) == (RF3_EVIL | RF3_GOOD))
335             align = _("善悪", "good&evil");
336         else if (r_ptr->flags3 & RF3_EVIL)
337             align = _("邪悪", "evil");
338         else if (r_ptr->flags3 & RF3_GOOD)
339             align = _("善良", "good");
340         else if ((m_ptr->sub_align & (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD)) == (SUB_ALIGN_EVIL | SUB_ALIGN_GOOD))
341             align = _("中立(善悪)", "neutral(good&evil)");
342         else if (m_ptr->sub_align & SUB_ALIGN_EVIL)
343             align = _("中立(邪悪)", "neutral(evil)");
344         else if (m_ptr->sub_align & SUB_ALIGN_GOOD)
345             align = _("中立(善良)", "neutral(good)");
346         else
347             align = _("中立", "neutral");
348
349         sprintf(buf, _("%s ... 属性:%s HP:%d/%d AC:%d 速度:%s%d 経験:", "%s ... align:%s HP:%d/%d AC:%d speed:%s%d exp:"), m_name, align, (int)m_ptr->hp,
350             (int)m_ptr->maxhp, r_ptr->ac, (speed > 0) ? "+" : "", speed);
351
352         if (r_ptr->next_r_idx) {
353             strcat(buf, format("%d/%d ", m_ptr->exp, r_ptr->next_exp));
354         } else {
355             strcat(buf, "xxx ");
356         }
357
358         if (monster_csleep_remaining(m_ptr))
359             strcat(buf, _("睡眠 ", "sleeping "));
360         if (monster_stunned_remaining(m_ptr))
361             strcat(buf, _("朦朧 ", "stunned "));
362         if (monster_fear_remaining(m_ptr))
363             strcat(buf, _("恐怖 ", "scared "));
364         if (monster_confused_remaining(m_ptr))
365             strcat(buf, _("混乱 ", "confused "));
366         if (monster_invulner_remaining(m_ptr))
367             strcat(buf, _("無敵 ", "invulnerable "));
368         buf[strlen(buf) - 1] = '\0';
369         prt(buf, 0, 0);
370
371         message_add(buf);
372         caster_ptr->window |= (PW_MESSAGE);
373         handle_stuff(caster_ptr);
374         move_cursor_relative(m_ptr->fy, m_ptr->fx);
375         inkey();
376         Term_erase(0, 0, 255);
377         if (lore_do_probe(caster_ptr, m_ptr->r_idx)) {
378             strcpy(buf, (r_name + r_ptr->name));
379 #ifdef JP
380             msg_format("%sについてさらに詳しくなった気がする。", buf);
381 #else
382             plural_aux(buf);
383             msg_format("You now know more about %s.", buf);
384 #endif
385             msg_print(NULL);
386         }
387
388         probe = TRUE;
389     }
390
391     Term->scr->cu = cu;
392     Term->scr->cv = cv;
393     Term_fresh();
394
395     if (probe) {
396         chg_virtue(caster_ptr, V_KNOWLEDGE, 1);
397         msg_print(_("これで全部です。", "That's all."));
398     }
399
400     return (probe);
401 }