OSDN Git Service

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