OSDN Git Service

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