OSDN Git Service

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